--- AnyEvent-MP/MP.pm 2012/03/21 15:22:16 1.136 +++ AnyEvent-MP/MP.pm 2012/10/02 13:58:07 1.145 @@ -49,13 +49,18 @@ die "kill the port, delayed"; }; -=head1 CURRENT STATUS + # distributed database - modification + db_set $family => $subkey [=> $value] # add a subkey + db_del $family => $subkey... # delete one or more subkeys + db_reg $family => $port [=> $value] # register a port + + # distributed database - queries + db_family $family => $cb->(\%familyhash) + db_keys $family => $cb->(\@keys) + db_values $family => $cb->(\@values) - bin/aemp - stable. - AnyEvent::MP - stable API, should work. - AnyEvent::MP::Intro - explains most concepts. - AnyEvent::MP::Kernel - mostly stable API. - AnyEvent::MP::Global - stable API. + # distributed database - monitoring a family + db_mon $family => $cb->(\%familyhash, \@added, \@changed, \@deleted) =head1 DESCRIPTION @@ -180,13 +185,23 @@ use AnyEvent::MP::Config (); use AnyEvent::MP::Kernel; -use AnyEvent::MP::Kernel qw(%NODE %PORT %PORT_DATA $UNIQ $RUNIQ $ID); +use AnyEvent::MP::Kernel qw( + %NODE %PORT %PORT_DATA $UNIQ $RUNIQ $ID + add_node load_func + + NODE $NODE + configure + node_of port_is_local + snd kil + db_set db_del + db_mon db_family db_keys db_values +); use common::sense; use Carp (); -use AE (); +use AnyEvent (); use Guard (); use base "Exporter"; @@ -194,12 +209,20 @@ our $VERSION = $AnyEvent::MP::Config::VERSION; our @EXPORT = qw( - NODE $NODE *SELF node_of after + NODE $NODE configure - snd rcv mon mon_guard kil psub peval spawn cal - port + node_of port_is_local + snd kil + db_set db_del + db_mon db_family db_keys db_values + + *SELF + + port rcv mon mon_guard psub peval spawn cal db_set db_del db_reg db_mon db_family db_keys db_values + + after ); our $SELF; @@ -220,6 +243,10 @@ Extracts and returns the node ID from a port ID or a node ID. +=item $is_local = port_is_local $port + +Returns true iff the port is a local port. + =item configure $profile, key => value... =item configure key => value... @@ -240,7 +267,7 @@ =item norc => $boolean (default false) If true, then the rc file (e.g. F<~/.perl-anyevent-mp>) will I -be consulted - all configuraiton options must be specified in the +be consulted - all configuration options must be specified in the C call. =item force => $boolean (default false) @@ -249,19 +276,6 @@ precedence over any values configured via the rc file. The default is for the rc file to override any options specified in the program. -=item secure => $pass->(@msg) - -In addition to specifying a boolean, you can specify a code reference that -is called for every code execution attempt - the execution request is -granted iff the callback returns a true value. - -Most of the time the callback should look only at -C<$AnyEvent::MP::Kernel::SRCNODE> to make a decision, and not at the -actual message (which can be about anything, and is mostly provided for -diagnostic purposes). - -See F for more info. - =back =over 4 @@ -474,7 +488,7 @@ my $port = shift; my ($nodeid, $portid) = split /#/, $port, 2; - $NODE{$nodeid} == $NODE{""} + $nodeid eq $NODE or Carp::croak "$port: rcv can only be called on local ports, caught"; while (@_) { @@ -528,7 +542,7 @@ =item peval $port, $coderef[, @args] Evaluates the given C<$codref> within the contetx of C<$port>, that is, -when the code throews an exception the C<$port> will be killed. +when the code throws an exception the C<$port> will be killed. Any remaining args will be passed to the callback. Any return values will be returned to the caller. @@ -603,43 +617,50 @@ } } -=item $guard = mon $port, $cb->(@reason) # call $cb when $port dies - =item $guard = mon $port, $rcvport # kill $rcvport when $port dies =item $guard = mon $port # kill $SELF when $port dies +=item $guard = mon $port, $cb->(@reason) # call $cb when $port dies + =item $guard = mon $port, $rcvport, @msg # send a message when $port dies Monitor the given port and do something when the port is killed or messages to it were lost, and optionally return a guard that can be used to stop monitoring again. -In the first form (callback), the callback is simply called with any -number of C<@reason> elements (no @reason means that the port was deleted -"normally"). Note also that I<< the callback B never die >>, so use -C if unsure. +The first two forms distinguish between "normal" and "abnormal" kil's: -In the second form (another port given), the other port (C<$rcvport>) -will be C'ed with C<@reason>, if a @reason was specified, i.e. on -"normal" kils nothing happens, while under all other conditions, the other -port is killed with the same reason. +In the first form (another port given), if the C<$port> is C'ed with +a non-empty reason, the other port (C<$rcvport>) will be kil'ed with the +same reason. That is, on "normal" kil's nothing happens, while under all +other conditions, the other port is killed with the same reason. -The third form (kill self) is the same as the second form, except that +The second form (kill self) is the same as the first form, except that C<$rvport> defaults to C<$SELF>. -In the last form (message), a message of the form C<@msg, @reason> will be -C. +The remaining forms don't distinguish between "normal" and "abnormal" kil's +- it's up to the callback or receiver to check whether the C<@reason> is +empty and act accordingly. + +In the third form (callback), the callback is simply called with any +number of C<@reason> elements (empty @reason means that the port was deleted +"normally"). Note also that I<< the callback B never die >>, so use +C if unsure. + +In the last form (message), a message of the form C<$rcvport, @msg, +@reason> will be C. Monitoring-actions are one-shot: once messages are lost (and a monitoring -alert was raised), they are removed and will not trigger again. +alert was raised), they are removed and will not trigger again, even if it +turns out that the port is still alive. -As a rule of thumb, monitoring requests should always monitor a port from -a local port (or callback). The reason is that kill messages might get -lost, just like any other message. Another less obvious reason is that -even monitoring requests can get lost (for example, when the connection -to the other node goes down permanently). When monitoring a port locally -these problems do not exist. +As a rule of thumb, monitoring requests should always monitor a remote +port locally (using a local C<$rcvport> or a callback). The reason is that +kill messages might get lost, just like any other message. Another less +obvious reason is that even monitoring requests can get lost (for example, +when the connection to the other node goes down permanently). When +monitoring a port locally these problems do not exist. C effectively guarantees that, in the absence of hardware failures, after starting the monitor, either all messages sent to the port will @@ -971,20 +992,55 @@ =over -=item db_set $family => $subkey [=> $value] +=item $guard = db_set $family => $subkey [=> $value] Sets (or replaces) a key to the database - if C<$value> is omitted, C is used instead. +When called in non-void context, C returns a guard that +automatically calls C when it is destroyed. + =item db_del $family => $subkey... Deletes one or more subkeys from the database family. -=item $guard = db_reg $family => $subkey [=> $value] +=item $guard = db_reg $family => $port => $value + +=item $guard = db_reg $family => $port + +=item $guard = db_reg $family + +Registers a port in the given family and optionally returns a guard to +remove it. + +This function basically does the same as: -Sets the key on the database and returns a guard. When the guard is -destroyed, the key is deleted from the database. If C<$value> is missing, -then C is used. + db_set $family => $port => $value + +Except that the port is monitored and automatically removed from the +database family when it is kil'ed. + +If C<$value> is missing, C is used. If C<$port> is missing, then +C<$SELF> is used. + +This function is most useful to register a port in some port group (which +is just another name for a database family), and have it removed when the +port is gone. This works best when the port is a local port. + +=cut + +sub db_reg($$;$) { + my $family = shift; + my $port = @_ ? shift : $SELF; + + my $clr = sub { db_del $family => $port }; + mon $port, $clr; + + db_set $family => $port => $_[0]; + + defined wantarray + and &Guard::guard ($clr) +} =item db_family $family => $cb->(\%familyhash) @@ -1001,7 +1057,7 @@ Same as C, except it only queries the family I and passes them as array reference to the callback. -=item $guard = db_mon $family => $cb->($familyhash, \@added, \@changed, \@deleted) +=item $guard = db_mon $family => $cb->(\%familyhash, \@added, \@changed, \@deleted) Creates a monitor on the given database family. Each time a key is set or or is deleted the callback is called with a hash containing the @@ -1219,6 +1275,114 @@ =back +=head1 PORTING FROM AnyEvent::MP VERSION 1.X + +AEMP version 2 has a few major incompatible changes compared to version 1: + +=over 4 + +=item AnyEvent::MP::Global no longer has group management functions. + +At least not officially - the grp_* functions are still exported and might +work, but they will be removed in some later release. + +AnyEvent::MP now comes with a distributed database that is more +powerful. Its database families map closely to port groups, but the API +has changed (the functions are also now exported by AnyEvent::MP). Here is +a rough porting guide: + + grp_reg $group, $port # old + db_reg $group, $port # new + + $list = grp_get $group # old + db_keys $group, sub { my $list = shift } # new + + grp_mon $group, $cb->(\@ports, $add, $del) # old + db_mon $group, $cb->(\%ports, $add, $change, $del) # new + +C is a no-brainer (just replace by C), but C is +no longer instant, because the local node might not have a copy of the +group. You can either modify your code to allow for a callback, or use +C to keep an updated copy of the group: + + my $local_group_copy; + db_mon $group => sub { $local_group_copy = $_[0] }; + + # now "keys %$local_group_copy" always returns the most up-to-date + # list of ports in the group. + +C can be replaced by C with minor changes - C +passes a hash as first argument, and an extra C<$chg> argument that can be +ignored: + + db_mon $group => sub { + my ($ports, $add, $chg, $lde) = @_; + $ports = [keys %$ports]; + + # now $ports, $add and $del are the same as + # were originally passed by grp_mon. + ... + }; + +=item Nodes not longer connect to all other nodes. + +In AEMP 1.x, every node automatically loads the L +module, which in turn would create connections to all other nodes in the +network (helped by the seed nodes). + +In version 2.x, global nodes still connect to all other global nodes, but +other nodes don't - now every node either is a global node itself, or +attaches itself to another global node. + +If a node isn't a global node itself, then it attaches itself to one +of its seed nodes. If that seed node isn't a global node yet, it will +automatically be upgraded to a global node. + +So in many cases, nothing needs to be changed - one just has to make sure +that all seed nodes are meshed together with the other seed nodes (as with +AEMP 1.x), and other nodes specify them as seed nodes. This is most easily +achieved by specifying the same set of seed nodes for all nodes in the +network. + +Not opening a connection to every other node is usually an advantage, +except when you need the lower latency of an already established +connection. To ensure a node establishes a connection to another node, +you can monitor the node port (C), which will attempt to +create the connection (and notify you when the connection fails). + +=item Listener-less nodes (nodes without binds) are gone. + +And are not coming back, at least not in their old form. If no C +are specified for a node, AnyEvent::MP assumes a default of C<*:*>. + +There are vague plans to implement some form of routing domains, which +might or might not bring back listener-less nodes, but don't count on it. + +The fact that most connections are now optional somewhat mitigates this, +as a node can be effectively unreachable from the outside without any +problems, as long as it isn't a global node and only reaches out to other +nodes (as opposed to being contacted from other nodes). + +=item $AnyEvent::MP::Kernel::WARN has gone. + +AnyEvent has acquired a logging framework (L), and AEMP now +uses this, and so should your programs. + +Every module now documents what kinds of messages it generates, with +AnyEvent::MP acting as a catch all. + +On the positive side, this means that instead of setting +C, you can get away by setting C - +much less to type. + +=back + +=head1 LOGGING + +AnyEvent::MP does not normally log anything by itself, but sinc eit is the +root of the contetx hierarchy for AnyEvent::MP modules, it will receive +all log messages by submodules. + =head1 SEE ALSO L - a gentle introduction.