ruby-lsapi 1.3 → 1.4

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/README CHANGED
@@ -2,7 +2,7 @@
2
2
  lsapi - LSAPI extension for Ruby
3
3
  ================================
4
4
 
5
- Version 0.1.0
5
+ Version 1.4
6
6
 
7
7
  INSTALL
8
8
  -------
@@ -16,8 +16,8 @@ USAGE
16
16
 
17
17
  General CGI scripts
18
18
  ```````````````````
19
- The most efficient way to use LSAPI interface is to modify your CGI script,
20
- you need to add the following to your CGI script
19
+ The most efficient way to use LSAPI interface is to modify your CGI scripts.
20
+ You need to add the following code to your CGI scripts:
21
21
 
22
22
  require 'lsapi'
23
23
 
@@ -28,10 +28,10 @@ you need to add the following to your CGI script
28
28
 
29
29
  end
30
30
 
31
- There is no need to change the way how CGI environment variables being
32
- accessed in your script.
31
+ There is no need to change the way that how CGI environment variables
32
+ are being accessed in your scripts.
33
33
 
34
- There are examples under examples/ folder.
34
+ You can find some examples under examples/ folder.
35
35
 
36
36
 
37
37
  Rails dispatcher
@@ -44,10 +44,10 @@ in public/.htaccess from
44
44
  to
45
45
  RewriteRule ^(.*)$ dispatch.lsapi [QSA,L]
46
46
 
47
- It is very expensive to start a fresh Rails application process, while on
47
+ It is very expensive to start a fresh Rails application process, and on
48
48
  the other hand, server hardware resources can be used more efficiently with
49
- dynamic spawning. In order to solve this conflict, instead of spawning a
50
- fresh Rails process, LSAPI dispatcher can dynamically fork children processes
49
+ dynamic spawning. In order to solve this problem, instead of spawning a
50
+ fresh Rails process, LSAPI dispatcher will dynamically fork children processes
51
51
  off an initialized Rails process.
52
52
 
53
53
  When you configure dispatch.lsapi as a LSAPI application, you should add
@@ -57,12 +57,28 @@ an extra environment variable
57
57
 
58
58
  n should match the "Max Conns" configuration entry of the LSAPI application.
59
59
 
60
+ Two new environment variables has been introduced since Ruby LSAPI 1.4:
61
+
62
+ LSAPI_MAX_REQS=n
63
+
64
+ n is the maximum number of requests that a child process can serve.
65
+ Default value is 1000. Once that number is reached, the child process will
66
+ exit automatically. This will help in case of any memory leaks in Rails.
67
+
68
+ LSAPI_MAX_IDLE=n
69
+
70
+ n is the maximum idle time in seconds that a child process will be waiting
71
+ for a new request. Once it is reached, the child process will quit.
72
+ Default value is 60. When n <= 0, the child process will wait indefinitely.
73
+ This option helps getting rid of idle children processes.
74
+
60
75
 
61
76
  Ruby Script Runner
62
77
  ``````````````````
63
- If you don't want to change your Ruby CGI code, you can use our Ruby script
64
- runner under scripts/ folder. You need to configure lsruby_runner.rb as a
65
- LSAPI application, then add a script handler for "rb" suffix.
78
+ If you don't want to change your existing Ruby CGI code, you can use our
79
+ Ruby script runner under scripts/ folder. You need to configure
80
+ lsruby_runner.rb as a LSAPI application, then add a script handler
81
+ for "rb" suffix.
66
82
 
67
83
 
68
84
  License
@@ -79,6 +95,6 @@ LSAPI ruby extension code is under Ruby license
79
95
  Copyright
80
96
  ---------
81
97
 
82
- Copyright (C) 2006 Lite Speed Technologes Inc.
98
+ Copyright (C) 2006 Lite Speed Technologies Inc.
83
99
 
84
100
 
data/ext/lsapi/lsapilib.c CHANGED
@@ -207,8 +207,18 @@ static int lsapi_writev( int fd, struct iovec ** pVec, int count, int totalLen )
207
207
  }
208
208
  }
209
209
  }
210
- else if (( ret == -1 )&&( errno != EINTR ))
211
- return ret;
210
+ else if ( ret == -1 )
211
+ {
212
+ if ( errno == EAGAIN )
213
+ {
214
+ if ( totalLen - left > 0 )
215
+ return totalLen - left;
216
+ else
217
+ return -1;
218
+ }
219
+ else if ( errno != EINTR )
220
+ return ret;
221
+ }
212
222
  }
213
223
  return totalLen - left;
214
224
  }
@@ -539,11 +549,16 @@ int LSAPI_Init(void)
539
549
  return 0;
540
550
  }
541
551
 
542
- void LSAPI_stop(void)
552
+ void LSAPI_Stop(void)
543
553
  {
544
554
  g_running = 0;
545
555
  }
546
556
 
557
+ int LSAPI_IsRunning(void)
558
+ {
559
+ return g_running;
560
+ }
561
+
547
562
  int LSAPI_InitRequest( LSAPI_Request * pReq, int fd )
548
563
  {
549
564
  if ( !pReq )
@@ -740,7 +755,7 @@ int LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, int bufLen )
740
755
  bufLen -= len;
741
756
  }
742
757
  else if ( len < 0 )
743
- return -1;
758
+ return (total)?total:-1;
744
759
  }
745
760
  pReq->m_reqBodyRead += total;
746
761
  return total;
data/ext/lsapi/lsapilib.h CHANGED
@@ -121,7 +121,7 @@ typedef int (*LSAPI_CB_EnvHandler )( const char * pKey, int keyLen,
121
121
 
122
122
  int LSAPI_Init(void);
123
123
 
124
- void LSAPI_stop(void);
124
+ void LSAPI_Stop(void);
125
125
 
126
126
  int LSAPI_Is_Listen_r( LSAPI_Request * pReq);
127
127
 
@@ -280,6 +280,7 @@ static inline int LSAPI_AppendRespHeader( char * pBuf, int len )
280
280
  static inline int LSAPI_SetRespStatus( int code )
281
281
  { return LSAPI_SetRespStatus_r( &g_req, code ); }
282
282
 
283
+ int LSAPI_IsRunning(void);
283
284
 
284
285
  #if defined (c_plusplus) || defined (__cplusplus)
285
286
  }
data/ext/lsapi/lsruby.c CHANGED
@@ -42,6 +42,9 @@ static lsapi_data * s_req_data;
42
42
 
43
43
  static int s_children = 0;
44
44
  static int s_cur_children = 0;
45
+ static int s_req_processed = 0;
46
+ static int s_max_reqs = 1000;
47
+ static int s_max_idle_secs = 60;
45
48
 
46
49
  static void lsapi_ruby_setenv(const char *name, const char *value)
47
50
  {
@@ -108,7 +111,7 @@ void lsapi_sigchild( int signal )
108
111
  {
109
112
  break;
110
113
  }
111
-
114
+ --s_cur_children;
112
115
  }
113
116
 
114
117
  }
@@ -120,6 +123,9 @@ static int lsapi_fork_child()
120
123
  char achPeer[128];
121
124
  socklen_t len;
122
125
  int nodelay = 1;
126
+ fd_set readfds;
127
+ struct timeval timeout;
128
+ int ret;
123
129
 
124
130
  setsid();
125
131
 
@@ -145,6 +151,31 @@ static int lsapi_fork_child()
145
151
  s_stop = 0;
146
152
  while( !s_stop )
147
153
  {
154
+ if ( s_cur_children >= (s_children << 1 ) )
155
+ {
156
+ usleep( 10000 );
157
+ continue;
158
+ }
159
+
160
+ FD_ZERO( &readfds );
161
+ FD_SET( g_req.m_fdListen, &readfds );
162
+ timeout.tv_sec = 0; timeout.tv_usec = 100000;
163
+ if ((ret = rb_thread_select(g_req.m_fdListen+1, &readfds, NULL, NULL, &timeout)) == 1 )
164
+ {
165
+ if ( s_cur_children >= s_children )
166
+ {
167
+ usleep( 10 );
168
+ FD_ZERO( &readfds );
169
+ FD_SET( g_req.m_fdListen, &readfds );
170
+ timeout.tv_sec = 0; timeout.tv_usec = 0;
171
+ if ( select(g_req.m_fdListen+1, &readfds, NULL, NULL, &timeout) == 0 )
172
+ continue;
173
+ }
174
+ }
175
+ else if ( ret == -1 )
176
+ break;
177
+ else
178
+ continue;
148
179
  len = sizeof( achPeer );
149
180
  g_req.m_fd = accept( g_req.m_fdListen,
150
181
  (struct sockaddr *)&achPeer, &len );
@@ -158,9 +189,10 @@ static int lsapi_fork_child()
158
189
  int pid = fork();
159
190
  if ( !pid )
160
191
  {
161
- close( g_req.m_fdListen );
162
- g_req.m_fdListen = -1;
163
-
192
+ //close( g_req.m_fdListen );
193
+ //g_req.m_fdListen = -1;
194
+ s_children = 0;
195
+
164
196
  /* don't catch our signals */
165
197
  sigaction( SIGCHLD, &old_child, 0 );
166
198
  sigaction( SIGTERM, &old_term, 0 );
@@ -172,10 +204,11 @@ static int lsapi_fork_child()
172
204
  else if ( pid == -1 )
173
205
  {
174
206
  perror( "fork() failed" );
175
- return -1;
207
+ break;
176
208
  }
177
209
  else
178
210
  {
211
+ ++s_cur_children;
179
212
  close( g_req.m_fd );
180
213
  g_req.m_fd = -1;
181
214
  }
@@ -200,6 +233,8 @@ static VALUE lsapi_s_accept( VALUE self )
200
233
  fd_set readfds;
201
234
  int fd;
202
235
  int ret;
236
+ int wait_secs;
237
+ struct timeval timeout;
203
238
 
204
239
  LSAPI_Finish_r( &g_req );
205
240
  if ( s_children )
@@ -208,36 +243,48 @@ static VALUE lsapi_s_accept( VALUE self )
208
243
  if ( lsapi_fork_child() == -1 )
209
244
  return Qnil;
210
245
  }
211
- if ( g_req.m_fd != -1 )
246
+ if ( s_req_processed < s_max_reqs )
212
247
  {
213
- fd = g_req.m_fd;
214
- }
215
- else if ( g_req.m_fdListen != -1 )
216
- fd = g_req.m_fdListen;
217
- else
218
- return Qnil;
219
-
220
- FD_ZERO( &readfds );
221
- FD_SET( fd, &readfds );
222
-
223
- if (rb_thread_select(fd+1, &readfds, NULL, NULL, NULL) < 1)
224
- {
225
- return Qnil;
226
- }
227
-
228
- ret = LSAPI_Accept_r( &g_req );
229
-
230
- if ( !ret )
231
- {
232
- // req = Data_Make_Struct( self, lsapi_data, lsapi_mark, free, req_data );
233
- // s_req = req;
234
- // req_data->req = &g_req;
235
- // rb_stdin = rb_stdout = req;
236
- //#if RUBY_VERSION_CODE < 180
237
- // rb_defout = req;
238
- //#endif
239
- setup_cgi_env( s_req_data );
240
- return s_req;
248
+ if ( g_req.m_fd != -1 )
249
+ {
250
+ fd = g_req.m_fd;
251
+ }
252
+ else if ( g_req.m_fdListen != -1 )
253
+ fd = g_req.m_fdListen;
254
+ else
255
+ return Qnil;
256
+ wait_secs = 0;
257
+ while( LSAPI_IsRunning() )
258
+ {
259
+ FD_ZERO( &readfds );
260
+ FD_SET( fd, &readfds );
261
+ timeout.tv_sec = 1;
262
+ timeout.tv_usec = 0;
263
+ if (rb_thread_select(fd+1, &readfds, NULL, NULL, &timeout) < 1)
264
+ {
265
+ ++wait_secs;
266
+ if (( s_max_idle_secs > 0 )&&(wait_secs >= s_max_idle_secs ))
267
+ return Qnil;
268
+ }
269
+ else
270
+ break;
271
+ }
272
+
273
+ ret = LSAPI_Accept_r( &g_req );
274
+
275
+ if ( !ret )
276
+ {
277
+ // req = Data_Make_Struct( self, lsapi_data, lsapi_mark, free, req_data );
278
+ // s_req = req;
279
+ // req_data->req = &g_req;
280
+ // rb_stdin = rb_stdout = req;
281
+ //#if RUBY_VERSION_CODE < 180
282
+ // rb_defout = req;
283
+ //#endif
284
+ ++s_req_processed;
285
+ setup_cgi_env( s_req_data );
286
+ return s_req;
287
+ }
241
288
  }
242
289
  return Qnil;
243
290
  }
@@ -435,6 +482,8 @@ static VALUE lsapi_read(int argc, VALUE *argv, VALUE self)
435
482
  lsapi_data *data;
436
483
  int n;
437
484
  int remain;
485
+ fd_set readfds;
486
+ int fd;
438
487
  char buff[8192];
439
488
 
440
489
  if (rb_safe_level() >= 4 && !OBJ_TAINTED(self))
@@ -455,8 +504,16 @@ static VALUE lsapi_read(int argc, VALUE *argv, VALUE self)
455
504
  }
456
505
  str = rb_str_buf_new( remain );
457
506
  OBJ_TAINT(str);
507
+ fd = data->req->m_fd;
458
508
  while( remain > 0 )
459
509
  {
510
+ FD_ZERO( &readfds );
511
+ FD_SET( fd, &readfds );
512
+
513
+ if (rb_thread_select(fd+1, &readfds, NULL, NULL, NULL) < 1)
514
+ {
515
+ return Qnil;
516
+ }
460
517
  n = LSAPI_ReadReqBody_r(data->req, buff,
461
518
  (remain > 8192)?8192:remain );
462
519
  if ( n > 0 )
@@ -519,12 +576,28 @@ static VALUE lsapi_setsync(VALUE self,VALUE sync)
519
576
 
520
577
  void Init_lsapi()
521
578
  {
579
+ int n;
522
580
  char * p = getenv( "LSAPI_CHILDREN" );
523
581
  if ( p )
524
582
  {
525
583
  s_children = atoi( p );
526
584
  }
527
585
 
586
+ p = getenv( "LSAPI_MAX_REQS" );
587
+ if ( p )
588
+ {
589
+ n = atoi( p );
590
+ if ( n > 0 )
591
+ s_max_reqs = n;
592
+ }
593
+
594
+ p = getenv( "LSAPI_MAX_IDLE" );
595
+ if ( p )
596
+ {
597
+ n = atoi( p );
598
+ s_max_idle_secs = n;
599
+ }
600
+
528
601
  orig_stdin = rb_stdin;
529
602
  orig_stdout = rb_stdout;
530
603
  #if RUBY_VERSION_CODE < 180
metadata CHANGED
@@ -3,7 +3,7 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: ruby-lsapi
5
5
  version: !ruby/object:Gem::Version
6
- version: "1.3"
6
+ version: "1.4"
7
7
  date: 2006-07-20 00:00:00 -04:00
8
8
  summary: A ruby extension for fast communication with LiteSpeed Web Server.
9
9
  require_paths: