Fossil SCM

Fix the "fossil server" command to allow up to FOSSIL_MAX_CONNECTIONS (default 1000) pending HTTP requests. This is an increase from 2. Add the --max-latency command-line option for "fossil server". Do a better job of harvesting dead child processes. Report the number of sibling HTTP request handler processes on the /test_env page.

drh 2017-12-23 00:50 trunk
Commit 05ec15cad53e8176b742e8e8c5e279a51194a4ea0946c4d220ac61ef74084e68
3 files changed +19 -10 +18 -2 +3
+19 -10
--- src/cgi.c
+++ src/cgi.c
@@ -1754,13 +1754,15 @@
17541754
17551755
#endif /* INTERFACE */
17561756
17571757
/*
17581758
** Maximum number of child processes that we can have running
1759
-** at one time before we start slowing things down.
1759
+** at one time. Set this to 0 for "no limit".
17601760
*/
1761
-#define MAX_PARALLEL 2
1761
+#ifndef FOSSIL_MAX_CONNECTIONS
1762
+# define FOSSIL_MAX_CONNECTIONS 1000
1763
+#endif
17621764
17631765
/*
17641766
** Implement an HTTP server daemon listening on port iPort.
17651767
**
17661768
** As new connections arrive, fork a child and let child return
@@ -1850,16 +1852,17 @@
18501852
if( system(zBrowser)<0 ){
18511853
fossil_warning("cannot start browser: %s\n", zBrowser);
18521854
}
18531855
}
18541856
while( 1 ){
1855
- if( nchildren>MAX_PARALLEL ){
1856
- /* Slow down if connections are arriving too fast */
1857
- sleep( nchildren-MAX_PARALLEL );
1857
+#if FOSSIL_MAX_CONNECTIONS>0
1858
+ while( nchildren>=FOSSIL_MAX_CONNECTIONS ){
1859
+ if( wait(0)>=0 ) nchildren--;
18581860
}
1859
- delay.tv_sec = 60;
1860
- delay.tv_usec = 0;
1861
+#endif
1862
+ delay.tv_sec = 0;
1863
+ delay.tv_usec = 100000;
18611864
FD_ZERO(&readfds);
18621865
assert( listener>=0 );
18631866
FD_SET( listener, &readfds);
18641867
select( listener+1, &readfds, 0, 0, &delay);
18651868
if( FD_ISSET(listener, &readfds) ){
@@ -1882,18 +1885,24 @@
18821885
close(2);
18831886
fd = dup(connection);
18841887
if( fd!=2 ) nErr++;
18851888
}
18861889
close(connection);
1890
+ g.nPendingRequest = nchildren+1;
18871891
return nErr;
18881892
}
18891893
}
18901894
}
18911895
/* Bury dead children */
1892
- while( waitpid(0, 0, WNOHANG)>0 ){
1893
- nchildren--;
1894
- }
1896
+ if( nchildren ){
1897
+ while(1){
1898
+ int iStatus = 0;
1899
+ pid_t x = waitpid(-1, &iStatus, WNOHANG);
1900
+ if( x<=0 ) break;
1901
+ nchildren--;
1902
+ }
1903
+ }
18951904
}
18961905
/* NOT REACHED */
18971906
fossil_exit(1);
18981907
#endif
18991908
/* NOT REACHED */
19001909
--- src/cgi.c
+++ src/cgi.c
@@ -1754,13 +1754,15 @@
1754
1755 #endif /* INTERFACE */
1756
1757 /*
1758 ** Maximum number of child processes that we can have running
1759 ** at one time before we start slowing things down.
1760 */
1761 #define MAX_PARALLEL 2
 
 
1762
1763 /*
1764 ** Implement an HTTP server daemon listening on port iPort.
1765 **
1766 ** As new connections arrive, fork a child and let child return
@@ -1850,16 +1852,17 @@
1850 if( system(zBrowser)<0 ){
1851 fossil_warning("cannot start browser: %s\n", zBrowser);
1852 }
1853 }
1854 while( 1 ){
1855 if( nchildren>MAX_PARALLEL ){
1856 /* Slow down if connections are arriving too fast */
1857 sleep( nchildren-MAX_PARALLEL );
1858 }
1859 delay.tv_sec = 60;
1860 delay.tv_usec = 0;
 
1861 FD_ZERO(&readfds);
1862 assert( listener>=0 );
1863 FD_SET( listener, &readfds);
1864 select( listener+1, &readfds, 0, 0, &delay);
1865 if( FD_ISSET(listener, &readfds) ){
@@ -1882,18 +1885,24 @@
1882 close(2);
1883 fd = dup(connection);
1884 if( fd!=2 ) nErr++;
1885 }
1886 close(connection);
 
1887 return nErr;
1888 }
1889 }
1890 }
1891 /* Bury dead children */
1892 while( waitpid(0, 0, WNOHANG)>0 ){
1893 nchildren--;
1894 }
 
 
 
 
 
1895 }
1896 /* NOT REACHED */
1897 fossil_exit(1);
1898 #endif
1899 /* NOT REACHED */
1900
--- src/cgi.c
+++ src/cgi.c
@@ -1754,13 +1754,15 @@
1754
1755 #endif /* INTERFACE */
1756
1757 /*
1758 ** Maximum number of child processes that we can have running
1759 ** at one time. Set this to 0 for "no limit".
1760 */
1761 #ifndef FOSSIL_MAX_CONNECTIONS
1762 # define FOSSIL_MAX_CONNECTIONS 1000
1763 #endif
1764
1765 /*
1766 ** Implement an HTTP server daemon listening on port iPort.
1767 **
1768 ** As new connections arrive, fork a child and let child return
@@ -1850,16 +1852,17 @@
1852 if( system(zBrowser)<0 ){
1853 fossil_warning("cannot start browser: %s\n", zBrowser);
1854 }
1855 }
1856 while( 1 ){
1857 #if FOSSIL_MAX_CONNECTIONS>0
1858 while( nchildren>=FOSSIL_MAX_CONNECTIONS ){
1859 if( wait(0)>=0 ) nchildren--;
1860 }
1861 #endif
1862 delay.tv_sec = 0;
1863 delay.tv_usec = 100000;
1864 FD_ZERO(&readfds);
1865 assert( listener>=0 );
1866 FD_SET( listener, &readfds);
1867 select( listener+1, &readfds, 0, 0, &delay);
1868 if( FD_ISSET(listener, &readfds) ){
@@ -1882,18 +1885,24 @@
1885 close(2);
1886 fd = dup(connection);
1887 if( fd!=2 ) nErr++;
1888 }
1889 close(connection);
1890 g.nPendingRequest = nchildren+1;
1891 return nErr;
1892 }
1893 }
1894 }
1895 /* Bury dead children */
1896 if( nchildren ){
1897 while(1){
1898 int iStatus = 0;
1899 pid_t x = waitpid(-1, &iStatus, WNOHANG);
1900 if( x<=0 ) break;
1901 nchildren--;
1902 }
1903 }
1904 }
1905 /* NOT REACHED */
1906 fossil_exit(1);
1907 #endif
1908 /* NOT REACHED */
1909
+18 -2
--- src/main.c
+++ src/main.c
@@ -231,14 +231,13 @@
231231
const char *azAuxName[MX_AUX]; /* Name of each aux() or option() value */
232232
char *azAuxParam[MX_AUX]; /* Param of each aux() or option() value */
233233
const char *azAuxVal[MX_AUX]; /* Value of each aux() or option() value */
234234
const char **azAuxOpt[MX_AUX]; /* Options of each option() value */
235235
int anAuxCols[MX_AUX]; /* Number of columns for option() values */
236
-
237236
int allowSymlinks; /* Cached "allow-symlinks" option */
238
-
239237
int mainTimerId; /* Set to fossil_timer_start() */
238
+ int nPendingRequest; /* # of HTTP requests in "fossil server" */
240239
#ifdef FOSSIL_ENABLE_JSON
241240
struct FossilJsonBits {
242241
int isJsonMode; /* True if running in JSON mode, else
243242
false. This changes how errors are
244243
reported. In JSON mode we try to
@@ -2323,10 +2322,19 @@
23232322
}
23242323
return 0;
23252324
}
23262325
#endif
23272326
#endif
2327
+
2328
+/*
2329
+** Send a time-out reply
2330
+*/
2331
+void sigalrm_handler(int x){
2332
+ printf("TIMEOUT\n");
2333
+ fflush(stdout);
2334
+ exit(1);
2335
+}
23282336
23292337
/*
23302338
** COMMAND: server*
23312339
** COMMAND: ui
23322340
**
@@ -2375,10 +2383,12 @@
23752383
** --page PAGE Start "ui" on PAGE. ex: --page "timeline?y=ci"
23762384
** --files GLOBLIST Comma-separated list of glob patterns for static files
23772385
** --localauth enable automatic login for requests from localhost
23782386
** --localhost listen on 127.0.0.1 only (always true for "ui")
23792387
** --https signal a request coming in via https
2388
+** --max-latency N Do not let any single HTTP request run for more than N
2389
+** seconds (only works on unix)
23802390
** --nojail Drop root privileges but do not enter the chroot jail
23812391
** --nossl signal that no SSL connections are available
23822392
** --notfound URL Redirect
23832393
** -P|--port TCPPORT listen to request on port TCPPORT
23842394
** --th-trace trace TH1 execution (for debugging purposes)
@@ -2402,10 +2412,11 @@
24022412
int noJail; /* Do not enter the chroot jail */
24032413
#endif
24042414
int allowRepoList; /* List repositories on URL "/" */
24052415
const char *zAltBase; /* Argument to the --baseurl option */
24062416
const char *zFileGlob; /* Static content must match this */
2417
+ const char *zMaxLatency; /* Maximum runtime of any single HTTP request */
24072418
char *zIpAddr = 0; /* Bind to this IP address */
24082419
int fCreate = 0; /* The --create flag */
24092420
const char *zInitPage = 0; /* Start on this page. --page option */
24102421
#if defined(_WIN32) && USE_SEE
24112422
const char *zPidKey;
@@ -2414,10 +2425,11 @@
24142425
#if defined(_WIN32)
24152426
const char *zStopperFile; /* Name of file used to terminate server */
24162427
zStopperFile = find_option("stopper", 0, 1);
24172428
#endif
24182429
2430
+ zMaxLatency = find_option("max-latency",0,1);
24192431
zFileGlob = find_option("files-urlenc",0,1);
24202432
if( zFileGlob ){
24212433
char *z = mprintf("%s", zFileGlob);
24222434
dehttpize(z);
24232435
zFileGlob = z;
@@ -2526,10 +2538,14 @@
25262538
if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT;
25272539
db_close(1);
25282540
if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){
25292541
fossil_fatal("unable to listen on TCP socket %d", iPort);
25302542
}
2543
+ if( zMaxLatency ){
2544
+ signal(SIGALRM, sigalrm_handler);
2545
+ alarm(atoi(zMaxLatency));
2546
+ }
25312547
g.httpIn = stdin;
25322548
g.httpOut = stdout;
25332549
if( g.fHttpTrace || g.fSqlTrace ){
25342550
fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
25352551
}
25362552
--- src/main.c
+++ src/main.c
@@ -231,14 +231,13 @@
231 const char *azAuxName[MX_AUX]; /* Name of each aux() or option() value */
232 char *azAuxParam[MX_AUX]; /* Param of each aux() or option() value */
233 const char *azAuxVal[MX_AUX]; /* Value of each aux() or option() value */
234 const char **azAuxOpt[MX_AUX]; /* Options of each option() value */
235 int anAuxCols[MX_AUX]; /* Number of columns for option() values */
236
237 int allowSymlinks; /* Cached "allow-symlinks" option */
238
239 int mainTimerId; /* Set to fossil_timer_start() */
 
240 #ifdef FOSSIL_ENABLE_JSON
241 struct FossilJsonBits {
242 int isJsonMode; /* True if running in JSON mode, else
243 false. This changes how errors are
244 reported. In JSON mode we try to
@@ -2323,10 +2322,19 @@
2323 }
2324 return 0;
2325 }
2326 #endif
2327 #endif
 
 
 
 
 
 
 
 
 
2328
2329 /*
2330 ** COMMAND: server*
2331 ** COMMAND: ui
2332 **
@@ -2375,10 +2383,12 @@
2375 ** --page PAGE Start "ui" on PAGE. ex: --page "timeline?y=ci"
2376 ** --files GLOBLIST Comma-separated list of glob patterns for static files
2377 ** --localauth enable automatic login for requests from localhost
2378 ** --localhost listen on 127.0.0.1 only (always true for "ui")
2379 ** --https signal a request coming in via https
 
 
2380 ** --nojail Drop root privileges but do not enter the chroot jail
2381 ** --nossl signal that no SSL connections are available
2382 ** --notfound URL Redirect
2383 ** -P|--port TCPPORT listen to request on port TCPPORT
2384 ** --th-trace trace TH1 execution (for debugging purposes)
@@ -2402,10 +2412,11 @@
2402 int noJail; /* Do not enter the chroot jail */
2403 #endif
2404 int allowRepoList; /* List repositories on URL "/" */
2405 const char *zAltBase; /* Argument to the --baseurl option */
2406 const char *zFileGlob; /* Static content must match this */
 
2407 char *zIpAddr = 0; /* Bind to this IP address */
2408 int fCreate = 0; /* The --create flag */
2409 const char *zInitPage = 0; /* Start on this page. --page option */
2410 #if defined(_WIN32) && USE_SEE
2411 const char *zPidKey;
@@ -2414,10 +2425,11 @@
2414 #if defined(_WIN32)
2415 const char *zStopperFile; /* Name of file used to terminate server */
2416 zStopperFile = find_option("stopper", 0, 1);
2417 #endif
2418
 
2419 zFileGlob = find_option("files-urlenc",0,1);
2420 if( zFileGlob ){
2421 char *z = mprintf("%s", zFileGlob);
2422 dehttpize(z);
2423 zFileGlob = z;
@@ -2526,10 +2538,14 @@
2526 if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT;
2527 db_close(1);
2528 if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){
2529 fossil_fatal("unable to listen on TCP socket %d", iPort);
2530 }
 
 
 
 
2531 g.httpIn = stdin;
2532 g.httpOut = stdout;
2533 if( g.fHttpTrace || g.fSqlTrace ){
2534 fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
2535 }
2536
--- src/main.c
+++ src/main.c
@@ -231,14 +231,13 @@
231 const char *azAuxName[MX_AUX]; /* Name of each aux() or option() value */
232 char *azAuxParam[MX_AUX]; /* Param of each aux() or option() value */
233 const char *azAuxVal[MX_AUX]; /* Value of each aux() or option() value */
234 const char **azAuxOpt[MX_AUX]; /* Options of each option() value */
235 int anAuxCols[MX_AUX]; /* Number of columns for option() values */
 
236 int allowSymlinks; /* Cached "allow-symlinks" option */
 
237 int mainTimerId; /* Set to fossil_timer_start() */
238 int nPendingRequest; /* # of HTTP requests in "fossil server" */
239 #ifdef FOSSIL_ENABLE_JSON
240 struct FossilJsonBits {
241 int isJsonMode; /* True if running in JSON mode, else
242 false. This changes how errors are
243 reported. In JSON mode we try to
@@ -2323,10 +2322,19 @@
2322 }
2323 return 0;
2324 }
2325 #endif
2326 #endif
2327
2328 /*
2329 ** Send a time-out reply
2330 */
2331 void sigalrm_handler(int x){
2332 printf("TIMEOUT\n");
2333 fflush(stdout);
2334 exit(1);
2335 }
2336
2337 /*
2338 ** COMMAND: server*
2339 ** COMMAND: ui
2340 **
@@ -2375,10 +2383,12 @@
2383 ** --page PAGE Start "ui" on PAGE. ex: --page "timeline?y=ci"
2384 ** --files GLOBLIST Comma-separated list of glob patterns for static files
2385 ** --localauth enable automatic login for requests from localhost
2386 ** --localhost listen on 127.0.0.1 only (always true for "ui")
2387 ** --https signal a request coming in via https
2388 ** --max-latency N Do not let any single HTTP request run for more than N
2389 ** seconds (only works on unix)
2390 ** --nojail Drop root privileges but do not enter the chroot jail
2391 ** --nossl signal that no SSL connections are available
2392 ** --notfound URL Redirect
2393 ** -P|--port TCPPORT listen to request on port TCPPORT
2394 ** --th-trace trace TH1 execution (for debugging purposes)
@@ -2402,10 +2412,11 @@
2412 int noJail; /* Do not enter the chroot jail */
2413 #endif
2414 int allowRepoList; /* List repositories on URL "/" */
2415 const char *zAltBase; /* Argument to the --baseurl option */
2416 const char *zFileGlob; /* Static content must match this */
2417 const char *zMaxLatency; /* Maximum runtime of any single HTTP request */
2418 char *zIpAddr = 0; /* Bind to this IP address */
2419 int fCreate = 0; /* The --create flag */
2420 const char *zInitPage = 0; /* Start on this page. --page option */
2421 #if defined(_WIN32) && USE_SEE
2422 const char *zPidKey;
@@ -2414,10 +2425,11 @@
2425 #if defined(_WIN32)
2426 const char *zStopperFile; /* Name of file used to terminate server */
2427 zStopperFile = find_option("stopper", 0, 1);
2428 #endif
2429
2430 zMaxLatency = find_option("max-latency",0,1);
2431 zFileGlob = find_option("files-urlenc",0,1);
2432 if( zFileGlob ){
2433 char *z = mprintf("%s", zFileGlob);
2434 dehttpize(z);
2435 zFileGlob = z;
@@ -2526,10 +2538,14 @@
2538 if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT;
2539 db_close(1);
2540 if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){
2541 fossil_fatal("unable to listen on TCP socket %d", iPort);
2542 }
2543 if( zMaxLatency ){
2544 signal(SIGALRM, sigalrm_handler);
2545 alarm(atoi(zMaxLatency));
2546 }
2547 g.httpIn = stdin;
2548 g.httpOut = stdout;
2549 if( g.fHttpTrace || g.fSqlTrace ){
2550 fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
2551 }
2552
--- src/style.c
+++ src/style.c
@@ -908,10 +908,13 @@
908908
}
909909
zCap[i] = 0;
910910
@ g.userUid = %d(g.userUid)<br />
911911
@ g.zLogin = %h(g.zLogin)<br />
912912
@ g.isHuman = %d(g.isHuman)<br />
913
+ if( g.nPendingRequest>1 ){
914
+ @ g.nPendingRequest = %d(g.nPendingRequest)<br />
915
+ }
913916
@ capabilities = %s(zCap)<br />
914917
for(i=0, c='a'; c<='z'; c++){
915918
if( login_has_capability(&c, 1, LOGIN_ANON)
916919
&& !login_has_capability(&c, 1, 0) ) zCap[i++] = c;
917920
}
918921
--- src/style.c
+++ src/style.c
@@ -908,10 +908,13 @@
908 }
909 zCap[i] = 0;
910 @ g.userUid = %d(g.userUid)<br />
911 @ g.zLogin = %h(g.zLogin)<br />
912 @ g.isHuman = %d(g.isHuman)<br />
 
 
 
913 @ capabilities = %s(zCap)<br />
914 for(i=0, c='a'; c<='z'; c++){
915 if( login_has_capability(&c, 1, LOGIN_ANON)
916 && !login_has_capability(&c, 1, 0) ) zCap[i++] = c;
917 }
918
--- src/style.c
+++ src/style.c
@@ -908,10 +908,13 @@
908 }
909 zCap[i] = 0;
910 @ g.userUid = %d(g.userUid)<br />
911 @ g.zLogin = %h(g.zLogin)<br />
912 @ g.isHuman = %d(g.isHuman)<br />
913 if( g.nPendingRequest>1 ){
914 @ g.nPendingRequest = %d(g.nPendingRequest)<br />
915 }
916 @ capabilities = %s(zCap)<br />
917 for(i=0, c='a'; c<='z'; c++){
918 if( login_has_capability(&c, 1, LOGIN_ANON)
919 && !login_has_capability(&c, 1, 0) ) zCap[i++] = c;
920 }
921

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button