Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Improvements to cloning performance. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
243e02bfbdf5629131d8c6b0709e538c |
User & Date: | drh 2008-05-18 15:51:05.000 |
Context
2008-05-18
| ||
17:18 | Improvements to clone performance. Skip cross-linking during the clone the automatically rebuild after the clone. Fixes to rebuild to make sure all artifacts are crosslinked. ... (check-in: 791a513c user: drh tags: trunk) | |
15:51 | Improvements to cloning performance. ... (check-in: 243e02bf user: drh tags: trunk) | |
2008-05-17
| ||
22:18 | Begin adding code to the sync logic to transfer configuration options upon request. ... (check-in: a241c811 user: drh tags: trunk) | |
Changes
Changes to src/clone.c.
︙ | ︙ | |||
72 73 74 75 76 77 78 79 80 81 82 83 | const char *zTab = db_column_text(&q, 0); db_multi_exec("INSERT OR IGNORE INTO %Q SELECT * FROM orig.%Q", zTab, zTab); } db_finalize(&q); }else{ url_enable_proxy(0); client_sync(0,0,1); } verify_cancel(); db_end_transaction(0); } | > > > > > > > > | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | const char *zTab = db_column_text(&q, 0); db_multi_exec("INSERT OR IGNORE INTO %Q SELECT * FROM orig.%Q", zTab, zTab); } db_finalize(&q); }else{ url_enable_proxy(0); g.xlinkClusterOnly = 1; client_sync(0,0,1); g.xlinkClusterOnly = 0; } verify_cancel(); db_end_transaction(0); db_close(); db_open_repository(g.argv[3]); db_begin_transaction(); printf("Rebuilding repository meta-data...\n"); rebuild_db(0, 1); db_end_transaction(0); } |
Changes to src/content.c.
︙ | ︙ | |||
363 364 365 366 367 368 369 | /* ** Write content into the database. Return the record ID. If the ** content is already in the database, just return the record ID. ** ** If srcId is specified, then pBlob is delta content from ** the srcId record. srcId might be a phantom. ** | > | < | | > > | 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 | /* ** Write content into the database. Return the record ID. If the ** content is already in the database, just return the record ID. ** ** If srcId is specified, then pBlob is delta content from ** the srcId record. srcId might be a phantom. ** ** zUuid is the UUID of the artifact, if it is specified. When srcId is ** specified then zUuid must always be specified. If srcId is zero, ** and zUuid is zero then the correct zUuid is computed from pBlob. ** ** If the record already exists but is a phantom, the pBlob content ** is inserted and the phatom becomes a real record. */ int content_put(Blob *pBlob, const char *zUuid, int srcId){ int size; int rid; Stmt s1; Blob cmpr; Blob hash; int markAsUnclustered = 0; int isDephantomize = 0; assert( g.repositoryOpen ); assert( pBlob!=0 ); assert( srcId==0 || zUuid!=0 ); if( zUuid==0 ){ assert( pBlob!=0 ); sha1sum_blob(pBlob, &hash); }else{ blob_init(&hash, zUuid, -1); } size = blob_size(pBlob); db_begin_transaction(); |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
72 73 74 75 76 77 78 79 80 81 82 83 84 85 | int iErrPriority; /* Priority of current error message */ char *zErrMsg; /* Text of an error message */ Blob cgiIn; /* Input to an xfer www method */ int cgiPanic; /* Write error messages to CGI */ Th_Interp *interp; /* The TH1 interpreter */ FILE *httpIn; /* Accept HTTP input from here */ FILE *httpOut; /* Send HTTP output here */ int *aCommitFile; /* Array of files to be committed */ int urlIsFile; /* True if a "file:" url */ char *urlName; /* Hostname for http: or filename for file: */ char *urlHostname; /* The HOST: parameter on http headers */ int urlPort; /* TCP port number for http: */ | > | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | int iErrPriority; /* Priority of current error message */ char *zErrMsg; /* Text of an error message */ Blob cgiIn; /* Input to an xfer www method */ int cgiPanic; /* Write error messages to CGI */ Th_Interp *interp; /* The TH1 interpreter */ FILE *httpIn; /* Accept HTTP input from here */ FILE *httpOut; /* Send HTTP output here */ int xlinkClusterOnly; /* Set when cloning. Only process clusters */ int *aCommitFile; /* Array of files to be committed */ int urlIsFile; /* True if a "file:" url */ char *urlName; /* Hostname for http: or filename for file: */ char *urlHostname; /* The HOST: parameter on http headers */ int urlPort; /* TCP port number for http: */ |
︙ | ︙ |
Changes to src/manifest.c.
︙ | ︙ | |||
752 753 754 755 756 757 758 | add_one_mlink(cid, 0, pChild->aFile[j].zUuid, pChild->aFile[j].zName); j++; } manifest_clear(&other); } /* | | | < > | | > | > > > > > > > > > > > > > > > > | 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 | add_one_mlink(cid, 0, pChild->aFile[j].zUuid, pChild->aFile[j].zName); j++; } manifest_clear(&other); } /* ** Scan artifact rid/pContent to see if it is a control artifact of ** any key: ** ** * Manifest ** * Control ** * Wiki Page ** * Ticket Change ** * Cluster ** ** If the input is a control artifact, then make appropriate entries ** in the auxiliary tables of the database in order to crosslink the ** artifact. ** ** If global variable g.xlinkClusterOnly is true, then ignore all ** control artifacts other than clusters. ** ** Historical note: This routine original processed manifests only. ** Processing for other control artifacts was added later. The name ** of the routine, "manifest_crosslink", and the name of this source ** file, is a legacy of its original use. */ int manifest_crosslink(int rid, Blob *pContent){ int i; Manifest m; Stmt q; int parentid = 0; if( manifest_parse(&m, pContent)==0 ){ return 0; } if( g.xlinkClusterOnly && m.type!=CFTYPE_CLUSTER ){ manifest_clear(&m); return 0; } db_begin_transaction(); if( m.type==CFTYPE_MANIFEST ){ if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){ for(i=0; i<m.nParent; i++){ int pid = uuid_to_rid(m.azParent[i], 1); db_multi_exec("INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime)" |
︙ | ︙ |
Changes to src/schema.c.
︙ | ︙ | |||
71 72 73 74 75 76 77 | @ -- will exist for the record and that entry will point to another @ -- entry that holds the source of the delta. Deltas can be chained. @ -- @ CREATE TABLE blob( @ rid INTEGER PRIMARY KEY, -- Record ID @ rcvid INTEGER, -- Origin of this record @ size INTEGER, -- Size of content. -1 for a phantom. | | | > | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | @ -- will exist for the record and that entry will point to another @ -- entry that holds the source of the delta. Deltas can be chained. @ -- @ CREATE TABLE blob( @ rid INTEGER PRIMARY KEY, -- Record ID @ rcvid INTEGER, -- Origin of this record @ size INTEGER, -- Size of content. -1 for a phantom. @ uuid TEXT UNIQUE NOT NULL, -- SHA1 hash of the content @ content BLOB, -- Compressed content of this record @ CHECK( length(uuid)==40 AND rid>0 ) @ ); @ CREATE TABLE delta( @ rid INTEGER PRIMARY KEY, -- Record ID @ srcid INTEGER NOT NULL REFERENCES blob -- Record holding source document @ ); @ CREATE INDEX delta_i1 ON delta(srcid); @ |
︙ | ︙ |
Changes to src/xfer.c.
︙ | ︙ | |||
63 64 65 66 67 68 69 | struct Xfer { Blob *pIn; /* Input text from the other side */ Blob *pOut; /* Compose our reply here */ Blob line; /* The current line of input */ Blob aToken[5]; /* Tokenized version of line */ Blob err; /* Error message text */ int nToken; /* Number of tokens in line */ | | | | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | struct Xfer { Blob *pIn; /* Input text from the other side */ Blob *pOut; /* Compose our reply here */ Blob line; /* The current line of input */ Blob aToken[5]; /* Tokenized version of line */ Blob err; /* Error message text */ int nToken; /* Number of tokens in line */ int nIGotSent; /* Number of "igot" cards sent */ int nGimmeSent; /* Number of gimme cards sent */ int nFileSent; /* Number of files sent */ int nDeltaSent; /* Number of deltas sent */ int nFileRcvd; /* Number of files received */ int nDeltaRcvd; /* Number of deltas received */ int nDanglingFile; /* Number of dangling deltas received */ int mxSend; /* Stop sending "file" with pOut reaches this size */ }; |
︙ | ︙ | |||
168 169 170 171 172 173 174 175 | }else{ pXfer->nFileRcvd++; } sha1sum_blob(&content, &hash); if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){ blob_appendf(&pXfer->err, "content does not match sha1 hash"); } blob_reset(&hash); | > < > | 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | }else{ pXfer->nFileRcvd++; } sha1sum_blob(&content, &hash); if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){ blob_appendf(&pXfer->err, "content does not match sha1 hash"); } rid = content_put(&content, blob_str(&hash), 0); blob_reset(&hash); if( rid==0 ){ blob_appendf(&pXfer->err, "%s", g.zErrMsg); }else{ /* db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid); */ manifest_crosslink(rid, &content); } remote_has(rid); } /* ** Try to send a file as a delta against its parent. |
︙ | ︙ | |||
458 459 460 461 462 463 464 | db_multi_exec("DELETE FROM unclustered"); content_put(&cluster, 0, 0); blob_reset(&cluster); } /* ** Send an igot message for every entry in unclustered table. | | > > > > > > > > > > > > > > | 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | db_multi_exec("DELETE FROM unclustered"); content_put(&cluster, 0, 0); blob_reset(&cluster); } /* ** Send an igot message for every entry in unclustered table. ** Return the number of cards sent. */ static int send_unclustered(Xfer *pXfer){ Stmt q; int cnt = 0; db_prepare(&q, "SELECT uuid FROM unclustered JOIN blob USING(rid)" " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)" ); while( db_step(&q)==SQLITE_ROW ){ blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0)); cnt++; } db_finalize(&q); return cnt; } /* ** Send an igot message for every artifact. */ static void send_all(Xfer *pXfer){ Stmt q; db_prepare(&q, "SELECT uuid FROM blob"); while( db_step(&q)==SQLITE_ROW ){ blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0)); } db_finalize(&q); } /* ** If this variable is set, disable login checks. Used for debugging ** only. */ static int disableLogin = 0; /* ** WEBPAGE: xfer ** ** This is the transfer handler on the server side. The transfer ** message has been uncompressed and placed in the g.cgiIn blob. ** Process this message and form an appropriate reply. */ void page_xfer(void){ int isPull = 0; int isPush = 0; int nErr = 0; Xfer xfer; int deltaFlag = 0; int isClone = 0; int nGimme = 0; memset(&xfer, 0, sizeof(xfer)); blobarray_zero(xfer.aToken, count(xfer.aToken)); cgi_set_content_type(g.zContentType); blob_zero(&xfer.err); xfer.pIn = &g.cgiIn; xfer.pOut = cgi_output_blob(); |
︙ | ︙ | |||
539 540 541 542 543 544 545 546 547 548 549 550 551 552 | ** ** Client is requesting a file. Send it. */ if( blob_eq(&xfer.aToken[0], "gimme") && xfer.nToken==2 && blob_is_uuid(&xfer.aToken[1]) ){ if( isPull ){ int rid = rid_from_uuid(&xfer.aToken[1], 0); if( rid ){ send_file(&xfer, rid, &xfer.aToken[1], deltaFlag); } } }else | > | 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 | ** ** Client is requesting a file. Send it. */ if( blob_eq(&xfer.aToken[0], "gimme") && xfer.nToken==2 && blob_is_uuid(&xfer.aToken[1]) ){ nGimme++; if( isPull ){ int rid = rid_from_uuid(&xfer.aToken[1], 0); if( rid ){ send_file(&xfer, rid, &xfer.aToken[1], deltaFlag); } } }else |
︙ | ︙ | |||
632 633 634 635 636 637 638 639 640 641 642 643 644 645 | login_check_credentials(); if( !g.okClone ){ cgi_reset_content(); @ error not\sauthorized\sto\sclone nErr++; break; } isPull = 1; deltaFlag = 1; @ push %s(db_get("server-code", "x")) %s(db_get("project-code", "x")) }else /* login USER NONCE SIGNATURE ** | > | 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 | login_check_credentials(); if( !g.okClone ){ cgi_reset_content(); @ error not\sauthorized\sto\sclone nErr++; break; } isClone = 1; isPull = 1; deltaFlag = 1; @ push %s(db_get("server-code", "x")) %s(db_get("project-code", "x")) }else /* login USER NONCE SIGNATURE ** |
︙ | ︙ | |||
696 697 698 699 700 701 702 | @ error bad\scommand:\s%F(blob_str(&xfer.line)) } blobarray_reset(xfer.aToken, xfer.nToken); } if( isPush ){ request_phantoms(&xfer, 500); } | > > > > > > > > > | | 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 | @ error bad\scommand:\s%F(blob_str(&xfer.line)) } blobarray_reset(xfer.aToken, xfer.nToken); } if( isPush ){ request_phantoms(&xfer, 500); } if( isClone && nGimme==0 ){ /* The initial "clone" message from client to server contains no ** "gimme" cards. On that initial message, send the client an "igot" ** card for every artifact currently in the respository. This will ** cause the client to create phantoms for all artifacts, which will ** in turn make sure that the entire repository is sent efficiently ** and expeditiously. */ send_all(&xfer); }else if( isPull ){ create_cluster(); send_unclustered(&xfer); } db_end_transaction(0); } /* |
︙ | ︙ | |||
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 | blob_zero(&g.cgiIn); blob_read_from_file(&g.cgiIn, g.argc==2 ? "-" : g.argv[2]); disableLogin = 1; page_xfer(); printf("%s\n", cgi_extract_content(¬Used)); } /* ** Sync to the host identified in g.urlName and g.urlPath. This ** routine is called by the client. ** ** Records are pushed to the server if pushFlag is true. Records ** are pulled if pullFlag is true. A full sync occurs if both are ** true. */ void client_sync(int pushFlag, int pullFlag, int cloneFlag){ int go = 1; /* Loop until zero */ const char *zSCode = db_get("server-code", "x"); const char *zPCode = db_get("project-code", 0); | > > > > > > | | 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 | blob_zero(&g.cgiIn); blob_read_from_file(&g.cgiIn, g.argc==2 ? "-" : g.argv[2]); disableLogin = 1; page_xfer(); printf("%s\n", cgi_extract_content(¬Used)); } /* ** Format strings for progress reporting. */ static const char zLabel[] = "%-10s %10s %10s %10s %10s %10s\n"; static const char zValue[] = "\r%-10s %10d %10d %10d %10d %10d\n"; /* ** Sync to the host identified in g.urlName and g.urlPath. This ** routine is called by the client. ** ** Records are pushed to the server if pushFlag is true. Records ** are pulled if pullFlag is true. A full sync occurs if both are ** true. */ void client_sync(int pushFlag, int pullFlag, int cloneFlag){ int go = 1; /* Loop until zero */ const char *zSCode = db_get("server-code", "x"); const char *zPCode = db_get("project-code", 0); int nCard = 0; /* Number of cards sent or received */ int nCycle = 0; /* Number of round trips to the server */ int nFileSend = 0; int nFileRecv; /* Number of files received */ int mxPhantomReq = 200; /* Max number of phantoms to request per comm */ const char *zCookie; /* Server cookie */ Blob send; /* Text we are sending to the server */ Blob recv; /* Reply we got back from the server */ |
︙ | ︙ | |||
784 785 786 787 788 789 790 | /* ** Always begin with a clone, pull, or push message */ if( cloneFlag ){ blob_appendf(&send, "clone\n"); pushFlag = 0; pullFlag = 0; | | | | | | | > > > > | | > | | | | | | | 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 | /* ** Always begin with a clone, pull, or push message */ if( cloneFlag ){ blob_appendf(&send, "clone\n"); pushFlag = 0; pullFlag = 0; nCard++; /* TBD: Request all transferable configuration values */ }else if( pullFlag ){ blob_appendf(&send, "pull %s %s\n", zSCode, zPCode); nCard++; } if( pushFlag ){ blob_appendf(&send, "push %s %s\n", zSCode, zPCode); nCard++; } printf(zLabel, "", "Bytes", "Cards", "Artifacts", "Deltas", "Dangling"); while( go ){ int newPhantom = 0; /* Send make the most recently received cookie. Let the server ** figure out if this is a cookie that it cares about. */ zCookie = db_get("cookie", 0); if( zCookie ){ blob_appendf(&send, "cookie %s\n", zCookie); } /* Generate gimme cards for phantoms and leaf cards ** for all leaves. */ if( pullFlag || cloneFlag ){ request_phantoms(&xfer, mxPhantomReq); } if( pushFlag ){ send_unsent(&xfer); nCard += send_unclustered(&xfer); } /* Exchange messages with the server */ nFileSend = xfer.nFileSent + xfer.nDeltaSent; printf(zValue, "Send:", blob_size(&send), nCard+xfer.nGimmeSent+xfer.nIGotSent, xfer.nFileSent, xfer.nDeltaSent, 0); #if 0 printf("Sent: %10d bytes, %5d cards, %5d files (%d+%d)\n", blob_size(&send), nCard+xfer.nGimmeSent+xfer.nIGotSent, nFileSend, xfer.nFileSent, xfer.nDeltaSent); #endif nCard = 0; xfer.nFileSent = 0; xfer.nDeltaSent = 0; xfer.nGimmeSent = 0; fflush(stdout); http_exchange(&send, &recv); blob_reset(&send); /* Begin constructing the next message (which might never be ** sent) by beginning with the pull or push cards */ if( pullFlag ){ blob_appendf(&send, "pull %s %s\n", zSCode, zPCode); nCard++; } if( pushFlag ){ blob_appendf(&send, "push %s %s\n", zSCode, zPCode); nCard++; } /* Process the reply that came back from the server */ while( blob_line(&recv, &xfer.line) ){ if( blob_buffer(&xfer.line)[0]=='#' ){ continue; } xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken)); nCard++; printf("\r%d", nCard); fflush(stdout); /* file UUID SIZE \n CONTENT ** file UUID DELTASRC SIZE \n CONTENT ** ** Receive a file transmitted from the server. */ |
︙ | ︙ | |||
918 919 920 921 922 923 924 | fossil_fatal("server loop"); } if( zPCode==0 ){ zPCode = mprintf("%b", &xfer.aToken[2]); db_set("project-code", zPCode, 0); } blob_appendf(&send, "clone\n"); | | | 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 | fossil_fatal("server loop"); } if( zPCode==0 ){ zPCode = mprintf("%b", &xfer.aToken[2]); db_set("project-code", zPCode, 0); } blob_appendf(&send, "clone\n"); nCard++; }else /* config NAME SIZE \n CONTENT ** ** Receive a configuration value from the server. */ if( blob_eq(&xfer.aToken[0],"config") ){ |
︙ | ︙ | |||
976 977 978 979 980 981 982 | if( blob_size(&xfer.err) ){ fossil_fatal("%b", &xfer.err); } blobarray_reset(xfer.aToken, xfer.nToken); blob_reset(&xfer.line); } | > > > > | | | | | 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 | if( blob_size(&xfer.err) ){ fossil_fatal("%b", &xfer.err); } blobarray_reset(xfer.aToken, xfer.nToken); blob_reset(&xfer.line); } printf(zValue, "Received:", blob_size(&recv), nCard, xfer.nFileRcvd, xfer.nDeltaRcvd, xfer.nDanglingFile); #if 0 printf("\rReceived: %10d bytes, %5d cards, %5d files (%d+%d+%d)\n", blob_size(&recv), nCard, xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile, xfer.nFileRcvd, xfer.nDeltaRcvd, xfer.nDanglingFile); #endif blob_reset(&recv); nCycle++; go = 0; /* If we received one or more files on the previous exchange but ** there are still phantoms, then go another round. */ nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile; if( (nFileRecv>0 || newPhantom) && db_exists("SELECT 1 FROM phantom") ){ go = 1; mxPhantomReq = nFileRecv*2; if( mxPhantomReq<200 ) mxPhantomReq = 200; } nCard = 0; xfer.nFileRcvd = 0; xfer.nDeltaRcvd = 0; xfer.nDanglingFile = 0; /* If we have one or more files queued to send, then go ** another round */ |
︙ | ︙ |