ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-MP/MP/Node.pm
Revision: 1.29
Committed: Fri Aug 28 00:31:14 2009 UTC (14 years, 9 months ago) by root
Branch: MAIN
Changes since 1.28: +2 -1 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 =head1 NAME
2
3 AnyEvent::MP::Node - a single processing node (CPU/process...)
4
5 =head1 SYNOPSIS
6
7 use AnyEvent::MP::Node;
8
9 =head1 DESCRIPTION
10
11 =cut
12
13 package AnyEvent::MP::Node;
14
15 use common::sense;
16
17 use AE ();
18 use AnyEvent::Util ();
19 use AnyEvent::Socket ();
20
21 use AnyEvent::MP::Transport ();
22
23 sub new {
24 my ($self, $id) = @_;
25
26 $self = bless { id => $id }, $self;
27
28 $self->init;
29 $self->transport_reset;
30
31 $self
32 }
33
34 sub init {
35 #
36 }
37
38 sub send {
39 &{ shift->{send} }
40 }
41
42 # nodes reachable via the network
43 package AnyEvent::MP::Node::External;
44
45 use base "AnyEvent::MP::Node";
46
47 # called at init time, mostly sets {send}
48 sub transport_reset {
49 my ($self) = @_;
50
51 delete $self->{transport};
52
53 Scalar::Util::weaken $self;
54
55 $self->{send} = sub {
56 push @{$self->{queue}}, shift;
57 $self->connect;
58 };
59
60 $self->connect
61 if $self->{autoconnect};
62 }
63
64 # called only after successful handshake
65 sub transport_error {
66 my ($self, @reason) = @_;
67
68 my $no_transport = !$self->{transport};
69
70 delete $self->{connect_w};
71 delete $self->{connect_to};
72
73 delete $self->{queue};
74 $self->transport_reset;
75
76 AnyEvent::MP::Kernel::_inject_nodeevent ($self, 0, @reason)
77 unless $no_transport;
78
79 if (my $mon = delete $self->{lmon}) {
80 $_->(@reason) for map @$_, values %$mon;
81 }
82 }
83
84 # called after handshake was successful
85 sub transport_connect {
86 my ($self, $transport) = @_;
87
88 delete $self->{trial};
89
90 $self->transport_error (transport_error => "switched connections")
91 if $self->{transport};
92
93 delete $self->{connect_w};
94 delete $self->{connect_to};
95
96 $self->{transport} = $transport;
97
98 my $transport_send = $transport->can ("send");
99
100 $self->{send} = sub {
101 $transport_send->($transport, $_[0]);
102 };
103
104 AnyEvent::MP::Kernel::_inject_nodeevent ($self, 1);
105
106 $transport->send ($_)
107 for @{ delete $self->{queue} || [] };
108 }
109
110 sub connect {
111 my ($self, @addresses) = @_;
112
113 return if $self->{transport};
114
115 Scalar::Util::weaken $self;
116
117 $self->{connect_to} ||= AE::timer
118 $AnyEvent::MP::Config::CFG{monitor_timeout} || $AnyEvent::MP::Kernel::MONITOR_TIMEOUT,
119 0,
120 sub {
121 $self->transport_error (transport_error => $self->{id}, "unable to connect");
122 };
123
124 return unless @addresses;
125
126 $AnyEvent::MP::Kernel::WARN->(9, "connecting to $self->{id} with [@addresses]");
127
128 unless ($self->{connect_w}) {
129 my @endpoints;
130
131 $self->{connect_w} = AE::timer
132 rand,
133 $AnyEvent::MP::Config::CFG{connect_interval} || $AnyEvent::MP::Kernel::CONNECT_INTERVAL,
134 sub {
135 @endpoints = @addresses
136 unless @endpoints;
137
138 my $endpoint = shift @endpoints;
139
140 $AnyEvent::MP::Kernel::WARN->(9, "connecting to $self->{id} at $endpoint");
141
142 $self->{trial}{$endpoint} ||= do {
143 my ($host, $port) = AnyEvent::Socket::parse_hostport $endpoint
144 or return $AnyEvent::MP::Kernel::WARN->(1, "$self->{id}: not a resolved node reference.");
145
146 AnyEvent::MP::Transport::mp_connect
147 $host, $port,
148 sub { delete $self->{trial}{$endpoint} },
149 };
150 }
151 ;
152 }
153 }
154
155 sub kill {
156 my ($self, $port, @reason) = @_;
157
158 $self->send (["", kil => $port, @reason]);
159 }
160
161 sub monitor {
162 my ($self, $portid, $cb) = @_;
163
164 my $list = $self->{lmon}{$portid} ||= [];
165
166 $self->send (["", mon1 => $portid])
167 unless @$list || !length $portid;
168
169 push @$list, $cb;
170 }
171
172 sub unmonitor {
173 my ($self, $portid, $cb) = @_;
174
175 my $list = $self->{lmon}{$portid}
176 or return;
177
178 @$list = grep $_ != $cb, @$list;
179
180 unless (@$list) {
181 $self->send (["", mon0 => $portid]);
182 delete $self->{monitor}{$portid};
183 }
184 }
185
186 # used for direct slave connections as well
187 package AnyEvent::MP::Node::Direct;
188
189 use base "AnyEvent::MP::Node::External";
190
191 package AnyEvent::MP::Node::Self;
192
193 use base "AnyEvent::MP::Node";
194
195 sub connect {
196 # we are trivially connected
197 }
198
199 sub transport_reset {
200 my ($self) = @_;
201
202 Scalar::Util::weaken $self;
203
204 $self->{send} = sub {
205 local $AnyEvent::MP::Kernel::SRCNODE = $self;
206 AnyEvent::MP::Kernel::_inject (@{ $_[0] });
207 };
208 }
209
210 sub transport_connect {
211 my ($self, $tp) = @_;
212
213 $AnyEvent::MP::Kernel::WARN->(9, "I refuse to talk to myself ($tp->{peerhost}:$tp->{peerport})");
214 }
215
216 sub kill {
217 my ($self, $port, @reason) = @_;
218
219 delete $AnyEvent::MP::Kernel::PORT{$port};
220 delete $AnyEvent::MP::Kernel::PORT_DATA{$port};
221
222 my $mon = delete $AnyEvent::MP::Kernel::LMON{$port}
223 or !@reason
224 or $AnyEvent::MP::Kernel::WARN->(2, "unmonitored local port $port died with reason: @reason");
225
226 $_->(@reason) for values %$mon;
227 }
228
229 sub monitor {
230 my ($self, $portid, $cb) = @_;
231
232 return $cb->(no_such_port => "cannot monitor nonexistent port")
233 unless exists $AnyEvent::MP::Kernel::PORT{$portid};
234
235 $AnyEvent::MP::Kernel::LMON{$portid}{$cb+0} = $cb;
236 }
237
238 sub unmonitor {
239 my ($self, $portid, $cb) = @_;
240
241 delete $AnyEvent::MP::Kernel::LMON{$portid}{$cb+0};
242 }
243
244 =head1 SEE ALSO
245
246 L<AnyEvent::MP>.
247
248 =head1 AUTHOR
249
250 Marc Lehmann <schmorp@schmorp.de>
251 http://home.schmorp.de/
252
253 =cut
254
255 1
256