From: drh <> Date: Thu, 12 Sep 2024 15:36:34 +0000 (+0000) Subject: Add a protocol version number to the first message, and give the two sides X-Git-Tag: version-3.47.0~118^2~17 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=f7c96ee98b47915bfd014a29162360886964a276;p=thirdparty%2Fsqlite.git Add a protocol version number to the first message, and give the two sides an opportunity to negotiate a suitable protocol number, for future compatibility. Send the page size as a power-of-two. FossilOrigin-Name: df0623aae1154281157409f62d6d3fb3ce41829281d53bc55868ce44b3d36883 --- diff --git a/manifest b/manifest index a0d9e1b120..aea0407ab4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\ssha1()\sfunctions\sto\sthe\sCLI.\s\sFix\ssha1b()\ssuch\sthat\sit\sactually\sreturns\na\sBLOB. -D 2024-09-12T14:43:05.090 +C Add\sa\sprotocol\sversion\snumber\sto\sthe\sfirst\smessage,\sand\sgive\sthe\stwo\ssides\nan\sopportunity\sto\snegotiate\sa\ssuitable\sprotocol\snumber,\sfor\sfuture\ncompatibility.\s\sSend\sthe\spage\ssize\sas\sa\spower-of-two. +D 2024-09-12T15:36:34.506 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -2174,7 +2174,7 @@ F tool/speedtest8inst1.c 7ce07da76b5e745783e703a834417d725b7d45fd F tool/spellsift.tcl 52b4b04dc4333c7ab024f09d9d66ed6b6f7c6eb00b38497a09f338fa55d40618 x F tool/split-sqlite3c.tcl 5aa60643afca558bc732b1444ae81a522326f91e1dc5665b369c54f09e20de60 F tool/sqldiff.c 847fc8fcfddf5ce4797b7394cad6372f2f5dc17d8186e2ef8fb44d50fae4f44a -F tool/sqlite3-rsync.c d9f8803f79c66dbc213761a345e24ae22c7de14fd334150086519c611ff1a705 +F tool/sqlite3-rsync.c f3283380beddab3cf876be781fbd2d00308249f08d6e4438411e64f27e7b67bd F tool/sqlite3_analyzer.c.in 8da2b08f56eeac331a715036cf707cc20f879f231362be0c22efd682e2b89b4f F tool/sqltclsh.c.in 1bcc2e9da58fadf17b0bf6a50e68c1159e602ce057210b655d50bad5aaaef898 F tool/sqltclsh.tcl 862f4cf1418df5e1315b5db3b5ebe88969e2a784525af5fbf9596592f14ed848 @@ -2213,8 +2213,8 @@ F vsixtest/vsixtest.tcl 6195aba1f12a5e10efc2b8c0009532167be5e301abe5b31385638080 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 80461e0d724963aaf2646005298f1194c5f1c4c9ae41c1085d4d137ed485bd9f -R 40763ccf45039aac90ad4e181b463c0b +P fe65821a3b912f061026e6fd7174be26897010e6b474e2780350cac60faebaad +R 70c38e114e917b5cf93c46e6c1a47f24 U drh -Z 969215ecb0944de74c8a9b9fbf319407 +Z 9a7103765746c5b1023f192fb95a127f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 86f93a2219..01d7fcfa05 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fe65821a3b912f061026e6fd7174be26897010e6b474e2780350cac60faebaad +df0623aae1154281157409f62d6d3fb3ce41829281d53bc55868ce44b3d36883 diff --git a/tool/sqlite3-rsync.c b/tool/sqlite3-rsync.c index 276b9af90f..315c7198a4 100644 --- a/tool/sqlite3-rsync.c +++ b/tool/sqlite3-rsync.c @@ -21,12 +21,19 @@ #include "sqlite3.h" static const char zUsage[] = - "sqlite3-rsync ORIGIN REPLICA\n" + "sqlite3-rsync ORIGIN REPLICA ?OPTIONS?\n" "\n" "One of ORIGIN or REPLICA is a pathname to a database on the local\n" "machine and the other is of the form \"USER@HOST:PATH\" describing\n" "a database on a remote machine. This utility makes REPLICA into a\n" "copy of ORIGIN\n" + "\n" + "OPTIONS:\n" + "\n" + " --exe PATH Name of the sqlite3-rsync program on the remote side\n" + " --help Show this help screen\n" + " --ssh PATH Name of the SSH program used to reach the remote side\n" + " -v Verbose. Multiple v's for increasing output\n" ; typedef unsigned char u8; @@ -43,6 +50,7 @@ struct SQLiteRsync { u8 eVerbose; /* Bigger for more output. 0 means none. */ u8 bCommCheck; /* True to debug the communication protocol */ u8 isRemote; /* On the remote side of a connection */ + u8 iProtocol; /* Protocol version number */ sqlite3_uint64 nOut; /* Bytes transmitted */ sqlite3_uint64 nIn; /* Bytes received */ unsigned int nPage; /* Total number of pages in the database */ @@ -51,6 +59,11 @@ struct SQLiteRsync { unsigned int nPageSent; /* Page contents sent (origin to replica) */ }; +/* The version number of the protocol. Sent in the *_BEGIN message +** to verify that both sides speak the same dialect. +*/ +#define PROTOCOL_VERSION 1 + /* Magic numbers to identify particular messages sent over the wire. */ @@ -553,6 +566,28 @@ void writeByte(SQLiteRsync *p, int c){ p->nOut++; } +/* Read a power of two encoded as a single byte. +*/ +int readPow2(SQLiteRsync *p){ + int x = readByte(p); + if( x>=32 ){ + p->nErr++; + return 0; + } + return 1<nErr++; + } + for(n=0; c>1; n++){ c /= 2; } + writeByte(p, n); +} + /* Read an array of bytes from the wire. */ void readBytes(SQLiteRsync *p, int nByte, void *pData){ @@ -838,16 +873,30 @@ static void originSide(SQLiteRsync *p){ if( p->nErr==0 ){ /* Send the ORIGIN_BEGIN message */ writeByte(p, ORIGIN_BEGIN); + writeByte(p, PROTOCOL_VERSION); + writePow2(p, szPg); writeUint32(p, nPage); - writeUint32(p, szPg); fflush(p->pOut); p->nPage = nPage; p->szPage = szPg; + p->iProtocol = PROTOCOL_VERSION; } /* Respond to message from the replica */ while( p->nErr==0 && (c = readByte(p))!=EOF && c!=REPLICA_END ){ switch( c ){ + case REPLICA_BEGIN: { + /* This message is only sent if the replica received an origin-protocol + ** that is larger than what it knows about. The replica sends back + ** a counter-proposal of an earlier protocol which the origin can + ** accept by resending a new ORIGIN_BEGIN. */ + p->iProtocol = readByte(p); + writeByte(p, ORIGIN_BEGIN); + writeByte(p, p->iProtocol); + writePow2(p, p->szPage); + writeUint32(p, p->nPage); + break; + } case REPLICA_ERROR: { readAndDisplayError(p); break; @@ -916,11 +965,13 @@ origin_end: ** Run the replica-side protocol. The protocol is passive in the sense ** that it only response to message from the origin side. ** -** ORIGIN_BEGIN nPage szPage +** ORIGIN_BEGIN idProtocol szPage nPage ** -** The origin is reporting the number of pages and the size of each -** pages. This procedure checks compatibility, and if everything is -** ok, it sends hash for all its extant pages. +** The origin is reporting the protocol version number, the size of +** each page in the origin database (sent as a single-byte power-of-2), +** and the number of pages in the origin database. +** This procedure checks compatibility, and if everything is ok, +** it starts sending hashes of pages already present back to the origin. ** ** ORIGIN_ERROR size text ** @@ -970,9 +1021,19 @@ static void replicaSide(SQLiteRsync *p){ sqlite3_stmt *pStmt = 0; closeDb(p); + p->iProtocol = readByte(p); + szOPage = readPow2(p); readUint32(p, &nOPage); - readUint32(p, &szOPage); if( p->nErr ) break; + if( p->iProtocol>PROTOCOL_VERSION ){ + /* If the protocol version on the origin side is larger, send back + ** a REPLICA_BEGIN message with the protocol version number of the + ** replica side. This gives the origin an opportunity to resend + ** a new ORIGIN_BEGIN with a reduced protocol version. */ + writeByte(p, REPLICA_BEGIN); + writeByte(p, PROTOCOL_VERSION); + break; + } p->nPage = nOPage; p->szPage = szOPage; rc = sqlite3_open(p->zReplica, &p->db); @@ -1003,6 +1064,8 @@ static void replicaSide(SQLiteRsync *p){ "replica is %d bytes", szOPage, szRPage); break; } + + pStmt = prepareStmt(p, "SELECT sha1b(data) FROM sqlite_dbpage" " WHERE pgno<=min(%d,%d)"