Fossil SCM

The xfer mechanism has been completely reworked to better support delta compression and to require fewer round-trips. The wire protocol is roughly the same but is different enough that you will need to recompile before sync will work.

drh 2007-08-10 02:59 trunk
Commit edbb332d548cc19d0f884d4c9277cbc81d3feb32
2 files changed +8 -7 +94 -67
+8 -7
--- src/verify.c
+++ src/verify.c
@@ -43,19 +43,20 @@
4343
blob_zero(&uuid);
4444
db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d", rid);
4545
if( blob_size(&uuid)!=UUID_SIZE ){
4646
fossil_panic("not a valid rid: %d", rid);
4747
}
48
- content_get(rid, &content);
49
- sha1sum_blob(&content, &hash);
50
- blob_reset(&content);
51
- if( blob_compare(&uuid, &hash) ){
52
- fossil_fatal("hash of rid %d (%b) does not match its uuid (%b)",
53
- rid, &hash, &uuid);
48
+ if( content_get(rid, &content) ){
49
+ sha1sum_blob(&content, &hash);
50
+ blob_reset(&content);
51
+ if( blob_compare(&uuid, &hash) ){
52
+ fossil_fatal("hash of rid %d (%b) does not match its uuid (%b)",
53
+ rid, &hash, &uuid);
54
+ }
55
+ blob_reset(&hash);
5456
}
5557
blob_reset(&uuid);
56
- blob_reset(&hash);
5758
}
5859
5960
/*
6061
**
6162
*/
6263
--- src/verify.c
+++ src/verify.c
@@ -43,19 +43,20 @@
43 blob_zero(&uuid);
44 db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d", rid);
45 if( blob_size(&uuid)!=UUID_SIZE ){
46 fossil_panic("not a valid rid: %d", rid);
47 }
48 content_get(rid, &content);
49 sha1sum_blob(&content, &hash);
50 blob_reset(&content);
51 if( blob_compare(&uuid, &hash) ){
52 fossil_fatal("hash of rid %d (%b) does not match its uuid (%b)",
53 rid, &hash, &uuid);
 
 
54 }
55 blob_reset(&uuid);
56 blob_reset(&hash);
57 }
58
59 /*
60 **
61 */
62
--- src/verify.c
+++ src/verify.c
@@ -43,19 +43,20 @@
43 blob_zero(&uuid);
44 db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d", rid);
45 if( blob_size(&uuid)!=UUID_SIZE ){
46 fossil_panic("not a valid rid: %d", rid);
47 }
48 if( content_get(rid, &content) ){
49 sha1sum_blob(&content, &hash);
50 blob_reset(&content);
51 if( blob_compare(&uuid, &hash) ){
52 fossil_fatal("hash of rid %d (%b) does not match its uuid (%b)",
53 rid, &hash, &uuid);
54 }
55 blob_reset(&hash);
56 }
57 blob_reset(&uuid);
 
58 }
59
60 /*
61 **
62 */
63
+94 -67
--- src/xfer.c
+++ src/xfer.c
@@ -36,13 +36,16 @@
3636
Blob *pOut; /* Compose our reply here */
3737
Blob line; /* The current line of input */
3838
Blob aToken[5]; /* Tokenized version of line */
3939
Blob err; /* Error message text */
4040
int nToken; /* Number of tokens in line */
41
- int nIGot; /* Number of "igot" messages sent */
42
- int nFile; /* Number of files sent or received */
43
- int nDelta; /* Number of deltas sent or received */
41
+ int nIGotSent; /* Number of "igot" messages sent */
42
+ int nGimmeSent; /* Number of gimme messages sent */
43
+ int nFileSent; /* Number of files sent */
44
+ int nDeltaSent; /* Number of deltas sent */
45
+ int nFileRcvd; /* Number of files received */
46
+ int nDeltaRcvd; /* Number of deltas received */
4447
int nDanglingFile; /* Number of dangling deltas received */
4548
int mxSend; /* Stop sending "file" with pOut reaches this size */
4649
};
4750
4851
@@ -100,20 +103,21 @@
100103
blob_extract(pXfer->pIn, n, &content);
101104
if( pXfer->nToken==4 ){
102105
Blob src;
103106
int srcid = rid_from_uuid(&pXfer->aToken[2], 1);
104107
if( content_get(srcid, &src)==0 ){
105
- content_put(&content, blob_str(&hash), srcid);
108
+ content_put(&content, blob_str(&pXfer->aToken[1]), srcid);
106109
blob_appendf(pXfer->pOut, "gimme %b\n", &pXfer->aToken[2]);
110
+ pXfer->nGimmeSent++;
107111
pXfer->nDanglingFile++;
108112
return;
109113
}
110
- pXfer->nDelta++;
114
+ pXfer->nDeltaRcvd++;
111115
blob_delta_apply(&src, &content, &content);
112116
blob_reset(&src);
113117
}else{
114
- pXfer->nFile++;
118
+ pXfer->nFileRcvd++;
115119
}
116120
sha1sum_blob(&content, &hash);
117121
if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){
118122
blob_appendf(&pXfer->err, "content does not match sha1 hash");
119123
}
@@ -139,51 +143,35 @@
139143
Blob *pContent, /* The content of the file to send */
140144
Blob *pUuid, /* The UUID of the file to send */
141145
int srcId /* Send as a delta against this record */
142146
){
143147
static const char *azQuery[] = {
144
- "SELECT srcid FROM delta JOIN pending ON pending.rid=delta.srcid"
145
- " WHERE delta.rid=%d"
146
- " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=srcid)",
147
-
148
- "SELECT delta.rid FROM delta JOIN pending ON pending.rid=delta.rid"
149
- " WHERE srcid=%d"
150
- " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=delta.rid)",
151
-
152
- "SELECT pid FROM plink JOIN pending ON rid=pid"
148
+ "SELECT pid FROM plink"
153149
" WHERE cid=%d"
154150
" AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)",
155151
156
- "SELECT cid FROM plink JOIN pending ON rid=cid"
157
- " WHERE pid=%d"
158
- " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=cid)",
159
-
160
- "SELECT pid FROM mlink JOIN pending ON rid=pid"
152
+ "SELECT pid FROM mlink"
161153
" WHERE fid=%d"
162154
" AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)",
163
-
164
- "SELECT fid FROM mlink JOIN pending ON rid=fid"
165
- " WHERE pid=%d"
166
- " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=fid)",
167155
};
168156
int i;
169157
Blob src, delta;
170158
int size = 0;
171159
172160
for(i=0; srcId==0 && i<count(azQuery); i++){
173161
srcId = db_int(0, azQuery[i], rid);
174162
}
175
- if( srcId && content_get(srcId, &src) ){
163
+ if( srcId>0 && content_get(srcId, &src) ){
176164
char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", srcId);
177165
blob_delta_create(&src, pContent, &delta);
178166
size = blob_size(&delta);
179167
if( size>=blob_size(pContent)-50 ){
180168
size = 0;
181169
}else{
182170
blob_appendf(pXfer->pOut, "file %b %s %d\n", pUuid, zUuid, size);
183171
blob_append(pXfer->pOut, blob_buffer(&delta), size);
184
- blob_appendf(pXfer->pOut, "\n", 1);
172
+ /* blob_appendf(pXfer->pOut, "\n", 1); */
185173
}
186174
blob_reset(&delta);
187175
free(zUuid);
188176
blob_reset(&src);
189177
}
@@ -190,10 +178,18 @@
190178
return size;
191179
}
192180
193181
/*
194182
** Send the file identified by rid.
183
+**
184
+** The pUuid can be NULL in which case the correct UUID is computed
185
+** from the rid.
186
+**
187
+** If srcId is positive, then a delta is sent against that srcId.
188
+** If srcId is zero, then an attempt is made to find an appropriate
189
+** file to delta against. If srcId is negative, the file is sent
190
+** without deltaing.
195191
*/
196192
static void send_file(Xfer *pXfer, int rid, Blob *pUuid, int srcId){
197193
Blob content, uuid;
198194
int size = 0;
199195
@@ -208,11 +204,11 @@
208204
}
209205
pUuid = &uuid;
210206
}
211207
if( pXfer->mxSend<=blob_size(pXfer->pOut) ){
212208
blob_appendf(pXfer->pOut, "igot %b\n", pUuid);
213
- pXfer->nIGot++;
209
+ pXfer->nIGotSent++;
214210
blob_reset(&uuid);
215211
return;
216212
}
217213
content_get(rid, &content);
218214
@@ -221,13 +217,13 @@
221217
}
222218
if( size==0 ){
223219
int size = blob_size(&content);
224220
blob_appendf(pXfer->pOut, "file %b %d\n", pUuid, size);
225221
blob_append(pXfer->pOut, blob_buffer(&content), size);
226
- pXfer->nFile++;
222
+ pXfer->nFileSent++;
227223
}else{
228
- pXfer->nDelta++;
224
+ pXfer->nDeltaSent++;
229225
}
230226
db_multi_exec("INSERT INTO sent VALUES(%d)", rid);
231227
blob_reset(&uuid);
232228
}
233229
@@ -293,10 +289,11 @@
293289
Stmt q;
294290
db_prepare(&q, "SELECT uuid FROM phantom JOIN blob USING(rid)");
295291
while( db_step(&q)==SQLITE_ROW ){
296292
const char *zUuid = db_column_text(&q, 0);
297293
blob_appendf(pXfer->pOut, "gimme %s\n", zUuid);
294
+ pXfer->nGimmeSent++;
298295
}
299296
db_finalize(&q);
300297
}
301298
302299
@@ -367,11 +364,10 @@
367364
** This is the transfer handler on the server side. The transfer
368365
** message has been uncompressed and placed in the g.cgiIn blob.
369366
** Process this message and form an appropriate reply.
370367
*/
371368
void page_xfer(void){
372
- int nToken;
373369
int isPull = 0;
374370
int isPush = 0;
375371
int nErr = 0;
376372
Xfer xfer;
377373
@@ -379,10 +375,11 @@
379375
blobarray_zero(xfer.aToken, count(xfer.aToken));
380376
cgi_set_content_type(g.zContentType);
381377
blob_zero(&xfer.err);
382378
xfer.pIn = &g.cgiIn;
383379
xfer.pOut = cgi_output_blob();
380
+ xfer.mxSend = db_get_int("max-download", 1000000);
384381
385382
db_begin_transaction();
386383
db_multi_exec(
387384
"CREATE TEMP TABLE sent(rid INTEGER PRIMARY KEY);"
388385
);
@@ -393,11 +390,11 @@
393390
** file UUID DELTASRC SIZE \n CONTENT
394391
**
395392
** Accept a file from the client.
396393
*/
397394
if( blob_eq(&xfer.aToken[0], "file") ){
398
- if( !isPush ){
395
+ if( !g.okWrite ){
399396
cgi_reset_content();
400397
@ error not\sauthorized\sto\swrite
401398
nErr++;
402399
break;
403400
}
@@ -416,11 +413,11 @@
416413
*/
417414
if( blob_eq(&xfer.aToken[0], "gimme")
418415
&& xfer.nToken==2
419416
&& blob_is_uuid(&xfer.aToken[1])
420417
){
421
- if( isPull ){
418
+ if( g.okRead ){
422419
int rid = rid_from_uuid(&xfer.aToken[1], 0);
423420
if( rid ){
424421
send_file(&xfer, rid, &xfer.aToken[1], 0);
425422
}
426423
}
@@ -432,11 +429,11 @@
432429
*/
433430
if( xfer.nToken==2
434431
&& blob_eq(&xfer.aToken[0], "igot")
435432
&& blob_is_uuid(&xfer.aToken[1])
436433
){
437
- if( isPush ){
434
+ if( g.okWrite ){
438435
rid_from_uuid(&xfer.aToken[1], 1);
439436
}
440437
}else
441438
442439
@@ -446,11 +443,11 @@
446443
*/
447444
if( xfer.nToken==2
448445
&& blob_eq(&xfer.aToken[0], "leaf")
449446
&& blob_is_uuid(&xfer.aToken[1])
450447
){
451
- if( isPull ){
448
+ if( g.okRead ){
452449
int rid = rid_from_uuid(&xfer.aToken[1], 0);
453450
leaf_response(&xfer, rid);
454451
}
455452
}else
456453
@@ -457,11 +454,11 @@
457454
/* pull SERVERCODE PROJECTCODE
458455
** push SERVERCODE PROJECTCODE
459456
**
460457
** The client wants either send or receive
461458
*/
462
- if( nToken==3
459
+ if( xfer.nToken==3
463460
&& (blob_eq(&xfer.aToken[0], "pull") || blob_eq(&xfer.aToken[0], "push"))
464461
&& blob_is_uuid(&xfer.aToken[1])
465462
&& blob_is_uuid(&xfer.aToken[2])
466463
){
467464
const char *zSCode;
@@ -511,28 +508,36 @@
511508
/* clone
512509
**
513510
** The client knows nothing. Tell all.
514511
*/
515512
if( blob_eq(&xfer.aToken[0], "clone") ){
513
+ int rootid;
516514
login_check_credentials();
517515
if( !g.okRead || !g.okHistory ){
518516
cgi_reset_content();
519517
@ error not\sauthorized\sto\sclone
520518
nErr++;
521519
break;
522520
}
523521
isPull = 1;
524522
@ push %s(db_get("server-code", "x")) %s(db_get("project-code", "x"))
525
- send_leaves(&xfer);
523
+ rootid = db_int(0,
524
+ "SELECT pid FROM plink AS a"
525
+ " WHERE NOT EXISTS(SELECT 1 FROM plink WHERE cid=a.pid)"
526
+ );
527
+ if( rootid ){
528
+ send_file(&xfer, rootid, 0, -1);
529
+ leaf_response(&xfer, rootid);
530
+ }
526531
}else
527532
528533
/* login USER NONCE SIGNATURE
529534
**
530535
** Check for a valid login. This has to happen before anything else.
531536
*/
532537
if( blob_eq(&xfer.aToken[0], "login")
533
- && nToken==4
538
+ && xfer.nToken==4
534539
){
535540
if( disableLogin ){
536541
g.okRead = g.okWrite = 1;
537542
}else{
538543
check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3]);
@@ -597,21 +602,21 @@
597602
*/
598603
void client_sync(int pushFlag, int pullFlag, int cloneFlag){
599604
int go = 1; /* Loop until zero */
600605
const char *zSCode = db_get("server-code", "x");
601606
const char *zPCode = db_get("project-code", 0);
602
- int nMsg = 0;
603
- int nReq = 0;
607
+ int nMsg = 0; /* Number of messages sent or received */
608
+ int nCycle = 0; /* Number of round trips to the server */
604609
int nFileSend = 0;
605
- int nNoFileCycle = 0;
606610
Blob send; /* Text we are sending to the server */
607611
Blob recv; /* Reply we got back from the server */
608612
Xfer xfer; /* Transfer data */
609613
610614
memset(&xfer, 0, sizeof(xfer));
611615
xfer.pIn = &recv;
612616
xfer.pOut = &send;
617
+ xfer.mxSend = db_get_int("max-upload", 250000);
613618
614619
assert( pushFlag || pullFlag || cloneFlag );
615620
assert( !g.urlIsFile ); /* This only works for networking */
616621
617622
db_begin_transaction();
@@ -620,15 +625,14 @@
620625
);
621626
blobarray_zero(xfer.aToken, count(xfer.aToken));
622627
blob_zero(&send);
623628
blob_zero(&recv);
624629
blob_zero(&xfer.err);
630
+ blob_zero(&xfer.line);
625631
626632
627633
while( go ){
628
- go = 0;
629
- nReq = nMsg = 0;
630634
631635
/* Generate a request to be sent to the server.
632636
** Always begin with a clone, pull, or push message
633637
*/
634638
@@ -637,32 +641,36 @@
637641
pushFlag = 0;
638642
pullFlag = 0;
639643
nMsg++;
640644
}else if( pullFlag ){
641645
blob_appendf(&send, "pull %s %s\n", zSCode, zPCode);
642
- send_leaves(&xfer);
646
+ nMsg++;
643647
request_phantoms(&xfer);
644
- nMsg++;
648
+ send_leaves(&xfer);
645649
}
646650
if( pushFlag ){
647651
blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
648652
nMsg++;
649653
}
650654
651655
/* Exchange messages with the server */
652
- nFileSend = xfer.nFile + xfer.nDelta + xfer.nDanglingFile;
653
- printf("Send: %3d files, %3d requests, %3d other msgs, %8d bytes\n",
654
- nFileSend, nReq, nMsg, blob_size(&send));
655
- xfer.nFile = 0;
656
- xfer.nDelta = 0;
657
- xfer.nDanglingFile = 0;
658
- nReq = nMsg = 0;
656
+ nFileSend = xfer.nFileSent + xfer.nDeltaSent;
657
+ printf("Send: %10d bytes, %3d messages, %3d files (%d+%d)\n",
658
+ blob_size(&send), nMsg+xfer.nGimmeSent+xfer.nIGotSent,
659
+ nFileSend, xfer.nFileSent, xfer.nDeltaSent);
660
+ nMsg = 0;
661
+ xfer.nFileSent = 0;
662
+ xfer.nDeltaSent = 0;
663
+ xfer.nGimmeSent = 0;
659664
http_exchange(&send, &recv);
660665
blob_reset(&send);
661666
662667
/* Process the reply that came back from the server */
663668
while( blob_line(&recv, &xfer.line) ){
669
+ if( blob_buffer(&xfer.line)[0]=='#' ){
670
+ continue;
671
+ }
664672
xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
665673
666674
/* file UUID SIZE \n CONTENT
667675
** file UUID DELTASRC SIZE \n CONTENT
668676
**
@@ -678,10 +686,11 @@
678686
*/
679687
if( blob_eq(&xfer.aToken[0], "gimme")
680688
&& xfer.nToken==2
681689
&& blob_is_uuid(&xfer.aToken[1])
682690
){
691
+ nMsg++;
683692
if( pushFlag ){
684693
int rid = rid_from_uuid(&xfer.aToken[1], 0);
685694
send_file(&xfer, rid, &xfer.aToken[1], 0);
686695
}
687696
}else
@@ -692,12 +701,16 @@
692701
*/
693702
if( xfer.nToken==2
694703
&& blob_eq(&xfer.aToken[0], "igot")
695704
&& blob_is_uuid(&xfer.aToken[1])
696705
){
706
+ nMsg++;
697707
if( pullFlag ){
698
- rid_from_uuid(&xfer.aToken[1], 1);
708
+ if( !db_exists("SELECT 1 FROM blob WHERE uuid='%b' AND size>=0",
709
+ &xfer.aToken[1]) ){
710
+ content_put(0, blob_str(&xfer.aToken[1]), 0);
711
+ }
699712
}
700713
}else
701714
702715
703716
/* leaf UUID
@@ -706,10 +719,11 @@
706719
*/
707720
if( xfer.nToken==2
708721
&& blob_eq(&xfer.aToken[0], "leaf")
709722
&& blob_is_uuid(&xfer.aToken[1])
710723
){
724
+ nMsg++;
711725
if( pushFlag ){
712726
int rid = rid_from_uuid(&xfer.aToken[1], 0);
713727
leaf_response(&xfer, rid);
714728
}
715729
}else
@@ -754,26 +768,39 @@
754768
755769
if( blob_size(&xfer.err) ){
756770
fossil_fatal("%b", &xfer.err);
757771
}
758772
blobarray_reset(xfer.aToken, xfer.nToken);
773
+ blob_reset(&xfer.line);
759774
}
760
- printf("Received: %3d files, %3d requests, %3d other msgs, %8d bytes\n",
761
- xfer.nFile + xfer.nDelta + xfer.nDanglingFile,
762
- nReq, nMsg, blob_size(&recv));
775
+ printf("Received: %10d bytes, %3d messages, %3d files (%d+%d+%d)\n",
776
+ blob_size(&recv), nMsg,
777
+ xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile,
778
+ xfer.nFileRcvd, xfer.nDeltaRcvd, xfer.nDanglingFile);
779
+
763780
blob_reset(&recv);
764
- if( nFileSend + xfer.nFile + xfer.nDelta + xfer.nDanglingFile==0 ){
765
- nNoFileCycle++;
766
- if( nNoFileCycle>1 ){
767
- go = 0;
768
- }
769
- }else{
770
- nNoFileCycle = 0;
771
- }
772
- nReq = nMsg = 0;
773
- xfer.nFile = 0;
774
- xfer.nDelta = 0;
775
- xfer.nDanglingFile = 0;
781
+ nMsg = 0;
782
+ xfer.nFileRcvd = 0;
783
+ xfer.nDeltaRcvd = 0;
784
+ xfer.nDanglingFile = 0;
785
+ nCycle++;
786
+ go = 0;
787
+
788
+ /* If we have received one or more files on this cycle and
789
+ ** we have one or more phantoms, then go for another round
790
+ */
791
+ if(xfer.nFileRcvd+xfer.nDeltaRcvd+xfer.nDanglingFile>0
792
+ && db_exists("SELECT 1 FROM phantom")
793
+ ){
794
+ go = 1;
795
+ }
796
+
797
+ /* If we have one or more files queued to send, then go
798
+ ** another round
799
+ */
800
+ if( xfer.nFileSent+xfer.nDeltaSent>0 ){
801
+ go = 1;
802
+ }
776803
};
777804
http_close();
778805
db_end_transaction(0);
779806
}
780807
--- src/xfer.c
+++ src/xfer.c
@@ -36,13 +36,16 @@
36 Blob *pOut; /* Compose our reply here */
37 Blob line; /* The current line of input */
38 Blob aToken[5]; /* Tokenized version of line */
39 Blob err; /* Error message text */
40 int nToken; /* Number of tokens in line */
41 int nIGot; /* Number of "igot" messages sent */
42 int nFile; /* Number of files sent or received */
43 int nDelta; /* Number of deltas sent or received */
 
 
 
44 int nDanglingFile; /* Number of dangling deltas received */
45 int mxSend; /* Stop sending "file" with pOut reaches this size */
46 };
47
48
@@ -100,20 +103,21 @@
100 blob_extract(pXfer->pIn, n, &content);
101 if( pXfer->nToken==4 ){
102 Blob src;
103 int srcid = rid_from_uuid(&pXfer->aToken[2], 1);
104 if( content_get(srcid, &src)==0 ){
105 content_put(&content, blob_str(&hash), srcid);
106 blob_appendf(pXfer->pOut, "gimme %b\n", &pXfer->aToken[2]);
 
107 pXfer->nDanglingFile++;
108 return;
109 }
110 pXfer->nDelta++;
111 blob_delta_apply(&src, &content, &content);
112 blob_reset(&src);
113 }else{
114 pXfer->nFile++;
115 }
116 sha1sum_blob(&content, &hash);
117 if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){
118 blob_appendf(&pXfer->err, "content does not match sha1 hash");
119 }
@@ -139,51 +143,35 @@
139 Blob *pContent, /* The content of the file to send */
140 Blob *pUuid, /* The UUID of the file to send */
141 int srcId /* Send as a delta against this record */
142 ){
143 static const char *azQuery[] = {
144 "SELECT srcid FROM delta JOIN pending ON pending.rid=delta.srcid"
145 " WHERE delta.rid=%d"
146 " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=srcid)",
147
148 "SELECT delta.rid FROM delta JOIN pending ON pending.rid=delta.rid"
149 " WHERE srcid=%d"
150 " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=delta.rid)",
151
152 "SELECT pid FROM plink JOIN pending ON rid=pid"
153 " WHERE cid=%d"
154 " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)",
155
156 "SELECT cid FROM plink JOIN pending ON rid=cid"
157 " WHERE pid=%d"
158 " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=cid)",
159
160 "SELECT pid FROM mlink JOIN pending ON rid=pid"
161 " WHERE fid=%d"
162 " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)",
163
164 "SELECT fid FROM mlink JOIN pending ON rid=fid"
165 " WHERE pid=%d"
166 " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=fid)",
167 };
168 int i;
169 Blob src, delta;
170 int size = 0;
171
172 for(i=0; srcId==0 && i<count(azQuery); i++){
173 srcId = db_int(0, azQuery[i], rid);
174 }
175 if( srcId && content_get(srcId, &src) ){
176 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", srcId);
177 blob_delta_create(&src, pContent, &delta);
178 size = blob_size(&delta);
179 if( size>=blob_size(pContent)-50 ){
180 size = 0;
181 }else{
182 blob_appendf(pXfer->pOut, "file %b %s %d\n", pUuid, zUuid, size);
183 blob_append(pXfer->pOut, blob_buffer(&delta), size);
184 blob_appendf(pXfer->pOut, "\n", 1);
185 }
186 blob_reset(&delta);
187 free(zUuid);
188 blob_reset(&src);
189 }
@@ -190,10 +178,18 @@
190 return size;
191 }
192
193 /*
194 ** Send the file identified by rid.
 
 
 
 
 
 
 
 
195 */
196 static void send_file(Xfer *pXfer, int rid, Blob *pUuid, int srcId){
197 Blob content, uuid;
198 int size = 0;
199
@@ -208,11 +204,11 @@
208 }
209 pUuid = &uuid;
210 }
211 if( pXfer->mxSend<=blob_size(pXfer->pOut) ){
212 blob_appendf(pXfer->pOut, "igot %b\n", pUuid);
213 pXfer->nIGot++;
214 blob_reset(&uuid);
215 return;
216 }
217 content_get(rid, &content);
218
@@ -221,13 +217,13 @@
221 }
222 if( size==0 ){
223 int size = blob_size(&content);
224 blob_appendf(pXfer->pOut, "file %b %d\n", pUuid, size);
225 blob_append(pXfer->pOut, blob_buffer(&content), size);
226 pXfer->nFile++;
227 }else{
228 pXfer->nDelta++;
229 }
230 db_multi_exec("INSERT INTO sent VALUES(%d)", rid);
231 blob_reset(&uuid);
232 }
233
@@ -293,10 +289,11 @@
293 Stmt q;
294 db_prepare(&q, "SELECT uuid FROM phantom JOIN blob USING(rid)");
295 while( db_step(&q)==SQLITE_ROW ){
296 const char *zUuid = db_column_text(&q, 0);
297 blob_appendf(pXfer->pOut, "gimme %s\n", zUuid);
 
298 }
299 db_finalize(&q);
300 }
301
302
@@ -367,11 +364,10 @@
367 ** This is the transfer handler on the server side. The transfer
368 ** message has been uncompressed and placed in the g.cgiIn blob.
369 ** Process this message and form an appropriate reply.
370 */
371 void page_xfer(void){
372 int nToken;
373 int isPull = 0;
374 int isPush = 0;
375 int nErr = 0;
376 Xfer xfer;
377
@@ -379,10 +375,11 @@
379 blobarray_zero(xfer.aToken, count(xfer.aToken));
380 cgi_set_content_type(g.zContentType);
381 blob_zero(&xfer.err);
382 xfer.pIn = &g.cgiIn;
383 xfer.pOut = cgi_output_blob();
 
384
385 db_begin_transaction();
386 db_multi_exec(
387 "CREATE TEMP TABLE sent(rid INTEGER PRIMARY KEY);"
388 );
@@ -393,11 +390,11 @@
393 ** file UUID DELTASRC SIZE \n CONTENT
394 **
395 ** Accept a file from the client.
396 */
397 if( blob_eq(&xfer.aToken[0], "file") ){
398 if( !isPush ){
399 cgi_reset_content();
400 @ error not\sauthorized\sto\swrite
401 nErr++;
402 break;
403 }
@@ -416,11 +413,11 @@
416 */
417 if( blob_eq(&xfer.aToken[0], "gimme")
418 && xfer.nToken==2
419 && blob_is_uuid(&xfer.aToken[1])
420 ){
421 if( isPull ){
422 int rid = rid_from_uuid(&xfer.aToken[1], 0);
423 if( rid ){
424 send_file(&xfer, rid, &xfer.aToken[1], 0);
425 }
426 }
@@ -432,11 +429,11 @@
432 */
433 if( xfer.nToken==2
434 && blob_eq(&xfer.aToken[0], "igot")
435 && blob_is_uuid(&xfer.aToken[1])
436 ){
437 if( isPush ){
438 rid_from_uuid(&xfer.aToken[1], 1);
439 }
440 }else
441
442
@@ -446,11 +443,11 @@
446 */
447 if( xfer.nToken==2
448 && blob_eq(&xfer.aToken[0], "leaf")
449 && blob_is_uuid(&xfer.aToken[1])
450 ){
451 if( isPull ){
452 int rid = rid_from_uuid(&xfer.aToken[1], 0);
453 leaf_response(&xfer, rid);
454 }
455 }else
456
@@ -457,11 +454,11 @@
457 /* pull SERVERCODE PROJECTCODE
458 ** push SERVERCODE PROJECTCODE
459 **
460 ** The client wants either send or receive
461 */
462 if( nToken==3
463 && (blob_eq(&xfer.aToken[0], "pull") || blob_eq(&xfer.aToken[0], "push"))
464 && blob_is_uuid(&xfer.aToken[1])
465 && blob_is_uuid(&xfer.aToken[2])
466 ){
467 const char *zSCode;
@@ -511,28 +508,36 @@
511 /* clone
512 **
513 ** The client knows nothing. Tell all.
514 */
515 if( blob_eq(&xfer.aToken[0], "clone") ){
 
516 login_check_credentials();
517 if( !g.okRead || !g.okHistory ){
518 cgi_reset_content();
519 @ error not\sauthorized\sto\sclone
520 nErr++;
521 break;
522 }
523 isPull = 1;
524 @ push %s(db_get("server-code", "x")) %s(db_get("project-code", "x"))
525 send_leaves(&xfer);
 
 
 
 
 
 
 
526 }else
527
528 /* login USER NONCE SIGNATURE
529 **
530 ** Check for a valid login. This has to happen before anything else.
531 */
532 if( blob_eq(&xfer.aToken[0], "login")
533 && nToken==4
534 ){
535 if( disableLogin ){
536 g.okRead = g.okWrite = 1;
537 }else{
538 check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3]);
@@ -597,21 +602,21 @@
597 */
598 void client_sync(int pushFlag, int pullFlag, int cloneFlag){
599 int go = 1; /* Loop until zero */
600 const char *zSCode = db_get("server-code", "x");
601 const char *zPCode = db_get("project-code", 0);
602 int nMsg = 0;
603 int nReq = 0;
604 int nFileSend = 0;
605 int nNoFileCycle = 0;
606 Blob send; /* Text we are sending to the server */
607 Blob recv; /* Reply we got back from the server */
608 Xfer xfer; /* Transfer data */
609
610 memset(&xfer, 0, sizeof(xfer));
611 xfer.pIn = &recv;
612 xfer.pOut = &send;
 
613
614 assert( pushFlag || pullFlag || cloneFlag );
615 assert( !g.urlIsFile ); /* This only works for networking */
616
617 db_begin_transaction();
@@ -620,15 +625,14 @@
620 );
621 blobarray_zero(xfer.aToken, count(xfer.aToken));
622 blob_zero(&send);
623 blob_zero(&recv);
624 blob_zero(&xfer.err);
 
625
626
627 while( go ){
628 go = 0;
629 nReq = nMsg = 0;
630
631 /* Generate a request to be sent to the server.
632 ** Always begin with a clone, pull, or push message
633 */
634
@@ -637,32 +641,36 @@
637 pushFlag = 0;
638 pullFlag = 0;
639 nMsg++;
640 }else if( pullFlag ){
641 blob_appendf(&send, "pull %s %s\n", zSCode, zPCode);
642 send_leaves(&xfer);
643 request_phantoms(&xfer);
644 nMsg++;
645 }
646 if( pushFlag ){
647 blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
648 nMsg++;
649 }
650
651 /* Exchange messages with the server */
652 nFileSend = xfer.nFile + xfer.nDelta + xfer.nDanglingFile;
653 printf("Send: %3d files, %3d requests, %3d other msgs, %8d bytes\n",
654 nFileSend, nReq, nMsg, blob_size(&send));
655 xfer.nFile = 0;
656 xfer.nDelta = 0;
657 xfer.nDanglingFile = 0;
658 nReq = nMsg = 0;
 
659 http_exchange(&send, &recv);
660 blob_reset(&send);
661
662 /* Process the reply that came back from the server */
663 while( blob_line(&recv, &xfer.line) ){
 
 
 
664 xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
665
666 /* file UUID SIZE \n CONTENT
667 ** file UUID DELTASRC SIZE \n CONTENT
668 **
@@ -678,10 +686,11 @@
678 */
679 if( blob_eq(&xfer.aToken[0], "gimme")
680 && xfer.nToken==2
681 && blob_is_uuid(&xfer.aToken[1])
682 ){
 
683 if( pushFlag ){
684 int rid = rid_from_uuid(&xfer.aToken[1], 0);
685 send_file(&xfer, rid, &xfer.aToken[1], 0);
686 }
687 }else
@@ -692,12 +701,16 @@
692 */
693 if( xfer.nToken==2
694 && blob_eq(&xfer.aToken[0], "igot")
695 && blob_is_uuid(&xfer.aToken[1])
696 ){
 
697 if( pullFlag ){
698 rid_from_uuid(&xfer.aToken[1], 1);
 
 
 
699 }
700 }else
701
702
703 /* leaf UUID
@@ -706,10 +719,11 @@
706 */
707 if( xfer.nToken==2
708 && blob_eq(&xfer.aToken[0], "leaf")
709 && blob_is_uuid(&xfer.aToken[1])
710 ){
 
711 if( pushFlag ){
712 int rid = rid_from_uuid(&xfer.aToken[1], 0);
713 leaf_response(&xfer, rid);
714 }
715 }else
@@ -754,26 +768,39 @@
754
755 if( blob_size(&xfer.err) ){
756 fossil_fatal("%b", &xfer.err);
757 }
758 blobarray_reset(xfer.aToken, xfer.nToken);
 
759 }
760 printf("Received: %3d files, %3d requests, %3d other msgs, %8d bytes\n",
761 xfer.nFile + xfer.nDelta + xfer.nDanglingFile,
762 nReq, nMsg, blob_size(&recv));
 
 
763 blob_reset(&recv);
764 if( nFileSend + xfer.nFile + xfer.nDelta + xfer.nDanglingFile==0 ){
765 nNoFileCycle++;
766 if( nNoFileCycle>1 ){
767 go = 0;
768 }
769 }else{
770 nNoFileCycle = 0;
771 }
772 nReq = nMsg = 0;
773 xfer.nFile = 0;
774 xfer.nDelta = 0;
775 xfer.nDanglingFile = 0;
 
 
 
 
 
 
 
 
 
 
776 };
777 http_close();
778 db_end_transaction(0);
779 }
780
--- src/xfer.c
+++ src/xfer.c
@@ -36,13 +36,16 @@
36 Blob *pOut; /* Compose our reply here */
37 Blob line; /* The current line of input */
38 Blob aToken[5]; /* Tokenized version of line */
39 Blob err; /* Error message text */
40 int nToken; /* Number of tokens in line */
41 int nIGotSent; /* Number of "igot" messages sent */
42 int nGimmeSent; /* Number of gimme messages sent */
43 int nFileSent; /* Number of files sent */
44 int nDeltaSent; /* Number of deltas sent */
45 int nFileRcvd; /* Number of files received */
46 int nDeltaRcvd; /* Number of deltas received */
47 int nDanglingFile; /* Number of dangling deltas received */
48 int mxSend; /* Stop sending "file" with pOut reaches this size */
49 };
50
51
@@ -100,20 +103,21 @@
103 blob_extract(pXfer->pIn, n, &content);
104 if( pXfer->nToken==4 ){
105 Blob src;
106 int srcid = rid_from_uuid(&pXfer->aToken[2], 1);
107 if( content_get(srcid, &src)==0 ){
108 content_put(&content, blob_str(&pXfer->aToken[1]), srcid);
109 blob_appendf(pXfer->pOut, "gimme %b\n", &pXfer->aToken[2]);
110 pXfer->nGimmeSent++;
111 pXfer->nDanglingFile++;
112 return;
113 }
114 pXfer->nDeltaRcvd++;
115 blob_delta_apply(&src, &content, &content);
116 blob_reset(&src);
117 }else{
118 pXfer->nFileRcvd++;
119 }
120 sha1sum_blob(&content, &hash);
121 if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){
122 blob_appendf(&pXfer->err, "content does not match sha1 hash");
123 }
@@ -139,51 +143,35 @@
143 Blob *pContent, /* The content of the file to send */
144 Blob *pUuid, /* The UUID of the file to send */
145 int srcId /* Send as a delta against this record */
146 ){
147 static const char *azQuery[] = {
148 "SELECT pid FROM plink"
 
 
 
 
 
 
 
 
149 " WHERE cid=%d"
150 " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)",
151
152 "SELECT pid FROM mlink"
 
 
 
 
153 " WHERE fid=%d"
154 " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)",
 
 
 
 
155 };
156 int i;
157 Blob src, delta;
158 int size = 0;
159
160 for(i=0; srcId==0 && i<count(azQuery); i++){
161 srcId = db_int(0, azQuery[i], rid);
162 }
163 if( srcId>0 && content_get(srcId, &src) ){
164 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", srcId);
165 blob_delta_create(&src, pContent, &delta);
166 size = blob_size(&delta);
167 if( size>=blob_size(pContent)-50 ){
168 size = 0;
169 }else{
170 blob_appendf(pXfer->pOut, "file %b %s %d\n", pUuid, zUuid, size);
171 blob_append(pXfer->pOut, blob_buffer(&delta), size);
172 /* blob_appendf(pXfer->pOut, "\n", 1); */
173 }
174 blob_reset(&delta);
175 free(zUuid);
176 blob_reset(&src);
177 }
@@ -190,10 +178,18 @@
178 return size;
179 }
180
181 /*
182 ** Send the file identified by rid.
183 **
184 ** The pUuid can be NULL in which case the correct UUID is computed
185 ** from the rid.
186 **
187 ** If srcId is positive, then a delta is sent against that srcId.
188 ** If srcId is zero, then an attempt is made to find an appropriate
189 ** file to delta against. If srcId is negative, the file is sent
190 ** without deltaing.
191 */
192 static void send_file(Xfer *pXfer, int rid, Blob *pUuid, int srcId){
193 Blob content, uuid;
194 int size = 0;
195
@@ -208,11 +204,11 @@
204 }
205 pUuid = &uuid;
206 }
207 if( pXfer->mxSend<=blob_size(pXfer->pOut) ){
208 blob_appendf(pXfer->pOut, "igot %b\n", pUuid);
209 pXfer->nIGotSent++;
210 blob_reset(&uuid);
211 return;
212 }
213 content_get(rid, &content);
214
@@ -221,13 +217,13 @@
217 }
218 if( size==0 ){
219 int size = blob_size(&content);
220 blob_appendf(pXfer->pOut, "file %b %d\n", pUuid, size);
221 blob_append(pXfer->pOut, blob_buffer(&content), size);
222 pXfer->nFileSent++;
223 }else{
224 pXfer->nDeltaSent++;
225 }
226 db_multi_exec("INSERT INTO sent VALUES(%d)", rid);
227 blob_reset(&uuid);
228 }
229
@@ -293,10 +289,11 @@
289 Stmt q;
290 db_prepare(&q, "SELECT uuid FROM phantom JOIN blob USING(rid)");
291 while( db_step(&q)==SQLITE_ROW ){
292 const char *zUuid = db_column_text(&q, 0);
293 blob_appendf(pXfer->pOut, "gimme %s\n", zUuid);
294 pXfer->nGimmeSent++;
295 }
296 db_finalize(&q);
297 }
298
299
@@ -367,11 +364,10 @@
364 ** This is the transfer handler on the server side. The transfer
365 ** message has been uncompressed and placed in the g.cgiIn blob.
366 ** Process this message and form an appropriate reply.
367 */
368 void page_xfer(void){
 
369 int isPull = 0;
370 int isPush = 0;
371 int nErr = 0;
372 Xfer xfer;
373
@@ -379,10 +375,11 @@
375 blobarray_zero(xfer.aToken, count(xfer.aToken));
376 cgi_set_content_type(g.zContentType);
377 blob_zero(&xfer.err);
378 xfer.pIn = &g.cgiIn;
379 xfer.pOut = cgi_output_blob();
380 xfer.mxSend = db_get_int("max-download", 1000000);
381
382 db_begin_transaction();
383 db_multi_exec(
384 "CREATE TEMP TABLE sent(rid INTEGER PRIMARY KEY);"
385 );
@@ -393,11 +390,11 @@
390 ** file UUID DELTASRC SIZE \n CONTENT
391 **
392 ** Accept a file from the client.
393 */
394 if( blob_eq(&xfer.aToken[0], "file") ){
395 if( !g.okWrite ){
396 cgi_reset_content();
397 @ error not\sauthorized\sto\swrite
398 nErr++;
399 break;
400 }
@@ -416,11 +413,11 @@
413 */
414 if( blob_eq(&xfer.aToken[0], "gimme")
415 && xfer.nToken==2
416 && blob_is_uuid(&xfer.aToken[1])
417 ){
418 if( g.okRead ){
419 int rid = rid_from_uuid(&xfer.aToken[1], 0);
420 if( rid ){
421 send_file(&xfer, rid, &xfer.aToken[1], 0);
422 }
423 }
@@ -432,11 +429,11 @@
429 */
430 if( xfer.nToken==2
431 && blob_eq(&xfer.aToken[0], "igot")
432 && blob_is_uuid(&xfer.aToken[1])
433 ){
434 if( g.okWrite ){
435 rid_from_uuid(&xfer.aToken[1], 1);
436 }
437 }else
438
439
@@ -446,11 +443,11 @@
443 */
444 if( xfer.nToken==2
445 && blob_eq(&xfer.aToken[0], "leaf")
446 && blob_is_uuid(&xfer.aToken[1])
447 ){
448 if( g.okRead ){
449 int rid = rid_from_uuid(&xfer.aToken[1], 0);
450 leaf_response(&xfer, rid);
451 }
452 }else
453
@@ -457,11 +454,11 @@
454 /* pull SERVERCODE PROJECTCODE
455 ** push SERVERCODE PROJECTCODE
456 **
457 ** The client wants either send or receive
458 */
459 if( xfer.nToken==3
460 && (blob_eq(&xfer.aToken[0], "pull") || blob_eq(&xfer.aToken[0], "push"))
461 && blob_is_uuid(&xfer.aToken[1])
462 && blob_is_uuid(&xfer.aToken[2])
463 ){
464 const char *zSCode;
@@ -511,28 +508,36 @@
508 /* clone
509 **
510 ** The client knows nothing. Tell all.
511 */
512 if( blob_eq(&xfer.aToken[0], "clone") ){
513 int rootid;
514 login_check_credentials();
515 if( !g.okRead || !g.okHistory ){
516 cgi_reset_content();
517 @ error not\sauthorized\sto\sclone
518 nErr++;
519 break;
520 }
521 isPull = 1;
522 @ push %s(db_get("server-code", "x")) %s(db_get("project-code", "x"))
523 rootid = db_int(0,
524 "SELECT pid FROM plink AS a"
525 " WHERE NOT EXISTS(SELECT 1 FROM plink WHERE cid=a.pid)"
526 );
527 if( rootid ){
528 send_file(&xfer, rootid, 0, -1);
529 leaf_response(&xfer, rootid);
530 }
531 }else
532
533 /* login USER NONCE SIGNATURE
534 **
535 ** Check for a valid login. This has to happen before anything else.
536 */
537 if( blob_eq(&xfer.aToken[0], "login")
538 && xfer.nToken==4
539 ){
540 if( disableLogin ){
541 g.okRead = g.okWrite = 1;
542 }else{
543 check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3]);
@@ -597,21 +602,21 @@
602 */
603 void client_sync(int pushFlag, int pullFlag, int cloneFlag){
604 int go = 1; /* Loop until zero */
605 const char *zSCode = db_get("server-code", "x");
606 const char *zPCode = db_get("project-code", 0);
607 int nMsg = 0; /* Number of messages sent or received */
608 int nCycle = 0; /* Number of round trips to the server */
609 int nFileSend = 0;
 
610 Blob send; /* Text we are sending to the server */
611 Blob recv; /* Reply we got back from the server */
612 Xfer xfer; /* Transfer data */
613
614 memset(&xfer, 0, sizeof(xfer));
615 xfer.pIn = &recv;
616 xfer.pOut = &send;
617 xfer.mxSend = db_get_int("max-upload", 250000);
618
619 assert( pushFlag || pullFlag || cloneFlag );
620 assert( !g.urlIsFile ); /* This only works for networking */
621
622 db_begin_transaction();
@@ -620,15 +625,14 @@
625 );
626 blobarray_zero(xfer.aToken, count(xfer.aToken));
627 blob_zero(&send);
628 blob_zero(&recv);
629 blob_zero(&xfer.err);
630 blob_zero(&xfer.line);
631
632
633 while( go ){
 
 
634
635 /* Generate a request to be sent to the server.
636 ** Always begin with a clone, pull, or push message
637 */
638
@@ -637,32 +641,36 @@
641 pushFlag = 0;
642 pullFlag = 0;
643 nMsg++;
644 }else if( pullFlag ){
645 blob_appendf(&send, "pull %s %s\n", zSCode, zPCode);
646 nMsg++;
647 request_phantoms(&xfer);
648 send_leaves(&xfer);
649 }
650 if( pushFlag ){
651 blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
652 nMsg++;
653 }
654
655 /* Exchange messages with the server */
656 nFileSend = xfer.nFileSent + xfer.nDeltaSent;
657 printf("Send: %10d bytes, %3d messages, %3d files (%d+%d)\n",
658 blob_size(&send), nMsg+xfer.nGimmeSent+xfer.nIGotSent,
659 nFileSend, xfer.nFileSent, xfer.nDeltaSent);
660 nMsg = 0;
661 xfer.nFileSent = 0;
662 xfer.nDeltaSent = 0;
663 xfer.nGimmeSent = 0;
664 http_exchange(&send, &recv);
665 blob_reset(&send);
666
667 /* Process the reply that came back from the server */
668 while( blob_line(&recv, &xfer.line) ){
669 if( blob_buffer(&xfer.line)[0]=='#' ){
670 continue;
671 }
672 xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
673
674 /* file UUID SIZE \n CONTENT
675 ** file UUID DELTASRC SIZE \n CONTENT
676 **
@@ -678,10 +686,11 @@
686 */
687 if( blob_eq(&xfer.aToken[0], "gimme")
688 && xfer.nToken==2
689 && blob_is_uuid(&xfer.aToken[1])
690 ){
691 nMsg++;
692 if( pushFlag ){
693 int rid = rid_from_uuid(&xfer.aToken[1], 0);
694 send_file(&xfer, rid, &xfer.aToken[1], 0);
695 }
696 }else
@@ -692,12 +701,16 @@
701 */
702 if( xfer.nToken==2
703 && blob_eq(&xfer.aToken[0], "igot")
704 && blob_is_uuid(&xfer.aToken[1])
705 ){
706 nMsg++;
707 if( pullFlag ){
708 if( !db_exists("SELECT 1 FROM blob WHERE uuid='%b' AND size>=0",
709 &xfer.aToken[1]) ){
710 content_put(0, blob_str(&xfer.aToken[1]), 0);
711 }
712 }
713 }else
714
715
716 /* leaf UUID
@@ -706,10 +719,11 @@
719 */
720 if( xfer.nToken==2
721 && blob_eq(&xfer.aToken[0], "leaf")
722 && blob_is_uuid(&xfer.aToken[1])
723 ){
724 nMsg++;
725 if( pushFlag ){
726 int rid = rid_from_uuid(&xfer.aToken[1], 0);
727 leaf_response(&xfer, rid);
728 }
729 }else
@@ -754,26 +768,39 @@
768
769 if( blob_size(&xfer.err) ){
770 fossil_fatal("%b", &xfer.err);
771 }
772 blobarray_reset(xfer.aToken, xfer.nToken);
773 blob_reset(&xfer.line);
774 }
775 printf("Received: %10d bytes, %3d messages, %3d files (%d+%d+%d)\n",
776 blob_size(&recv), nMsg,
777 xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile,
778 xfer.nFileRcvd, xfer.nDeltaRcvd, xfer.nDanglingFile);
779
780 blob_reset(&recv);
781 nMsg = 0;
782 xfer.nFileRcvd = 0;
783 xfer.nDeltaRcvd = 0;
784 xfer.nDanglingFile = 0;
785 nCycle++;
786 go = 0;
787
788 /* If we have received one or more files on this cycle and
789 ** we have one or more phantoms, then go for another round
790 */
791 if(xfer.nFileRcvd+xfer.nDeltaRcvd+xfer.nDanglingFile>0
792 && db_exists("SELECT 1 FROM phantom")
793 ){
794 go = 1;
795 }
796
797 /* If we have one or more files queued to send, then go
798 ** another round
799 */
800 if( xfer.nFileSent+xfer.nDeltaSent>0 ){
801 go = 1;
802 }
803 };
804 http_close();
805 db_end_transaction(0);
806 }
807

Keyboard Shortcuts

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