Skip to content

Commit 3ab1d1a

Browse files
committed
Speed up class list importing.
Use a batch insertion and update for users, permissions, and passwords when importing a class list. This improves the speed of imporing large class lists quite a bit. For example, importing a classlist containing 5000 users improves from around 22 seconds to around 7 seconds in my testing.
1 parent f18833f commit 3ab1d1a

File tree

1 file changed

+29
-27
lines changed

1 file changed

+29
-27
lines changed

lib/WeBWorK/ContentGenerator/Instructor/UserList.pm

+29-27
Original file line numberDiff line numberDiff line change
@@ -626,50 +626,47 @@ sub menuLabels ($c, $hashRef) {
626626
}
627627

628628
sub importUsersFromCSV ($c, $fileName, $replaceExisting, $fallbackPasswordSource, @replaceList) {
629-
my $ce = $c->ce;
630-
my $db = $c->db;
631-
my $dir = $ce->{courseDirs}{templates};
632-
my $user = $c->param('user');
633-
my $perm = $c->{userPermission};
629+
my $ce = $c->ce;
630+
my $db = $c->db;
634631

635-
die $c->maketext("Illegal '/' character in input.") if $fileName =~ m|/|;
636-
die $c->maketext("File [_1]/[_2] either does not exist or is not readable.", $dir, $fileName)
637-
unless -r "$dir/$fileName";
632+
die $c->maketext(q{Illegal '/' character in input.}) if $fileName =~ m|/|;
633+
die $c->maketext('File [_1]/[_2] either does not exist or is not readable.',
634+
$ce->{courseDirs}{templates}, $fileName)
635+
unless -r "$ce->{courseDirs}{templates}/$fileName";
638636

639637
my %allUserIDs = map { $_ => 1 } @{ $c->{allUserIDs} };
640638

641639
my %replaceOK;
642-
if ($replaceExisting eq 'none') {
643-
%replaceOK = ();
644-
} elsif ($replaceExisting eq 'listed') {
640+
if ($replaceExisting eq 'listed') {
645641
%replaceOK = map { $_ => 1 } @replaceList;
646642
} elsif ($replaceExisting eq 'any') {
647643
%replaceOK = %allUserIDs;
648644
}
649645

650646
my $default_permission_level = $ce->{default_permission_level};
651647

652-
my (@replaced, @added, @skipped);
648+
my (@usersToInsert, @passwordsToInsert, @permissionsToInsert,
649+
@usersToUpdate, @passwordsToUpdate, @permissionsToUpdate, @skipped);
653650

654651
# get list of hashrefs representing lines in classlist file
655-
my @classlist = parse_classlist("$dir/$fileName");
652+
my @classlist = parse_classlist("$ce->{courseDirs}{templates}/$fileName");
656653

657654
# Default status is enrolled -- fetch abbreviation for enrolled
658655
my $default_status_abbrev = $ce->{statuses}{Enrolled}{abbrevs}[0];
659656

660-
foreach my $record (@classlist) {
657+
for my $record (@classlist) {
661658
my %record = %$record;
662659
my $user_id = $record{user_id};
663660

664661
unless (WeBWorK::DB::check_user_id($user_id)) { # try to catch lines with bad characters
665662
push @skipped, $user_id;
666663
next;
667664
}
668-
if ($user_id eq $user) { # don't replace yourself!!
665+
if ($user_id eq $c->param('user')) { # don't replace yourself!!
669666
push @skipped, $user_id;
670667
next;
671668
}
672-
if ($record{permission} && $perm < $record{permission}) {
669+
if ($record{permission} && $c->{userPermission} < $record{permission}) {
673670
push @skipped, $user_id;
674671
next;
675672
}
@@ -681,7 +678,7 @@ sub importUsersFromCSV ($c, $fileName, $replaceExisting, $fallbackPasswordSource
681678

682679
# set default status is status field is "empty"
683680
$record{status} = $default_status_abbrev
684-
unless defined $record{status} and $record{status} ne "";
681+
unless defined $record{status} && $record{status} ne '';
685682

686683
# Determine what to use for the password (if anything).
687684
if (!$record{password}) {
@@ -697,32 +694,37 @@ sub importUsersFromCSV ($c, $fileName, $replaceExisting, $fallbackPasswordSource
697694

698695
# set default permission level if permission level is "empty"
699696
$record{permission} = $default_permission_level
700-
unless defined $record{permission} and $record{permission} ne "";
697+
unless defined $record{permission} && $record{permission} ne '';
701698

702699
my $User = $db->newUser(%record);
703700
my $PermissionLevel = $db->newPermissionLevel(user_id => $user_id, permission => $record{permission});
704701
my $Password = $record{password} ? $db->newPassword(user_id => $user_id, password => $record{password}) : undef;
705702

706703
# DBFIXME use REPLACE
707704
if (exists $allUserIDs{$user_id}) {
708-
$db->putUser($User);
709-
$db->putPermissionLevel($PermissionLevel);
710-
$db->putPassword($Password) if $Password;
705+
push(@usersToUpdate, $User);
706+
push(@permissionsToUpdate, $PermissionLevel);
707+
push(@passwordsToUpdate, $Password) if $Password;
711708
$User->{permission} = $PermissionLevel->permission;
712709
$User->{passwordExists} = 1 if $Password;
713-
push @replaced, $User;
714710
} else {
715711
$allUserIDs{$user_id} = 1;
716-
$db->addUser($User);
717-
$db->addPermissionLevel($PermissionLevel);
718-
$db->addPassword($Password) if $Password;
712+
push(@usersToInsert, $User);
713+
push(@permissionsToInsert, $PermissionLevel);
714+
push(@passwordsToInsert, $Password) if $Password;
719715
$User->{permission} = $PermissionLevel->permission;
720716
$User->{passwordExists} = 1 if $Password;
721-
push @added, $User;
722717
}
723718
}
724719

725-
return \@replaced, \@added, \@skipped;
720+
$db->User->insert_records(\@usersToInsert) if @usersToInsert;
721+
$db->User->update_records(\@usersToUpdate) if @usersToUpdate;
722+
$db->Password->insert_records(\@passwordsToInsert) if @passwordsToInsert;
723+
$db->Password->update_records(\@passwordsToUpdate) if @passwordsToUpdate;
724+
$db->PermissionLevel->insert_records(\@permissionsToInsert) if @permissionsToInsert;
725+
$db->PermissionLevel->update_records(\@permissionsToUpdate) if @permissionsToUpdate;
726+
727+
return \@usersToUpdate, \@usersToInsert, \@skipped;
726728
}
727729

728730
sub exportUsersToCSV ($c, $fileName, @userIDsToExport) {

0 commit comments

Comments
 (0)