Skip to content

Commit d214308

Browse files
committed
Speed up assignments of achievements.
If you have payed attention (or tested openwebwork#2709 and openwebwork#2710), then you know that this takes a long time if there are a large number of users. Way to long to be at all reasonable. This uses techniques like those used for assigning multiple sets to users, i.e., the `WeBWorK::DB::Schema::NewSQL::Std::insert_records` and `WeBWorK::DB::Schema::NewSQL::Std::update_records` methods, to speed up assignment of achievements to users. This brings the assignment time for 5000 users down from more than 8 minutes, to less than 30 seconds.
1 parent 311ec9e commit d214308

File tree

1 file changed

+24
-27
lines changed

1 file changed

+24
-27
lines changed

lib/WeBWorK/ContentGenerator/Instructor/AchievementList.pm

+24-27
Original file line numberDiff line numberDiff line change
@@ -181,50 +181,47 @@ sub edit_handler ($c) {
181181
# Handler for assigning achievements to users
182182
sub assign_handler ($c) {
183183
my $db = $c->db;
184-
my @users = $db->listUsers;
185184
my $overwrite = $c->param('action.assign.overwrite') eq 'everything';
186185
my $scope = $c->param('action.assign.scope');
187186
my @achievementIDs = $scope eq 'all' ? @{ $c->{allAchievementIDs} } : @{ $c->{selectedAchievementIDs} };
188187

189-
# Enable all achievements
188+
my @users = $db->listUsers;
190189
my @achievements = $db->getAchievements(@achievementIDs);
191190

192-
for my $achievement (@achievements) {
193-
$achievement->enabled(1);
194-
$db->putAchievement($achievement);
195-
}
196-
197-
# Assign globalUserAchievement data, overwriting if necc
191+
# Enable all achievements.
192+
for my $achievement (@achievements) { $achievement->enabled(1); }
193+
$db->Achievement->update_records(\@achievements) if @achievements;
198194

195+
# Assign globalUserAchievement data, overwriting if necessary.
196+
my (@globalAchievementRecordsToAdd, @globalAchievementRecordsToPut);
197+
my %existingGlobalUserAchievements = map { $_ => 1 } $db->listGlobalUserAchievements;
199198
for my $user (@users) {
200-
if (not $db->existsGlobalUserAchievement($user)) {
201-
my $globalUserAchievement = $db->newGlobalUserAchievement();
202-
$globalUserAchievement->user_id($user);
203-
$db->addGlobalUserAchievement($globalUserAchievement);
199+
my $globalUserAchievement = $db->newGlobalUserAchievement(user_id => $user);
200+
if (!$existingGlobalUserAchievements{$user}) {
201+
push(@globalAchievementRecordsToAdd, $globalUserAchievement);
204202
} elsif ($overwrite) {
205-
my $globalUserAchievement = $db->newGlobalUserAchievement();
206-
$globalUserAchievement->user_id($user);
207-
$db->putGlobalUserAchievement($globalUserAchievement);
203+
push(@globalAchievementRecordsToPut, $globalUserAchievement);
208204
}
209205
}
206+
$db->GlobalUserAchievement->insert_records(\@globalAchievementRecordsToAdd) if @globalAchievementRecordsToAdd;
207+
$db->GlobalUserAchievement->update_records(\@globalAchievementRecordsToPut) if @globalAchievementRecordsToPut;
210208

211-
# Assign userAchievement data, overwriting if necc
212-
209+
# Assign userAchievement data, overwriting if necessary.
210+
my (@userAchievementRecordsToAdd, @userAchievementRecordsToPut);
213211
for my $achievementID (@achievementIDs) {
212+
my %existingUserAchievements =
213+
map { $_->[0] => 1 } $db->listUserAchievementsWhere({ achievement_id => $achievementID });
214214
for my $user (@users) {
215-
if (not $db->existsUserAchievement($user, $achievementID)) {
216-
my $userAchievement = $db->newUserAchievement();
217-
$userAchievement->user_id($user);
218-
$userAchievement->achievement_id($achievementID);
219-
$db->addUserAchievement($userAchievement);
215+
my $userAchievement = $db->newUserAchievement(user_id => $user, achievement_id => $achievementID);
216+
if (!$existingUserAchievements{$user}) {
217+
push(@userAchievementRecordsToAdd, $userAchievement);
220218
} elsif ($overwrite) {
221-
my $userAchievement = $db->newUserAchievement();
222-
$userAchievement->user_id($user);
223-
$userAchievement->achievement_id($achievementID);
224-
$db->putUserAchievement($userAchievement);
219+
push(@userAchievementRecordsToPut, $userAchievement);
225220
}
226221
}
227222
}
223+
$db->UserAchievement->insert_records(\@userAchievementRecordsToAdd) if @userAchievementRecordsToAdd;
224+
$db->UserAchievement->update_records(\@userAchievementRecordsToPut) if @userAchievementRecordsToPut;
228225

229226
return (1, $c->maketext('Assigned achievements to users.'));
230227
}
@@ -447,7 +444,7 @@ sub import_handler ($c) {
447444
$count++;
448445
$allAchievementIDs{$achievement_id} = 1;
449446

450-
# Assign to usesrs if neccessary
447+
# Assign to users if necessary.
451448
if ($assign eq "all") {
452449
for my $user (@users) {
453450
if (not $db->existsGlobalUserAchievement($user)) {

0 commit comments

Comments
 (0)