Bug 29483: Check ItemsAnyAvailableAndNotRestricted once per patron

ItemsAnyAvailableAndNotRestricted can take a long time and create nested loops.
We can check it once per patron, however, this requires us to flip the loops.
Since an item can only be used once, we now add a check to see if this item has already
been assigned to a borrower.

To test:
1 - Find or create a biblio with 100 items
2 - Place ten 'Next available' holds on a biblio
3 - Set preference 'AllowRenewalIfOtherItemsAvailable' to 'Allow'
    Set circ rules 'On shelf holds allowed' to 'If any unavailable'
4 - Checkout one of the items to a patron, backdated to be overdue
5 - Note a long loading time for the patron's checkouts
6 - Apply patch, restart_all
7 - Patron loads much faster

Signed-off-by: Andrew Fuerste-Henry <andrew@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Fridolin Somers <fridolin.somers@biblibre.com>
This commit is contained in:
Nick Clemens 2021-11-15 13:54:00 +00:00 committed by Fridolin Somers
parent 4113f765b6
commit 68c92b49d1

View file

@ -27,7 +27,7 @@ use Encode;
use Koha::DateUtils qw( dt_from_string output_pref );
use C4::Context;
use C4::Stats qw( UpdateStats );
use C4::Reserves qw( CheckReserves CanItemBeReserved MoveReserve ModReserve ModReserveMinusPriority RevertWaitingStatus IsItemOnHoldAndFound IsAvailableForItemLevelRequest );
use C4::Reserves qw( CheckReserves CanItemBeReserved MoveReserve ModReserve ModReserveMinusPriority RevertWaitingStatus IsItemOnHoldAndFound IsAvailableForItemLevelRequest ItemsAnyAvailableAndNotRestricted );
use C4::Biblio qw( UpdateTotalIssues );
use C4::Items qw( ModItemTransfer ModDateLastSeen CartToShelf );
use C4::Accounts;
@ -2958,19 +2958,23 @@ sub CanBookBeRenewed {
# can be filled with available items. We can get the union of the sets simply
# by pushing all the elements onto an array and removing the duplicates.
my @reservable;
ITEM: while ( my $item = $items->next ) {
next if IsItemOnHoldAndFound( $item->itemnumber );
while ( my $patron = $patrons->next ) {
next unless IsAvailableForItemLevelRequest($item, $patron);
next unless CanItemBeReserved($patron,$item,undef,{ignore_hold_counts=>1})->{status} eq 'OK';
push @reservable, $item->itemnumber;
my %matched_items;
PATRON: while ( my $patron = $patrons->next ) {
my $items_any_available = ItemsAnyAvailableAndNotRestricted( { biblionumber => $item->biblionumber, patron => $patron });
while ( my $other_item = $items->next ) {
next if $matched_items{$other_item->itemnumber} == 1;
next if IsItemOnHoldAndFound( $other_item->itemnumber );
next unless IsAvailableForItemLevelRequest($other_item, $patron, undef, $items_any_available);
next unless CanItemBeReserved($patron,$other_item,undef,{ignore_hold_counts=>1})->{status} eq 'OK';
push @reservable, $other_item->itemnumber;
if (@reservable >= @borrowernumbers) {
$resfound = 0;
last ITEM;
last PATRON;
}
$matched_items{$other_item->itemnumber} = 1;
last;
}
$patrons->reset;
$items->reset;
}
}
}