log-courier 1.9.0 → 2.7.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,324 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # Copyright 2014 Jason Woods.
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
-
17
- begin
18
- require 'ffi-rzmq'
19
- require 'ffi-rzmq/version'
20
- require 'ffi-rzmq-core/version'
21
- rescue LoadError => e
22
- raise "ZMQPoll could not initialise: #{e}"
23
- end
24
-
25
- module ZMQPoll
26
- class ZMQError < StandardError; end
27
- class ZMQTerm < StandardError; end
28
- class TimeoutError < StandardError; end
29
-
30
- class ZMQPoll
31
- def initialize(context, logger=nil)
32
- @logger = logger
33
- @context = context
34
- @poller = ZMQ::Poller.new
35
- @sockets = []
36
- @socket_to_socket = []
37
- @handlers = {}
38
- @queues = {}
39
- end
40
-
41
- def readables
42
- @poller.readables
43
- end
44
-
45
- def writables
46
- @poller.writables
47
- end
48
-
49
- def shutdown
50
- @queues.each_key do |queue|
51
- deregister_queue queue
52
- end
53
-
54
- @socket_to_socket.each do |socket|
55
- _close_socket_to_socket socket
56
- end
57
-
58
- @sockets.each do |socket|
59
- socket.close
60
- end
61
- return
62
- end
63
-
64
- def register_socket(socket, flags)
65
- @poller.register socket, flags
66
- return
67
- end
68
-
69
- def deregister_socket(socket)
70
- return if @handlers.key?(socket)
71
-
72
- @poller.delete socket
73
- return
74
- end
75
-
76
- def register_queue_to_socket(queue, socket)
77
- s2s_state = _create_socket_to_socket(socket)
78
-
79
- state = {
80
- state: s2s_state,
81
- mutex: Mutex.new,
82
- shutdown: false,
83
- }
84
-
85
- state[:thread] = Thread.new do
86
- loop do
87
- data = queue.pop
88
- break if data.nil?
89
- begin
90
- send s2s_state[:sender], data
91
- rescue TimeoutError
92
- state[:mutex].synchronize do
93
- break if state[:shutdown]
94
- end
95
- retry
96
- end
97
- end
98
- end
99
-
100
- @queues[queue] = state
101
- return
102
- end
103
-
104
- def deregister_queue(queue)
105
- return if !@queues.key?(queue)
106
-
107
- # Push nil so if we're idle we jump into action and exit
108
- # But also set shutdown to try so if we're mid-send and timeout, we exit
109
- @queues[queue][:mutex].synchronize do
110
- queue.push nil
111
- @queues[queue][:shutdown] = true
112
- end
113
- @queues[queue][:thread].join
114
-
115
- _close_socket_to_socket @queues[queue][:state]
116
- @queues.delete queue
117
- return
118
- end
119
-
120
- def create_socket_to_socket(socket)
121
- state = _create_socket_to_socket(socket)
122
- @socket_to_socket[state[:sender]] = state
123
- state[:sender]
124
- end
125
-
126
- def close_socket_to_socket(socket)
127
- return if !@socket_to_socket.include?(socket)
128
- state = @socket_to_socket[socket]
129
- @socket_to_socket.delete socket
130
- _close_socket_to_socket(state)
131
- return
132
- end
133
-
134
- def poll(timeout)
135
- if @poller.size == 0
136
- fail ZMQError, 'poll run called with zero socket/queues'
137
- end
138
-
139
- rc = @poller.poll(timeout)
140
- unless ZMQ::Util.resultcode_ok?(rc)
141
- # If we get ETERM or ENOTSOCK - we may have hit JRuby bug where finalisers are called too early
142
- # We throw it so the caller knows NOT to retry and hit a bad loop
143
- # The downside is - this Jruby bug will cause an inevitable deadlock
144
- # The finaliser for the context will have run before finalisers for sockets (random order?)
145
- # The resulting ZMQ context termination will block, waiting for sockets to be closed
146
- # However, when closing a socket, ffi-rzmq will attempt to remove it's finaliser
147
- # This removal will deadlock as it attempts to lock the finaliser list, which is locked by the
148
- # thread that is running the ZMQ context termination, which is blocked...
149
- # TODO: Raise issue in JRuby github and try to track down why finalisers run while code is running
150
- # if the exit! call is made
151
- fail ZMQTerm, 'poll error: ' + ZMQ::Util.error_string if ZMQ::Util.errno == ZMQ::ETERM || ZMQ::Util.errno == ZMQ::ENOTSOCK
152
- fail ZMQError, 'poll error: ' + ZMQ::Util.error_string
153
- end
154
-
155
- return if rc == 0
156
-
157
- ready = (@poller.readables|@poller.writables)
158
-
159
- ready.each do |socket|
160
- if @handlers.key?(socket)
161
- __send__ @handlers[socket][:callback], @handlers[socket]
162
- end
163
-
164
- yield socket, @poller.readables.include?(socket), @poller.writables.include?(socket)
165
- end
166
-
167
- return
168
- end
169
-
170
- private
171
-
172
- def _create_socket_to_socket(socket)
173
- receiver = @context.socket(ZMQ::PULL)
174
- fail ZMQError, 'socket creation error: ' + ZMQ::Util.error_string if receiver.nil?
175
-
176
- rc = receiver.setsockopt(ZMQ::LINGER, 0)
177
- fail ZMQError, 'setsockopt LINGER failure: ' + ZMQ::Util.error_string unless ZMQ::Util.resultcode_ok?(rc)
178
-
179
- rc = receiver.bind("inproc://zmqpollreceiver-#{receiver.hash}")
180
- fail ZMQError, 'bind error: ' + ZMQ::Util.error_string unless ZMQ::Util.resultcode_ok?(rc)
181
-
182
- sender = @context.socket(ZMQ::PUSH)
183
- fail ZMQError, 'socket creation error: ' + ZMQ::Util.error_string if sender.nil?
184
-
185
- rc = sender.setsockopt(ZMQ::LINGER, 0)
186
- fail ZMQError, 'setsockopt LINGER failure: ' + ZMQ::Util.error_string unless ZMQ::Util.resultcode_ok?(rc)
187
-
188
- rc = sender.connect("inproc://zmqpollreceiver-#{receiver.hash}")
189
- fail ZMQError, 'bind error: ' + ZMQ::Util.error_string unless ZMQ::Util.resultcode_ok?(rc)
190
-
191
- state = {
192
- :callback => :handle_socket_to_socket,
193
- :sender => sender,
194
- :receiver => receiver,
195
- :socket => socket,
196
- :buffer => nil,
197
- :send_ok => false,
198
- :recv_ok => false,
199
- }
200
-
201
- @poller.register receiver, ZMQ::POLLIN
202
- @poller.register socket, ZMQ::POLLOUT
203
- @handlers[receiver] = state
204
- @handlers[socket] = state
205
-
206
- @sockets.push sender
207
-
208
- state
209
- end
210
-
211
- def _close_socket_to_socket(state)
212
- @sockets.delete state[:sender]
213
-
214
- @poller.delete state[:receiver]
215
- @poller.delete state[:socket]
216
-
217
- state[:sender].close
218
- state[:receiver].close
219
-
220
- @handlers.delete state[:receiver]
221
- @handlers.delete state[:socket]
222
-
223
- return
224
- end
225
-
226
- def handle_socket_to_socket(state)
227
- state[:recv_ok] = @poller.readables.include?(state[:receiver]) || state[:recv_ok]
228
- state[:send_ok] = @poller.writables.include?(state[:socket]) || state[:send_ok]
229
-
230
- loop do
231
- if state[:send_ok] && !state[:buffer].nil?
232
- begin
233
- send state[:socket], state[:buffer]
234
- rescue TimeoutError
235
- end
236
- state[:buffer] = nil if state[:buffer].length == 0
237
- state[:send_ok] = false
238
- end
239
-
240
- break if !state[:recv_ok]
241
-
242
- if state[:recv_ok] && state[:buffer].nil?
243
- begin
244
- state[:buffer] = recv(state[:receiver])
245
- rescue TimeoutError
246
- end
247
- state[:recv_ok] = false
248
- end
249
-
250
- break if !state[:send_ok]
251
- end
252
-
253
- if state[:recv_ok]
254
- @poller.deregister state[:receiver], ZMQ::POLLIN
255
- else
256
- @poller.register state[:receiver], ZMQ::POLLIN
257
- end
258
-
259
- if state[:send_ok]
260
- @poller.deregister state[:socket], ZMQ::POLLOUT
261
- else
262
- @poller.register state[:socket], ZMQ::POLLOUT
263
- end
264
-
265
- return
266
- end
267
-
268
- def recv(socket)
269
- data = []
270
-
271
- poll_eagain(socket, ZMQ::POLLIN, 5) do
272
- # recv_strings appears to be safe, ZMQ documents that a client will either
273
- # receive 0 parts or all parts
274
- socket.recv_strings(data, ZMQ::DONTWAIT)
275
- end
276
-
277
- data
278
- end
279
-
280
- def send(socket, data)
281
- while data.length != 1
282
- send_part socket, data.shift, true
283
- end
284
- send_part socket, data.shift
285
- return
286
- end
287
-
288
- def send_part(socket, data, more=false)
289
- poll_eagain(socket, ZMQ::POLLOUT, 5) do
290
- # Try to send a message but never block
291
- # We could use send_strings but it is vague on if ZMQ can return an
292
- # error midway through sending parts...
293
- socket.send_string(data, (more ? ZMQ::SNDMORE : 0) | ZMQ::DONTWAIT)
294
- end
295
-
296
- return
297
- end
298
-
299
- def poll_eagain(socket, flag, timeout, &block)
300
- poller = nil
301
- timeout = Time.now.to_i + timeout
302
- loop do
303
- rc = block.call()
304
- break if ZMQ::Util.resultcode_ok?(rc)
305
- if ZMQ::Util.errno != ZMQ::EAGAIN
306
- fail ZMQError, 'message receive failed: ' + ZMQ::Util.error_string if flag == ZMQ::POLLIN
307
- fail ZMQError, 'message send failed: ' + ZMQ::Util.error_string
308
- end
309
-
310
- # Wait for send to become available, handling timeouts
311
- if poller.nil?
312
- poller = ZMQ::Poller.new
313
- poller.register socket, flag
314
- end
315
-
316
- while poller.poll(1_000) == 0
317
- # Using this inner while triggers pollThreadEvents in JRuby which checks for Thread.raise immediately
318
- fail TimeoutError while Time.now.to_i >= timeout
319
- end
320
- end
321
- return
322
- end
323
- end
324
- end