arya-pandemic 0.5.0 → 0.5.1
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/Rakefile +1 -1
- data/lib/pandemic.rb +1 -0
- data/lib/pandemic/connection_pool.rb +1 -1
- data/lib/pandemic/server_side/client.rb +11 -10
- data/lib/pandemic/server_side/peer.rb +24 -24
- data/lib/pandemic/server_side/request.rb +8 -2
- data/lib/pandemic/server_side/server.rb +14 -14
- data/pandemic.gemspec +2 -2
- metadata +2 -2
data/Rakefile
CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
|
|
2
2
|
require 'rake'
|
3
3
|
require 'echoe'
|
4
4
|
|
5
|
-
Echoe.new('pandemic', '0.5.
|
5
|
+
Echoe.new('pandemic', '0.5.1') do |p|
|
6
6
|
p.description = "A framework for distributing work for real-time services and offline tasks."
|
7
7
|
p.url = "https://github.com/arya/pandemic/"
|
8
8
|
p.author = "Arya Asemanfar"
|
data/lib/pandemic.rb
CHANGED
@@ -30,6 +30,7 @@ require 'pandemic/client_side/pandemize'
|
|
30
30
|
TCP_NO_DELAY_AVAILABLE =
|
31
31
|
RUBY_VERSION < '1.9' ? Socket.constants.include?('TCP_NODELAY') : Socket.constants.include?(:TCP_NODELAY)
|
32
32
|
|
33
|
+
MONITOR_TIMEOUT_AVAILABLE = (RUBY_VERSION < '1.9')
|
33
34
|
def epidemic!(options = {})
|
34
35
|
if $pandemic_logger.nil?
|
35
36
|
$pandemic_logger = Logger.new(options[:log_file] || "pandemic.log")
|
@@ -12,7 +12,7 @@ module Pandemic
|
|
12
12
|
@max_connections = options[:max_connections] || 10
|
13
13
|
@min_connections = options[:min_connections] || 1
|
14
14
|
@connect_at_define = options.include?(:connect_at_define) ? options[:connect_at_define] : true
|
15
|
-
@timeout = options[:timeout] || 3
|
15
|
+
@timeout = MONITOR_TIMEOUT_AVAILABLE ? options[:timeout] || 3 : nil
|
16
16
|
end
|
17
17
|
|
18
18
|
def add_connection!
|
@@ -2,6 +2,7 @@ module Pandemic
|
|
2
2
|
module ServerSide
|
3
3
|
class Client
|
4
4
|
REQUEST_FLAGS = {:async => 'a'}
|
5
|
+
EMPTY_STRING = ""
|
5
6
|
REQUEST_REGEXP = /^([0-9]+)(?: ([#{REQUEST_FLAGS.values.join('')}]*))?$/
|
6
7
|
class DisconnectClient < Exception; end
|
7
8
|
include Util
|
@@ -22,21 +23,21 @@ module Pandemic
|
|
22
23
|
@listener_thread = Thread.new do
|
23
24
|
begin
|
24
25
|
while @server.running
|
25
|
-
debug("Waiting for incoming request")
|
26
|
+
# debug("Waiting for incoming request")
|
26
27
|
request = @connection.gets
|
27
|
-
info("Received incoming request")
|
28
|
+
# info("Received incoming request")
|
28
29
|
@received_requests += 1
|
29
30
|
|
30
31
|
if request.nil?
|
31
|
-
debug("Incoming request is nil")
|
32
|
+
# debug("Incoming request is nil")
|
32
33
|
@connection.close
|
33
34
|
@connection = nil
|
34
35
|
break
|
35
36
|
elsif request.strip! =~ REQUEST_REGEXP
|
36
|
-
size, flags = $1.to_i, $2.to_s.split(
|
37
|
-
debug("Reading request body (size #{size})")
|
37
|
+
size, flags = $1.to_i, $2.to_s.split(EMPTY_STRING)
|
38
|
+
# debug("Reading request body (size #{size})")
|
38
39
|
body = @connection.read(size)
|
39
|
-
debug("Finished reading request body")
|
40
|
+
# debug("Finished reading request body")
|
40
41
|
if flags.include?(REQUEST_FLAGS[:async])
|
41
42
|
Thread.new do
|
42
43
|
handle_request(body)
|
@@ -45,18 +46,18 @@ module Pandemic
|
|
45
46
|
else
|
46
47
|
response = handle_request(body)
|
47
48
|
if response
|
48
|
-
debug("Writing response to client")
|
49
|
+
# debug("Writing response to client")
|
49
50
|
|
50
51
|
# the connection could be closed, we'll let it be rescued if it is.
|
51
52
|
@connection.write("#{response.size}\n#{response}")
|
52
53
|
@connection.flush
|
53
|
-
debug("Finished writing response to client")
|
54
|
+
# debug("Finished writing response to client")
|
54
55
|
else
|
55
|
-
debug("Writing error code to client")
|
56
|
+
# debug("Writing error code to client")
|
56
57
|
|
57
58
|
@connection.write("-1\n")
|
58
59
|
@connection.flush
|
59
|
-
debug("Finished writing error code to client")
|
60
|
+
# debug("Finished writing error code to client")
|
60
61
|
end
|
61
62
|
@responded_requests.inc
|
62
63
|
end
|
@@ -29,18 +29,18 @@ module Pandemic
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def client_request(request, body)
|
32
|
-
debug("Sending client's request to peer")
|
33
|
-
debug("Connection pool has #{@connection_pool.available_count} of #{@connection_pool.connections_count} connections available")
|
32
|
+
# debug("Sending client's request to peer")
|
33
|
+
# debug("Connection pool has #{@connection_pool.available_count} of #{@connection_pool.connections_count} connections available")
|
34
34
|
# TODO: Consider adding back threads here if it will be faster that way in Ruby 1.9
|
35
35
|
@connection_pool.with_connection do |connection|
|
36
36
|
if connection && !connection.closed?
|
37
37
|
@pending_requests.synchronize do
|
38
38
|
@pending_requests[request.hash] = request
|
39
39
|
end
|
40
|
-
debug("Writing client's request")
|
40
|
+
# debug("Writing client's request")
|
41
41
|
connection.write("PROCESS #{request.hash} #{body.size}\n#{body}")
|
42
42
|
connection.flush
|
43
|
-
debug("Finished writing client's request")
|
43
|
+
# debug("Finished writing client's request")
|
44
44
|
end # TODO: else? fail silently? reconnect?
|
45
45
|
end
|
46
46
|
end
|
@@ -55,15 +55,15 @@ module Pandemic
|
|
55
55
|
begin
|
56
56
|
debug("Incoming connection thread started")
|
57
57
|
while @server.running
|
58
|
-
debug("Listening for incoming requests")
|
58
|
+
# debug("Listening for incoming requests")
|
59
59
|
request = connection.gets
|
60
|
-
debug("Read incoming request from peer")
|
60
|
+
# debug("Read incoming request from peer")
|
61
61
|
|
62
62
|
if request.nil?
|
63
|
-
debug("Incoming connection request is nil")
|
63
|
+
# debug("Incoming connection request is nil")
|
64
64
|
break
|
65
65
|
else
|
66
|
-
debug("Received incoming (#{request.strip})")
|
66
|
+
# debug("Received incoming (#{request.strip})")
|
67
67
|
handle_incoming_request(request, connection) if request =~ /^PROCESS/
|
68
68
|
handle_incoming_response(request, connection) if request =~ /^RESPONSE/
|
69
69
|
end
|
@@ -114,23 +114,23 @@ module Pandemic
|
|
114
114
|
end
|
115
115
|
|
116
116
|
def handle_incoming_request(request, connection)
|
117
|
-
debug("Identified as request")
|
117
|
+
# debug("Identified as request")
|
118
118
|
if request.strip =~ /^PROCESS ([A-Za-z0-9]+) ([0-9]+)$/
|
119
119
|
hash = $1
|
120
120
|
size = $2.to_i
|
121
|
-
debug("Incoming request: #{hash} #{size}")
|
121
|
+
# debug("Incoming request: #{hash} #{size}")
|
122
122
|
begin
|
123
|
-
debug("Reading request body")
|
123
|
+
# debug("Reading request body")
|
124
124
|
request_body = connection.read(size)
|
125
|
-
debug("Finished reading request body")
|
125
|
+
# debug("Finished reading request body")
|
126
126
|
rescue EOFError, TruncatedDataError
|
127
|
-
debug("Failed to read request body")
|
127
|
+
# debug("Failed to read request body")
|
128
128
|
# TODO: what to do here?
|
129
129
|
return false
|
130
130
|
rescue Exception => e
|
131
131
|
warn("Unhandled exception in incoming request read:\n#{e.inspect}\n#{e.backtrace.join("\n")}")
|
132
132
|
end
|
133
|
-
debug("Processing body")
|
133
|
+
# debug("Processing body")
|
134
134
|
process_request(hash, request_body)
|
135
135
|
else
|
136
136
|
warn("Malformed incoming request: #{request.strip}")
|
@@ -143,13 +143,13 @@ module Pandemic
|
|
143
143
|
if response.strip =~ /^RESPONSE ([A-Za-z0-9]+) ([0-9]+)$/
|
144
144
|
hash = $1
|
145
145
|
size = $2.to_i
|
146
|
-
debug("Incoming response: #{hash} #{size}")
|
146
|
+
# debug("Incoming response: #{hash} #{size}")
|
147
147
|
begin
|
148
|
-
debug("Reading response body")
|
148
|
+
# debug("Reading response body")
|
149
149
|
response_body = connection.read(size)
|
150
|
-
debug("Finished reading response body")
|
150
|
+
# debug("Finished reading response body")
|
151
151
|
rescue EOFError, TruncatedDataError
|
152
|
-
debug("Failed to read response body")
|
152
|
+
# debug("Failed to read response body")
|
153
153
|
# TODO: what to do here?
|
154
154
|
return false
|
155
155
|
rescue Exception => e
|
@@ -167,14 +167,14 @@ module Pandemic
|
|
167
167
|
def process_request(hash, body)
|
168
168
|
Thread.new do
|
169
169
|
begin
|
170
|
-
debug("Starting processing thread (#{hash})")
|
170
|
+
# debug("Starting processing thread (#{hash})")
|
171
171
|
response = @server.process(body)
|
172
|
-
debug("Processing finished (#{hash})")
|
172
|
+
# debug("Processing finished (#{hash})")
|
173
173
|
@connection_pool.with_connection do |connection|
|
174
|
-
debug( "Sending response (#{hash})")
|
174
|
+
# debug( "Sending response (#{hash})")
|
175
175
|
connection.write("RESPONSE #{hash} #{response.size}\n#{response}")
|
176
176
|
connection.flush
|
177
|
-
debug( "Finished sending response (#{hash})")
|
177
|
+
# debug( "Finished sending response (#{hash})")
|
178
178
|
end
|
179
179
|
rescue Exception => e
|
180
180
|
warn("Unhandled exception in process request thread:\n#{e.inspect}\n#{e.backtrace.join("\n")}")
|
@@ -185,10 +185,10 @@ module Pandemic
|
|
185
185
|
def process_response(hash, body)
|
186
186
|
Thread.new do
|
187
187
|
begin
|
188
|
-
debug("Finding original request (#{hash})")
|
188
|
+
# debug("Finding original request (#{hash})")
|
189
189
|
original_request = @pending_requests.synchronize { @pending_requests.delete(hash) }
|
190
190
|
if original_request
|
191
|
-
debug("Found original request, adding response")
|
191
|
+
# debug("Found original request, adding response")
|
192
192
|
original_request.add_response(body)
|
193
193
|
else
|
194
194
|
warn("Original response not found (#{hash})")
|
@@ -32,10 +32,10 @@ module Pandemic
|
|
32
32
|
@@late_responses.inc
|
33
33
|
return
|
34
34
|
end
|
35
|
-
debug("Adding response")
|
35
|
+
# debug("Adding response")
|
36
36
|
@responses << response
|
37
37
|
if @max_responses && @responses.size >= @max_responses
|
38
|
-
debug("Hit max responses, waking up waiting thread")
|
38
|
+
# debug("Hit max responses, waking up waiting thread")
|
39
39
|
wakeup_waiting_thread
|
40
40
|
@complete = true
|
41
41
|
end
|
@@ -62,6 +62,12 @@ module Pandemic
|
|
62
62
|
return if @complete
|
63
63
|
if Config.response_timeout <= 0
|
64
64
|
@waiter.wait
|
65
|
+
elsif !MONITOR_TIMEOUT_AVAILABLE
|
66
|
+
Thread.new do
|
67
|
+
sleep Config.response_timeout
|
68
|
+
wakeup_waiting_thread
|
69
|
+
end
|
70
|
+
@waiter.wait
|
65
71
|
else
|
66
72
|
@waiter.wait(Config.response_timeout)
|
67
73
|
end
|
@@ -57,14 +57,14 @@ module Pandemic
|
|
57
57
|
@running = true
|
58
58
|
@running_since = Time.now
|
59
59
|
|
60
|
-
debug("Connecting to peers")
|
60
|
+
# debug("Connecting to peers")
|
61
61
|
@peers.values.each { |peer| peer.connect }
|
62
62
|
|
63
63
|
@listener_thread = Thread.new do
|
64
64
|
begin
|
65
65
|
while @running
|
66
66
|
begin
|
67
|
-
debug("Listening")
|
67
|
+
# debug("Listening")
|
68
68
|
conn = @listener.accept
|
69
69
|
Thread.new(conn) { |c| handle_connection(c) }
|
70
70
|
rescue Errno::ECONNABORTED, Errno::EINTR # TODO: what else can wrong here? this should be more robust.
|
@@ -95,15 +95,15 @@ module Pandemic
|
|
95
95
|
connection.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) if TCP_NO_DELAY_AVAILABLE
|
96
96
|
|
97
97
|
identification = connection.gets.strip
|
98
|
-
info("Incoming connection from #{connection.peeraddr.values_at(3,1).join(":")} (#{identification})")
|
98
|
+
# info("Incoming connection from #{connection.peeraddr.values_at(3,1).join(":")} (#{identification})")
|
99
99
|
if identification =~ /^SERVER ([a-zA-Z0-9.]+:[0-9]+)$/
|
100
|
-
debug("Recognized as peer")
|
100
|
+
# debug("Recognized as peer")
|
101
101
|
host, port = host_port($1)
|
102
102
|
matching_peer = @peers.values.detect { |peer| [peer.host, peer.port] == [host, port] }
|
103
103
|
if matching_peer
|
104
|
-
debug("Found matching peer")
|
104
|
+
# debug("Found matching peer")
|
105
105
|
else
|
106
|
-
debug("Didn't find matching peer, adding it")
|
106
|
+
# debug("Didn't find matching peer, adding it")
|
107
107
|
matching_peer = @peers.synchronize do
|
108
108
|
hostport = "#{host}:#{port}"
|
109
109
|
@servers.push(hostport) unless @servers.include?(hostport)
|
@@ -112,13 +112,13 @@ module Pandemic
|
|
112
112
|
end
|
113
113
|
matching_peer.add_incoming_connection(connection)
|
114
114
|
elsif identification =~ /^CLIENT$/
|
115
|
-
debug("Recognized as client")
|
115
|
+
# debug("Recognized as client")
|
116
116
|
@clients_mutex.synchronize do
|
117
117
|
@clients << Client.new(connection, self).listen
|
118
118
|
@total_clients += 1
|
119
119
|
end
|
120
120
|
elsif identification =~ /^stats$/
|
121
|
-
debug("Stats request received")
|
121
|
+
# debug("Stats request received")
|
122
122
|
print_stats(connection)
|
123
123
|
else
|
124
124
|
debug("Unrecognized connection. Closing.")
|
@@ -130,10 +130,10 @@ module Pandemic
|
|
130
130
|
end
|
131
131
|
|
132
132
|
def handle_client_request(request)
|
133
|
-
info("Handling client request")
|
133
|
+
# info("Handling client request")
|
134
134
|
map = @handler_instance.partition(request, connection_statuses)
|
135
135
|
request.max_responses = map.size
|
136
|
-
debug("Sending client request to #{map.size} handlers (#{request.hash})")
|
136
|
+
# debug("Sending client request to #{map.size} handlers (#{request.hash})")
|
137
137
|
|
138
138
|
map.each do |peer, body|
|
139
139
|
if @peers[peer]
|
@@ -142,7 +142,7 @@ module Pandemic
|
|
142
142
|
end
|
143
143
|
|
144
144
|
if map[signature]
|
145
|
-
debug("Processing #{request.hash}")
|
145
|
+
# debug("Processing #{request.hash}")
|
146
146
|
Thread.new do
|
147
147
|
begin
|
148
148
|
request.add_response(self.process(map[signature]))
|
@@ -154,10 +154,10 @@ module Pandemic
|
|
154
154
|
|
155
155
|
@requests_per_second.hit
|
156
156
|
|
157
|
-
debug("Waiting for responses")
|
157
|
+
# debug("Waiting for responses")
|
158
158
|
request.wait_for_responses
|
159
159
|
|
160
|
-
debug("Done waiting for responses, calling reduce")
|
160
|
+
# debug("Done waiting for responses, calling reduce")
|
161
161
|
@handler_instance.reduce(request)
|
162
162
|
end
|
163
163
|
|
@@ -173,7 +173,7 @@ module Pandemic
|
|
173
173
|
end
|
174
174
|
|
175
175
|
def signature
|
176
|
-
"#{@host}:#{@port}"
|
176
|
+
@signature ||= "#{@host}:#{@port}"
|
177
177
|
end
|
178
178
|
|
179
179
|
def connection_statuses
|
data/pandemic.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{pandemic}
|
5
|
-
s.version = "0.5.
|
5
|
+
s.version = "0.5.1"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Arya Asemanfar"]
|
9
|
-
s.date = %q{2009-08-
|
9
|
+
s.date = %q{2009-08-09}
|
10
10
|
s.description = %q{A framework for distributing work for real-time services and offline tasks.}
|
11
11
|
s.email = %q{aryaasemanfar@gmail.com}
|
12
12
|
s.extra_rdoc_files = ["lib/pandemic/client_side/cluster_connection.rb", "lib/pandemic/client_side/config.rb", "lib/pandemic/client_side/connection.rb", "lib/pandemic/client_side/connection_proxy.rb", "lib/pandemic/client_side/pandemize.rb", "lib/pandemic/connection_pool.rb", "lib/pandemic/mutex_counter.rb", "lib/pandemic/requests_per_second.rb", "lib/pandemic/server_side/client.rb", "lib/pandemic/server_side/config.rb", "lib/pandemic/server_side/handler.rb", "lib/pandemic/server_side/peer.rb", "lib/pandemic/server_side/processor.rb", "lib/pandemic/server_side/request.rb", "lib/pandemic/server_side/server.rb", "lib/pandemic/util.rb", "lib/pandemic.rb", "README.markdown"]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arya-pandemic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arya Asemanfar
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-08-
|
12
|
+
date: 2009-08-09 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|