eventmachine-maglev- 1.0.0.beta.4 → 1.0.0.rc.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/rubymain.cpp CHANGED
@@ -233,7 +233,7 @@ static VALUE t_add_oneshot_timer (VALUE self, VALUE interval)
233
233
  {
234
234
  const unsigned long f = evma_install_oneshot_timer (FIX2INT (interval));
235
235
  if (!f)
236
- rb_raise (rb_eRuntimeError, "ran out of timers; use #set_max_timers to increase limit");
236
+ rb_raise (rb_eRuntimeError, "%s", "ran out of timers; use #set_max_timers to increase limit");
237
237
  return ULONG2NUM (f);
238
238
  }
239
239
 
@@ -246,7 +246,7 @@ static VALUE t_start_server (VALUE self, VALUE server, VALUE port)
246
246
  {
247
247
  const unsigned long f = evma_create_tcp_server (StringValuePtr(server), FIX2INT(port));
248
248
  if (!f)
249
- rb_raise (rb_eRuntimeError, "no acceptor (port is in use or requires root privileges)");
249
+ rb_raise (rb_eRuntimeError, "%s", "no acceptor (port is in use or requires root privileges)");
250
250
  return ULONG2NUM (f);
251
251
  }
252
252
 
@@ -269,7 +269,7 @@ static VALUE t_start_unix_server (VALUE self, VALUE filename)
269
269
  {
270
270
  const unsigned long f = evma_create_unix_domain_server (StringValuePtr(filename));
271
271
  if (!f)
272
- rb_raise (rb_eRuntimeError, "no unix-domain acceptor");
272
+ rb_raise (rb_eRuntimeError, "%s", "no unix-domain acceptor");
273
273
  return ULONG2NUM (f);
274
274
  }
275
275
 
@@ -504,10 +504,10 @@ static VALUE t_connect_server (VALUE self, VALUE server, VALUE port)
504
504
  try {
505
505
  const unsigned long f = evma_connect_to_server (NULL, 0, StringValuePtr(server), NUM2INT(port));
506
506
  if (!f)
507
- rb_raise (EM_eConnectionError, "no connection");
507
+ rb_raise (EM_eConnectionError, "%s", "no connection");
508
508
  return ULONG2NUM (f);
509
509
  } catch (std::runtime_error e) {
510
- rb_raise (EM_eConnectionError, e.what());
510
+ rb_raise (EM_eConnectionError, "%s", e.what());
511
511
  }
512
512
  return Qnil;
513
513
  }
@@ -525,10 +525,10 @@ static VALUE t_bind_connect_server (VALUE self, VALUE bind_addr, VALUE bind_port
525
525
  try {
526
526
  const unsigned long f = evma_connect_to_server (StringValuePtr(bind_addr), NUM2INT(bind_port), StringValuePtr(server), NUM2INT(port));
527
527
  if (!f)
528
- rb_raise (EM_eConnectionError, "no connection");
528
+ rb_raise (EM_eConnectionError, "%s", "no connection");
529
529
  return ULONG2NUM (f);
530
530
  } catch (std::runtime_error e) {
531
- rb_raise (EM_eConnectionError, e.what());
531
+ rb_raise (EM_eConnectionError, "%s", e.what());
532
532
  }
533
533
  return Qnil;
534
534
  }
@@ -541,7 +541,7 @@ static VALUE t_connect_unix_server (VALUE self, VALUE serversocket)
541
541
  {
542
542
  const unsigned long f = evma_connect_to_unix_server (StringValuePtr(serversocket));
543
543
  if (!f)
544
- rb_raise (rb_eRuntimeError, "no connection");
544
+ rb_raise (rb_eRuntimeError, "%s", "no connection");
545
545
  return ULONG2NUM (f);
546
546
  }
547
547
 
@@ -553,7 +553,7 @@ static VALUE t_attach_fd (VALUE self, VALUE file_descriptor, VALUE watch_mode)
553
553
  {
554
554
  const unsigned long f = evma_attach_fd (NUM2INT(file_descriptor), watch_mode == Qtrue);
555
555
  if (!f)
556
- rb_raise (rb_eRuntimeError, "no connection");
556
+ rb_raise (rb_eRuntimeError, "%s", "no connection");
557
557
  return ULONG2NUM (f);
558
558
  }
559
559
 
@@ -583,6 +583,44 @@ static VALUE t_get_sock_opt (VALUE self, VALUE signature, VALUE lev, VALUE optna
583
583
  return rb_str_new(buf, len);
584
584
  }
585
585
 
586
+ /**************
587
+ t_set_sock_opt
588
+ **************/
589
+
590
+ static VALUE t_set_sock_opt (VALUE self, VALUE signature, VALUE lev, VALUE optname, VALUE optval)
591
+ {
592
+ int fd = evma_get_file_descriptor (NUM2ULONG (signature));
593
+ int level = NUM2INT(lev), option = NUM2INT(optname);
594
+ int i;
595
+ void *v;
596
+ socklen_t len;
597
+
598
+ switch (TYPE(optval)) {
599
+ case T_FIXNUM:
600
+ i = FIX2INT(optval);
601
+ goto numval;
602
+ case T_FALSE:
603
+ i = 0;
604
+ goto numval;
605
+ case T_TRUE:
606
+ i = 1;
607
+ numval:
608
+ v = (void*)&i; len = sizeof(i);
609
+ break;
610
+ default:
611
+ StringValue(optval);
612
+ v = RSTRING_PTR(optval);
613
+ len = RSTRING_LENINT(optval);
614
+ break;
615
+ }
616
+
617
+
618
+ if (setsockopt(fd, level, option, (char *)v, len) < 0)
619
+ rb_sys_fail("setsockopt");
620
+
621
+ return INT2FIX(0);
622
+ }
623
+
586
624
  /********************
587
625
  t_is_notify_readable
588
626
  ********************/
@@ -648,6 +686,15 @@ static VALUE t_paused_p (VALUE self, VALUE signature)
648
686
  return evma_is_paused(NUM2ULONG (signature)) ? Qtrue : Qfalse;
649
687
  }
650
688
 
689
+ /*********************
690
+ t_num_close_scheduled
691
+ *********************/
692
+
693
+ static VALUE t_num_close_scheduled (VALUE self)
694
+ {
695
+ return INT2FIX(evma_num_close_scheduled());
696
+ }
697
+
651
698
  /*****************
652
699
  t_open_udp_socket
653
700
  *****************/
@@ -656,7 +703,7 @@ static VALUE t_open_udp_socket (VALUE self, VALUE server, VALUE port)
656
703
  {
657
704
  const unsigned long f = evma_open_datagram_socket (StringValuePtr(server), FIX2INT(port));
658
705
  if (!f)
659
- rb_raise (rb_eRuntimeError, "no datagram socket");
706
+ rb_raise (rb_eRuntimeError, "%s", "no datagram socket");
660
707
  return ULONG2NUM (f);
661
708
  }
662
709
 
@@ -758,7 +805,7 @@ static VALUE t_invoke_popen (VALUE self, VALUE cmd)
758
805
  int len = RARRAY (cmd)->len;
759
806
  #endif
760
807
  if (len >= 2048)
761
- rb_raise (rb_eRuntimeError, "too many arguments to popen");
808
+ rb_raise (rb_eRuntimeError, "%s", "too many arguments to popen");
762
809
  char *strings [2048];
763
810
  for (int i=0; i < len; i++) {
764
811
  VALUE ix = INT2FIX (i);
@@ -791,7 +838,7 @@ static VALUE t_read_keyboard (VALUE self)
791
838
  {
792
839
  const unsigned long f = evma_open_keyboard();
793
840
  if (!f)
794
- rb_raise (rb_eRuntimeError, "no keyboard reader");
841
+ rb_raise (rb_eRuntimeError, "%s", "no keyboard reader");
795
842
  return ULONG2NUM (f);
796
843
  }
797
844
 
@@ -805,7 +852,7 @@ static VALUE t_watch_filename (VALUE self, VALUE fname)
805
852
  try {
806
853
  return ULONG2NUM(evma_watch_filename(StringValuePtr(fname)));
807
854
  } catch (std::runtime_error e) {
808
- rb_raise (EM_eUnsupported, e.what());
855
+ rb_raise (EM_eUnsupported, "%s", e.what());
809
856
  }
810
857
  return Qnil;
811
858
  }
@@ -831,7 +878,7 @@ static VALUE t_watch_pid (VALUE self, VALUE pid)
831
878
  try {
832
879
  return ULONG2NUM(evma_watch_pid(NUM2INT(pid)));
833
880
  } catch (std::runtime_error e) {
834
- rb_raise (EM_eUnsupported, e.what());
881
+ rb_raise (EM_eUnsupported, "%s", e.what());
835
882
  }
836
883
  return Qnil;
837
884
  }
@@ -878,7 +925,7 @@ t__epoll_set
878
925
  static VALUE t__epoll_set (VALUE self, VALUE val)
879
926
  {
880
927
  if (t__epoll_p(self) == Qfalse)
881
- rb_raise (EM_eUnsupported, "epoll is not supported on this platform");
928
+ rb_raise (EM_eUnsupported, "%s", "epoll is not supported on this platform");
882
929
 
883
930
  evma_set_epoll (val == Qtrue ? 1 : 0);
884
931
  return val;
@@ -915,7 +962,7 @@ t__kqueue_set
915
962
  static VALUE t__kqueue_set (VALUE self, VALUE val)
916
963
  {
917
964
  if (t__kqueue_p(self) == Qfalse)
918
- rb_raise (EM_eUnsupported, "kqueue is not supported on this platform");
965
+ rb_raise (EM_eUnsupported, "%s", "kqueue is not supported on this platform");
919
966
 
920
967
  evma_set_kqueue (val == Qtrue ? 1 : 0);
921
968
  return val;
@@ -953,7 +1000,7 @@ static VALUE t_send_file_data (VALUE self, VALUE signature, VALUE filename)
953
1000
 
954
1001
  int b = evma_send_file_data_to_connection (NUM2ULONG (signature), StringValuePtr(filename));
955
1002
  if (b == -1)
956
- rb_raise(rb_eRuntimeError, "File too large. send_file_data() supports files under 32k.");
1003
+ rb_raise(rb_eRuntimeError, "%s", "File too large. send_file_data() supports files under 32k.");
957
1004
  if (b > 0) {
958
1005
  char *err = strerror (b);
959
1006
  char buf[1024];
@@ -1031,7 +1078,7 @@ static VALUE t_start_proxy (VALUE self, VALUE from, VALUE to, VALUE bufsize, VAL
1031
1078
  try {
1032
1079
  evma_start_proxy(NUM2ULONG (from), NUM2ULONG (to), NUM2ULONG(bufsize), NUM2ULONG(length));
1033
1080
  } catch (std::runtime_error e) {
1034
- rb_raise (EM_eConnectionError, e.what());
1081
+ rb_raise (EM_eConnectionError, "%s", e.what());
1035
1082
  }
1036
1083
  return Qnil;
1037
1084
  }
@@ -1046,11 +1093,49 @@ static VALUE t_stop_proxy (VALUE self, VALUE from)
1046
1093
  try{
1047
1094
  evma_stop_proxy(NUM2ULONG (from));
1048
1095
  } catch (std::runtime_error e) {
1049
- rb_raise (EM_eConnectionError, e.what());
1096
+ rb_raise (EM_eConnectionError, "%s", e.what());
1050
1097
  }
1051
1098
  return Qnil;
1052
1099
  }
1053
1100
 
1101
+ /***************
1102
+ t_proxied_bytes
1103
+ ****************/
1104
+
1105
+ static VALUE t_proxied_bytes (VALUE self, VALUE from)
1106
+ {
1107
+ try{
1108
+ return ULONG2NUM(evma_proxied_bytes(NUM2ULONG (from)));
1109
+ } catch (std::runtime_error e) {
1110
+ rb_raise (EM_eConnectionError, "%s", e.what());
1111
+ }
1112
+ return Qnil;
1113
+ }
1114
+
1115
+ /***************
1116
+ t_get_idle_time
1117
+ ****************/
1118
+
1119
+ static VALUE t_get_idle_time (VALUE self, VALUE from)
1120
+ {
1121
+ try{
1122
+ uint64_t current_time = evma_get_current_loop_time();
1123
+ uint64_t time = evma_get_last_activity_time(NUM2ULONG (from));
1124
+ if (current_time != 0 && time != 0) {
1125
+ if (time >= current_time)
1126
+ return ULONG2NUM(0);
1127
+ else {
1128
+ uint64_t diff = current_time - time;
1129
+ float seconds = diff / (1000.0*1000.0);
1130
+ return rb_float_new(seconds);
1131
+ }
1132
+ return Qnil;
1133
+ }
1134
+ } catch (std::runtime_error e) {
1135
+ rb_raise (EM_eConnectionError, "%s", e.what());
1136
+ }
1137
+ return Qnil;
1138
+ }
1054
1139
 
1055
1140
  /************************
1056
1141
  t_get_heartbeat_interval
@@ -1137,6 +1222,7 @@ extern "C" void Init_rubyeventmachine()
1137
1222
  rb_define_module_function (EmModule, "attach_fd", (VALUE (*)(...))t_attach_fd, 2);
1138
1223
  rb_define_module_function (EmModule, "detach_fd", (VALUE (*)(...))t_detach_fd, 1);
1139
1224
  rb_define_module_function (EmModule, "get_sock_opt", (VALUE (*)(...))t_get_sock_opt, 3);
1225
+ rb_define_module_function (EmModule, "set_sock_opt", (VALUE (*)(...))t_set_sock_opt, 4);
1140
1226
  rb_define_module_function (EmModule, "set_notify_readable", (VALUE (*)(...))t_set_notify_readable, 2);
1141
1227
  rb_define_module_function (EmModule, "set_notify_writable", (VALUE (*)(...))t_set_notify_writable, 2);
1142
1228
  rb_define_module_function (EmModule, "is_notify_readable", (VALUE (*)(...))t_is_notify_readable, 1);
@@ -1145,9 +1231,11 @@ extern "C" void Init_rubyeventmachine()
1145
1231
  rb_define_module_function (EmModule, "pause_connection", (VALUE (*)(...))t_pause, 1);
1146
1232
  rb_define_module_function (EmModule, "resume_connection", (VALUE (*)(...))t_resume, 1);
1147
1233
  rb_define_module_function (EmModule, "connection_paused?", (VALUE (*)(...))t_paused_p, 1);
1234
+ rb_define_module_function (EmModule, "num_close_scheduled", (VALUE (*)(...))t_num_close_scheduled, 0);
1148
1235
 
1149
1236
  rb_define_module_function (EmModule, "start_proxy", (VALUE (*)(...))t_start_proxy, 4);
1150
1237
  rb_define_module_function (EmModule, "stop_proxy", (VALUE (*)(...))t_stop_proxy, 1);
1238
+ rb_define_module_function (EmModule, "get_proxied_bytes", (VALUE (*)(...))t_proxied_bytes, 1);
1151
1239
 
1152
1240
  rb_define_module_function (EmModule, "watch_filename", (VALUE (*)(...))t_watch_filename, 1);
1153
1241
  rb_define_module_function (EmModule, "unwatch_filename", (VALUE (*)(...))t_unwatch_filename, 1);
@@ -1171,6 +1259,7 @@ extern "C" void Init_rubyeventmachine()
1171
1259
  rb_define_module_function (EmModule, "send_file_data", (VALUE(*)(...))t_send_file_data, 2);
1172
1260
  rb_define_module_function (EmModule, "get_heartbeat_interval", (VALUE(*)(...))t_get_heartbeat_interval, 0);
1173
1261
  rb_define_module_function (EmModule, "set_heartbeat_interval", (VALUE(*)(...))t_set_heartbeat_interval, 1);
1262
+ rb_define_module_function (EmModule, "get_idle_time", (VALUE(*)(...))t_get_idle_time, 1);
1174
1263
 
1175
1264
  rb_define_module_function (EmModule, "get_peername", (VALUE(*)(...))t_get_peername, 1);
1176
1265
  rb_define_module_function (EmModule, "get_sockname", (VALUE(*)(...))t_get_sockname, 1);
data/ext/ssl.cpp CHANGED
@@ -137,7 +137,7 @@ SslContext_t::SslContext_t (bool is_server, const string &privkeyfile, const str
137
137
  bLibraryInitialized = true;
138
138
  SSL_library_init();
139
139
  OpenSSL_add_ssl_algorithms();
140
- OpenSSL_add_all_algorithms();
140
+ OpenSSL_add_all_algorithms();
141
141
  SSL_load_error_strings();
142
142
  ERR_load_crypto_strings();
143
143
 
@@ -151,6 +151,9 @@ SslContext_t::SslContext_t (bool is_server, const string &privkeyfile, const str
151
151
 
152
152
  SSL_CTX_set_options (pCtx, SSL_OP_ALL);
153
153
  //SSL_CTX_set_options (pCtx, (SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3));
154
+ #ifdef SSL_MODE_RELEASE_BUFFERS
155
+ SSL_CTX_set_mode (pCtx, SSL_MODE_RELEASE_BUFFERS);
156
+ #endif
154
157
 
155
158
  if (is_server) {
156
159
  // The SSL_CTX calls here do NOT allocate memory.
@@ -159,11 +162,14 @@ SslContext_t::SslContext_t (bool is_server, const string &privkeyfile, const str
159
162
  e = SSL_CTX_use_PrivateKey_file (pCtx, privkeyfile.c_str(), SSL_FILETYPE_PEM);
160
163
  else
161
164
  e = SSL_CTX_use_PrivateKey (pCtx, DefaultPrivateKey);
165
+ if (e <= 0) ERR_print_errors_fp(stderr);
162
166
  assert (e > 0);
167
+
163
168
  if (certchainfile.length() > 0)
164
169
  e = SSL_CTX_use_certificate_chain_file (pCtx, certchainfile.c_str());
165
170
  else
166
171
  e = SSL_CTX_use_certificate (pCtx, DefaultCertificate);
172
+ if (e <= 0) ERR_print_errors_fp(stderr);
167
173
  assert (e > 0);
168
174
  }
169
175
 
@@ -177,10 +183,12 @@ SslContext_t::SslContext_t (bool is_server, const string &privkeyfile, const str
177
183
  int e;
178
184
  if (privkeyfile.length() > 0) {
179
185
  e = SSL_CTX_use_PrivateKey_file (pCtx, privkeyfile.c_str(), SSL_FILETYPE_PEM);
186
+ if (e <= 0) ERR_print_errors_fp(stderr);
180
187
  assert (e > 0);
181
188
  }
182
189
  if (certchainfile.length() > 0) {
183
190
  e = SSL_CTX_use_certificate_chain_file (pCtx, certchainfile.c_str());
191
+ if (e <= 0) ERR_print_errors_fp(stderr);
184
192
  assert (e > 0);
185
193
  }
186
194
  }
@@ -524,6 +524,10 @@ public class EmReactor {
524
524
  return Connections.get(sig).getPeerName();
525
525
  }
526
526
 
527
+ public Object[] getSockName (long sig) {
528
+ return Connections.get(sig).getSockName();
529
+ }
530
+
527
531
  public long attachChannel (SocketChannel sc, boolean watch_mode) {
528
532
  long b = createBinding();
529
533
 
@@ -60,6 +60,7 @@ public interface EventableChannel {
60
60
  public void setCommInactivityTimeout (long seconds);
61
61
 
62
62
  public Object[] getPeerName();
63
+ public Object[] getSockName();
63
64
 
64
65
  public boolean isWatchOnly();
65
66
 
@@ -183,6 +183,12 @@ public class EventableDatagramChannel implements EventableChannel {
183
183
  }
184
184
  }
185
185
 
186
+ public Object[] getSockName () {
187
+ DatagramSocket socket = channel.socket();
188
+ return new Object[]{ socket.getLocalPort(),
189
+ socket.getLocalAddress().getHostAddress() };
190
+ }
191
+
186
192
  public boolean isWatchOnly() { return false; }
187
193
  public boolean isNotifyReadable() { return false; }
188
194
  public boolean isNotifyWritable() { return false; }
@@ -302,6 +302,12 @@ public class EventableSocketChannel implements EventableChannel {
302
302
  return new Object[]{ sock.getPort(), sock.getInetAddress().getHostAddress() };
303
303
  }
304
304
 
305
+ public Object[] getSockName () {
306
+ Socket sock = channel.socket();
307
+ return new Object[]{ sock.getLocalPort(),
308
+ sock.getLocalAddress().getHostAddress() };
309
+ }
310
+
305
311
  public void setWatchOnly() {
306
312
  bWatchOnly = true;
307
313
  updateEvents();
data/lib/em/completion.rb CHANGED
@@ -16,7 +16,7 @@
16
16
  #
17
17
  # == Basic Usage
18
18
  #
19
- # As already mentioned, the basic usage of a Completion is simply for it's two
19
+ # As already mentioned, the basic usage of a Completion is simply for its two
20
20
  # final states, :succeeded and :failed.
21
21
  #
22
22
  # An asynchronous operation will complete at some future point in time, and
@@ -24,8 +24,8 @@
24
24
  # some common interface to react to these events.
25
25
  #
26
26
  # In the following example, the user wants to know when a short lived
27
- # connection has completed it's exchange with the remote server. The simple
28
- # protocol just waits for an ack to it's message.
27
+ # connection has completed its exchange with the remote server. The simple
28
+ # protocol just waits for an ack to its message.
29
29
  #
30
30
  # class Protocol < EM::Connection
31
31
  # include EM::P::LineText2
@@ -199,6 +199,7 @@ module EventMachine
199
199
  @callbacks[state] << EM::Callback(*a, &b)
200
200
  end
201
201
  execute_callbacks
202
+ self
202
203
  end
203
204
 
204
205
  # Callbacks are called when you enter (or are in) a :succeeded state.
data/lib/em/connection.rb CHANGED
@@ -121,7 +121,7 @@ module EventMachine
121
121
  # been completed, as a result of calling #start_tls to initiate SSL/TLS on the connection.
122
122
  #
123
123
  # This callback exists because {#post_init} and {#connection_completed} are **not** reliable
124
- # for indicating when an SSL/TLS connection is ready to have it's certificate queried for.
124
+ # for indicating when an SSL/TLS connection is ready to have its certificate queried for.
125
125
  #
126
126
  # @see #get_peer_cert
127
127
  def ssl_handshake_completed
@@ -238,6 +238,12 @@ module EventMachine
238
238
  EventMachine::disable_proxy(self)
239
239
  end
240
240
 
241
+ # The number of bytes proxied to another connection. Reset to zero when
242
+ # EventMachine::Connection#proxy_incoming_to is called, and incremented whenever data is proxied.
243
+ def get_proxied_bytes
244
+ EventMachine::get_proxied_bytes(@signature)
245
+ end
246
+
241
247
  # EventMachine::Connection#close_connection is called only by user code, and never
242
248
  # by the event loop. You may call this method against a connection object in any
243
249
  # callback handler, whether or not the callback was made against the connection
@@ -270,6 +276,10 @@ module EventMachine
270
276
  EventMachine::get_sock_opt @signature, level, option
271
277
  end
272
278
 
279
+ def set_sock_opt level, optname, optval
280
+ EventMachine::set_sock_opt @signature, level, optname, optval
281
+ end
282
+
273
283
  # A variant of {#close_connection}.
274
284
  # All of the descriptive comments given for close_connection also apply to
275
285
  # close_connection_after_writing, *with one exception*: if the connection has
@@ -467,7 +477,7 @@ module EventMachine
467
477
  # # -----END CERTIFICATE-----
468
478
  #
469
479
  # You can do whatever you want with the certificate String, such as load it
470
- # as a certificate object using the OpenSSL library, and check it's fields.
480
+ # as a certificate object using the OpenSSL library, and check its fields.
471
481
  #
472
482
  # @return [String] the remote [X509 certificate](http://en.wikipedia.org/wiki/X.509), in the popular [PEM format](http://en.wikipedia.org/wiki/Privacy_Enhanced_Mail),
473
483
  # if TLS is active on the connection
@@ -566,6 +576,11 @@ module EventMachine
566
576
  EventMachine::get_subprocess_status @signature
567
577
  end
568
578
 
579
+ # The number of seconds since the last send/receive activity on this connection.
580
+ def get_idle_time
581
+ EventMachine::get_idle_time @signature
582
+ end
583
+
569
584
  # comm_inactivity_timeout returns the current value (float in seconds) of the inactivity-timeout
570
585
  # property of network-connection and datagram-socket objects. A nonzero value
571
586
  # indicates that the connection or socket will automatically be closed if no read or write
data/lib/em/iterator.rb CHANGED
@@ -4,46 +4,46 @@ module EventMachine
4
4
  # Unlike ruby's built-in iterators, the end of the current iteration cycle is signaled manually,
5
5
  # instead of happening automatically after the yielded block finishes executing. For example:
6
6
  #
7
- # (0..10).each{ |num| }
7
+ # (0..10).each{ |num| }
8
8
  #
9
9
  # becomes:
10
10
  #
11
- # EM::Iterator.new(0..10).each{ |num,iter| iter.next }
11
+ # EM::Iterator.new(0..10).each{ |num,iter| iter.next }
12
12
  #
13
13
  # This is especially useful when doing asynchronous work via reactor libraries and
14
14
  # functions. For example, given a sync and async http api:
15
15
  #
16
- # response = sync_http_get(url); ...
17
- # async_http_get(url){ |response| ... }
16
+ # response = sync_http_get(url); ...
17
+ # async_http_get(url){ |response| ... }
18
18
  #
19
19
  # a synchronous iterator such as:
20
20
  #
21
- # responses = urls.map{ |url| sync_http_get(url) }
22
- # ...
23
- # puts 'all done!'
21
+ # responses = urls.map{ |url| sync_http_get(url) }
22
+ # ...
23
+ # puts 'all done!'
24
24
  #
25
25
  # could be written as:
26
26
  #
27
- # EM::Iterator.new(urls).map(proc{ |url,iter|
28
- # async_http_get(url){ |res|
29
- # iter.return(res)
30
- # }
31
- # }, proc{ |responses|
32
- # ...
33
- # puts 'all done!'
34
- # })
27
+ # EM::Iterator.new(urls).map(proc{ |url,iter|
28
+ # async_http_get(url){ |res|
29
+ # iter.return(res)
30
+ # }
31
+ # }, proc{ |responses|
32
+ # ...
33
+ # puts 'all done!'
34
+ # })
35
35
  #
36
36
  # Now, you can take advantage of the asynchronous api to issue requests in parallel. For example,
37
37
  # to fetch 10 urls at a time, simply pass in a concurrency of 10:
38
38
  #
39
- # EM::Iterator.new(urls, 10).each do |url,iter|
40
- # async_http_get(url){ iter.next }
41
- # end
39
+ # EM::Iterator.new(urls, 10).each do |url,iter|
40
+ # async_http_get(url){ iter.next }
41
+ # end
42
42
  #
43
43
  class Iterator
44
44
  # Create a new parallel async iterator with specified concurrency.
45
45
  #
46
- # i = EM::Iterator.new(1..100, 10)
46
+ # i = EM::Iterator.new(1..100, 10)
47
47
  #
48
48
  # will create an iterator over the range that processes 10 items at a time. Iteration
49
49
  # is started via #each, #map or #inject
@@ -70,17 +70,17 @@ module EventMachine
70
70
 
71
71
  # Iterate over a set of items using the specified block or proc.
72
72
  #
73
- # EM::Iterator.new(1..100).each do |num, iter|
74
- # puts num
75
- # iter.next
76
- # end
73
+ # EM::Iterator.new(1..100).each do |num, iter|
74
+ # puts num
75
+ # iter.next
76
+ # end
77
77
  #
78
78
  # An optional second proc is invoked after the iteration is complete.
79
79
  #
80
- # EM::Iterator.new(1..100).each(
81
- # proc{ |num,iter| iter.next },
82
- # proc{ puts 'all done' }
83
- # )
80
+ # EM::Iterator.new(1..100).each(
81
+ # proc{ |num,iter| iter.next },
82
+ # proc{ puts 'all done' }
83
+ # )
84
84
  #
85
85
  def each(foreach=nil, after=nil, &blk)
86
86
  raise ArgumentError, 'proc or block required for iteration' unless foreach ||= blk
@@ -136,13 +136,13 @@ module EventMachine
136
136
 
137
137
  # Collect the results of an asynchronous iteration into an array.
138
138
  #
139
- # EM::Iterator.new(%w[ pwd uptime uname date ], 2).map(proc{ |cmd,iter|
140
- # EM.system(cmd){ |output,status|
141
- # iter.return(output)
142
- # }
143
- # }, proc{ |results|
144
- # p results
145
- # })
139
+ # EM::Iterator.new(%w[ pwd uptime uname date ], 2).map(proc{ |cmd,iter|
140
+ # EM.system(cmd){ |output,status|
141
+ # iter.return(output)
142
+ # }
143
+ # }, proc{ |results|
144
+ # p results
145
+ # })
146
146
  #
147
147
  def map(foreach, after)
148
148
  index = 0
@@ -174,14 +174,14 @@ module EventMachine
174
174
 
175
175
  # Inject the results of an asynchronous iteration onto a given object.
176
176
  #
177
- # EM::Iterator.new(%w[ pwd uptime uname date ], 2).inject({}, proc{ |hash,cmd,iter|
178
- # EM.system(cmd){ |output,status|
179
- # hash[cmd] = status.exitstatus == 0 ? output.strip : nil
180
- # iter.return(hash)
181
- # }
182
- # }, proc{ |results|
183
- # p results
184
- # })
177
+ # EM::Iterator.new(%w[ pwd uptime uname date ], 2).inject({}, proc{ |hash,cmd,iter|
178
+ # EM.system(cmd){ |output,status|
179
+ # hash[cmd] = status.exitstatus == 0 ? output.strip : nil
180
+ # iter.return(hash)
181
+ # }
182
+ # }, proc{ |results|
183
+ # p results
184
+ # })
185
185
  #
186
186
  def inject(obj, foreach, after)
187
187
  each(proc{ |item,iter|
data/lib/em/pool.rb CHANGED
@@ -122,7 +122,10 @@ module EventMachine
122
122
 
123
123
  def failure resource
124
124
  if @on_error
125
+ @contents.delete resource
125
126
  @on_error.call resource
127
+ # Prevent users from calling a leak.
128
+ @removed.delete resource
126
129
  else
127
130
  requeue resource
128
131
  end
@@ -140,7 +143,9 @@ module EventMachine
140
143
  else
141
144
  raise ArgumentError, "deferrable expected from work"
142
145
  end
146
+ rescue Exception
147
+ failure resource
148
+ raise
143
149
  end
144
-
145
150
  end
146
- end
151
+ end
@@ -24,7 +24,6 @@
24
24
  #
25
25
  #
26
26
 
27
- require 'readbytes'
28
27
  require 'postgres-pr/message'
29
28
  require 'postgres-pr/connection'
30
29
  require 'stringio'
@@ -35,15 +34,14 @@ class StringIO
35
34
  #
36
35
  # If the data read is nil an EOFError is raised.
37
36
  #
38
- # If the data read is too short a TruncatedDataError is raised and the read
39
- # data is obtainable via its #data method.
37
+ # If the data read is too short an IOError is raised
40
38
  def readbytes(n)
41
39
  str = read(n)
42
40
  if str == nil
43
41
  raise EOFError, "End of file reached"
44
42
  end
45
43
  if str.size < n
46
- raise TruncatedDataError.new("data truncated", str)
44
+ raise IOError, "data truncated"
47
45
  end
48
46
  str
49
47
  end
@@ -68,15 +66,15 @@ module EventMachine
68
66
  # in basically a production-ready state, and the wire protocol isn't that complicated
69
67
  # anyway.
70
68
  #
71
- # We need to monkeypatch StringIO because it lacks the #readbytes method needed
72
- # by postgres-pr.
73
- #
74
69
  # We're tucking in a bunch of require statements that may not be present in garden-variety
75
70
  # EM installations. Until we find a good way to only require these if a program
76
71
  # requires postgres, this file will need to be required explicitly.
77
72
  #
78
- # The StringIO monkeypatch is lifted verbatim from the standard library readbytes.rb,
73
+ # We need to monkeypatch StringIO because it lacks the #readbytes method needed
74
+ # by postgres-pr.
75
+ # The StringIO monkeypatch is lifted from the standard library readbytes.rb,
79
76
  # which adds method #readbytes directly to class IO. But StringIO is not a subclass of IO.
77
+ # It is modified to raise an IOError instead of TruncatedDataException since the exception is unused.
80
78
  #
81
79
  # We cloned the handling of postgres messages from lib/postgres-pr/connection.rb
82
80
  # in the postgres-pr library, and modified it for event-handling.