X-Git-Url: http://git.indexdata.com/?p=irspy-moved-to-github.git;a=blobdiff_plain;f=lib%2FZOOM%2FPod.pm;h=5faee4d7cb74098b02ea26b4385b406e22d87bea;hp=a8f6d7993b46845ed8d046320faf2344444a4a6c;hb=d3725cdc5d765df0eff9c525c6e3de015c8ca47c;hpb=1f1a0a20a51a260c1b7735ae6f95ceff42bf4374 diff --git a/lib/ZOOM/Pod.pm b/lib/ZOOM/Pod.pm index a8f6d79..5faee4d 100644 --- a/lib/ZOOM/Pod.pm +++ b/lib/ZOOM/Pod.pm @@ -1,4 +1,4 @@ -# $Id: Pod.pm,v 1.8 2006-05-12 11:37:48 mike Exp $ +# $Id: Pod.pm,v 1.22 2006-10-06 11:33:07 mike Exp $ package ZOOM::Pod; @@ -8,7 +8,7 @@ use warnings; use ZOOM; BEGIN { - # Just register the name + # Just register the names: this doesn't turn the levels on ZOOM::Log::mask_str("pod"); ZOOM::Log::mask_str("pod_unhandled"); } @@ -72,7 +72,6 @@ handle errors. $pod = new ZOOM::Pod("bagel.indexdata.com/gils", "bagel.indexdata.com/marc"); - Creates a new pod containing one or more connections. Each connection may be specified either by an existing C object, which I be asynchronous; or by a ZOOM target string, in which @@ -82,12 +81,20 @@ Returns the new pod. =cut +# Functionality to be added: +# +# If the constructor's first argument is a number, then it is +# taken as a limit on the number of connections to handle at any +# one time. In this case, the pod initially multiplexes between +# the first I connections, and brings further connections +# into the active subset whenever already-active connections are +# closed. + sub new { my $class = shift(); my(@conn) = @_; die "$class with no connections" if @conn == 0; - my @state; # Hashrefs with application state associated with connections foreach my $conn (@conn) { if (!ref $conn) { $conn = new ZOOM::Connection($conn, 0, async => 1); @@ -95,17 +102,30 @@ sub new { # server. Such errors are caught later, by the _check() # call in wait(). } - push @state, {}; } return bless { conn => \@conn, - state => \@state, rs => [], callback => {}, }, $class; } + +=head2 connections() + + @c = $pod->connections(); + +Returns a list of the connection objects in the pod. + +=cut + +sub connections { + my $this = shift(); + return @{ $this->{conn} } +} + + =head2 option() $oldElemSet = $pod->option("elementSetName"); @@ -145,9 +165,9 @@ acceptable to nominate the same function as the callback for multiple events, by multiple invocations of C. When an event occurs during the execution of C, the relevant -callback function is passed four arguments: the connection that the -event happened on; a state hash-reference associated with the -connection; the result-set associated with the connection; and the +callback function is called with four arguments: the connection that the +event happened on; the argument that was passed into C; +the result-set associated with the connection (if there is one); and the event-type (so that a single function that handles events of multiple types can switch on the code where necessary). The callback function can handle the event as it wishes, finishing up by returning an @@ -155,10 +175,10 @@ integer. If this is zero, then C continues as normal; if it is anything else, then that value is immediately returned from C. -So a typical, simple, event-handler might look like this: +So a simple event-handler might look like this: sub got_event { - ($conn, $state, $rs, $event) = @_; + ($conn, $arg, $rs, $event) = @_; print "event $event on connection ", $conn->option("host"), "\n"; print "Found ", $rs->size(), " records\n" if $event == ZOOM::Event::RECV_SEARCH; @@ -168,30 +188,30 @@ So a typical, simple, event-handler might look like this: In addition to the event-type callbacks discussed above, there is a special callback, C<"exception">, which is invoked if an exception occurs. This will nearly always be a ZOOM error, but this can be -tested using C. This callback is +tested using C<$exception-Eisa("ZOOM::Exception")>. This callback is invoked with the same arguments as described above, except that instead of the event-type, the fourth argument is a copy of the exception, C<$@>. Exception-handling callbacks may of course re-throw -the exception using C. +the exception using C. So a simple error-handler might look like this: sub got_error { - ($conn, $state, $rs, $exception) = @_; + ($conn, $arg, $rs, $exception) = @_; if ($exception->isa("ZOOM::Exception")) { - print "Caught error $exception -- continuing"; + print "Caught error $exception - continuing"; return 0; } die $exception; } -The C<$state> argument is a reference to an initially empty hash, -which the application can use as it sees fit, to store its own -connection-relation information. For example, an application might -use C<$state->{last}> to keep a record of which was the last record is -retrieved from the associated connection. The pod module itself does -not use the state hash at all, and applications are also welcome to -ignore it if they do not need it. +The C<$arg> argument could be anything at all - it is whatever the +application code passed into C. For example, it could be +a reference to a hash indexed by the host string of the connections to +yield some per-connection state information. +An application might use such information +to keep a record of which was the last record +retrieved from the associated connection. =cut @@ -200,31 +220,44 @@ sub callback { my($event, $sub) = @_; my $old = $this->{callback}->{$event}; - $this->{callback}->{$event} = $sub - if defined $sub; + $this->{callback}->{$event} = $sub; return $old; } +=head2 remove_callbacks() + + $pod->remove_callbacks(); + +Removes all registed callbacks from the pod. This is useful when the +pod has completed one operation and is about to start the next. + +=cut + +sub remove_callbacks { + my $this = shift(); + $this->{callback} = {}; +} + =head2 search_pqf() $pod->search_pqf("@attr 1=1003 wedel"); Submits the specified query to each of the connections in a pod, delegating to the same-named method of the C class -and storing eacdh result in a result-set object associated with the +and storing each result in a result-set object associated with the connection that generated it. Returns no value: success or failure -must subsequently be detected by the events and exceptions generated -by Cing on the pod. +must subsequently be detected by inspecting the events and exceptions +generated by Cing on the pod. B An important simplifying assumption is that each connection can only -have one search active on it at a time - this allows the pod to +have one search active on it at a time: this allows the pod to maintain the one-to-one mapping between connections and result-sets. Submitting a new search on a connection before the old one has -complete will result in a total failure in the nature of causality, -and the spontaneous existence-failure of the universe. Do not do -this. +completed will result in a total failure in the nature of causality, +and the spontaneous existence-failure of the universe. Try to avoid +doing this too often. =cut @@ -233,60 +266,90 @@ sub search_pqf { my($pqf) = @_; foreach my $i (0..@{ $this->{conn} }-1) { - $this->{rs}->[$i] = $this->{conn}->[$i]->search_pqf($pqf); + my $conn = $this->{conn}->[$i]; + $this->{rs}->[$i] = $conn->search_pqf($pqf) + if !$conn->option("pod_omit"); } } =head2 wait() $err = $pod->wait(); + # or + $err = $pod->wait($arg); die "$pod->wait() failed with error $err" if $err; Waits for events on the connections that make up the pod, usually continuing until there are no more events left and then returning zero. Whenever an event occurs, a callback function is dispatched as -described above in the documentation of the C method; if +described above; if an argument was passed to C, then that +same argument is also passed to each callback invocation. If that function returns a non-zero value, then C terminates immediately, whether or not any events remain, and returns that value. If an error occurs on one of the connection in the pod, then it is -normally thrown as a . If, however, there is a +normally thrown as a C. If, however, there is a special C<"exception"> callback registered, then the exception object is passed to this instead. As usual, the return value of the callback indicates whether C should continue (return-value 0) or return immediately (any other value). Exception-handling callbacks may of course re-throw the exception. +Connections that have the C option set are omitted from +consideration. This is useful if, for example, a connection that is +part of a pod is known to have encountered an unrecoverable error. + =cut sub wait { my $this = shift(); + my($arg) = @_; + my $res = 0; - while ((my $i = ZOOM::event($this->{conn})) != 0) { + while (1) { + my @conn; + my @idxmap; # maps indexes into conn to global indexes + foreach my $i (0 .. @{ $this->{conn} }-1) { + my $conn = $this->{conn}->[$i]; + if ($conn->option("pod_omit")) { + #ZOOM::Log::log("pod", "connection $i omitted (", + #$conn->option("host"), ")"); + } else { + push @conn, $conn; + push @idxmap, $i; + #ZOOM::Log::log("pod", "connection $i included (", + #$conn->option("host"), ")"); + } + } + + last if @conn == 0; + my $i0 = ZOOM::event(\@conn); + last if $i0 == 0; + my $i = 1+$idxmap[$i0-1]; my $conn = $this->{conn}->[$i-1]; + die "connection-mapping screwup" if $conn ne $conn[$i0-1]; + my $ev = $conn->last_event(); my $evstr = ZOOM::event_str($ev); - ZOOM::Log::log("pod", "connection ", $i-1, ": $evstr"); + ZOOM::Log::log("pod", "connection ", $i-1, ": event $ev ($evstr)"); eval { $conn->_check(); }; if ($@) { my $sub = $this->{callback}->{exception}; die $@ if !defined $sub; - $res = &$sub($conn, $this->{state}->[$i-1], - $this->{rs}->[$i-1], $@); + $res = &$sub($conn, $arg, $this->{rs}->[$i-1], $@); last if $res != 0; next; } my $sub = $this->{callback}->{$ev}; if (defined $sub) { - $res = &$sub($conn, $this->{state}->[$i-1], - $this->{rs}->[$i-1], $ev); + $res = &$sub($conn, $arg, $this->{rs}->[$i-1], $ev); last if $res != 0; } else { - ZOOM::Log::log("pod_unhandled", "unhandled event $ev ($evstr)"); + ZOOM::Log::log("pod_unhandled", "connection ", $i-1, ": unhandled event $ev ($evstr)"); } }