evdispatch 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,8 @@
1
+ == 0.2.2 2008-04-14
2
+ * Make options optional in request method
3
+ * Improve timeouts
4
+ * Add flush method, to flush out any buffered responses
5
+
1
6
  == 0.2 2008-04-13
2
7
  * Add HTTP headers to response
3
8
  * Expose some basic libcurl options (useragent, cookie, followlocation, etc.. see libdispatch Changelog for details
data/Manifest.txt CHANGED
@@ -29,6 +29,7 @@ website/stylesheets/screen.css
29
29
  website/template.html.erb
30
30
  ext/revdispatch/server.rb
31
31
  ext/revdispatch/test.rb
32
+ ext/revdispatch/stest.rb
32
33
  ext/revdispatch/extconf.rb
33
34
  ext/revdispatch/revdispatch.cc
34
35
  ext/revdispatch/libdispatch-0.1/
@@ -100,6 +100,18 @@ bool Dispatch::start()
100
100
  return (count < 100);
101
101
  }
102
102
 
103
+ void Dispatch::flush()
104
+ {
105
+ // lock the responses
106
+ m_responses.m_lock.lock();
107
+ while( !m_responses.m_queue.empty() ){
108
+ m_responses.m_queue.pop();
109
+ }
110
+ // empty out the thread local buffer
111
+ m_responded.clear();
112
+ m_responses.m_lock.unlock();
113
+ }
114
+
103
115
  // tell the background event listener to terminate
104
116
  void Dispatch::stop()
105
117
  {
@@ -245,10 +257,12 @@ Queue<Response>::POP_STATE Dispatch::wait_for_response_by_id( request_t id, Time
245
257
 
246
258
  if( loc != m_responded.end() ){ return Queue<Response>::POPPED; }
247
259
 
260
+ timeout.update();
248
261
  while( (rep = m_responses.pop_or_wait( &rstate, m_loop_started, timeout )) ) {
249
262
  //printf( "rep: %s, id: %d\n", rep->name.c_str(), rep->id );
250
263
  m_responded[rep->id] = rep;
251
264
  if( rep->id == id ){ return rstate; }
265
+ timeout.update();
252
266
  }
253
267
 
254
268
  return rstate;
@@ -259,6 +273,7 @@ Response *Dispatch::get_next_response( Timer timer )
259
273
  Response *rep = NULL;
260
274
  Queue<Response>::POP_STATE rstate;
261
275
 
276
+ timer.update();
262
277
  do {
263
278
  rep = m_responses.pop_or_wait( &rstate, m_loop_started, timer );
264
279
  if( rstate == Queue<Response>::EXITING ){ rep = NULL; break; }
@@ -276,6 +291,7 @@ Response *Dispatch::get_next_response( Timer timer )
276
291
  else if( rep ) {
277
292
  --m_pending;
278
293
  }
294
+ timer.update();
279
295
 
280
296
  } while( !rep && rstate == Queue<Response>::EXPIRED );
281
297
 
@@ -17,14 +17,22 @@ namespace EVD {
17
17
  typedef unsigned long request_t;
18
18
 
19
19
  struct Timer {
20
- Timer( long int seconds, long int nanoseconds ) {
20
+
21
+ Timer( long int seconds, long int nanoseconds ) : m_seconds( seconds ), m_nanoseconds( nanoseconds ) { update(); }
22
+
23
+ // offset the timer from now
24
+ void update() {
21
25
  struct timeval now;
22
26
  current_time( &now );
23
- m_time.tv_sec = now.tv_sec + seconds;
24
- m_time.tv_nsec = (now.tv_usec * 1000) + nanoseconds;
27
+ m_time.tv_sec = now.tv_sec + m_seconds;
28
+ m_time.tv_nsec = (now.tv_usec*1000) + m_nanoseconds;
29
+ //printf( "seconds: %ld, nanoseconds: %ld, from s: %ld, ns: %ld, based s: %ld, us: %ld\n", m_time.tv_sec, m_time.tv_nsec, m_seconds, m_nanoseconds, now.tv_sec, now.tv_usec );
25
30
  }
31
+
26
32
  inline static int current_time( struct timeval *now) { return gettimeofday(now, NULL); }
27
33
  static double elapsed_time( struct timeval *then );
34
+ int long m_seconds;
35
+ int long m_nanoseconds;
28
36
  struct timespec m_time;
29
37
  };
30
38
 
@@ -146,6 +154,7 @@ namespace EVD {
146
154
  req = m_queue.front();
147
155
  }
148
156
  while( !req ) {
157
+ timer.update();
149
158
  m_cond.timed_wait( m_lock, timer );
150
159
  if( !cond ){ *rstate = EXITING; break; }
151
160
  size = m_queue.size();
@@ -224,6 +233,9 @@ namespace EVD {
224
233
  // tell the background event listener to terminate
225
234
  void stop();
226
235
 
236
+ // empty the response local buffer and queue
237
+ void flush();
238
+
227
239
  request_t request( Request *req );
228
240
 
229
241
  // from the main thread, get the next available response
@@ -32,7 +32,10 @@ static void run_tests( Dispatch &dispatcher, int count )
32
32
  Response *rep = NULL;
33
33
  double longest_request = 0.0;
34
34
 
35
- while( expected_response_count > 0 && (rep = dispatcher.get_next_response(Timer(1,0))) ){
35
+ // timer issues
36
+ Timer timeout(1,(500*1000*1000));
37
+
38
+ while( expected_response_count > 0 && (rep = dispatcher.get_next_response(timeout)) ){
36
39
  if( longest_request < rep->response_time ){
37
40
  longest_request = rep->response_time;
38
41
  }
@@ -41,32 +41,27 @@ static void run_tests( Dispatch &dispatcher, int count )
41
41
  FD_ZERO(&wr);
42
42
  FD_ZERO(&er);
43
43
  FD_SET(pfd[0], &rd);
44
- tv.tv_sec = 0;
44
+ tv.tv_sec = 1;
45
45
  tv.tv_usec = 0;
46
46
 
47
- try {
48
- while( (retval = select( pfd[0]+1, &rd, &wr, &er, NULL )) ) {
49
- if( retval == -1 && errno == EINTR ) { continue; }
50
- if( retval < 0 ){ perror("select"); break; }
51
- if( FD_ISSET(pfd[0],&rd) ){
52
- retval = read(pfd[0],READ_BUFFER,read_size);
53
- if( retval >= 0 ) {
54
- result_buffer.append(READ_BUFFER,retval);
55
- if( retval == 0 ){ break; }
56
- }
57
- else {
58
- perror("read");
59
- break;
60
- }
47
+ while( (retval = select( pfd[0]+1, &rd, &wr, &er, &tv )) ) {
48
+ if( retval == -1 && errno == EINTR ) { continue; }
49
+ if( retval < 0 ){ perror("select"); break; }
50
+ if( FD_ISSET(pfd[0],&rd) ){
51
+ retval = read(pfd[0],READ_BUFFER,read_size);
52
+ if( retval >= 0 ) {
53
+ result_buffer.append(READ_BUFFER,retval);
54
+ if( retval == 0 ){ break; }
55
+ }
56
+ else {
57
+ perror("read");
58
+ break;
61
59
  }
62
60
  }
63
- fprintf( stderr, "loop returnd\n" );
64
- printf("response: %s, in %.5lf seconds of Content-Length: %d bytes\n%s", res->name.c_str(), res->response_time, result_buffer.length(), res->m_header.c_str() );
65
- delete res;
66
- }catch(const std::exception &exp){
67
- perror("select");
68
61
  }
69
62
  fprintf( stderr, "loop returnd\n" );
63
+ printf("response: %s, in %.5lf seconds of Content-Length: %d bytes\n%s", res->name.c_str(), res->response_time, result_buffer.length(), res->m_header.c_str() );
64
+ delete res;
70
65
  }
71
66
 
72
67
  int main(int argc, char **argv)
@@ -91,13 +91,19 @@ VALUE Loop_request_http( VALUE self, VALUE url )
91
91
  }
92
92
 
93
93
  static
94
- VALUE Loop_request( VALUE self, VALUE url, VALUE options )
94
+ VALUE Loop_request( int argc, VALUE *argv, VALUE self )
95
95
  {
96
96
  EVD::Dispatch *d;
97
97
  const int VALUE_BUFFER_SIZE = 1024;
98
98
  char VALUE_BUFFER[VALUE_BUFFER_SIZE];
99
99
  Data_Get_Struct( self, EVD::Dispatch, d );
100
100
 
101
+ VALUE url, options;
102
+
103
+ // required 1 argument the 'url' and 1 optional the hash of options
104
+ if( rb_scan_args( argc, argv, "11", &url, &options ) == 1 ) {
105
+ options = rb_hash_new();
106
+ }
101
107
 
102
108
  EVD::HttpRequest *req = new EVD::HttpRequest( *d, RSTRING_PTR(url) );
103
109
 
@@ -122,7 +128,7 @@ VALUE Loop_wait_for_response( VALUE self, VALUE id, VALUE timeout_seconds, VALUE
122
128
 
123
129
  Data_Get_Struct( self, EVD::Dispatch, d );
124
130
 
125
- rstate = d->wait_for_response_by_id( rid, EVD::Timer(FIX2LONG(timeout_seconds), FIX2LONG(timeout_mseconds)) );
131
+ rstate = d->wait_for_response_by_id( rid, EVD::Timer(FIX2LONG(timeout_seconds), (FIX2LONG(timeout_mseconds)*1000*1000)) );
126
132
 
127
133
  return rb_int_new(rstate);
128
134
  }
@@ -137,7 +143,7 @@ VALUE Loop_response_for( VALUE self, VALUE id )
137
143
  EVD::request_t rid = FIX2LONG(id);
138
144
 
139
145
  res = (EVD::HttpResponse*)d->response_for( rid );
140
- if( res ){
146
+ if( res ) {
141
147
 
142
148
  VALUE result = rb_hash_new();
143
149
 
@@ -154,6 +160,16 @@ VALUE Loop_response_for( VALUE self, VALUE id )
154
160
  return Qnil;
155
161
  }
156
162
 
163
+ static
164
+ VALUE Loop_flush( VALUE self )
165
+ {
166
+ EVD::Dispatch *d;
167
+ Data_Get_Struct( self, EVD::Dispatch, d );
168
+
169
+ d->flush();
170
+ return Qnil;
171
+ }
172
+
157
173
  static
158
174
  VALUE Loop_stop( VALUE self )
159
175
  {
@@ -191,7 +207,8 @@ extern "C" void Init_revdispatch()
191
207
 
192
208
  rb_define_method( rb_Loop, "start", (VALUE (*)(...))Loop_start, 0 );
193
209
  rb_define_method( rb_Loop, "request_http", (VALUE (*)(...))Loop_request_http, 1 );
194
- rb_define_method( rb_Loop, "request", (VALUE (*)(...))Loop_request, 2 );
210
+ rb_define_method( rb_Loop, "request", (VALUE (*)(...))Loop_request, -1 );
211
+ rb_define_method( rb_Loop, "flush", (VALUE (*)(...))Loop_flush, 0 );
195
212
  rb_define_method( rb_Loop, "response_for", (VALUE (*)(...))Loop_response_for, 1 );
196
213
  rb_define_method( rb_Loop, "wait_for_response", (VALUE (*)(...))Loop_wait_for_response, 3 );
197
214
  rb_define_method( rb_Loop, "stop", (VALUE (*)(...))Loop_stop, 0 );
@@ -0,0 +1,44 @@
1
+ $:.unshift File.join(File.dirname(__FILE__),'..','..','lib')
2
+
3
+ require 'evdispatch'
4
+ require 'test/unit'
5
+
6
+ $d = Evdispatch::Loop.new
7
+ # start the event loop thread
8
+ $d.start
9
+
10
+ class TestRequests < Test::Unit::TestCase
11
+
12
+ def test_response
13
+ id = $d.request_http("http://127.0.0.1:4044/bytes/10")
14
+ response = $d.response( id )
15
+ #puts response.inspect
16
+ #{:response_time=>0.003444, :name=>"http://127.0.0.1:4044/bytes/10", :id=>0, :body=>"CCCCCCCCCC"}
17
+ assert_equal("http://127.0.0.1:4044/bytes/10", response[:name])
18
+ assert_equal("CCCCCCCCCC", response[:body])
19
+ assert_equal("HTTP/1.1 200 OK\r\nContent-Type: text/json\r\nContent-Length: 10\r\nConnection: close\r\n\r\n", response[:header])
20
+ assert(response.keys.include?(:response_time))
21
+ assert(response.keys.include?(:id))
22
+ end
23
+
24
+ def test_options_request
25
+ id = $d.request("http://127.0.0.1:4044/redir/1", :followlocation => 1, :referer => 'pizza')
26
+ response = $d.response( id )
27
+ assert_match(/ 302 Moved Temporarily/,response[:header])
28
+ assert_match(/ 200 OK/,response[:header])
29
+ end
30
+
31
+ def test_delayed_with_flush
32
+ id = $d.request("http://127.0.0.1:4044/delay/0")
33
+ tid = $d.request("http://127.0.0.1:4044/delay/3")
34
+ res = $d.response( id, 1.0, 1 )
35
+ res2 = $d.response( tid, 1.0, 1 )
36
+ if !res or !res2
37
+ $d.flush # flush because we aborted before we finished, still the issue of the request is still running, but any previous responses that were delayed will be flushed
38
+ end
39
+ puts res.inspect
40
+ puts res2.inspect
41
+ end
42
+ end
43
+
44
+ # not bothering to cleanup
@@ -62,8 +62,8 @@ def run_trial
62
62
 
63
63
  ebbbase = "http://127.0.0.1:4044/"
64
64
  timer = Time.now
65
- ids = request_bytes_from( d, ebbbase, 100, 1000 )
66
- ids += request_delay_from( d, ebbbase, 100, 1 )
65
+ ids = request_bytes_from( d, ebbbase, 400, 10000 )
66
+ #ids += request_delay_from( d, ebbbase, 100, 1 )
67
67
 
68
68
  # wait for each response
69
69
  puts "expecting #{ids.size} responses..."
@@ -4,11 +4,21 @@ require 'revdispatch'
4
4
  # ruby threads can execute while we waiting for a response
5
5
  module Evdispatch
6
6
  class Loop
7
- def response(id)
8
- while wait_for_response( id, 1, 0 )
7
+ def response(id, timeout = 1.0, max_attempts = 100)
8
+ attempts = 0
9
+ ms = timeout * 1000 # convert to miliseconds
10
+ ms_i = ms.to_i
11
+ seconds = ms_i / 1000
12
+ mseconds = (ms - (seconds*1000)).to_i
13
+ #puts "Waiting #{seconds} seconds and #{mseconds} miliseconds"
14
+
15
+ while (wait_for_response( id, seconds, mseconds ) and attempts < max_attempts )
9
16
  res = response_for( id )
10
17
  break if res
18
+ attempts += 1
19
+ #puts "Attempt: #{attempts}"
11
20
  end
21
+ return nil if !res and attempts == max_attempts
12
22
  res = response_for( id ) unless res
13
23
  res
14
24
  end
@@ -2,7 +2,7 @@ module Evdispatch #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 2
5
- TINY = 1
5
+ TINY = 2
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
data/website/index.html CHANGED
@@ -18,7 +18,7 @@
18
18
  <h1>evdispatch</h1>
19
19
  <div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/evdispatch"; return false'>
20
20
  <p>Get Version</p>
21
- <a href="http://rubyforge.org/projects/evdispatch" class="numbers">0.2.0</a>
21
+ <a href="http://rubyforge.org/projects/evdispatch" class="numbers">0.2.1</a>
22
22
  </div>
23
23
  <h4 style="float:right;padding-right:10px;">&#x2192; &#8216;evdispatch&#8217;</h4>
24
24
 
@@ -56,9 +56,9 @@ web applications to make multiple concurrent service requests to satisify a sing
56
56
 
57
57
  <span class="keyword">class </span><span class="class">DashController</span> <span class="punct">&lt;</span> <span class="constant">ApplicationController</span>
58
58
  <span class="keyword">def </span><span class="method">index</span>
59
- <span class="attribute">@blogs_id</span> <span class="punct">=</span> <span class="global">$dispatcher</span><span class="punct">.</span><span class="ident">request_http</span><span class="punct">(&quot;</span><span class="string">http://10.0.6.45/service/blogs</span><span class="punct">&quot;)</span>
60
- <span class="attribute">@news_id</span> <span class="punct">=</span> <span class="global">$dispatcher</span><span class="punct">.</span><span class="ident">request_http</span><span class="punct">(&quot;</span><span class="string">http://10.0.6.45/service/news</span><span class="punct">&quot;)</span>
61
- <span class="attribute">@messages_id</span> <span class="punct">=</span> <span class="global">$dispatcher</span><span class="punct">.</span><span class="ident">request_http</span><span class="punct">(&quot;</span><span class="string">http://10.0.6.45/service/messages</span><span class="punct">&quot;)</span>
59
+ <span class="attribute">@blogs_id</span> <span class="punct">=</span> <span class="global">$dispatcher</span><span class="punct">.</span><span class="ident">request</span><span class="punct">(&quot;</span><span class="string">http://10.0.6.45/service/blogs</span><span class="punct">&quot;)</span>
60
+ <span class="attribute">@news_id</span> <span class="punct">=</span> <span class="global">$dispatcher</span><span class="punct">.</span><span class="ident">request</span><span class="punct">(&quot;</span><span class="string">http://10.0.6.45/service/news</span><span class="punct">&quot;)</span>
61
+ <span class="attribute">@messages_id</span> <span class="punct">=</span> <span class="global">$dispatcher</span><span class="punct">.</span><span class="ident">request</span><span class="punct">(&quot;</span><span class="string">http://10.0.6.45/service/messages</span><span class="punct">&quot;)</span>
62
62
  <span class="keyword">end</span>
63
63
  <span class="keyword">end</span>
64
64
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: evdispatch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Todd A. Fisher
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-04-13 00:00:00 -04:00
12
+ date: 2008-04-14 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -58,6 +58,7 @@ files:
58
58
  - website/template.html.erb
59
59
  - ext/revdispatch/server.rb
60
60
  - ext/revdispatch/test.rb
61
+ - ext/revdispatch/stest.rb
61
62
  - ext/revdispatch/extconf.rb
62
63
  - ext/revdispatch/revdispatch.cc
63
64
  - ext/revdispatch/libdispatch-0.1/