Fossil SCM
Add new option max-download-time to limit the processing time of pull/sync /clone requests. This helps to significantly cut down the number of time outs clients receive on busy server with reverse proxy configuration. It generally provides better response times.
Commit
ee6ae580eee084d28279cc84c3e6e7596345e291
Parent
80bf94e0f7ea9eb…
2 files changed
+9
+8
-2
+9
| --- src/setup.c | ||
| +++ src/setup.c | ||
| @@ -917,10 +917,19 @@ | ||
| 917 | 917 | @ to this many bytes, uncompressed. If the client requires more data |
| 918 | 918 | @ than this, then the client will issue multiple HTTP requests. |
| 919 | 919 | @ Values below 1 million are not recommended. 5 million is a |
| 920 | 920 | @ reasonable number.</p> |
| 921 | 921 | |
| 922 | + @ <hr /> | |
| 923 | + entry_attribute("Download time limit", 11, "max-download-time", "mxdwnt", | |
| 924 | + "30"); | |
| 925 | + | |
| 926 | + @ <p>Fossil tries to spend less than this many seconds gathering | |
| 927 | + @ the out-bound data of sync, clone, and pull packets. | |
| 928 | + @ If the client request takes longer, a partial reply is given similar | |
| 929 | + @ to the download packet limit. 30s is a reasonable default.</p> | |
| 930 | + | |
| 922 | 931 | @ <hr /> |
| 923 | 932 | onoff_attribute( |
| 924 | 933 | "Enable hyperlinks for \"nobody\" based on User-Agent and Javascript", |
| 925 | 934 | "auto-hyperlink", "autohyperlink", 1); |
| 926 | 935 | @ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users |
| 927 | 936 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -917,10 +917,19 @@ | |
| 917 | @ to this many bytes, uncompressed. If the client requires more data |
| 918 | @ than this, then the client will issue multiple HTTP requests. |
| 919 | @ Values below 1 million are not recommended. 5 million is a |
| 920 | @ reasonable number.</p> |
| 921 | |
| 922 | @ <hr /> |
| 923 | onoff_attribute( |
| 924 | "Enable hyperlinks for \"nobody\" based on User-Agent and Javascript", |
| 925 | "auto-hyperlink", "autohyperlink", 1); |
| 926 | @ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users |
| 927 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -917,10 +917,19 @@ | |
| 917 | @ to this many bytes, uncompressed. If the client requires more data |
| 918 | @ than this, then the client will issue multiple HTTP requests. |
| 919 | @ Values below 1 million are not recommended. 5 million is a |
| 920 | @ reasonable number.</p> |
| 921 | |
| 922 | @ <hr /> |
| 923 | entry_attribute("Download time limit", 11, "max-download-time", "mxdwnt", |
| 924 | "30"); |
| 925 | |
| 926 | @ <p>Fossil tries to spend less than this many seconds gathering |
| 927 | @ the out-bound data of sync, clone, and pull packets. |
| 928 | @ If the client request takes longer, a partial reply is given similar |
| 929 | @ to the download packet limit. 30s is a reasonable default.</p> |
| 930 | |
| 931 | @ <hr /> |
| 932 | onoff_attribute( |
| 933 | "Enable hyperlinks for \"nobody\" based on User-Agent and Javascript", |
| 934 | "auto-hyperlink", "autohyperlink", 1); |
| 935 | @ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users |
| 936 |
+8
-2
| --- src/xfer.c | ||
| +++ src/xfer.c | ||
| @@ -18,10 +18,12 @@ | ||
| 18 | 18 | ** This file contains code to implement the file transfer protocol. |
| 19 | 19 | */ |
| 20 | 20 | #include "config.h" |
| 21 | 21 | #include "xfer.h" |
| 22 | 22 | |
| 23 | +#include <time.h> | |
| 24 | + | |
| 23 | 25 | /* |
| 24 | 26 | ** This structure holds information about the current state of either |
| 25 | 27 | ** a client or a server that is participating in xfer. |
| 26 | 28 | */ |
| 27 | 29 | typedef struct Xfer Xfer; |
| @@ -40,10 +42,11 @@ | ||
| 40 | 42 | int nDeltaRcvd; /* Number of deltas received */ |
| 41 | 43 | int nDanglingFile; /* Number of dangling deltas received */ |
| 42 | 44 | int mxSend; /* Stop sending "file" with pOut reaches this size */ |
| 43 | 45 | u8 syncPrivate; /* True to enable syncing private content */ |
| 44 | 46 | u8 nextIsPrivate; /* If true, next "file" received is a private */ |
| 47 | + time_t maxTime; /* Time when this transfer should be finished */ | |
| 45 | 48 | }; |
| 46 | 49 | |
| 47 | 50 | |
| 48 | 51 | /* |
| 49 | 52 | ** The input blob contains a UUID. Convert it into a record ID. |
| @@ -393,11 +396,11 @@ | ||
| 393 | 396 | } |
| 394 | 397 | if( uuid_is_shunned(blob_str(pUuid)) ){ |
| 395 | 398 | blob_reset(&uuid); |
| 396 | 399 | return; |
| 397 | 400 | } |
| 398 | - if( pXfer->mxSend<=blob_size(pXfer->pOut) ){ | |
| 401 | + if( time(NULL) >= pXfer->maxTime || pXfer->mxSend<=blob_size(pXfer->pOut) ){ | |
| 399 | 402 | const char *zFormat = isPriv ? "igot %b 1\n" : "igot %b\n"; |
| 400 | 403 | blob_appendf(pXfer->pOut, zFormat, pUuid); |
| 401 | 404 | pXfer->nIGotSent++; |
| 402 | 405 | blob_reset(&uuid); |
| 403 | 406 | return; |
| @@ -867,10 +870,11 @@ | ||
| 867 | 870 | } |
| 868 | 871 | blob_zero(&xfer.err); |
| 869 | 872 | xfer.pIn = &g.cgiIn; |
| 870 | 873 | xfer.pOut = cgi_output_blob(); |
| 871 | 874 | xfer.mxSend = db_get_int("max-download", 5000000); |
| 875 | + xfer.maxTime = time(NULL) + db_get_int("max-download-time", 30); | |
| 872 | 876 | g.xferPanic = 1; |
| 873 | 877 | |
| 874 | 878 | db_begin_transaction(); |
| 875 | 879 | db_multi_exec( |
| 876 | 880 | "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);" |
| @@ -1034,11 +1038,12 @@ | ||
| 1034 | 1038 | if( iVers>=3 ){ |
| 1035 | 1039 | cgi_set_content_type("application/x-fossil-uncompressed"); |
| 1036 | 1040 | } |
| 1037 | 1041 | blob_is_int(&xfer.aToken[2], &seqno); |
| 1038 | 1042 | max = db_int(0, "SELECT max(rid) FROM blob"); |
| 1039 | - while( xfer.mxSend>blob_size(xfer.pOut) && seqno<=max ){ | |
| 1043 | + while( xfer.mxSend>blob_size(xfer.pOut) && seqno<=max){ | |
| 1044 | + if( time(NULL) >= xfer.maxTime ) break; | |
| 1040 | 1045 | if( iVers>=3 ){ |
| 1041 | 1046 | send_compressed_file(&xfer, seqno); |
| 1042 | 1047 | }else{ |
| 1043 | 1048 | send_file(&xfer, seqno, 0, 1); |
| 1044 | 1049 | } |
| @@ -1328,10 +1333,11 @@ | ||
| 1328 | 1333 | socket_global_init(); |
| 1329 | 1334 | memset(&xfer, 0, sizeof(xfer)); |
| 1330 | 1335 | xfer.pIn = &recv; |
| 1331 | 1336 | xfer.pOut = &send; |
| 1332 | 1337 | xfer.mxSend = db_get_int("max-upload", 250000); |
| 1338 | + xfer.maxTime = -1; | |
| 1333 | 1339 | if( syncFlags & SYNC_PRIVATE ){ |
| 1334 | 1340 | g.perm.Private = 1; |
| 1335 | 1341 | xfer.syncPrivate = 1; |
| 1336 | 1342 | } |
| 1337 | 1343 | |
| 1338 | 1344 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -18,10 +18,12 @@ | |
| 18 | ** This file contains code to implement the file transfer protocol. |
| 19 | */ |
| 20 | #include "config.h" |
| 21 | #include "xfer.h" |
| 22 | |
| 23 | /* |
| 24 | ** This structure holds information about the current state of either |
| 25 | ** a client or a server that is participating in xfer. |
| 26 | */ |
| 27 | typedef struct Xfer Xfer; |
| @@ -40,10 +42,11 @@ | |
| 40 | int nDeltaRcvd; /* Number of deltas received */ |
| 41 | int nDanglingFile; /* Number of dangling deltas received */ |
| 42 | int mxSend; /* Stop sending "file" with pOut reaches this size */ |
| 43 | u8 syncPrivate; /* True to enable syncing private content */ |
| 44 | u8 nextIsPrivate; /* If true, next "file" received is a private */ |
| 45 | }; |
| 46 | |
| 47 | |
| 48 | /* |
| 49 | ** The input blob contains a UUID. Convert it into a record ID. |
| @@ -393,11 +396,11 @@ | |
| 393 | } |
| 394 | if( uuid_is_shunned(blob_str(pUuid)) ){ |
| 395 | blob_reset(&uuid); |
| 396 | return; |
| 397 | } |
| 398 | if( pXfer->mxSend<=blob_size(pXfer->pOut) ){ |
| 399 | const char *zFormat = isPriv ? "igot %b 1\n" : "igot %b\n"; |
| 400 | blob_appendf(pXfer->pOut, zFormat, pUuid); |
| 401 | pXfer->nIGotSent++; |
| 402 | blob_reset(&uuid); |
| 403 | return; |
| @@ -867,10 +870,11 @@ | |
| 867 | } |
| 868 | blob_zero(&xfer.err); |
| 869 | xfer.pIn = &g.cgiIn; |
| 870 | xfer.pOut = cgi_output_blob(); |
| 871 | xfer.mxSend = db_get_int("max-download", 5000000); |
| 872 | g.xferPanic = 1; |
| 873 | |
| 874 | db_begin_transaction(); |
| 875 | db_multi_exec( |
| 876 | "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);" |
| @@ -1034,11 +1038,12 @@ | |
| 1034 | if( iVers>=3 ){ |
| 1035 | cgi_set_content_type("application/x-fossil-uncompressed"); |
| 1036 | } |
| 1037 | blob_is_int(&xfer.aToken[2], &seqno); |
| 1038 | max = db_int(0, "SELECT max(rid) FROM blob"); |
| 1039 | while( xfer.mxSend>blob_size(xfer.pOut) && seqno<=max ){ |
| 1040 | if( iVers>=3 ){ |
| 1041 | send_compressed_file(&xfer, seqno); |
| 1042 | }else{ |
| 1043 | send_file(&xfer, seqno, 0, 1); |
| 1044 | } |
| @@ -1328,10 +1333,11 @@ | |
| 1328 | socket_global_init(); |
| 1329 | memset(&xfer, 0, sizeof(xfer)); |
| 1330 | xfer.pIn = &recv; |
| 1331 | xfer.pOut = &send; |
| 1332 | xfer.mxSend = db_get_int("max-upload", 250000); |
| 1333 | if( syncFlags & SYNC_PRIVATE ){ |
| 1334 | g.perm.Private = 1; |
| 1335 | xfer.syncPrivate = 1; |
| 1336 | } |
| 1337 | |
| 1338 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -18,10 +18,12 @@ | |
| 18 | ** This file contains code to implement the file transfer protocol. |
| 19 | */ |
| 20 | #include "config.h" |
| 21 | #include "xfer.h" |
| 22 | |
| 23 | #include <time.h> |
| 24 | |
| 25 | /* |
| 26 | ** This structure holds information about the current state of either |
| 27 | ** a client or a server that is participating in xfer. |
| 28 | */ |
| 29 | typedef struct Xfer Xfer; |
| @@ -40,10 +42,11 @@ | |
| 42 | int nDeltaRcvd; /* Number of deltas received */ |
| 43 | int nDanglingFile; /* Number of dangling deltas received */ |
| 44 | int mxSend; /* Stop sending "file" with pOut reaches this size */ |
| 45 | u8 syncPrivate; /* True to enable syncing private content */ |
| 46 | u8 nextIsPrivate; /* If true, next "file" received is a private */ |
| 47 | time_t maxTime; /* Time when this transfer should be finished */ |
| 48 | }; |
| 49 | |
| 50 | |
| 51 | /* |
| 52 | ** The input blob contains a UUID. Convert it into a record ID. |
| @@ -393,11 +396,11 @@ | |
| 396 | } |
| 397 | if( uuid_is_shunned(blob_str(pUuid)) ){ |
| 398 | blob_reset(&uuid); |
| 399 | return; |
| 400 | } |
| 401 | if( time(NULL) >= pXfer->maxTime || pXfer->mxSend<=blob_size(pXfer->pOut) ){ |
| 402 | const char *zFormat = isPriv ? "igot %b 1\n" : "igot %b\n"; |
| 403 | blob_appendf(pXfer->pOut, zFormat, pUuid); |
| 404 | pXfer->nIGotSent++; |
| 405 | blob_reset(&uuid); |
| 406 | return; |
| @@ -867,10 +870,11 @@ | |
| 870 | } |
| 871 | blob_zero(&xfer.err); |
| 872 | xfer.pIn = &g.cgiIn; |
| 873 | xfer.pOut = cgi_output_blob(); |
| 874 | xfer.mxSend = db_get_int("max-download", 5000000); |
| 875 | xfer.maxTime = time(NULL) + db_get_int("max-download-time", 30); |
| 876 | g.xferPanic = 1; |
| 877 | |
| 878 | db_begin_transaction(); |
| 879 | db_multi_exec( |
| 880 | "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);" |
| @@ -1034,11 +1038,12 @@ | |
| 1038 | if( iVers>=3 ){ |
| 1039 | cgi_set_content_type("application/x-fossil-uncompressed"); |
| 1040 | } |
| 1041 | blob_is_int(&xfer.aToken[2], &seqno); |
| 1042 | max = db_int(0, "SELECT max(rid) FROM blob"); |
| 1043 | while( xfer.mxSend>blob_size(xfer.pOut) && seqno<=max){ |
| 1044 | if( time(NULL) >= xfer.maxTime ) break; |
| 1045 | if( iVers>=3 ){ |
| 1046 | send_compressed_file(&xfer, seqno); |
| 1047 | }else{ |
| 1048 | send_file(&xfer, seqno, 0, 1); |
| 1049 | } |
| @@ -1328,10 +1333,11 @@ | |
| 1333 | socket_global_init(); |
| 1334 | memset(&xfer, 0, sizeof(xfer)); |
| 1335 | xfer.pIn = &recv; |
| 1336 | xfer.pOut = &send; |
| 1337 | xfer.mxSend = db_get_int("max-upload", 250000); |
| 1338 | xfer.maxTime = -1; |
| 1339 | if( syncFlags & SYNC_PRIVATE ){ |
| 1340 | g.perm.Private = 1; |
| 1341 | xfer.syncPrivate = 1; |
| 1342 | } |
| 1343 | |
| 1344 |