Skip to content

Commit 7fe15ed

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::put_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 1de70d2 commit 7fe15ed

File tree

1 file changed

+26
-28
lines changed

1 file changed

+26
-28
lines changed

lib/WeBWorK/ContentGenerator/Instructor/AchievementList.pm

+26-28
Original file line numberDiff line numberDiff line change
@@ -196,50 +196,48 @@ sub edit_handler ($c) {
196196
# Handler for assigning achievements to users
197197
sub assign_handler ($c) {
198198
my $db = $c->db;
199-
my @users = $db->listUsers;
200199
my $overwrite = $c->param('action.assign.overwrite') eq 'everything';
201200
my $scope = $c->param('action.assign.scope');
202201
my @achievementIDs = $scope eq 'all' ? @{ $c->{allAchievementIDs} } : @{ $c->{selectedAchievementIDs} };
203202

204-
# Enable all achievements
205-
my @achievements = $db->getAchievements(@achievementIDs);
203+
my @users = $db->listUsers;
204+
my @achievements = $db->getAchievementsWhere({ achievement_id => \@achievementIDs });
206205

207-
for my $achievement (@achievements) {
208-
$achievement->enabled(1);
209-
$db->putAchievement($achievement);
210-
}
211-
212-
# Assign globalUserAchievement data, overwriting if necc
206+
# Enable all achievements.
207+
for my $achievement (@achievements) { $achievement->enabled(1); }
208+
$db->{achievement}->update_records(\@achievements) if @achievements;
213209

210+
# Assign globalUserAchievement data, overwriting if necessary.
211+
my (@globalAchievementRecordsToAdd, @globalAchievementRecordsToPut);
212+
my %existingGlobalUserAchievements =
213+
map { $_->user_id => $_ } $db->getGlobalUserAchievementsWhere({ user_id => \@users });
214214
for my $user (@users) {
215-
if (not $db->existsGlobalUserAchievement($user)) {
216-
my $globalUserAchievement = $db->newGlobalUserAchievement();
217-
$globalUserAchievement->user_id($user);
218-
$db->addGlobalUserAchievement($globalUserAchievement);
215+
my $globalUserAchievement = $db->newGlobalUserAchievement(user_id => $user);
216+
if (!$existingGlobalUserAchievements{$user}) {
217+
push(@globalAchievementRecordsToAdd, $globalUserAchievement);
219218
} elsif ($overwrite) {
220-
my $globalUserAchievement = $db->newGlobalUserAchievement();
221-
$globalUserAchievement->user_id($user);
222-
$db->putGlobalUserAchievement($globalUserAchievement);
219+
push(@globalAchievementRecordsToPut, $globalUserAchievement);
223220
}
224221
}
222+
$db->{global_user_achievement}->insert_records(\@globalAchievementRecordsToAdd) if @globalAchievementRecordsToAdd;
223+
$db->{global_user_achievement}->update_records(\@globalAchievementRecordsToPut) if @globalAchievementRecordsToPut;
225224

226-
# Assign userAchievement data, overwriting if necc
227-
225+
# Assign userAchievement data, overwriting if necessary.
226+
my (@userAchievementRecordsToAdd, @userAchievementRecordsToPut);
228227
for my $achievementID (@achievementIDs) {
228+
my %existingUserAchievements =
229+
map { $_->user_id => $_ } $db->getUserAchievementsWhere({ achievement_id => $achievementID });
229230
for my $user (@users) {
230-
if (not $db->existsUserAchievement($user, $achievementID)) {
231-
my $userAchievement = $db->newUserAchievement();
232-
$userAchievement->user_id($user);
233-
$userAchievement->achievement_id($achievementID);
234-
$db->addUserAchievement($userAchievement);
231+
my $userAchievement = $db->newUserAchievement(user_id => $user, achievement_id => $achievementID);
232+
if (!$existingUserAchievements{$user}) {
233+
push(@userAchievementRecordsToAdd, $userAchievement);
235234
} elsif ($overwrite) {
236-
my $userAchievement = $db->newUserAchievement();
237-
$userAchievement->user_id($user);
238-
$userAchievement->achievement_id($achievementID);
239-
$db->putUserAchievement($userAchievement);
235+
push(@userAchievementRecordsToPut, $userAchievement);
240236
}
241237
}
242238
}
239+
$db->{achievement_user}->insert_records(\@userAchievementRecordsToAdd) if @userAchievementRecordsToAdd;
240+
$db->{achievement_user}->update_records(\@userAchievementRecordsToPut) if @userAchievementRecordsToPut;
243241

244242
return (1, $c->maketext('Assigned achievements to users.'));
245243
}
@@ -462,7 +460,7 @@ sub import_handler ($c) {
462460
$count++;
463461
$allAchievementIDs{$achievement_id} = 1;
464462

465-
# Assign to usesrs if neccessary
463+
# Assign to users if necessary.
466464
if ($assign eq "all") {
467465
for my $user (@users) {
468466
if (not $db->existsGlobalUserAchievement($user)) {

0 commit comments

Comments
 (0)