Fossil SCM

Limit the amount of unversioned content sent with each HTTP request. Also: fix up source code lines in xfer.c to be less than 80 characters long.

drh 2016-08-17 13:37 UTC unversioned-files
Commit faa73ae0c4a82af20e48134750dddf21ae37859e
1 file changed +87 -51
+87 -51
--- src/xfer.c
+++ src/xfer.c
@@ -2,11 +2,11 @@
22
** Copyright (c) 2007 D. Richard Hipp
33
**
44
** This program is free software; you can redistribute it and/or
55
** modify it under the terms of the Simplified BSD License (also
66
** known as the "2-Clause License" or "FreeBSD License".)
7
-
7
+**
88
** This program is distributed in the hope that it will be useful,
99
** but without any warranty; without even the implied warranty of
1010
** merchantability or fitness for a particular purpose.
1111
**
1212
** Author contact information:
@@ -305,21 +305,21 @@
305305
** The sender might have omitted the content because it is too big to
306306
** transmit, or because it is unchanged and this record exists purely
307307
** to update the MTIME.
308308
*/
309309
static void xfer_accept_unversioned_file(Xfer *pXfer, int isWriter){
310
- sqlite3_int64 mtime; /* The MTIME */
311
- Blob *pHash; /* The HASH value */
312
- int sz; /* The SIZE */
313
- int flags; /* The FLAGS */
314
- Blob content; /* The CONTENT */
315
- Blob hash; /* Hash computed from CONTENT to compare with HASH */
316
- Blob x; /* Compressed content */
317
- Stmt q; /* SQL statements for comparison and insert */
318
- int isDelete; /* HASH is "-" indicating this is a delete operation */
319
- int nullContent; /* True of CONTENT is NULL */
320
- int iStatus; /* Result from unversioned_status() */
310
+ sqlite3_int64 mtime; /* The MTIME */
311
+ Blob *pHash; /* The HASH value */
312
+ int sz; /* The SIZE */
313
+ int flags; /* The FLAGS */
314
+ Blob content; /* The CONTENT */
315
+ Blob hash; /* Hash computed from CONTENT to compare with HASH */
316
+ Blob x; /* Compressed content */
317
+ Stmt q; /* SQL statements for comparison and insert */
318
+ int isDelete; /* HASH is "-" indicating this is a delete */
319
+ int nullContent; /* True of CONTENT is NULL */
320
+ int iStatus; /* Result from unversioned_status() */
321321
322322
pHash = &pXfer->aToken[3];
323323
if( pXfer->nToken==5
324324
|| !blob_is_filename(&pXfer->aToken[1])
325325
|| !blob_is_int64(&pXfer->aToken[2], &mtime)
@@ -350,27 +350,29 @@
350350
351351
/* Check to see if current content really should be overwritten. Ideally,
352352
** a uvfile card should never have been sent unless the overwrite should
353353
** occur. But do not trust the sender. Double-check.
354354
*/
355
- iStatus = unversioned_status(blob_str(&pXfer->aToken[1]), mtime, blob_str(pHash));
355
+ iStatus = unversioned_status(blob_str(&pXfer->aToken[1]), mtime,
356
+ blob_str(pHash));
356357
if( iStatus>=3 ) goto end_accept_unversioned_file;
357358
358359
/* Store the content */
359360
isDelete = blob_eq(pHash, "-");
360361
if( isDelete ){
361362
db_prepare(&q,
362363
"UPDATE unversioned"
363
- " SET rcvid=:rcvid, mtime=:mtime, hash=NULL, sz=0, encoding=0, content=NULL"
364
+ " SET rcvid=:rcvid, mtime=:mtime, hash=NULL,"
365
+ " sz=0, encoding=0, content=NULL"
364366
" WHERE name=:name"
365367
);
366368
db_bind_int(&q, ":rcvid", g.rcvid);
367369
}else if( iStatus==4 ){
368370
db_prepare(&q, "UPDATE unversioned SET mtime=:mtime WHERE name=:name");
369371
}else{
370372
db_prepare(&q,
371
- "REPLACE INTO unversioned(name, rcvid, mtime, hash, sz, encoding, content)"
373
+ "REPLACE INTO unversioned(name,rcvid,mtime,hash,sz,encoding,content)"
372374
" VALUES(:name,:rcvid,:mtime,:hash,:sz,:encoding,:content)"
373375
);
374376
db_bind_int(&q, ":rcvid", g.rcvid);
375377
db_bind_text(&q, ":hash", blob_str(pHash));
376378
db_bind_int(&q, ":sz", blob_size(&content));
@@ -645,49 +647,60 @@
645647
** Send the unversioned file identified by zName by generating the
646648
** appropriate "uvfile" card.
647649
**
648650
** uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT
649651
**
650
-** If the noContent flag is set, omit the CONTENT and set the 0x0004 flag in FLAGS.
652
+** If the noContent flag is set, omit the CONTENT and set the 0x0004
653
+** flag in FLAGS.
651654
*/
652
-static void send_unversioned_file(Xfer *pXfer, const char *zName, int noContent){
655
+static void send_unversioned_file(
656
+ Xfer *pXfer, /* Transfer context */
657
+ const char *zName, /* Name of unversioned file to be sent */
658
+ int noContent /* True to omit the content */
659
+){
653660
Stmt q1;
654661
662
+ if( blob_size(pXfer->pOut)>=pXfer->mxSend ) noContent = 1;
655663
if( noContent ){
656664
db_prepare(&q1,
657665
"SELECT mtime, hash, encoding, sz FROM unversioned WHERE name=%Q",
658666
zName
659667
);
660668
}else{
661669
db_prepare(&q1,
662
- "SELECT mtime, hash, encoding, sz, content FROM unversioned WHERE name=%Q",
670
+ "SELECT mtime, hash, encoding, sz, content FROM unversioned"
671
+ " WHERE name=%Q",
663672
zName
664673
);
665674
}
666675
if( db_step(&q1)==SQLITE_ROW ){
667676
sqlite3_int64 mtime = db_column_int64(&q1, 0);
668677
const char *zHash = db_column_text(&q1, 1);
669
- blob_appendf(pXfer->pOut, "uvfile %s %lld", zName, mtime);
670
- if( zHash==0 ){
671
- blob_append(pXfer->pOut, " - 0 1\n", -1);
672
- }else if( noContent ){
673
- blob_appendf(pXfer->pOut, " %s %d 4\n", zHash, db_column_int(&q1,3));
678
+ if( blob_size(pXfer->pOut)>=pXfer->mxSend ){
679
+ /* If we have already reached the send size limit, send a (short)
680
+ ** uvigot card rather than a uvfile card. This only happens on the
681
+ ** server side. The uvigot card will provoke the client to resend
682
+ ** another uvgimme on the next cycle. */
683
+ blob_appendf(pXfer->pOut, "uvigot %s %lld %s %d\n",
684
+ zName, mtime, zHash, db_column_int(&q1,3));
674685
}else{
675
- Blob content;
676
- blob_init(&content, 0, 0);
677
- db_column_blob(&q1, 4, &content);
678
- if( db_column_int(&q1, 2) ){
679
- blob_uncompress(&content, &content);
680
- }
681
- blob_appendf(pXfer->pOut, " %s %d 0\n", zHash, blob_size(&content));
682
- blob_append(pXfer->pOut, blob_buffer(&content), blob_size(&content));
683
-#if 0
684
- if( blob_buffer(pXfer->pOut)[blob_size(pXfer->pOut)-1]!='\n' ){
685
- blob_append(pXfer->pOut, "\n", 1);
686
- }
687
-#endif
688
- blob_reset(&content);
686
+ blob_appendf(pXfer->pOut, "uvfile %s %lld", zName, mtime);
687
+ if( zHash==0 ){
688
+ blob_append(pXfer->pOut, " - 0 1\n", -1);
689
+ }else if( noContent ){
690
+ blob_appendf(pXfer->pOut, " %s %d 4\n", zHash, db_column_int(&q1,3));
691
+ }else{
692
+ Blob content;
693
+ blob_init(&content, 0, 0);
694
+ db_column_blob(&q1, 4, &content);
695
+ if( db_column_int(&q1, 2) ){
696
+ blob_uncompress(&content, &content);
697
+ }
698
+ blob_appendf(pXfer->pOut, " %s %d 0\n", zHash, blob_size(&content));
699
+ blob_append(pXfer->pOut, blob_buffer(&content), blob_size(&content));
700
+ blob_reset(&content);
701
+ }
689702
}
690703
}
691704
db_finalize(&q1);
692705
}
693706
@@ -757,11 +770,13 @@
757770
Stmt q;
758771
int rc = -1;
759772
char *zLogin = blob_terminate(pLogin);
760773
defossilize(zLogin);
761774
762
- if( fossil_strcmp(zLogin, "nobody")==0 || fossil_strcmp(zLogin,"anonymous")==0 ){
775
+ if( fossil_strcmp(zLogin, "nobody")==0
776
+ || fossil_strcmp(zLogin,"anonymous")==0
777
+ ){
763778
return 0; /* Anybody is allowed to sync as "nobody" or "anonymous" */
764779
}
765780
if( fossil_strcmp(P("REMOTE_USER"), zLogin)==0
766781
&& db_get_boolean("remote_user_ok",0) ){
767782
return 0; /* Accept Basic Authorization */
@@ -1517,11 +1532,13 @@
15171532
**
15181533
** The client wants to make sure that unversioned files are all synced.
15191534
** If the HASH does not match, send a complete catalog of
15201535
** "uvigot" cards.
15211536
*/
1522
- if( blob_eq(&xfer.aToken[1], "uv-hash") && blob_is_uuid(&xfer.aToken[2]) ){
1537
+ if( blob_eq(&xfer.aToken[1], "uv-hash")
1538
+ && blob_is_uuid(&xfer.aToken[2])
1539
+ ){
15231540
if( g.perm.Read && g.perm.WrUnver ){
15241541
@ pragma uv-push-ok
15251542
send_unversioned_catalog(&xfer);
15261543
}else if( g.perm.Read ){
15271544
@ pragma uv-pull-only
@@ -1684,11 +1701,13 @@
16841701
int nArtifactRcvd = 0; /* Total artifacts received */
16851702
const char *zOpType = 0;/* Push, Pull, Sync, Clone */
16861703
double rSkew = 0.0; /* Maximum time skew */
16871704
int uvHashSent = 0; /* The "pragma uv-hash" message has been sent */
16881705
int uvStatus = 0; /* 0: no I/O. 1: pull-only 2: push-and-pull */
1689
- int uvDoPush = 0; /* If true, generate uvfile messages to send to server */
1706
+ int uvDoPush = 0; /* Generate uvfile messages to send to server */
1707
+ int nUvGimmeSent = 0; /* Number of uvgimme cards sent on this cycle */
1708
+ int nUvFileRcvd = 0; /* Number of uvfile cards received on this cycle */
16901709
sqlite3_int64 mtime; /* Modification time on a UV file */
16911710
16921711
if( db_get_boolean("dont-push", 0) ) syncFlags &= ~SYNC_PUSH;
16931712
if( (syncFlags & (SYNC_PUSH|SYNC_PULL|SYNC_CLONE|SYNC_UNVERSIONED))==0
16941713
&& configRcvMask==0 && configSendMask==0 ) return 0;
@@ -1861,20 +1880,24 @@
18611880
/* Send unversioned files present here on the client but missing or
18621881
** obsolete on the server.
18631882
*/
18641883
if( uvDoPush ){
18651884
Stmt uvq;
1885
+ int rc = SQLITE_OK;
18661886
assert( (syncFlags & SYNC_UNVERSIONED)!=0 );
18671887
assert( uvStatus==2 );
18681888
db_prepare(&uvq, "SELECT name, mtimeOnly FROM uv_tosend");
1869
- while( db_step(&uvq)==SQLITE_ROW ){
1870
- send_unversioned_file(&xfer, db_column_text(&uvq,0), db_column_int(&uvq,1));
1889
+ while( (rc = db_step(&uvq))==SQLITE_ROW ){
1890
+ const char *zName = db_column_text(&uvq, 0);
1891
+ send_unversioned_file(&xfer, zName, db_column_int(&uvq,1));
18711892
nCardSent++;
18721893
nArtifactSent++;
1894
+ db_multi_exec("DELETE FROM uv_tosend WHERE name=%Q", zName);
1895
+ if( blob_size(xfer.pOut)>xfer.mxSend ) break;
18731896
}
18741897
db_finalize(&uvq);
1875
- uvDoPush = 0;
1898
+ if( rc==SQLITE_DONE ) uvDoPush = 0;
18761899
}
18771900
18781901
/* Append randomness to the end of the message. This makes all
18791902
** messages unique so that that the login-card nonce will always
18801903
** be unique.
@@ -1932,10 +1955,12 @@
19321955
if( syncFlags & SYNC_PUSH ){
19331956
blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
19341957
nCardSent++;
19351958
}
19361959
go = 0;
1960
+ nUvGimmeSent = 0;
1961
+ nUvFileRcvd = 0;
19371962
19381963
/* Process the reply that came back from the server */
19391964
while( blob_line(&recv, &xfer.line) ){
19401965
if( blob_buffer(&xfer.line)[0]=='#' ){
19411966
const char *zLine = blob_buffer(&xfer.line);
@@ -1944,11 +1969,13 @@
19441969
double rDiff;
19451970
sqlite3_snprintf(sizeof(zTime), zTime, "%.19s", &zLine[12]);
19461971
rDiff = db_double(9e99, "SELECT julianday('%q') - %.17g",
19471972
zTime, rArrivalTime);
19481973
if( rDiff>9e98 || rDiff<-9e98 ) rDiff = 0.0;
1949
- if( rDiff*24.0*3600.0 >= -(blob_size(&recv)/5000.0 + 20) ) rDiff = 0.0;
1974
+ if( rDiff*24.0*3600.0 >= -(blob_size(&recv)/5000.0 + 20) ){
1975
+ rDiff = 0.0;
1976
+ }
19501977
if( fossil_fabs(rDiff)>fossil_fabs(rSkew) ) rSkew = rDiff;
19511978
}
19521979
nCardRcvd++;
19531980
continue;
19541981
}
@@ -1988,10 +2015,11 @@
19882015
** Accept an unversioned file from the client.
19892016
*/
19902017
if( blob_eq(&xfer.aToken[0], "uvfile") ){
19912018
xfer_accept_unversioned_file(&xfer, 1);
19922019
nArtifactRcvd++;
2020
+ nUvFileRcvd++;
19932021
}else
19942022
19952023
/* gimme UUID
19962024
**
19972025
** Server is requesting a file. If the file is a manifest, assume
@@ -2043,14 +2071,15 @@
20432071
** Server announces that it has a particular unversioned file. The
20442072
** server will only send this card if the client had previously sent
20452073
** a "pragma uv-hash" card with a hash that does not match.
20462074
**
20472075
** If the identified file needs to be transferred, then setup for the
2048
- ** transfer. Generate a "uvgimme" card in the reply if the server version
2049
- ** is newer than the client. Generate a "uvfile" card if the client version
2050
- ** is newer than the server. If HASH is "-" (indicating that the file has
2051
- ** been deleted) and MTIME is newer, then do the deletion.
2076
+ ** transfer. Generate a "uvgimme" card in the reply if the server
2077
+ ** version is newer than the client. Generate a "uvfile" card if
2078
+ ** the client version is newer than the server. If HASH is "-"
2079
+ ** (indicating that the file has been deleted) and MTIME is newer,
2080
+ ** then do the deletion.
20522081
*/
20532082
if( xfer.nToken==5
20542083
&& blob_eq(&xfer.aToken[0], "uvigot")
20552084
&& blob_is_filename(&xfer.aToken[1])
20562085
&& blob_is_int64(&xfer.aToken[2], &mtime)
@@ -2064,10 +2093,11 @@
20642093
iStatus = unversioned_status(zName, mtime, zHash);
20652094
if( iStatus<=1 ){
20662095
if( zHash[0]!='-' ){
20672096
blob_appendf(xfer.pOut, "uvgimme %s\n", zName);
20682097
nCardSent++;
2098
+ nUvGimmeSent++;
20692099
}else if( iStatus==1 ){
20702100
db_multi_exec(
20712101
"UPDATE unversioned"
20722102
" SET mtime=%lld, hash=NULL, sz=0, encoding=0, content=NULL"
20732103
" WHERE name=%Q", mtime, zName
@@ -2081,13 +2111,14 @@
20812111
db_unset("uv-hash", 0);
20822112
}
20832113
if( iStatus<=3 ){
20842114
db_multi_exec("DELETE FROM uv_tosend WHERE name=%Q", zName);
20852115
}else if( iStatus==4 ){
2086
- db_multi_exec("UPDATE uv_tosend SET mtimeOnly=1 WHERE name=%Q", zName);
2116
+ db_multi_exec("UPDATE uv_tosend SET mtimeOnly=1 WHERE name=%Q",zName);
20872117
}else if( iStatus==5 ){
2088
- db_multi_exec("REPLACE INTO uv_tosend(name,mtimeOnly) VALUES(%Q,0)", zName);
2118
+ db_multi_exec("REPLACE INTO uv_tosend(name,mtimeOnly) VALUES(%Q,0)",
2119
+ zName);
20892120
}
20902121
}else
20912122
20922123
/* push SERVERCODE PRODUCTCODE
20932124
**
@@ -2172,11 +2203,12 @@
21722203
** to the next cycle.
21732204
*/
21742205
if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){
21752206
char *zMsg = blob_terminate(&xfer.aToken[1]);
21762207
defossilize(zMsg);
2177
- if( (syncFlags & SYNC_PUSH) && zMsg && sqlite3_strglob("pull only *", zMsg)==0 ){
2208
+ if( (syncFlags & SYNC_PUSH) && zMsg
2209
+ && sqlite3_strglob("pull only *", zMsg)==0 ){
21782210
syncFlags &= ~SYNC_PUSH;
21792211
zMsg = 0;
21802212
}
21812213
if( zMsg && zMsg[0] ){
21822214
fossil_force_newline();
@@ -2302,10 +2334,14 @@
23022334
** another round
23032335
*/
23042336
if( xfer.nFileSent+xfer.nDeltaSent>0 || uvDoPush ){
23052337
go = 1;
23062338
}
2339
+
2340
+ /* Continue looping as long as new uvfile cards are being received
2341
+ ** and uvgimme cards are being sent. */
2342
+ if( nUvGimmeSent>0 && nUvFileRcvd>0 ) go = 1;
23072343
23082344
/* If this is a clone, the go at least two rounds */
23092345
if( (syncFlags & SYNC_CLONE)!=0 && nCycle==1 ) go = 1;
23102346
23112347
/* Stop the cycle if the server sends a "clone_seqno 0" card and
23122348
--- src/xfer.c
+++ src/xfer.c
@@ -2,11 +2,11 @@
2 ** Copyright (c) 2007 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
@@ -305,21 +305,21 @@
305 ** The sender might have omitted the content because it is too big to
306 ** transmit, or because it is unchanged and this record exists purely
307 ** to update the MTIME.
308 */
309 static void xfer_accept_unversioned_file(Xfer *pXfer, int isWriter){
310 sqlite3_int64 mtime; /* The MTIME */
311 Blob *pHash; /* The HASH value */
312 int sz; /* The SIZE */
313 int flags; /* The FLAGS */
314 Blob content; /* The CONTENT */
315 Blob hash; /* Hash computed from CONTENT to compare with HASH */
316 Blob x; /* Compressed content */
317 Stmt q; /* SQL statements for comparison and insert */
318 int isDelete; /* HASH is "-" indicating this is a delete operation */
319 int nullContent; /* True of CONTENT is NULL */
320 int iStatus; /* Result from unversioned_status() */
321
322 pHash = &pXfer->aToken[3];
323 if( pXfer->nToken==5
324 || !blob_is_filename(&pXfer->aToken[1])
325 || !blob_is_int64(&pXfer->aToken[2], &mtime)
@@ -350,27 +350,29 @@
350
351 /* Check to see if current content really should be overwritten. Ideally,
352 ** a uvfile card should never have been sent unless the overwrite should
353 ** occur. But do not trust the sender. Double-check.
354 */
355 iStatus = unversioned_status(blob_str(&pXfer->aToken[1]), mtime, blob_str(pHash));
 
356 if( iStatus>=3 ) goto end_accept_unversioned_file;
357
358 /* Store the content */
359 isDelete = blob_eq(pHash, "-");
360 if( isDelete ){
361 db_prepare(&q,
362 "UPDATE unversioned"
363 " SET rcvid=:rcvid, mtime=:mtime, hash=NULL, sz=0, encoding=0, content=NULL"
 
364 " WHERE name=:name"
365 );
366 db_bind_int(&q, ":rcvid", g.rcvid);
367 }else if( iStatus==4 ){
368 db_prepare(&q, "UPDATE unversioned SET mtime=:mtime WHERE name=:name");
369 }else{
370 db_prepare(&q,
371 "REPLACE INTO unversioned(name, rcvid, mtime, hash, sz, encoding, content)"
372 " VALUES(:name,:rcvid,:mtime,:hash,:sz,:encoding,:content)"
373 );
374 db_bind_int(&q, ":rcvid", g.rcvid);
375 db_bind_text(&q, ":hash", blob_str(pHash));
376 db_bind_int(&q, ":sz", blob_size(&content));
@@ -645,49 +647,60 @@
645 ** Send the unversioned file identified by zName by generating the
646 ** appropriate "uvfile" card.
647 **
648 ** uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT
649 **
650 ** If the noContent flag is set, omit the CONTENT and set the 0x0004 flag in FLAGS.
 
651 */
652 static void send_unversioned_file(Xfer *pXfer, const char *zName, int noContent){
 
 
 
 
653 Stmt q1;
654
 
655 if( noContent ){
656 db_prepare(&q1,
657 "SELECT mtime, hash, encoding, sz FROM unversioned WHERE name=%Q",
658 zName
659 );
660 }else{
661 db_prepare(&q1,
662 "SELECT mtime, hash, encoding, sz, content FROM unversioned WHERE name=%Q",
 
663 zName
664 );
665 }
666 if( db_step(&q1)==SQLITE_ROW ){
667 sqlite3_int64 mtime = db_column_int64(&q1, 0);
668 const char *zHash = db_column_text(&q1, 1);
669 blob_appendf(pXfer->pOut, "uvfile %s %lld", zName, mtime);
670 if( zHash==0 ){
671 blob_append(pXfer->pOut, " - 0 1\n", -1);
672 }else if( noContent ){
673 blob_appendf(pXfer->pOut, " %s %d 4\n", zHash, db_column_int(&q1,3));
 
 
674 }else{
675 Blob content;
676 blob_init(&content, 0, 0);
677 db_column_blob(&q1, 4, &content);
678 if( db_column_int(&q1, 2) ){
679 blob_uncompress(&content, &content);
680 }
681 blob_appendf(pXfer->pOut, " %s %d 0\n", zHash, blob_size(&content));
682 blob_append(pXfer->pOut, blob_buffer(&content), blob_size(&content));
683 #if 0
684 if( blob_buffer(pXfer->pOut)[blob_size(pXfer->pOut)-1]!='\n' ){
685 blob_append(pXfer->pOut, "\n", 1);
686 }
687 #endif
688 blob_reset(&content);
 
 
689 }
690 }
691 db_finalize(&q1);
692 }
693
@@ -757,11 +770,13 @@
757 Stmt q;
758 int rc = -1;
759 char *zLogin = blob_terminate(pLogin);
760 defossilize(zLogin);
761
762 if( fossil_strcmp(zLogin, "nobody")==0 || fossil_strcmp(zLogin,"anonymous")==0 ){
 
 
763 return 0; /* Anybody is allowed to sync as "nobody" or "anonymous" */
764 }
765 if( fossil_strcmp(P("REMOTE_USER"), zLogin)==0
766 && db_get_boolean("remote_user_ok",0) ){
767 return 0; /* Accept Basic Authorization */
@@ -1517,11 +1532,13 @@
1517 **
1518 ** The client wants to make sure that unversioned files are all synced.
1519 ** If the HASH does not match, send a complete catalog of
1520 ** "uvigot" cards.
1521 */
1522 if( blob_eq(&xfer.aToken[1], "uv-hash") && blob_is_uuid(&xfer.aToken[2]) ){
 
 
1523 if( g.perm.Read && g.perm.WrUnver ){
1524 @ pragma uv-push-ok
1525 send_unversioned_catalog(&xfer);
1526 }else if( g.perm.Read ){
1527 @ pragma uv-pull-only
@@ -1684,11 +1701,13 @@
1684 int nArtifactRcvd = 0; /* Total artifacts received */
1685 const char *zOpType = 0;/* Push, Pull, Sync, Clone */
1686 double rSkew = 0.0; /* Maximum time skew */
1687 int uvHashSent = 0; /* The "pragma uv-hash" message has been sent */
1688 int uvStatus = 0; /* 0: no I/O. 1: pull-only 2: push-and-pull */
1689 int uvDoPush = 0; /* If true, generate uvfile messages to send to server */
 
 
1690 sqlite3_int64 mtime; /* Modification time on a UV file */
1691
1692 if( db_get_boolean("dont-push", 0) ) syncFlags &= ~SYNC_PUSH;
1693 if( (syncFlags & (SYNC_PUSH|SYNC_PULL|SYNC_CLONE|SYNC_UNVERSIONED))==0
1694 && configRcvMask==0 && configSendMask==0 ) return 0;
@@ -1861,20 +1880,24 @@
1861 /* Send unversioned files present here on the client but missing or
1862 ** obsolete on the server.
1863 */
1864 if( uvDoPush ){
1865 Stmt uvq;
 
1866 assert( (syncFlags & SYNC_UNVERSIONED)!=0 );
1867 assert( uvStatus==2 );
1868 db_prepare(&uvq, "SELECT name, mtimeOnly FROM uv_tosend");
1869 while( db_step(&uvq)==SQLITE_ROW ){
1870 send_unversioned_file(&xfer, db_column_text(&uvq,0), db_column_int(&uvq,1));
 
1871 nCardSent++;
1872 nArtifactSent++;
 
 
1873 }
1874 db_finalize(&uvq);
1875 uvDoPush = 0;
1876 }
1877
1878 /* Append randomness to the end of the message. This makes all
1879 ** messages unique so that that the login-card nonce will always
1880 ** be unique.
@@ -1932,10 +1955,12 @@
1932 if( syncFlags & SYNC_PUSH ){
1933 blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
1934 nCardSent++;
1935 }
1936 go = 0;
 
 
1937
1938 /* Process the reply that came back from the server */
1939 while( blob_line(&recv, &xfer.line) ){
1940 if( blob_buffer(&xfer.line)[0]=='#' ){
1941 const char *zLine = blob_buffer(&xfer.line);
@@ -1944,11 +1969,13 @@
1944 double rDiff;
1945 sqlite3_snprintf(sizeof(zTime), zTime, "%.19s", &zLine[12]);
1946 rDiff = db_double(9e99, "SELECT julianday('%q') - %.17g",
1947 zTime, rArrivalTime);
1948 if( rDiff>9e98 || rDiff<-9e98 ) rDiff = 0.0;
1949 if( rDiff*24.0*3600.0 >= -(blob_size(&recv)/5000.0 + 20) ) rDiff = 0.0;
 
 
1950 if( fossil_fabs(rDiff)>fossil_fabs(rSkew) ) rSkew = rDiff;
1951 }
1952 nCardRcvd++;
1953 continue;
1954 }
@@ -1988,10 +2015,11 @@
1988 ** Accept an unversioned file from the client.
1989 */
1990 if( blob_eq(&xfer.aToken[0], "uvfile") ){
1991 xfer_accept_unversioned_file(&xfer, 1);
1992 nArtifactRcvd++;
 
1993 }else
1994
1995 /* gimme UUID
1996 **
1997 ** Server is requesting a file. If the file is a manifest, assume
@@ -2043,14 +2071,15 @@
2043 ** Server announces that it has a particular unversioned file. The
2044 ** server will only send this card if the client had previously sent
2045 ** a "pragma uv-hash" card with a hash that does not match.
2046 **
2047 ** If the identified file needs to be transferred, then setup for the
2048 ** transfer. Generate a "uvgimme" card in the reply if the server version
2049 ** is newer than the client. Generate a "uvfile" card if the client version
2050 ** is newer than the server. If HASH is "-" (indicating that the file has
2051 ** been deleted) and MTIME is newer, then do the deletion.
 
2052 */
2053 if( xfer.nToken==5
2054 && blob_eq(&xfer.aToken[0], "uvigot")
2055 && blob_is_filename(&xfer.aToken[1])
2056 && blob_is_int64(&xfer.aToken[2], &mtime)
@@ -2064,10 +2093,11 @@
2064 iStatus = unversioned_status(zName, mtime, zHash);
2065 if( iStatus<=1 ){
2066 if( zHash[0]!='-' ){
2067 blob_appendf(xfer.pOut, "uvgimme %s\n", zName);
2068 nCardSent++;
 
2069 }else if( iStatus==1 ){
2070 db_multi_exec(
2071 "UPDATE unversioned"
2072 " SET mtime=%lld, hash=NULL, sz=0, encoding=0, content=NULL"
2073 " WHERE name=%Q", mtime, zName
@@ -2081,13 +2111,14 @@
2081 db_unset("uv-hash", 0);
2082 }
2083 if( iStatus<=3 ){
2084 db_multi_exec("DELETE FROM uv_tosend WHERE name=%Q", zName);
2085 }else if( iStatus==4 ){
2086 db_multi_exec("UPDATE uv_tosend SET mtimeOnly=1 WHERE name=%Q", zName);
2087 }else if( iStatus==5 ){
2088 db_multi_exec("REPLACE INTO uv_tosend(name,mtimeOnly) VALUES(%Q,0)", zName);
 
2089 }
2090 }else
2091
2092 /* push SERVERCODE PRODUCTCODE
2093 **
@@ -2172,11 +2203,12 @@
2172 ** to the next cycle.
2173 */
2174 if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){
2175 char *zMsg = blob_terminate(&xfer.aToken[1]);
2176 defossilize(zMsg);
2177 if( (syncFlags & SYNC_PUSH) && zMsg && sqlite3_strglob("pull only *", zMsg)==0 ){
 
2178 syncFlags &= ~SYNC_PUSH;
2179 zMsg = 0;
2180 }
2181 if( zMsg && zMsg[0] ){
2182 fossil_force_newline();
@@ -2302,10 +2334,14 @@
2302 ** another round
2303 */
2304 if( xfer.nFileSent+xfer.nDeltaSent>0 || uvDoPush ){
2305 go = 1;
2306 }
 
 
 
 
2307
2308 /* If this is a clone, the go at least two rounds */
2309 if( (syncFlags & SYNC_CLONE)!=0 && nCycle==1 ) go = 1;
2310
2311 /* Stop the cycle if the server sends a "clone_seqno 0" card and
2312
--- src/xfer.c
+++ src/xfer.c
@@ -2,11 +2,11 @@
2 ** Copyright (c) 2007 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7 **
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
@@ -305,21 +305,21 @@
305 ** The sender might have omitted the content because it is too big to
306 ** transmit, or because it is unchanged and this record exists purely
307 ** to update the MTIME.
308 */
309 static void xfer_accept_unversioned_file(Xfer *pXfer, int isWriter){
310 sqlite3_int64 mtime; /* The MTIME */
311 Blob *pHash; /* The HASH value */
312 int sz; /* The SIZE */
313 int flags; /* The FLAGS */
314 Blob content; /* The CONTENT */
315 Blob hash; /* Hash computed from CONTENT to compare with HASH */
316 Blob x; /* Compressed content */
317 Stmt q; /* SQL statements for comparison and insert */
318 int isDelete; /* HASH is "-" indicating this is a delete */
319 int nullContent; /* True of CONTENT is NULL */
320 int iStatus; /* Result from unversioned_status() */
321
322 pHash = &pXfer->aToken[3];
323 if( pXfer->nToken==5
324 || !blob_is_filename(&pXfer->aToken[1])
325 || !blob_is_int64(&pXfer->aToken[2], &mtime)
@@ -350,27 +350,29 @@
350
351 /* Check to see if current content really should be overwritten. Ideally,
352 ** a uvfile card should never have been sent unless the overwrite should
353 ** occur. But do not trust the sender. Double-check.
354 */
355 iStatus = unversioned_status(blob_str(&pXfer->aToken[1]), mtime,
356 blob_str(pHash));
357 if( iStatus>=3 ) goto end_accept_unversioned_file;
358
359 /* Store the content */
360 isDelete = blob_eq(pHash, "-");
361 if( isDelete ){
362 db_prepare(&q,
363 "UPDATE unversioned"
364 " SET rcvid=:rcvid, mtime=:mtime, hash=NULL,"
365 " sz=0, encoding=0, content=NULL"
366 " WHERE name=:name"
367 );
368 db_bind_int(&q, ":rcvid", g.rcvid);
369 }else if( iStatus==4 ){
370 db_prepare(&q, "UPDATE unversioned SET mtime=:mtime WHERE name=:name");
371 }else{
372 db_prepare(&q,
373 "REPLACE INTO unversioned(name,rcvid,mtime,hash,sz,encoding,content)"
374 " VALUES(:name,:rcvid,:mtime,:hash,:sz,:encoding,:content)"
375 );
376 db_bind_int(&q, ":rcvid", g.rcvid);
377 db_bind_text(&q, ":hash", blob_str(pHash));
378 db_bind_int(&q, ":sz", blob_size(&content));
@@ -645,49 +647,60 @@
647 ** Send the unversioned file identified by zName by generating the
648 ** appropriate "uvfile" card.
649 **
650 ** uvfile NAME MTIME HASH SIZE FLAGS \n CONTENT
651 **
652 ** If the noContent flag is set, omit the CONTENT and set the 0x0004
653 ** flag in FLAGS.
654 */
655 static void send_unversioned_file(
656 Xfer *pXfer, /* Transfer context */
657 const char *zName, /* Name of unversioned file to be sent */
658 int noContent /* True to omit the content */
659 ){
660 Stmt q1;
661
662 if( blob_size(pXfer->pOut)>=pXfer->mxSend ) noContent = 1;
663 if( noContent ){
664 db_prepare(&q1,
665 "SELECT mtime, hash, encoding, sz FROM unversioned WHERE name=%Q",
666 zName
667 );
668 }else{
669 db_prepare(&q1,
670 "SELECT mtime, hash, encoding, sz, content FROM unversioned"
671 " WHERE name=%Q",
672 zName
673 );
674 }
675 if( db_step(&q1)==SQLITE_ROW ){
676 sqlite3_int64 mtime = db_column_int64(&q1, 0);
677 const char *zHash = db_column_text(&q1, 1);
678 if( blob_size(pXfer->pOut)>=pXfer->mxSend ){
679 /* If we have already reached the send size limit, send a (short)
680 ** uvigot card rather than a uvfile card. This only happens on the
681 ** server side. The uvigot card will provoke the client to resend
682 ** another uvgimme on the next cycle. */
683 blob_appendf(pXfer->pOut, "uvigot %s %lld %s %d\n",
684 zName, mtime, zHash, db_column_int(&q1,3));
685 }else{
686 blob_appendf(pXfer->pOut, "uvfile %s %lld", zName, mtime);
687 if( zHash==0 ){
688 blob_append(pXfer->pOut, " - 0 1\n", -1);
689 }else if( noContent ){
690 blob_appendf(pXfer->pOut, " %s %d 4\n", zHash, db_column_int(&q1,3));
691 }else{
692 Blob content;
693 blob_init(&content, 0, 0);
694 db_column_blob(&q1, 4, &content);
695 if( db_column_int(&q1, 2) ){
696 blob_uncompress(&content, &content);
697 }
698 blob_appendf(pXfer->pOut, " %s %d 0\n", zHash, blob_size(&content));
699 blob_append(pXfer->pOut, blob_buffer(&content), blob_size(&content));
700 blob_reset(&content);
701 }
702 }
703 }
704 db_finalize(&q1);
705 }
706
@@ -757,11 +770,13 @@
770 Stmt q;
771 int rc = -1;
772 char *zLogin = blob_terminate(pLogin);
773 defossilize(zLogin);
774
775 if( fossil_strcmp(zLogin, "nobody")==0
776 || fossil_strcmp(zLogin,"anonymous")==0
777 ){
778 return 0; /* Anybody is allowed to sync as "nobody" or "anonymous" */
779 }
780 if( fossil_strcmp(P("REMOTE_USER"), zLogin)==0
781 && db_get_boolean("remote_user_ok",0) ){
782 return 0; /* Accept Basic Authorization */
@@ -1517,11 +1532,13 @@
1532 **
1533 ** The client wants to make sure that unversioned files are all synced.
1534 ** If the HASH does not match, send a complete catalog of
1535 ** "uvigot" cards.
1536 */
1537 if( blob_eq(&xfer.aToken[1], "uv-hash")
1538 && blob_is_uuid(&xfer.aToken[2])
1539 ){
1540 if( g.perm.Read && g.perm.WrUnver ){
1541 @ pragma uv-push-ok
1542 send_unversioned_catalog(&xfer);
1543 }else if( g.perm.Read ){
1544 @ pragma uv-pull-only
@@ -1684,11 +1701,13 @@
1701 int nArtifactRcvd = 0; /* Total artifacts received */
1702 const char *zOpType = 0;/* Push, Pull, Sync, Clone */
1703 double rSkew = 0.0; /* Maximum time skew */
1704 int uvHashSent = 0; /* The "pragma uv-hash" message has been sent */
1705 int uvStatus = 0; /* 0: no I/O. 1: pull-only 2: push-and-pull */
1706 int uvDoPush = 0; /* Generate uvfile messages to send to server */
1707 int nUvGimmeSent = 0; /* Number of uvgimme cards sent on this cycle */
1708 int nUvFileRcvd = 0; /* Number of uvfile cards received on this cycle */
1709 sqlite3_int64 mtime; /* Modification time on a UV file */
1710
1711 if( db_get_boolean("dont-push", 0) ) syncFlags &= ~SYNC_PUSH;
1712 if( (syncFlags & (SYNC_PUSH|SYNC_PULL|SYNC_CLONE|SYNC_UNVERSIONED))==0
1713 && configRcvMask==0 && configSendMask==0 ) return 0;
@@ -1861,20 +1880,24 @@
1880 /* Send unversioned files present here on the client but missing or
1881 ** obsolete on the server.
1882 */
1883 if( uvDoPush ){
1884 Stmt uvq;
1885 int rc = SQLITE_OK;
1886 assert( (syncFlags & SYNC_UNVERSIONED)!=0 );
1887 assert( uvStatus==2 );
1888 db_prepare(&uvq, "SELECT name, mtimeOnly FROM uv_tosend");
1889 while( (rc = db_step(&uvq))==SQLITE_ROW ){
1890 const char *zName = db_column_text(&uvq, 0);
1891 send_unversioned_file(&xfer, zName, db_column_int(&uvq,1));
1892 nCardSent++;
1893 nArtifactSent++;
1894 db_multi_exec("DELETE FROM uv_tosend WHERE name=%Q", zName);
1895 if( blob_size(xfer.pOut)>xfer.mxSend ) break;
1896 }
1897 db_finalize(&uvq);
1898 if( rc==SQLITE_DONE ) uvDoPush = 0;
1899 }
1900
1901 /* Append randomness to the end of the message. This makes all
1902 ** messages unique so that that the login-card nonce will always
1903 ** be unique.
@@ -1932,10 +1955,12 @@
1955 if( syncFlags & SYNC_PUSH ){
1956 blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
1957 nCardSent++;
1958 }
1959 go = 0;
1960 nUvGimmeSent = 0;
1961 nUvFileRcvd = 0;
1962
1963 /* Process the reply that came back from the server */
1964 while( blob_line(&recv, &xfer.line) ){
1965 if( blob_buffer(&xfer.line)[0]=='#' ){
1966 const char *zLine = blob_buffer(&xfer.line);
@@ -1944,11 +1969,13 @@
1969 double rDiff;
1970 sqlite3_snprintf(sizeof(zTime), zTime, "%.19s", &zLine[12]);
1971 rDiff = db_double(9e99, "SELECT julianday('%q') - %.17g",
1972 zTime, rArrivalTime);
1973 if( rDiff>9e98 || rDiff<-9e98 ) rDiff = 0.0;
1974 if( rDiff*24.0*3600.0 >= -(blob_size(&recv)/5000.0 + 20) ){
1975 rDiff = 0.0;
1976 }
1977 if( fossil_fabs(rDiff)>fossil_fabs(rSkew) ) rSkew = rDiff;
1978 }
1979 nCardRcvd++;
1980 continue;
1981 }
@@ -1988,10 +2015,11 @@
2015 ** Accept an unversioned file from the client.
2016 */
2017 if( blob_eq(&xfer.aToken[0], "uvfile") ){
2018 xfer_accept_unversioned_file(&xfer, 1);
2019 nArtifactRcvd++;
2020 nUvFileRcvd++;
2021 }else
2022
2023 /* gimme UUID
2024 **
2025 ** Server is requesting a file. If the file is a manifest, assume
@@ -2043,14 +2071,15 @@
2071 ** Server announces that it has a particular unversioned file. The
2072 ** server will only send this card if the client had previously sent
2073 ** a "pragma uv-hash" card with a hash that does not match.
2074 **
2075 ** If the identified file needs to be transferred, then setup for the
2076 ** transfer. Generate a "uvgimme" card in the reply if the server
2077 ** version is newer than the client. Generate a "uvfile" card if
2078 ** the client version is newer than the server. If HASH is "-"
2079 ** (indicating that the file has been deleted) and MTIME is newer,
2080 ** then do the deletion.
2081 */
2082 if( xfer.nToken==5
2083 && blob_eq(&xfer.aToken[0], "uvigot")
2084 && blob_is_filename(&xfer.aToken[1])
2085 && blob_is_int64(&xfer.aToken[2], &mtime)
@@ -2064,10 +2093,11 @@
2093 iStatus = unversioned_status(zName, mtime, zHash);
2094 if( iStatus<=1 ){
2095 if( zHash[0]!='-' ){
2096 blob_appendf(xfer.pOut, "uvgimme %s\n", zName);
2097 nCardSent++;
2098 nUvGimmeSent++;
2099 }else if( iStatus==1 ){
2100 db_multi_exec(
2101 "UPDATE unversioned"
2102 " SET mtime=%lld, hash=NULL, sz=0, encoding=0, content=NULL"
2103 " WHERE name=%Q", mtime, zName
@@ -2081,13 +2111,14 @@
2111 db_unset("uv-hash", 0);
2112 }
2113 if( iStatus<=3 ){
2114 db_multi_exec("DELETE FROM uv_tosend WHERE name=%Q", zName);
2115 }else if( iStatus==4 ){
2116 db_multi_exec("UPDATE uv_tosend SET mtimeOnly=1 WHERE name=%Q",zName);
2117 }else if( iStatus==5 ){
2118 db_multi_exec("REPLACE INTO uv_tosend(name,mtimeOnly) VALUES(%Q,0)",
2119 zName);
2120 }
2121 }else
2122
2123 /* push SERVERCODE PRODUCTCODE
2124 **
@@ -2172,11 +2203,12 @@
2203 ** to the next cycle.
2204 */
2205 if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){
2206 char *zMsg = blob_terminate(&xfer.aToken[1]);
2207 defossilize(zMsg);
2208 if( (syncFlags & SYNC_PUSH) && zMsg
2209 && sqlite3_strglob("pull only *", zMsg)==0 ){
2210 syncFlags &= ~SYNC_PUSH;
2211 zMsg = 0;
2212 }
2213 if( zMsg && zMsg[0] ){
2214 fossil_force_newline();
@@ -2302,10 +2334,14 @@
2334 ** another round
2335 */
2336 if( xfer.nFileSent+xfer.nDeltaSent>0 || uvDoPush ){
2337 go = 1;
2338 }
2339
2340 /* Continue looping as long as new uvfile cards are being received
2341 ** and uvgimme cards are being sent. */
2342 if( nUvGimmeSent>0 && nUvFileRcvd>0 ) go = 1;
2343
2344 /* If this is a clone, the go at least two rounds */
2345 if( (syncFlags & SYNC_CLONE)!=0 && nCycle==1 ) go = 1;
2346
2347 /* Stop the cycle if the server sends a "clone_seqno 0" card and
2348

Keyboard Shortcuts

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