arya-pandemic 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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.0') do |p|
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"
@@ -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
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{pandemic}
5
- s.version = "0.5.0"
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-07}
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.0
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-07 00:00:00 -07:00
12
+ date: 2009-08-09 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency