eventmachine 0.12.10-x86-mswin32-60 → 1.0.0.beta.2-x86-mswin32-60
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Gemfile +1 -0
- data/README +80 -81
- data/Rakefile +7 -370
- data/docs/COPYING +60 -60
- data/docs/ChangeLog +211 -211
- data/docs/DEFERRABLES +246 -133
- data/docs/EPOLL +141 -141
- data/docs/GNU +281 -281
- data/docs/INSTALL +13 -13
- data/docs/KEYBOARD +42 -38
- data/docs/LEGAL +25 -25
- data/docs/LIGHTWEIGHT_CONCURRENCY +130 -70
- data/docs/PURE_RUBY +75 -75
- data/docs/RELEASE_NOTES +94 -94
- data/docs/SMTP +4 -2
- data/docs/SPAWNED_PROCESSES +148 -89
- data/docs/TODO +8 -8
- data/eventmachine.gemspec +19 -26
- data/examples/ex_channel.rb +42 -42
- data/examples/ex_queue.rb +2 -2
- data/examples/ex_tick_loop_array.rb +15 -0
- data/examples/ex_tick_loop_counter.rb +32 -0
- data/examples/helper.rb +1 -1
- data/ext/binder.cpp +0 -1
- data/ext/cmain.cpp +36 -25
- data/ext/ed.cpp +104 -113
- data/ext/ed.h +24 -30
- data/ext/em.cpp +349 -283
- data/ext/em.h +25 -29
- data/ext/eventmachine.h +5 -4
- data/ext/extconf.rb +58 -49
- data/ext/fastfilereader/extconf.rb +5 -3
- data/ext/fastfilereader/mapper.cpp +214 -214
- data/ext/fastfilereader/mapper.h +59 -59
- data/ext/fastfilereader/rubymain.cpp +127 -127
- data/ext/kb.cpp +1 -3
- data/ext/page.cpp +107 -107
- data/ext/page.h +51 -51
- data/ext/pipe.cpp +9 -11
- data/ext/project.h +12 -8
- data/ext/rubymain.cpp +138 -104
- data/java/.classpath +8 -8
- data/java/.project +17 -17
- data/java/src/com/rubyeventmachine/EmReactor.java +1 -0
- data/java/src/com/rubyeventmachine/EmReactorException.java +40 -40
- data/lib/em/buftok.rb +138 -138
- data/lib/em/callback.rb +25 -25
- data/lib/em/channel.rb +1 -1
- data/lib/em/connection.rb +6 -1
- data/lib/em/deferrable.rb +16 -2
- data/lib/em/file_watch.rb +53 -53
- data/lib/em/future.rb +61 -61
- data/lib/em/iterator.rb +270 -0
- data/lib/em/messages.rb +66 -66
- data/lib/em/process_watch.rb +43 -43
- data/lib/em/protocols.rb +1 -1
- data/lib/em/protocols/header_and_content.rb +138 -138
- data/lib/em/protocols/httpclient.rb +267 -262
- data/lib/em/protocols/line_protocol.rb +28 -0
- data/lib/em/protocols/memcache.rb +322 -322
- data/lib/em/protocols/postgres3.rb +247 -247
- data/lib/em/protocols/saslauth.rb +175 -175
- data/lib/em/protocols/smtpserver.rb +640 -547
- data/lib/em/protocols/stomp.rb +200 -200
- data/lib/em/protocols/tcptest.rb +52 -52
- data/lib/{pr_eventmachine.rb → em/pure_ruby.rb} +1013 -1022
- data/lib/em/queue.rb +1 -0
- data/lib/em/spawnable.rb +85 -85
- data/lib/em/streamer.rb +130 -130
- data/lib/em/tick_loop.rb +85 -0
- data/lib/em/timers.rb +2 -1
- data/lib/em/version.rb +1 -1
- data/lib/eventmachine.rb +40 -84
- data/lib/jeventmachine.rb +2 -1
- data/lib/rubyeventmachine.rb +2 -0
- data/setup.rb +1585 -1585
- data/tasks/doc.rake +30 -0
- data/tasks/package.rake +85 -0
- data/tasks/test.rake +6 -0
- data/tests/client.crt +31 -31
- data/tests/client.key +51 -51
- data/tests/test_attach.rb +13 -3
- data/tests/test_basic.rb +60 -95
- data/tests/test_channel.rb +3 -2
- data/tests/test_defer.rb +49 -47
- data/tests/test_deferrable.rb +35 -0
- data/tests/test_error_handler.rb +35 -35
- data/tests/test_errors.rb +82 -82
- data/tests/test_exc.rb +55 -55
- data/tests/test_file_watch.rb +49 -49
- data/tests/test_futures.rb +198 -198
- data/tests/test_handler_check.rb +36 -36
- data/tests/test_hc.rb +190 -218
- data/tests/test_httpclient.rb +227 -218
- data/tests/test_httpclient2.rb +3 -2
- data/tests/test_inactivity_timeout.rb +3 -3
- data/tests/test_kb.rb +60 -60
- data/tests/test_ltp.rb +13 -5
- data/tests/test_ltp2.rb +317 -317
- data/tests/test_next_tick.rb +1 -1
- data/tests/test_object_protocol.rb +36 -36
- data/tests/test_pending_connect_timeout.rb +2 -2
- data/tests/test_process_watch.rb +50 -48
- data/tests/test_proxy_connection.rb +52 -0
- data/tests/test_pure.rb +134 -125
- data/tests/test_queue.rb +44 -44
- data/tests/test_running.rb +42 -42
- data/tests/test_sasl.rb +72 -72
- data/tests/test_send_file.rb +251 -242
- data/tests/test_servers.rb +76 -76
- data/tests/test_smtpclient.rb +83 -83
- data/tests/test_smtpserver.rb +85 -85
- data/tests/test_spawn.rb +322 -322
- data/tests/test_ssl_methods.rb +49 -49
- data/tests/test_ssl_verify.rb +82 -82
- data/tests/test_tick_loop.rb +59 -0
- data/tests/test_timers.rb +13 -15
- data/tests/test_ud.rb +36 -36
- data/tests/testem.rb +31 -31
- metadata +66 -51
- data/ext/cplusplus.cpp +0 -202
- data/ext/emwin.cpp +0 -300
- data/ext/emwin.h +0 -94
- data/ext/epoll.cpp +0 -26
- data/ext/epoll.h +0 -25
- data/ext/eventmachine_cpp.h +0 -96
- data/ext/files.cpp +0 -94
- data/ext/files.h +0 -65
- data/ext/sigs.cpp +0 -89
- data/ext/sigs.h +0 -32
- data/java/src/com/rubyeventmachine/application/Application.java +0 -194
- data/java/src/com/rubyeventmachine/application/Connection.java +0 -74
- data/java/src/com/rubyeventmachine/application/ConnectionFactory.java +0 -37
- data/java/src/com/rubyeventmachine/application/DefaultConnectionFactory.java +0 -46
- data/java/src/com/rubyeventmachine/application/PeriodicTimer.java +0 -38
- data/java/src/com/rubyeventmachine/application/Timer.java +0 -54
- data/java/src/com/rubyeventmachine/tests/ApplicationTest.java +0 -109
- data/java/src/com/rubyeventmachine/tests/ConnectTest.java +0 -148
- data/java/src/com/rubyeventmachine/tests/EMTest.java +0 -80
- data/java/src/com/rubyeventmachine/tests/TestDatagrams.java +0 -53
- data/java/src/com/rubyeventmachine/tests/TestServers.java +0 -75
- data/java/src/com/rubyeventmachine/tests/TestTimers.java +0 -90
- data/lib/evma.rb +0 -32
- data/lib/evma/callback.rb +0 -32
- data/lib/evma/container.rb +0 -75
- data/lib/evma/factory.rb +0 -77
- data/lib/evma/protocol.rb +0 -87
- data/lib/evma/reactor.rb +0 -48
- data/web/whatis +0 -7
data/docs/DEFERRABLES
CHANGED
@@ -1,133 +1,246 @@
|
|
1
|
-
EventMachine (EM) adds two different formalisms for lightweight concurrency
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
df.
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
1
|
+
EventMachine (EM) adds two different formalisms for lightweight concurrency
|
2
|
+
to the Ruby programmer's toolbox: spawned processes and deferrables. This
|
3
|
+
note will show you how to use deferrables. For more information, see the
|
4
|
+
separate document LIGHTWEIGHT_CONCURRENCY.
|
5
|
+
|
6
|
+
=== What are Deferrables?
|
7
|
+
|
8
|
+
EventMachine's Deferrable borrows heavily from the "deferred" object in
|
9
|
+
Python's "Twisted" event-handling framework. Here's a minimal example that
|
10
|
+
illustrates Deferrable:
|
11
|
+
|
12
|
+
require 'eventmachine'
|
13
|
+
|
14
|
+
class MyClass
|
15
|
+
include EM::Deferrable
|
16
|
+
|
17
|
+
def print_value x
|
18
|
+
puts "MyClass instance received #{x}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
EM.run {
|
23
|
+
df = MyClass.new
|
24
|
+
df.callback {|x|
|
25
|
+
df.print_value(x)
|
26
|
+
EM.stop
|
27
|
+
}
|
28
|
+
|
29
|
+
EM::Timer.new(2) {
|
30
|
+
df.set_deferred_status :succeeded, 100
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
|
35
|
+
This program will spin for two seconds, print out the string "MyClass
|
36
|
+
instance received 100" and then exit. The Deferrable pattern relies on
|
37
|
+
an unusual metaphor that may be unfamiliar to you, unless you've used
|
38
|
+
Python's Twisted. You may need to read the following material through
|
39
|
+
more than once before you get the idea.
|
40
|
+
|
41
|
+
EventMachine::Deferrable is simply a Ruby Module that you can include
|
42
|
+
in your own classes. (There also is a class named
|
43
|
+
EventMachine::DefaultDeferrable for when you want to create one without
|
44
|
+
including it in code of your own.)
|
45
|
+
|
46
|
+
An object that includes EventMachine::Deferrable is like any other Ruby
|
47
|
+
object: it can be created whenever you want, returned from your functions,
|
48
|
+
or passed as an argument to other functions.
|
49
|
+
|
50
|
+
The Deferrable pattern allows you to specify any number of Ruby code
|
51
|
+
blocks (callbacks or errbacks) that will be executed at some future time
|
52
|
+
when the status of the Deferrable object changes.
|
53
|
+
|
54
|
+
How might that be useful? Well, imagine that you're implementing an HTTP
|
55
|
+
server, but you need to make a call to some other server in order to fulfill
|
56
|
+
a client request.
|
57
|
+
|
58
|
+
When you receive a request from one of your clients, you can create and
|
59
|
+
return a Deferrable object. Some other section of your program can add a
|
60
|
+
callback to the Deferrable that will cause the client's request to be
|
61
|
+
fulfilled. Simultaneously, you initiate an event-driven or threaded client
|
62
|
+
request to some different server. And then your EM program will continue to
|
63
|
+
process other events and service other client requests.
|
64
|
+
|
65
|
+
When your client request to the other server completes some time later, you
|
66
|
+
will call the #set_deferred_status method on the Deferrable object, passing
|
67
|
+
either a success or failure status, and an arbitrary number of parameters
|
68
|
+
(which might include the data you received from the other server).
|
69
|
+
|
70
|
+
At that point, the status of the Deferrable object becomes known, and its
|
71
|
+
callback or errback methods are immediately executed. Callbacks and errbacks
|
72
|
+
are code blocks that are attached to Deferrable objects at any time through
|
73
|
+
the methods #callback and #errback.
|
74
|
+
|
75
|
+
The deep beauty of this pattern is that it decouples the disposition of one
|
76
|
+
operation (such as a client request to an outboard server) from the
|
77
|
+
subsequent operations that depend on that disposition (which may include
|
78
|
+
responding to a different client or any other operation).
|
79
|
+
|
80
|
+
The code which invokes the deferred operation (that will eventually result
|
81
|
+
in a success or failure status together with associated data) is completely
|
82
|
+
separate from the code which depends on that status and data. This achieves
|
83
|
+
one of the primary goals for which threading is typically used in
|
84
|
+
sophisticated applications, with none of the nondeterminacy or debugging
|
85
|
+
difficulties of threads.
|
86
|
+
|
87
|
+
As soon as the deferred status of a Deferrable becomes known by way of a call
|
88
|
+
to #set_deferred_status, the Deferrable will IMMEDIATELY execute all of its
|
89
|
+
callbacks or errbacks in the order in which they were added to the Deferrable.
|
90
|
+
|
91
|
+
Callbacks and errbacks can be added to a Deferrable object at any time, not
|
92
|
+
just when the object is created. They can even be added after the status of
|
93
|
+
the object has been determined! (In this case, they will be executed
|
94
|
+
immediately when they are added.)
|
95
|
+
|
96
|
+
A call to Deferrable#set_deferred_status takes :succeeded or :failed as its
|
97
|
+
first argument. (This determines whether the object will call its callbacks
|
98
|
+
or its errbacks.) #set_deferred_status also takes zero or more additional
|
99
|
+
parameters, that will in turn be passed as parameters to the callbacks or
|
100
|
+
errbacks.
|
101
|
+
|
102
|
+
In general, you can only call #set_deferred_status ONCE on a Deferrable
|
103
|
+
object. A call to #set_deferred_status will not return until all of the
|
104
|
+
associated callbacks or errbacks have been called. If you add callbacks or
|
105
|
+
errbacks AFTER making a call to #set_deferred_status, those additional
|
106
|
+
callbacks or errbacks will execute IMMEDIATELY. Any given callback or
|
107
|
+
errback will be executed AT MOST once.
|
108
|
+
|
109
|
+
It's possible to call #set_deferred_status AGAIN, during the execution a
|
110
|
+
callback or errback. This makes it possible to change the parameters which
|
111
|
+
will be sent to the callbacks or errbacks farther down the chain, enabling
|
112
|
+
some extremely elegant use-cases. You can transform the data returned from
|
113
|
+
a deferred operation in arbitrary ways as needed by subsequent users, without
|
114
|
+
changing any of the code that generated the original data.
|
115
|
+
|
116
|
+
A call to #set_deferred_status will not return until all of the associated
|
117
|
+
callbacks or errbacks have been called. If you add callbacks or errbacks
|
118
|
+
AFTER making a call to #set_deferred_status, those additional callbacks or
|
119
|
+
errbacks will execute IMMEDIATELY.
|
120
|
+
|
121
|
+
Let's look at some more sample code. It turns out that many of the internal
|
122
|
+
protocol implementations in the EventMachine package rely on Deferrable. One
|
123
|
+
of these is EM::Protocols::HttpClient.
|
124
|
+
|
125
|
+
To make an evented HTTP request, use the module function
|
126
|
+
EM::Protocols::HttpClient#request, which returns a Deferrable object.
|
127
|
+
Here's how:
|
128
|
+
|
129
|
+
require 'eventmachine'
|
130
|
+
|
131
|
+
EM.run {
|
132
|
+
df = EM::Protocols::HttpClient.request( :host=>"www.example.com",
|
133
|
+
:request=>"/index.html" )
|
134
|
+
|
135
|
+
df.callback {|response|
|
136
|
+
puts "Succeeded: #{response[:content]}"
|
137
|
+
EM.stop
|
138
|
+
}
|
139
|
+
|
140
|
+
df.errback {|response|
|
141
|
+
puts "ERROR: #{response[:status]}"
|
142
|
+
EM.stop
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
(See the documentation of EventMachine::Protocols::HttpClient for information
|
147
|
+
on the object returned by #request.)
|
148
|
+
|
149
|
+
In this code, we make a call to HttpClient#request, which immediately returns
|
150
|
+
a Deferrable object. In the background, an HTTP client request is being made
|
151
|
+
to www.example.com, although your code will continue to run concurrently.
|
152
|
+
|
153
|
+
At some future point, the HTTP client request will complete, and the code in
|
154
|
+
EM::Protocols::HttpClient will process either a valid HTTP response (including
|
155
|
+
returned content), or an error.
|
156
|
+
|
157
|
+
At that point, EM::Protocols::HttpClient will call
|
158
|
+
EM::Deferrable#set_deferred_status on the Deferrable object that was returned
|
159
|
+
to your program, as the return value from EM::Protocols::HttpClient.request.
|
160
|
+
You don't have to do anything to make this happen. All you have to do is tell
|
161
|
+
the Deferrable what to do in case of either success, failure, or both.
|
162
|
+
|
163
|
+
In our code sample, we set one callback and one errback. The former will be
|
164
|
+
called if the HTTP call succeeds, and the latter if it fails. (For
|
165
|
+
simplicity, we have both of them calling EM#stop to end the program, although
|
166
|
+
real programs would be very unlikely to do this.)
|
167
|
+
|
168
|
+
Setting callbacks and errbacks is optional. They are handlers to defined
|
169
|
+
events in the lifecycle of the Deferrable event. It's not an error if you
|
170
|
+
fail to set either a callback, an errback, or both. But of course your
|
171
|
+
program will then fail to receive those notifications.
|
172
|
+
|
173
|
+
If through some bug it turns out that #set_deferred_status is never called
|
174
|
+
on a Deferrable object, then that object's callbacks or errbacks will NEVER
|
175
|
+
be called. It's also possible to set a timeout on a Deferrable. If the
|
176
|
+
timeout elapses before any other call to #set_deferred_status, the Deferrable
|
177
|
+
object will behave as is you had called set_deferred_status(:failed) on it.
|
178
|
+
|
179
|
+
|
180
|
+
Now let's modify the example to illustrate some additional points:
|
181
|
+
|
182
|
+
require 'eventmachine'
|
183
|
+
|
184
|
+
EM.run {
|
185
|
+
df = EM::Protocols::HttpClient.request( :host=>"www.example.com",
|
186
|
+
:request=>"/index.html" )
|
187
|
+
|
188
|
+
df.callback {|response|
|
189
|
+
df.set_deferred_status :succeeded, response[:content]
|
190
|
+
}
|
191
|
+
|
192
|
+
df.callback {|string|
|
193
|
+
puts "Succeeded: #{string}"
|
194
|
+
EM.stop
|
195
|
+
}
|
196
|
+
|
197
|
+
df.errback {|response|
|
198
|
+
puts "ERROR: #{response[:status]}"
|
199
|
+
EM.stop
|
200
|
+
}
|
201
|
+
}
|
202
|
+
|
203
|
+
|
204
|
+
Just for the sake of illustration, we've now set two callbacks instead of
|
205
|
+
one. If the deferrable operation (the HTTP client-request) succeeds, then
|
206
|
+
both of the callbacks will be executed in order.
|
207
|
+
|
208
|
+
But notice that we've also made our own call to #set_deferred_status in the
|
209
|
+
first callback. This isn't required, because the HttpClient implementation
|
210
|
+
already made a call to #set_deferred_status. (Otherwise, of course, the
|
211
|
+
callback would not be executing.)
|
212
|
+
|
213
|
+
But we used #set_deferred_status in the first callback in order to change the
|
214
|
+
parameters that will be sent to subsequent callbacks in the chain. In this
|
215
|
+
way, you can construct powerful sequences of layered functionality. If you
|
216
|
+
want, you can even change the status of the Deferrable from :succeeded to
|
217
|
+
:failed, which would abort the chain of callback calls, and invoke the chain
|
218
|
+
of errbacks instead.
|
219
|
+
|
220
|
+
Now of course it's somewhat trivial to define two callbacks in the same
|
221
|
+
method, even with the parameter-changing effect we just described. It would
|
222
|
+
be much more interesting to pass the Deferrable to some other function (for
|
223
|
+
example, a function defined in another module or a different gem), that would
|
224
|
+
in turn add callbacks and/or errbacks of its own. That would illustrate the
|
225
|
+
true power of the Deferrable pattern: to isolate the HTTP client-request
|
226
|
+
from other functions that use the data that it returns without caring where
|
227
|
+
those data came from.
|
228
|
+
|
229
|
+
Remember that you can add a callback or an errback to a Deferrable at any
|
230
|
+
point in time, regardless of whether the status of the deferred operation is
|
231
|
+
known (more precisely, regardless of when #set_deferred_status is called on
|
232
|
+
the object). Even hours or days later.
|
233
|
+
|
234
|
+
When you add a callback or errback to a Deferrable object on which
|
235
|
+
#set_deferred_status has not yet been called, the callback/errback is queued
|
236
|
+
up for future execution, inside the Deferrable object. When you add a
|
237
|
+
callback or errback to a Deferrable on which #set_deferred_status has
|
238
|
+
already been called, the callback/errback will be executed immediately.
|
239
|
+
Your code doesn't have to worry about the ordering, and there are no timing
|
240
|
+
issues, as there would be with a threaded approach.
|
241
|
+
|
242
|
+
For more information on Deferrables and their typical usage patterns, look
|
243
|
+
in the EM unit tests. There are also quite a few sugarings (including
|
244
|
+
EM::Deferrable#future) that make typical Deferrable usages syntactically
|
245
|
+
easier to work with.
|
246
|
+
|
data/docs/EPOLL
CHANGED
@@ -1,141 +1,141 @@
|
|
1
|
-
EventMachine now supports epoll, bringing large increases in performance and scalability to Ruby programs.
|
2
|
-
|
3
|
-
Epoll(7) is a alternative mechanism for multiplexed I/O that is available in Linux 2.6 kernels.
|
4
|
-
It features significantly greater performance than the standard select(2) mechanism, when used in
|
5
|
-
applications that require very large numbers of open I/O descriptors.
|
6
|
-
|
7
|
-
EventMachine has always used select(2) because its behavior is well standardized and broadly supported.
|
8
|
-
But select becomes unreasonably slow when a program has a
|
9
|
-
very large number of file descriptors or sockets. Ruby's version of select hardcodes a limit
|
10
|
-
of 1024 descriptors per process, but heavily loaded processes will start to show performance
|
11
|
-
degradation even after only a few hundred descriptors are in use.
|
12
|
-
|
13
|
-
Epoll is an extended version of the poll(2) call, and it solves the problems with select. Programs
|
14
|
-
based on epoll can easily scale past Ruby's 1024-descriptor limit, potentially to tens of thousands
|
15
|
-
of connectors, with no significant impact on performance.
|
16
|
-
|
17
|
-
(Another alternative which is very similar to epoll in principle is kqueue, supplied on BSD and its
|
18
|
-
variants.)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
This note shows you how to use epoll in your programs.
|
23
|
-
|
24
|
-
=== Compiling EventMachine to use epoll.
|
25
|
-
|
26
|
-
You don't have to do anything to get epoll support in EventMachine.
|
27
|
-
When you compile EventMachine on a platform that supports epoll, EM will
|
28
|
-
automatically generate a Makefile that includes epoll. (At this writing, this will only work
|
29
|
-
on Linux 2.6 kernels.) If you compile EM on a platform without epoll, then epoll support will
|
30
|
-
be omitted from the Makefile, and EM will work just as it always has.
|
31
|
-
|
32
|
-
=== Using epoll in your programs.
|
33
|
-
|
34
|
-
First, you need to tell EventMachine to use epoll instead of select (but see below, as this requirement
|
35
|
-
will be removed in a future EventMachine version). Second, you need to prepare your program to use
|
36
|
-
more than 1024 descriptors, an operation that generally requires superuser privileges. Third, you will probably
|
37
|
-
want your process to drop the superuser privileges after you increase your process's descriptor limit.
|
38
|
-
|
39
|
-
=== Using EventMachine#epoll
|
40
|
-
|
41
|
-
Call the method EventMachine#epoll anytime before you call EventMachine#run, and your program will
|
42
|
-
automatically use epoll, if available. It's safe to call EventMachine#epoll on any platform because
|
43
|
-
it compiles to a no-op on platforms that don't support epoll.
|
44
|
-
|
45
|
-
require 'rubygems'
|
46
|
-
require 'eventmachine'
|
47
|
-
|
48
|
-
EM.epoll
|
49
|
-
EM.run {
|
50
|
-
...
|
51
|
-
}
|
52
|
-
|
53
|
-
|
54
|
-
EventMachine#epoll was included in this initial release only to avoid changing the behavior of existing
|
55
|
-
programs. However, it's expected that a future release of EM will convert EventMachine#epoll to a no-op,
|
56
|
-
and run epoll by default on platforms that support it.
|
57
|
-
|
58
|
-
=== Using EventMachine#set_descriptor_table_size
|
59
|
-
|
60
|
-
In Linux (as in every Unix-like platform), every process has a internal table that determines the maximum
|
61
|
-
number of file and socket descriptors you may have open at any given time. The size of this table is
|
62
|
-
generally fixed at 1024, although it may be increased within certain system-defined hard and soft limits.
|
63
|
-
|
64
|
-
If you want your EventMachine program to support more than 1024 total descriptors, you must use
|
65
|
-
EventMachine#set_descriptor_table_size, as follows:
|
66
|
-
|
67
|
-
require 'rubygems'
|
68
|
-
require 'eventmachine'
|
69
|
-
|
70
|
-
new_size = EM.set_descriptor_table_size( 60000 )
|
71
|
-
$>.puts "New descriptor-table size is #{new_size}"
|
72
|
-
|
73
|
-
EM.run {
|
74
|
-
...
|
75
|
-
}
|
76
|
-
|
77
|
-
If successful, this example will increase the maximum number of descriptors that epoll can use to 60,000.
|
78
|
-
Call EventMachine#set_descriptor_table_size without an argument at any time to find out the current
|
79
|
-
size of the descriptor table.
|
80
|
-
|
81
|
-
Using EventMachine#set_descriptor_table_size ONLY affects the number of descriptors that can be used
|
82
|
-
by epoll. It has no useful effect on platforms that don't support epoll, and it does NOT increase the
|
83
|
-
number of descriptors that Ruby's own I/O functions can use.
|
84
|
-
|
85
|
-
#set_descriptor_table_size can fail if your process is not running as superuser, or if you try to set a
|
86
|
-
table size that exceeds the hard limits imposed by your system. In the latter case, try a smaller number.
|
87
|
-
|
88
|
-
|
89
|
-
=== Using EventMachine#set_effective_user
|
90
|
-
|
91
|
-
In general, you must run your program with elevated or superuser privileges if you want to increase
|
92
|
-
your descriptor-table size beyond 1024 descriptors. This is easy enough to verify. Try running the
|
93
|
-
sample program given above, that increases the descriptor limit to 60,000. You will probably find that
|
94
|
-
the table size will not be increased if you don't run your program as root or with elevated privileges.
|
95
|
-
|
96
|
-
But of course network servers, especially long-running ones, should not run with elevated privileges.
|
97
|
-
You will want to drop superuser privileges as soon as possible after initialization. To do this,
|
98
|
-
use EventMachine#set_effective_user:
|
99
|
-
|
100
|
-
require 'rubygems'
|
101
|
-
require 'eventmachine'
|
102
|
-
|
103
|
-
# (Here, program is running as superuser)
|
104
|
-
|
105
|
-
EM.set_descriptor_table_size( 60000 )
|
106
|
-
EM.set_effective_user( "nobody" )
|
107
|
-
# (Here, program is running as nobody)
|
108
|
-
|
109
|
-
EM.run {
|
110
|
-
...
|
111
|
-
}
|
112
|
-
|
113
|
-
Of course, you will need to replace "nobody" in the example with the name of an unprivileged user
|
114
|
-
that is valid on your system. What if you want to drop privileges after opening a server socket
|
115
|
-
on a privileged (low-numbered) port? Easy, just call #set_effective_user after opening your sockets:
|
116
|
-
|
117
|
-
require 'rubygems'
|
118
|
-
require 'eventmachine'
|
119
|
-
|
120
|
-
# (Here, program is running as superuser)
|
121
|
-
|
122
|
-
EM.set_descriptor_table_size( 60000 )
|
123
|
-
|
124
|
-
EM.run {
|
125
|
-
EM.start_server( "0.0.0.0", 80, MyHttpServer )
|
126
|
-
EM.start_server( "0.0.0.0", 443, MyEncryptedHttpServer )
|
127
|
-
|
128
|
-
EM.set_effective_user( "nobody" )
|
129
|
-
# (Here, program is running as nobody)
|
130
|
-
|
131
|
-
...
|
132
|
-
}
|
133
|
-
|
134
|
-
|
135
|
-
Because EventMachine#set_effective_user is used to enforce security
|
136
|
-
requirements, it has no nonfatal errors. If you try to set a nonexistent or invalid effective user,
|
137
|
-
#set_effective_user will abort your program, rather than continue to run with elevated privileges.
|
138
|
-
|
139
|
-
EventMachine#set_effective_user is a silent no-op on platforms that don't support it, such as Windows.
|
140
|
-
|
141
|
-
|
1
|
+
EventMachine now supports epoll, bringing large increases in performance and scalability to Ruby programs.
|
2
|
+
|
3
|
+
Epoll(7) is a alternative mechanism for multiplexed I/O that is available in Linux 2.6 kernels.
|
4
|
+
It features significantly greater performance than the standard select(2) mechanism, when used in
|
5
|
+
applications that require very large numbers of open I/O descriptors.
|
6
|
+
|
7
|
+
EventMachine has always used select(2) because its behavior is well standardized and broadly supported.
|
8
|
+
But select becomes unreasonably slow when a program has a
|
9
|
+
very large number of file descriptors or sockets. Ruby's version of select hardcodes a limit
|
10
|
+
of 1024 descriptors per process, but heavily loaded processes will start to show performance
|
11
|
+
degradation even after only a few hundred descriptors are in use.
|
12
|
+
|
13
|
+
Epoll is an extended version of the poll(2) call, and it solves the problems with select. Programs
|
14
|
+
based on epoll can easily scale past Ruby's 1024-descriptor limit, potentially to tens of thousands
|
15
|
+
of connectors, with no significant impact on performance.
|
16
|
+
|
17
|
+
(Another alternative which is very similar to epoll in principle is kqueue, supplied on BSD and its
|
18
|
+
variants.)
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
This note shows you how to use epoll in your programs.
|
23
|
+
|
24
|
+
=== Compiling EventMachine to use epoll.
|
25
|
+
|
26
|
+
You don't have to do anything to get epoll support in EventMachine.
|
27
|
+
When you compile EventMachine on a platform that supports epoll, EM will
|
28
|
+
automatically generate a Makefile that includes epoll. (At this writing, this will only work
|
29
|
+
on Linux 2.6 kernels.) If you compile EM on a platform without epoll, then epoll support will
|
30
|
+
be omitted from the Makefile, and EM will work just as it always has.
|
31
|
+
|
32
|
+
=== Using epoll in your programs.
|
33
|
+
|
34
|
+
First, you need to tell EventMachine to use epoll instead of select (but see below, as this requirement
|
35
|
+
will be removed in a future EventMachine version). Second, you need to prepare your program to use
|
36
|
+
more than 1024 descriptors, an operation that generally requires superuser privileges. Third, you will probably
|
37
|
+
want your process to drop the superuser privileges after you increase your process's descriptor limit.
|
38
|
+
|
39
|
+
=== Using EventMachine#epoll
|
40
|
+
|
41
|
+
Call the method EventMachine#epoll anytime before you call EventMachine#run, and your program will
|
42
|
+
automatically use epoll, if available. It's safe to call EventMachine#epoll on any platform because
|
43
|
+
it compiles to a no-op on platforms that don't support epoll.
|
44
|
+
|
45
|
+
require 'rubygems'
|
46
|
+
require 'eventmachine'
|
47
|
+
|
48
|
+
EM.epoll
|
49
|
+
EM.run {
|
50
|
+
...
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
EventMachine#epoll was included in this initial release only to avoid changing the behavior of existing
|
55
|
+
programs. However, it's expected that a future release of EM will convert EventMachine#epoll to a no-op,
|
56
|
+
and run epoll by default on platforms that support it.
|
57
|
+
|
58
|
+
=== Using EventMachine#set_descriptor_table_size
|
59
|
+
|
60
|
+
In Linux (as in every Unix-like platform), every process has a internal table that determines the maximum
|
61
|
+
number of file and socket descriptors you may have open at any given time. The size of this table is
|
62
|
+
generally fixed at 1024, although it may be increased within certain system-defined hard and soft limits.
|
63
|
+
|
64
|
+
If you want your EventMachine program to support more than 1024 total descriptors, you must use
|
65
|
+
EventMachine#set_descriptor_table_size, as follows:
|
66
|
+
|
67
|
+
require 'rubygems'
|
68
|
+
require 'eventmachine'
|
69
|
+
|
70
|
+
new_size = EM.set_descriptor_table_size( 60000 )
|
71
|
+
$>.puts "New descriptor-table size is #{new_size}"
|
72
|
+
|
73
|
+
EM.run {
|
74
|
+
...
|
75
|
+
}
|
76
|
+
|
77
|
+
If successful, this example will increase the maximum number of descriptors that epoll can use to 60,000.
|
78
|
+
Call EventMachine#set_descriptor_table_size without an argument at any time to find out the current
|
79
|
+
size of the descriptor table.
|
80
|
+
|
81
|
+
Using EventMachine#set_descriptor_table_size ONLY affects the number of descriptors that can be used
|
82
|
+
by epoll. It has no useful effect on platforms that don't support epoll, and it does NOT increase the
|
83
|
+
number of descriptors that Ruby's own I/O functions can use.
|
84
|
+
|
85
|
+
#set_descriptor_table_size can fail if your process is not running as superuser, or if you try to set a
|
86
|
+
table size that exceeds the hard limits imposed by your system. In the latter case, try a smaller number.
|
87
|
+
|
88
|
+
|
89
|
+
=== Using EventMachine#set_effective_user
|
90
|
+
|
91
|
+
In general, you must run your program with elevated or superuser privileges if you want to increase
|
92
|
+
your descriptor-table size beyond 1024 descriptors. This is easy enough to verify. Try running the
|
93
|
+
sample program given above, that increases the descriptor limit to 60,000. You will probably find that
|
94
|
+
the table size will not be increased if you don't run your program as root or with elevated privileges.
|
95
|
+
|
96
|
+
But of course network servers, especially long-running ones, should not run with elevated privileges.
|
97
|
+
You will want to drop superuser privileges as soon as possible after initialization. To do this,
|
98
|
+
use EventMachine#set_effective_user:
|
99
|
+
|
100
|
+
require 'rubygems'
|
101
|
+
require 'eventmachine'
|
102
|
+
|
103
|
+
# (Here, program is running as superuser)
|
104
|
+
|
105
|
+
EM.set_descriptor_table_size( 60000 )
|
106
|
+
EM.set_effective_user( "nobody" )
|
107
|
+
# (Here, program is running as nobody)
|
108
|
+
|
109
|
+
EM.run {
|
110
|
+
...
|
111
|
+
}
|
112
|
+
|
113
|
+
Of course, you will need to replace "nobody" in the example with the name of an unprivileged user
|
114
|
+
that is valid on your system. What if you want to drop privileges after opening a server socket
|
115
|
+
on a privileged (low-numbered) port? Easy, just call #set_effective_user after opening your sockets:
|
116
|
+
|
117
|
+
require 'rubygems'
|
118
|
+
require 'eventmachine'
|
119
|
+
|
120
|
+
# (Here, program is running as superuser)
|
121
|
+
|
122
|
+
EM.set_descriptor_table_size( 60000 )
|
123
|
+
|
124
|
+
EM.run {
|
125
|
+
EM.start_server( "0.0.0.0", 80, MyHttpServer )
|
126
|
+
EM.start_server( "0.0.0.0", 443, MyEncryptedHttpServer )
|
127
|
+
|
128
|
+
EM.set_effective_user( "nobody" )
|
129
|
+
# (Here, program is running as nobody)
|
130
|
+
|
131
|
+
...
|
132
|
+
}
|
133
|
+
|
134
|
+
|
135
|
+
Because EventMachine#set_effective_user is used to enforce security
|
136
|
+
requirements, it has no nonfatal errors. If you try to set a nonexistent or invalid effective user,
|
137
|
+
#set_effective_user will abort your program, rather than continue to run with elevated privileges.
|
138
|
+
|
139
|
+
EventMachine#set_effective_user is a silent no-op on platforms that don't support it, such as Windows.
|
140
|
+
|
141
|
+
|