eventmachine 1.0.0.beta.3 → 1.0.0.beta.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. data/.gitignore +5 -0
  2. data/.yardopts +5 -1
  3. data/{docs/GNU → GNU} +0 -0
  4. data/Gemfile +1 -0
  5. data/{docs/COPYING → LICENSE} +0 -0
  6. data/README.md +109 -0
  7. data/Rakefile +8 -0
  8. data/docs/DocumentationGuidesIndex.md +27 -0
  9. data/docs/GettingStarted.md +521 -0
  10. data/docs/{ChangeLog → old/ChangeLog} +0 -0
  11. data/docs/{DEFERRABLES → old/DEFERRABLES} +0 -0
  12. data/docs/{EPOLL → old/EPOLL} +0 -0
  13. data/docs/{INSTALL → old/INSTALL} +0 -0
  14. data/docs/{KEYBOARD → old/KEYBOARD} +0 -0
  15. data/docs/{LEGAL → old/LEGAL} +0 -0
  16. data/docs/{LIGHTWEIGHT_CONCURRENCY → old/LIGHTWEIGHT_CONCURRENCY} +0 -0
  17. data/docs/{PURE_RUBY → old/PURE_RUBY} +0 -0
  18. data/docs/{RELEASE_NOTES → old/RELEASE_NOTES} +0 -0
  19. data/docs/{SMTP → old/SMTP} +0 -0
  20. data/docs/{SPAWNED_PROCESSES → old/SPAWNED_PROCESSES} +0 -0
  21. data/docs/{TODO → old/TODO} +0 -0
  22. data/eventmachine.gemspec +4 -1
  23. data/examples/guides/getting_started/01_eventmachine_echo_server.rb +18 -0
  24. data/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb +22 -0
  25. data/examples/guides/getting_started/03_simple_chat_server.rb +149 -0
  26. data/examples/guides/getting_started/04_simple_chat_server_step_one.rb +27 -0
  27. data/examples/guides/getting_started/05_simple_chat_server_step_two.rb +43 -0
  28. data/examples/guides/getting_started/06_simple_chat_server_step_three.rb +98 -0
  29. data/examples/guides/getting_started/07_simple_chat_server_step_four.rb +121 -0
  30. data/examples/guides/getting_started/08_simple_chat_server_step_five.rb +141 -0
  31. data/examples/{ex_channel.rb → old/ex_channel.rb} +3 -3
  32. data/examples/{ex_queue.rb → old/ex_queue.rb} +0 -0
  33. data/examples/{ex_tick_loop_array.rb → old/ex_tick_loop_array.rb} +0 -0
  34. data/examples/{ex_tick_loop_counter.rb → old/ex_tick_loop_counter.rb} +0 -0
  35. data/examples/{helper.rb → old/helper.rb} +0 -0
  36. data/ext/cmain.cpp +3 -3
  37. data/ext/ed.cpp +90 -15
  38. data/ext/ed.h +5 -5
  39. data/ext/em.cpp +47 -55
  40. data/ext/em.h +12 -2
  41. data/ext/pipe.cpp +2 -2
  42. data/ext/project.h +1 -1
  43. data/ext/rubymain.cpp +48 -3
  44. data/ext/ssl.cpp +5 -0
  45. data/java/src/com/rubyeventmachine/EmReactor.java +2 -2
  46. data/lib/em/buftok.rb +35 -63
  47. data/lib/em/callback.rb +43 -11
  48. data/lib/em/channel.rb +21 -14
  49. data/lib/em/completion.rb +304 -0
  50. data/lib/em/connection.rb +339 -209
  51. data/lib/em/deferrable.rb +4 -0
  52. data/lib/em/deferrable/pool.rb +2 -0
  53. data/lib/em/file_watch.rb +37 -18
  54. data/lib/em/iterator.rb +42 -42
  55. data/lib/em/pool.rb +146 -0
  56. data/lib/em/process_watch.rb +5 -4
  57. data/lib/em/processes.rb +8 -4
  58. data/lib/em/protocols/httpclient.rb +22 -11
  59. data/lib/em/protocols/httpclient2.rb +15 -5
  60. data/lib/em/protocols/line_protocol.rb +2 -1
  61. data/lib/em/protocols/memcache.rb +17 -9
  62. data/lib/em/protocols/object_protocol.rb +2 -1
  63. data/lib/em/protocols/postgres3.rb +8 -9
  64. data/lib/em/protocols/smtpclient.rb +19 -11
  65. data/lib/em/protocols/smtpserver.rb +1 -1
  66. data/lib/em/protocols/stomp.rb +8 -6
  67. data/lib/em/protocols/tcptest.rb +3 -2
  68. data/lib/em/pure_ruby.rb +212 -208
  69. data/lib/em/queue.rb +22 -13
  70. data/lib/em/resolver.rb +70 -64
  71. data/lib/em/spawnable.rb +6 -3
  72. data/lib/em/streamer.rb +33 -45
  73. data/lib/em/threaded_resource.rb +90 -0
  74. data/lib/em/timers.rb +6 -2
  75. data/lib/em/version.rb +1 -1
  76. data/lib/eventmachine.rb +538 -602
  77. data/lib/jeventmachine.rb +22 -1
  78. data/tasks/package.rake +12 -2
  79. data/tasks/test.rake +1 -0
  80. data/tests/em_test_helper.rb +12 -3
  81. data/tests/test_completion.rb +177 -0
  82. data/tests/test_epoll.rb +2 -2
  83. data/tests/test_httpclient.rb +9 -9
  84. data/tests/test_httpclient2.rb +11 -9
  85. data/tests/test_ltp.rb +2 -10
  86. data/tests/test_pool.rb +128 -0
  87. data/tests/test_processes.rb +20 -2
  88. data/tests/test_queue.rb +8 -0
  89. data/tests/test_resolver.rb +1 -1
  90. data/tests/test_set_sock_opt.rb +37 -0
  91. data/tests/test_shutdown_hooks.rb +23 -0
  92. data/tests/test_threaded_resource.rb +53 -0
  93. data/tests/test_unbind_reason.rb +31 -0
  94. metadata +262 -192
  95. data/README +0 -81
  96. data/tasks/doc.rake +0 -30
@@ -25,6 +25,7 @@
25
25
 
26
26
  module EventMachine
27
27
  module Deferrable
28
+ autoload :Pool, 'em/deferrable/pool'
28
29
 
29
30
  # Specify a block to be executed if and when the Deferrable object receives
30
31
  # a status of :succeeded. See #set_deferred_status for more information.
@@ -49,6 +50,7 @@ module EventMachine
49
50
  @callbacks ||= []
50
51
  @callbacks.unshift block # << block
51
52
  end
53
+ self
52
54
  end
53
55
 
54
56
  # Cancels an outstanding callback to &block if any. Undoes the action of #callback.
@@ -74,6 +76,7 @@ module EventMachine
74
76
  @errbacks ||= []
75
77
  @errbacks.unshift block # << block
76
78
  end
79
+ self
77
80
  end
78
81
 
79
82
  # Cancels an outstanding errback to &block if any. Undoes the action of #errback.
@@ -168,6 +171,7 @@ module EventMachine
168
171
  cancel_timeout
169
172
  me = self
170
173
  @deferred_timeout = EventMachine::Timer.new(seconds) {me.fail(*args)}
174
+ self
171
175
  end
172
176
 
173
177
  # Cancels an outstanding timeout if any. Undoes the action of #timeout.
@@ -0,0 +1,2 @@
1
+ warn "EM::Deferrable::Pool is deprecated, please use EM::Pool"
2
+ EM::Deferrable::Pool = EM::Pool
@@ -1,15 +1,24 @@
1
1
  module EventMachine
2
-
3
- # This is subclassed from EventMachine::Connection for use with the file monitoring API. Read the
4
- # documentation on the instance methods of this class, and for a full explanation see EventMachine.watch_file.
2
+ # Utility class that is useful for file monitoring. Supported events are
3
+ #
4
+ # * File is modified
5
+ # * File is deleted
6
+ # * File is moved
7
+ #
8
+ # @note On Mac OS X, file watching only works when kqueue is enabled
9
+ #
10
+ # @see EventMachine.watch_file
5
11
  class FileWatch < Connection
6
- # :stopdoc:
12
+ # @private
7
13
  Cmodified = 'modified'.freeze
14
+ # @private
8
15
  Cdeleted = 'deleted'.freeze
16
+ # @private
9
17
  Cmoved = 'moved'.freeze
10
- # :startdoc:
11
18
 
12
- def receive_data(data) #:nodoc:
19
+
20
+ # @private
21
+ def receive_data(data)
13
22
  case data
14
23
  when Cmodified
15
24
  file_modified
@@ -20,35 +29,45 @@ module EventMachine
20
29
  end
21
30
  end
22
31
 
23
- # Returns the path that EventMachine::watch_file was originally called with. The current implementation
24
- # does not pick up on the new filename after a rename occurs.
32
+ # Returns the path that is being monitored.
33
+ #
34
+ # @note Current implementation does not pick up on the new filename after a rename occurs.
35
+ #
36
+ # @return [String]
37
+ # @see EventMachine.watch_file
25
38
  def path
26
39
  @path
27
40
  end
28
41
 
29
- # Should be redefined with the user's custom callback that will be fired when the file is modified.
42
+ # Will be called when the file is modified. Supposed to be redefined by subclasses.
43
+ #
44
+ # @abstract
30
45
  def file_modified
31
46
  end
32
47
 
33
- # Should be redefined with the user's custom callback that will be fired when the file is deleted.
48
+ # Will be called when the file is deleted. Supposed to be redefined by subclasses.
34
49
  # When the file is deleted, stop_watching will be called after this to make sure everything is
35
50
  # cleaned up correctly.
36
51
  #
37
- # Note that on linux (with inotify), file_deleted will not be called until all open file descriptors to
38
- # the file have been closed.
52
+ # @note On Linux (with {http://en.wikipedia.org/wiki/Inotify inotify}), this method will not be called until *all* open file descriptors to
53
+ # the file have been closed.
54
+ #
55
+ # @abstract
39
56
  def file_deleted
40
57
  end
41
58
 
42
- # Should be redefined with the user's custom callback that will be fired when the file is moved or renamed.
59
+ # Will be called when the file is moved or renamed. Supposed to be redefined by subclasses.
60
+ #
61
+ # @abstract
43
62
  def file_moved
44
63
  end
45
64
 
46
65
  # Discontinue monitoring of the file.
47
- # This involves cleaning up the underlying monitoring details with kqueue/inotify, and in turn firing unbind.
66
+ #
67
+ # This involves cleaning up the underlying monitoring details with kqueue/inotify, and in turn firing {EventMachine::Connection#unbind}.
48
68
  # This will be called automatically when a file is deleted. User code may call it as well.
49
69
  def stop_watching
50
70
  EventMachine::unwatch_filename(@signature)
51
- end
52
- end
53
-
54
- end
71
+ end # stop_watching
72
+ end # FileWatch
73
+ end # EventMachine
@@ -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|
@@ -0,0 +1,146 @@
1
+ module EventMachine
2
+ # = EventMachine::Pool
3
+ #
4
+ # A simple async resource pool based on a resource and work queue. Resources
5
+ # are enqueued and work waits for resources to become available.
6
+ #
7
+ # Example:
8
+ #
9
+ # EM.run do
10
+ # pool = EM::Pool.new
11
+ # spawn = lambda { pool.add EM::HttpRequest.new('http://example.org') }
12
+ # 10.times { spawn[] }
13
+ # done, scheduled = 0, 0
14
+ #
15
+ # check = lambda do
16
+ # done += 1
17
+ # if done >= scheduled
18
+ # EM.stop
19
+ # end
20
+ # end
21
+ #
22
+ # pool.on_error { |conn| spawn[] }
23
+ #
24
+ # 100.times do
25
+ # pool.perform do |conn|
26
+ # req = conn.get :path => '/', :keepalive => true
27
+ #
28
+ # req.callback do
29
+ # p [:success, conn.object_id, i, req.response.size]
30
+ # check[]
31
+ # end
32
+ #
33
+ # req.errback { check[] }
34
+ #
35
+ # req
36
+ # end
37
+ # end
38
+ # end
39
+ #
40
+ # Resources are expected to be controlled by an object responding to a
41
+ # deferrable/completion style API with callback and errback blocks.
42
+ #
43
+ class Pool
44
+
45
+ def initialize
46
+ @resources = EM::Queue.new
47
+ @removed = []
48
+ @contents = []
49
+ @on_error = nil
50
+ end
51
+
52
+ def add resource
53
+ @contents << resource
54
+ requeue resource
55
+ end
56
+
57
+ def remove resource
58
+ @contents.delete resource
59
+ @removed << resource
60
+ end
61
+
62
+ # Returns a list for introspection purposes only. You should *NEVER* call
63
+ # modification or work oriented methods on objects in this list. A good
64
+ # example use case is periodic statistics collection against a set of
65
+ # connection resources.
66
+ #
67
+ # For example:
68
+ # pool.contents.inject(0) { |sum, connection| connection.num_bytes }
69
+ def contents
70
+ @contents.dup
71
+ end
72
+
73
+ # Define a default catch-all for when the deferrables returned by work
74
+ # blocks enter a failed state. By default all that happens is that the
75
+ # resource is returned to the pool. If on_error is defined, this block is
76
+ # responsible for re-adding the resource to the pool if it is still usable.
77
+ # In other words, it is generally assumed that on_error blocks explicitly
78
+ # handle the rest of the lifetime of the resource.
79
+ def on_error *a, &b
80
+ @on_error = EM::Callback(*a, &b)
81
+ end
82
+
83
+ # Perform a given #call-able object or block. The callable object will be
84
+ # called with a resource from the pool as soon as one is available, and is
85
+ # expected to return a deferrable.
86
+ #
87
+ # The deferrable will have callback and errback added such that when the
88
+ # deferrable enters a finished state, the object is returned to the pool.
89
+ #
90
+ # If on_error is defined, then objects are not automatically returned to the
91
+ # pool.
92
+ def perform(*a, &b)
93
+ work = EM::Callback(*a, &b)
94
+
95
+ @resources.pop do |resource|
96
+ if removed? resource
97
+ @removed.delete resource
98
+ reschedule work
99
+ else
100
+ process work, resource
101
+ end
102
+ end
103
+ end
104
+ alias reschedule perform
105
+
106
+ # A peek at the number of enqueued jobs waiting for resources
107
+ def num_waiting
108
+ @resources.num_waiting
109
+ end
110
+
111
+ # Removed will show resources in a partial pruned state. Resources in the
112
+ # removed list may not appear in the contents list if they are currently in
113
+ # use.
114
+ def removed? resource
115
+ @removed.include? resource
116
+ end
117
+
118
+ protected
119
+ def requeue resource
120
+ @resources.push resource
121
+ end
122
+
123
+ def failure resource
124
+ if @on_error
125
+ @on_error.call resource
126
+ else
127
+ requeue resource
128
+ end
129
+ end
130
+
131
+ def completion deferrable, resource
132
+ deferrable.callback { requeue resource }
133
+ deferrable.errback { failure resource }
134
+ end
135
+
136
+ def process work, resource
137
+ deferrable = work.call resource
138
+ if deferrable.kind_of?(EM::Deferrable)
139
+ completion deferrable, resource
140
+ else
141
+ raise ArgumentError, "deferrable expected from work"
142
+ end
143
+ end
144
+
145
+ end
146
+ end
@@ -3,12 +3,13 @@ module EventMachine
3
3
  # This is subclassed from EventMachine::Connection for use with the process monitoring API. Read the
4
4
  # documentation on the instance methods of this class, and for a full explanation see EventMachine.watch_process.
5
5
  class ProcessWatch < Connection
6
- # :stopdoc:
6
+ # @private
7
7
  Cfork = 'fork'.freeze
8
+ # @private
8
9
  Cexit = 'exit'.freeze
9
- # :startdoc:
10
10
 
11
- def receive_data(data) # :nodoc:
11
+ # @private
12
+ def receive_data(data)
12
13
  case data
13
14
  when Cfork
14
15
  process_forked
@@ -41,4 +42,4 @@ module EventMachine
41
42
  end
42
43
  end
43
44
 
44
- end
45
+ end
@@ -39,7 +39,8 @@ module EventMachine
39
39
  class DeferrableChildProcess < EventMachine::Connection
40
40
  include EventMachine::Deferrable
41
41
 
42
- def initialize # :nodoc:
42
+ # @private
43
+ def initialize
43
44
  super
44
45
  @data = []
45
46
  end
@@ -60,16 +61,19 @@ module EventMachine
60
61
  EventMachine.popen( cmd, DeferrableChildProcess )
61
62
  end
62
63
 
63
- def receive_data data # :nodoc:
64
+ # @private
65
+ def receive_data data
64
66
  @data << data
65
67
  end
66
68
 
67
- def unbind # :nodoc:
69
+ # @private
70
+ def unbind
68
71
  succeed( @data.join )
69
72
  end
70
73
  end
71
74
 
72
- class SystemCmd < EventMachine::Connection # :nodoc:
75
+ # @private
76
+ class SystemCmd < EventMachine::Connection
73
77
  def initialize cb
74
78
  @cb = cb
75
79
  @output = []