@@ -, +, @@ 'If all unavailable' 100 items: 50 seconds 200 items: 3.2 minutes 300 items: 7.3 minutes 100 items: 4.4 seconds 200 items: 7.5 seconds 300 items: 10.4 seconds --- C4/Reserves.pm | 13 ++++++++++++- reserve/request.pl | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) --- a/C4/Reserves.pm +++ a/C4/Reserves.pm @@ -1225,7 +1225,12 @@ and canreservefromotherbranches. =cut sub IsAvailableForItemLevelRequest { - my ( $item, $patron, $pickup_branchcode ) = @_; + my $item = shift; + my $patron = shift; + my $pickup_branchcode = shift; + # items_any_available is precalculated status passed from request.pl when set of items + # looped outside of IsAvailableForItemLevelRequest to avoid nested loops: + my $items_any_available = shift; my $dbh = C4::Context->dbh; # must check the notforloan setting of the itemtype @@ -1260,6 +1265,12 @@ sub IsAvailableForItemLevelRequest { if ( $on_shelf_holds == 1 ) { return 1; } elsif ( $on_shelf_holds == 2 ) { + + # if we have this param predefined from outer caller sub, we just need + # to return it, so we saving from having loop inside other loop: + return $items_any_available ? 0 : 1 + if defined $items_any_available; + my $any_available = ItemsAnyAvailableForHold( { biblionumber => $item->biblionumber, patron => $patron }); return $any_available ? 0 : 1; } else { # on_shelf_holds == 0 "If any unavailable" (the description is rather cryptic and could still be improved) --- a/reserve/request.pl +++ a/reserve/request.pl @@ -445,6 +445,15 @@ foreach my $biblionumber (@biblionumbers) { $itemtypes->{ $biblioitem->{itemtype} }{imageurl} ); } + # iterating through all items first to check if any of them available + # to pass this value further inside down to IsAvailableForItemLevelRequest to + # it's complicated logic to analyse. + # (before this loop was inside that sub loop so it was O(n^2) ) + my $items_any_available; + + $items_any_available = ItemsAnyAvailableForHold( { biblionumber => $biblioitemnumber, patron => $patron }) + if $patron; + foreach my $itemnumber ( @{ $itemnumbers_of_biblioitem{$biblioitemnumber} } ) { my $item = $iteminfos_of->{$itemnumber}; my $do_check; @@ -558,7 +567,9 @@ foreach my $biblionumber (@biblionumbers) { !$item->{cantreserve} && !$exceeded_maxreserves && $can_item_be_reserved eq 'OK' - && IsAvailableForItemLevelRequest($item_object, $patron) + # items_any_available defined outside of the current loop, + # so we avoiding loop inside IsAvailableForItemLevelRequest: + && IsAvailableForItemLevelRequest($item_object, $patron, undef, $items_any_available) ) { $item->{available} = 1; --