Bug 29632: Schema update
[koha.git] / Koha / Z3950Responder / ZebraSession.pm
1 package Koha::Z3950Responder::ZebraSession;
2
3 # Copyright ByWater Solutions 2016
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20 use Modern::Perl;
21
22 use base qw( Koha::Z3950Responder::Session );
23
24 use Koha::Logger;
25
26 use ZOOM;
27
28 =head1 NAME
29
30 Koha::Z3950Responder::ZebraSession
31
32 =head1 SYNOPSIS
33
34 Zebra-specific session class that uses C<Koha::Session> as the base class.
35
36 =head1 FUNCTIONS
37
38 =head2 INSTANCE METHODS
39
40 =head3 start_search
41
42     my ($resultset, $hits) = $self->_start_search( $args, $self->{server}->{num_to_prefetch} );
43
44 Connect to Zebra and do the search
45
46 =cut
47
48 sub start_search {
49     my ( $self, $args, $num_to_prefetch, $in_retry ) = @_;
50
51     my $database = $args->{DATABASES}->[0];
52     my ( $connection, $results );
53
54     eval {
55         $connection = C4::Context->Zconn(
56             # We're depending on the caller to have done some validation.
57             $database eq 'biblios' ? 'biblioserver' : 'authorityserver',
58             0 # No, no async, doesn't really help much for single-server searching
59         );
60
61         $results = $connection->search_pqf( $args->{QUERY} );
62
63         $self->log_debug('    retry successful') if ($in_retry);
64     };
65     if ($@) {
66         die $@ if ( ref($@) ne 'ZOOM::Exception' );
67
68         if ( $@->diagset() eq 'ZOOM' && $@->code() == 10004 && !$in_retry ) {
69             $self->log_debug('    upstream server lost connection, retrying');
70             return $self->_start_search( $args, $num_to_prefetch, 1 );
71         }
72
73         $self->_set_error_from_zoom( $args, $@ );
74         $connection = undef;
75     }
76
77     my $hits = $results ? $results->size() : -1;
78     my $resultset = {
79         database => $database,
80         connection => $connection,
81         results => $results,
82         query => $args->{QUERY},
83         hits => $hits
84     };
85
86     return ( $resultset, $hits );
87 }
88
89 =head3 fetch_record
90
91     my $record = $self->_fetch_record( $resultset, $args, $offset, $server->{num_to_prefetch} );
92
93 Fetch a record from Zebra. Caches records in session to avoid too many fetches.
94
95 =cut
96
97 sub fetch_record {
98     my ( $self, $resultset, $args, $index, $num_to_prefetch ) = @_;
99
100     my $record;
101
102     eval {
103         if ( !$resultset->{results}->record_immediate( $index ) ) {
104             my $start = $num_to_prefetch ? int( $index / $num_to_prefetch ) * $num_to_prefetch : $index;
105
106             if ( $start + $num_to_prefetch >= $resultset->{results}->size() ) {
107                 $num_to_prefetch = $resultset->{results}->size() - $start;
108             }
109
110             $self->log_debug("    fetch uncached, fetching $num_to_prefetch records starting at $start");
111
112             $resultset->{results}->records( $start, $num_to_prefetch, 0 );
113         }
114
115         $record = $resultset->{results}->record_immediate( $index )->raw();
116     };
117     if ($@) {
118         die $@ if ( ref($@) ne 'ZOOM::Exception' );
119         $self->_set_error_from_zoom( $args, $@ );
120         return;
121     } else {
122         return $record;
123     }
124 }
125
126 =head3 close_handler
127
128 Callback that is called when a session is terminated
129
130 =cut
131
132 sub close_handler {
133     my ( $self, $args ) = @_;
134
135     foreach my $resultset ( values %{ $self->{resultsets} } ) {
136         $resultset->{results}->destroy();
137     }
138 }
139
140 =head3 _set_error_from_zoom
141
142     $self->_set_error_from_zoom( $args, $@ );
143
144 Log and set error code and diagnostic message from a ZOOM exception
145
146 =cut
147
148 sub _set_error_from_zoom {
149     my ( $self, $args, $exception ) = @_;
150
151     $self->set_error( $args, $self->ERR_TEMPORARY_ERROR, 'Cannot connect to upstream server' );
152     $self->log_error(
153         "Zebra upstream error: " .
154         $exception->message() . " (" .
155         $exception->code() . ") " .
156         ( $exception->addinfo() // '' ) . " " .
157         $exception->diagset()
158     );
159 }
160
161 1;