evdispatch 0.2.1 → 0.2.2

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/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/