Skip to content

Commit 50e7de0

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 2d4cbcc commit 50e7de0

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
@@ -196,50 +196,47 @@ 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
203+
my @users = $db->listUsers;
205204
my @achievements = $db->getAchievements(@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 = map { $_ => 1 } $db->listGlobalUserAchievements;
214213
for my $user (@users) {
215-
if (not $db->existsGlobalUserAchievement($user)) {
216-
my $globalUserAchievement = $db->newGlobalUserAchievement();
217-
$globalUserAchievement->user_id($user);
218-
$db->addGlobalUserAchievement($globalUserAchievement);
214+
my $globalUserAchievement = $db->newGlobalUserAchievement(user_id => $user);
215+
if (!$existingGlobalUserAchievements{$user}) {
216+
push(@globalAchievementRecordsToAdd, $globalUserAchievement);
219217
} elsif ($overwrite) {
220-
my $globalUserAchievement = $db->newGlobalUserAchievement();
221-
$globalUserAchievement->user_id($user);
222-
$db->putGlobalUserAchievement($globalUserAchievement);
218+
push(@globalAchievementRecordsToPut, $globalUserAchievement);
223219
}
224220
}
221+
$db->GlobalUserAchievement->insert_records(\@globalAchievementRecordsToAdd) if @globalAchievementRecordsToAdd;
222+
$db->GlobalUserAchievement->update_records(\@globalAchievementRecordsToPut) if @globalAchievementRecordsToPut;
225223

226-
# Assign userAchievement data, overwriting if necc
227-
224+
# Assign userAchievement data, overwriting if necessary.
225+
my (@userAchievementRecordsToAdd, @userAchievementRecordsToPut);
228226
for my $achievementID (@achievementIDs) {
227+
my %existingUserAchievements =
228+
map { $_->[0] => 1 } $db->listUserAchievementsWhere({ achievement_id => $achievementID });
229229
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);
230+
my $userAchievement = $db->newUserAchievement(user_id => $user, achievement_id => $achievementID);
231+
if (!$existingUserAchievements{$user}) {
232+
push(@userAchievementRecordsToAdd, $userAchievement);
235233
} elsif ($overwrite) {
236-
my $userAchievement = $db->newUserAchievement();
237-
$userAchievement->user_id($user);
238-
$userAchievement->achievement_id($achievementID);
239-
$db->putUserAchievement($userAchievement);
234+
push(@userAchievementRecordsToPut, $userAchievement);
240235
}
241236
}
242237
}
238+
$db->UserAchievement->insert_records(\@userAchievementRecordsToAdd) if @userAchievementRecordsToAdd;
239+
$db->UserAchievement->update_records(\@userAchievementRecordsToPut) if @userAchievementRecordsToPut;
243240

244241
return (1, $c->maketext('Assigned achievements to users.'));
245242
}
@@ -462,7 +459,7 @@ sub import_handler ($c) {
462459
$count++;
463460
$allAchievementIDs{$achievement_id} = 1;
464461

465-
# Assign to usesrs if neccessary
462+
# Assign to users if necessary.
466463
if ($assign eq "all") {
467464
for my $user (@users) {
468465
if (not $db->existsGlobalUserAchievement($user)) {

0 commit comments

Comments
 (0)