aboutsummaryrefslogtreecommitdiff
path: root/tool/sqlite3_rsync.c
diff options
context:
space:
mode:
Diffstat (limited to 'tool/sqlite3_rsync.c')
-rw-r--r--tool/sqlite3_rsync.c113
1 files changed, 106 insertions, 7 deletions
diff --git a/tool/sqlite3_rsync.c b/tool/sqlite3_rsync.c
index 6fb365094..bf8a8dfb9 100644
--- a/tool/sqlite3_rsync.c
+++ b/tool/sqlite3_rsync.c
@@ -46,9 +46,11 @@ struct SQLiteRsync {
const char *zOrigin; /* Name of the origin */
const char *zReplica; /* Name of the replica */
const char *zErrFile; /* Append error messages to this file */
+ const char *zDebugFile; /* Append debugging messages to this file */
FILE *pOut; /* Transmit to the other side */
FILE *pIn; /* Receive from the other side */
FILE *pLog; /* Duplicate output here if not NULL */
+ FILE *pDebug; /* Write debug info here if not NULL */
sqlite3 *db; /* Database connection */
int nErr; /* Number of errors encountered */
int nWrErr; /* Number of failed attempts to write on the pipe */
@@ -70,7 +72,7 @@ struct SQLiteRsync {
/* The version number of the protocol. Sent in the *_BEGIN message
** to verify that both sides speak the same dialect.
*/
-#define PROTOCOL_VERSION 1
+#define PROTOCOL_VERSION 2
/* Magic numbers to identify particular messages sent over the wire.
@@ -882,6 +884,25 @@ static void logError(SQLiteRsync *p, const char *zFormat, ...){
p->nErr++;
}
+/*
+** Append text to the debugging mesage file, if an that file is
+** specified.
+*/
+static void debugMessage(SQLiteRsync *p, const char *zFormat, ...){
+ if( p->zDebugFile ){
+ if( p->pDebug==0 ){
+ p->pDebug = fopen(p->zDebugFile, "wb");
+ }
+ if( p->pDebug ){
+ va_list ap;
+ va_start(ap, zFormat);
+ vfprintf(p->pDebug, zFormat, ap);
+ va_end(ap);
+ fflush(p->pDebug);
+ }
+ }
+}
+
/* Read a single big-endian 32-bit unsigned integer from the input
** stream. Return 0 on success and 1 if there are any errors.
@@ -1334,12 +1355,19 @@ static void originSide(SQLiteRsync *p){
** a counter-proposal of an earlier protocol which the origin can
** accept by resending a new ORIGIN_BEGIN. */
u8 newProtocol = readByte(p);
+ if( p->zDebugFile ){
+ debugMessage(p, "<- REPLICA_BEGIN %d\n", (int)newProtocol);
+ }
if( newProtocol < p->iProtocol ){
p->iProtocol = newProtocol;
writeByte(p, ORIGIN_BEGIN);
writeByte(p, p->iProtocol);
writePow2(p, p->szPage);
writeUint32(p, p->nPage);
+ if( p->zDebugFile ){
+ debugMessage(p, "-> ORIGIN_BEGIN %d %d %u\n", p->iProtocol,
+ p->szPage, p->nPage);
+ }
}else{
reportError(p, "Invalid REPLICA_BEGIN reply");
}
@@ -1353,6 +1381,9 @@ static void originSide(SQLiteRsync *p){
case REPLICA_CONFIG: {
readUint32(p, &iHash);
readUint32(p, &nHash);
+ if( p->zDebugFile ){
+ debugMessage(p, "<- REPLICA_CONFIG %u %u\n", iHash, nHash);
+ }
break;
}
case REPLICA_HASH: {
@@ -1369,14 +1400,17 @@ static void originSide(SQLiteRsync *p){
if( pInsHash==0 ) break;
}
p->nHashSent++;
+ if( p->zDebugFile ){
+ debugMessage(p, "<- REPLICA_HASH %u %u\n", iHash, nHash);
+ }
if( nHash>1 ){
if( pCkHashN==0 ){
pCkHashN = prepareStmt(p,
"WITH a1(pgno) AS "
"(VALUES(?1) UNION ALL SELECT pgno+1 FROM a1 WHERE pgno<?2)"
- "SELECT 1 FROM a1 CROSS JOIN sqlite_dbpage('main')"
+ "SELECT count(*) FROM a1 CROSS JOIN sqlite_dbpage('main')"
" USING(pgno)"
- " WHERE agghash(hash(data))!=?3");
+ " HAVING agghash(hash(data))!=?3");
if( pCkHashN==0 ) break;
}
sqlite3_bind_int64(pCkHashN, 1, iHash);
@@ -1415,19 +1449,28 @@ static void originSide(SQLiteRsync *p){
break;
}
case REPLICA_READY: {
+ if( p->zDebugFile ){
+ debugMessage(p, "<- REPLICA_READY\n");
+ }
if( nMulti>0 ){
sqlite3_stmt *pStmt;
pStmt = prepareStmt(p,"SELECT pgno, sz FROM badHash WHERE sz>1");
if( pStmt==0 ) break;
while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ unsigned int pgno = (unsigned int)sqlite3_column_int64(pStmt,0);
+ unsigned int cnt = (unsigned int)sqlite3_column_int64(pStmt,1);
writeByte(p, ORIGIN_DETAIL);
- writeUint32(p, sqlite3_column_int(pStmt, 0));
- writeUint32(p, sqlite3_column_int(pStmt, 1));
+ writeUint32(p, pgno);
+ writeUint32(p, cnt);
+ if( p->zDebugFile ){
+ debugMessage(p, "-> ORIGIN_DETAIL %u %u\n", pgno, cnt);
+ }
}
sqlite3_finalize(pStmt);
runSql(p, "DELETE FROM badHash WHERE sz>1");
nMulti = 0;
writeByte(p, ORIGIN_READY);
+ if( p->zDebugFile ) debugMessage(p, "-> ORIGIN_READY\n");
}else{
sqlite3_stmt *pStmt;
sqlite3_finalize(pCkHash);
@@ -1456,10 +1499,16 @@ static void originSide(SQLiteRsync *p){
writeUint32(p, pgno);
writeBytes(p, szPg, pContent);
p->nPageSent++;
+ if( p->zDebugFile ){
+ debugMessage(p, "-> ORIGIN_PAGE %u\n", pgno);
+ }
}
sqlite3_finalize(pStmt);
writeByte(p, ORIGIN_TXN);
writeUint32(p, nPage);
+ if( p->zDebugFile ){
+ debugMessage(p, "-> ORIGIN_TXN %u\n", nPage);
+ }
writeByte(p, ORIGIN_END);
}
fflush(p->pOut);
@@ -1517,9 +1566,13 @@ static void sendHashMessages(
writeByte(p, REPLICA_CONFIG);
writeUint32(p, pgno);
writeUint32(p, npg);
+ if( p->zDebugFile ){
+ debugMessage(p, "-> REPLICA_CONFIG %u %u\n", pgno, npg);
+ }
}
writeByte(p, REPLICA_HASH);
writeBytes(p, 20, a);
+ if( p->zDebugFile ) debugMessage(p, "-> REPLICA_HASH %u\n", iHash);
p->nHashSent++;
iHash = pgno + npg;
nHash = npg;
@@ -1528,6 +1581,7 @@ static void sendHashMessages(
runSql(p, "DELETE FROM sendHash");
writeByte(p, REPLICA_READY);
fflush(p->pOut);
+ if( p->zDebugFile ) debugMessage(p, "-> REPLICA_READY\n", iHash);
}
/*
@@ -1555,8 +1609,8 @@ static void subdivideHashRange(
"WITH RECURSIVE c(n) AS"
" (VALUES(%u) UNION ALL SELECT n+%u FROM c WHERE n<%llu)"
"REPLACE INTO sendHash(fpg,npg)"
- " SELECT n, min(%llu-fpg,%u) FROM c",
- fpg, nChunk, iEnd, iEnd, nChunk
+ " SELECT n, min(%llu-n,%u) FROM c",
+ fpg, nChunk, iEnd-nChunk, iEnd, nChunk
);
}
@@ -1643,6 +1697,10 @@ static void replicaSide(SQLiteRsync *p){
p->iProtocol = readByte(p);
szOPage = readPow2(p);
readUint32(p, &nOPage);
+ if( p->zDebugFile ){
+ debugMessage(p, "<- ORIGIN_BEGIN %d %d %u\n", p->iProtocol, szOPage,
+ nOPage);
+ }
if( p->nErr ) break;
if( p->iProtocol>PROTOCOL_VERSION ){
/* If the protocol version on the origin side is larger, send back
@@ -1651,6 +1709,9 @@ static void replicaSide(SQLiteRsync *p){
** a new ORIGIN_BEGIN with a reduced protocol version. */
writeByte(p, REPLICA_BEGIN);
writeByte(p, PROTOCOL_VERSION);
+ if( p->zDebugFile ){
+ debugMessage(p, "-> REPLICA_BEGIN %u\n", PROTOCOL_VERSION);
+ }
break;
}
p->nPage = nOPage;
@@ -1726,16 +1787,25 @@ static void replicaSide(SQLiteRsync *p){
unsigned int fpg, npg;
readUint32(p, &fpg);
readUint32(p, &npg);
+ if( p->zDebugFile ){
+ debugMessage(p, "<- ORIGIN_DETAIL %u %u\n", fpg, npg);
+ }
subdivideHashRange(p, fpg, npg);
break;
}
case ORIGIN_READY: {
+ if( p->zDebugFile ){
+ debugMessage(p, "<- ORIGIN_READY\n");
+ }
sendHashMessages(p, 0, 0);
break;
}
case ORIGIN_TXN: {
unsigned int nOPage = 0;
readUint32(p, &nOPage);
+ if( p->zDebugFile ){
+ debugMessage(p, "<- ORIGIN_TXN %u\n", nOPage);
+ }
if( pIns==0 ){
/* Nothing has changed */
runSql(p, "COMMIT");
@@ -1763,6 +1833,9 @@ static void replicaSide(SQLiteRsync *p){
unsigned int pgno = 0;
int rc;
readUint32(p, &pgno);
+ if( p->zDebugFile ){
+ debugMessage(p, "<- ORIGIN_PAGE %u\n", pgno);
+ }
if( p->nErr ) break;
if( pIns==0 ){
pIns = prepareStmt(p,
@@ -1910,6 +1983,7 @@ int main(int argc, char const * const *argv){
sqlite3_int64 tmEnd;
sqlite3_int64 tmElapse;
const char *zRemoteErrFile = 0;
+ const char *zRemoteDebugFile = 0;
#define cli_opt_val cmdline_option_value(argc, argv, ++i)
memset(&ctx, 0, sizeof(ctx));
@@ -1961,6 +2035,19 @@ int main(int argc, char const * const *argv){
zRemoteErrFile = cli_opt_val;
continue;
}
+ if( strcmp(z, "-debugfile")==0 ){
+ /* DEBUG OPTION: --debugfile FILENAME
+ ** Debugging messages on the local side are written into FILENAME */
+ ctx.zDebugFile = cli_opt_val;
+ continue;
+ }
+ if( strcmp(z, "-remote-debugfile")==0 ){
+ /* DEBUG OPTION: --remote-debugfile FILENAME
+ ** Error messages on the remote side are written into FILENAME on
+ ** the remote side. */
+ zRemoteDebugFile = cli_opt_val;
+ continue;
+ }
if( strcmp(z, "-wal-only")==0 ){
ctx.bWalOnly = 1;
continue;
@@ -2070,6 +2157,10 @@ int main(int argc, char const * const *argv){
append_escaped_arg(pStr, "--errorfile", 0);
append_escaped_arg(pStr, zRemoteErrFile, 1);
}
+ if( zRemoteDebugFile ){
+ append_escaped_arg(pStr, "--debugfile", 0);
+ append_escaped_arg(pStr, zRemoteDebugFile, 1);
+ }
if( ctx.bWalOnly ){
append_escaped_arg(pStr, "--wal-only", 0);
}
@@ -2099,6 +2190,10 @@ int main(int argc, char const * const *argv){
append_escaped_arg(pStr, "--errorfile", 0);
append_escaped_arg(pStr, zRemoteErrFile, 1);
}
+ if( zRemoteDebugFile ){
+ append_escaped_arg(pStr, "--debugfile", 0);
+ append_escaped_arg(pStr, zRemoteDebugFile, 1);
+ }
append_escaped_arg(pStr, file_tail(ctx.zOrigin), 1);
append_escaped_arg(pStr, zDiv, 1);
zCmd = sqlite3_str_finish(pStr);
@@ -2120,6 +2215,10 @@ int main(int argc, char const * const *argv){
append_escaped_arg(pStr, "--errorfile", 0);
append_escaped_arg(pStr, zRemoteErrFile, 1);
}
+ if( zRemoteDebugFile ){
+ append_escaped_arg(pStr, "--debugfile", 0);
+ append_escaped_arg(pStr, zRemoteDebugFile, 1);
+ }
append_escaped_arg(pStr, ctx.zOrigin, 1);
append_escaped_arg(pStr, ctx.zReplica, 1);
zCmd = sqlite3_str_finish(pStr);