11#include <sqlite3.h>
22#include <stdio.h>
3+ #include <stdlib.h>
4+ #include <stdint.h>
35#include <string.h>
46#include <assert.h>
57
8+ #define eprintf (...) fprintf(stderr, __VA_ARGS__)
9+ #define ensure (condition , ...) { if (!(condition)) { eprintf(__VA_ARGS__); exit(1); } }
10+
611#if 0
712static void dump_frame (unsigned char * frame , size_t size ){
813 for (int addr = 0 ; addr < size ; addr += 16 ){
@@ -26,140 +31,100 @@ static void dump_frame(unsigned char *frame, size_t size){
2631}
2732#endif
2833
29- static int cmp_data (sqlite3 * db1 , sqlite3 * db2 ){
34+ static void cmp_data (sqlite3 * db1 , sqlite3 * db2 ){
3035 sqlite3_stmt * stmt1 , * stmt2 ;
31- int rc ;
32-
33- rc = sqlite3_prepare_v2 (db1 , "SELECT HEX(x) FROM t" , -1 , & stmt1 , 0 );
34- if ( rc != SQLITE_OK ){
35- fprintf (stderr , "Can't prepare statement: %s\n" , sqlite3_errmsg (db1 ));
36- return 1 ;
37- }
38-
39- rc = sqlite3_prepare_v2 (db2 , "SELECT HEX(x) FROM t" , -1 , & stmt2 , 0 );
40- if ( rc != SQLITE_OK ){
41- fprintf (stderr , "Can't prepare statement: %s\n" , sqlite3_errmsg (db2 ));
42- return 1 ;
43- }
36+ ensure (sqlite3_prepare_v2 (db1 , "SELECT HEX(x) FROM t" , -1 , & stmt1 , 0 ) == SQLITE_OK , "can't prepare statement: %s\n" , sqlite3_errmsg (db1 ));
37+ ensure (sqlite3_prepare_v2 (db2 , "SELECT HEX(x) FROM t" , -1 , & stmt2 , 0 ) == SQLITE_OK , "can't prepare statement: %s\n" , sqlite3_errmsg (db2 ));
4438
4539 for (;;){
4640 int step1 = sqlite3_step (stmt1 );
4741 int step2 = sqlite3_step (stmt2 );
48- if ( step1 != step2 ){
49- fprintf (stderr , "Step mismatch: %d != %d\n" , step1 , step2 );
50- return 1 ;
51- }
42+ ensure (step1 == step2 , "step mismatch: %d != %d\n" , step1 , step2 );
5243 if ( step1 != SQLITE_ROW ){
5344 break ;
5445 }
5546 const unsigned char * text1 = sqlite3_column_text (stmt1 , 0 );
5647 const unsigned char * text2 = sqlite3_column_text (stmt2 , 0 );
57- if ( strncmp ((const char * )text1 , (const char * )text2 , 4096 )!= 0 ){
58- fprintf (stderr , "Data mismatch\n" );
59- return 1 ;
60- }
48+ ensure (strncmp ((const char * )text1 , (const char * )text2 , 4096 ) == 0 , "data mismatch" );
6149 }
62- return 0 ;
6350}
6451
65- static int sync_db (sqlite3 * db_primary , sqlite3 * db_backup ){
52+ static void sync_db (sqlite3 * db_primary , sqlite3 * db_backup ){
6653 unsigned int max_frame ;
67- int rc ;
68-
69- rc = libsql_wal_frame_count (db_primary , & max_frame );
70- if ( rc != SQLITE_OK ){
71- fprintf (stderr , "Can't get frame count: %s\n" , sqlite3_errmsg (db_primary ));
72- return 1 ;
73- }
74- rc = libsql_wal_insert_begin (db_backup );
75- if ( rc != SQLITE_OK ){
76- fprintf (stderr , "Can't begin commit: %s\n" , sqlite3_errmsg (db_backup ));
77- return 1 ;
78- }
54+ ensure (libsql_wal_frame_count (db_primary , & max_frame ) == SQLITE_OK , "can't get frame count: %s\n" , sqlite3_errmsg (db_primary ));
55+ ensure (libsql_wal_insert_begin (db_backup ) == SQLITE_OK , "can't begin commit: %s\n" , sqlite3_errmsg (db_backup ));
7956 for (int i = 1 ; i <=max_frame ; i ++ ){
8057 char frame [4096 + 24 ];
81- rc = libsql_wal_get_frame (db_primary , i , frame , sizeof (frame ));
82- if ( rc != SQLITE_OK ){
83- fprintf (stderr , "Can't get frame: %s\n" , sqlite3_errmsg (db_primary ));
84- return 1 ;
85- }
86- rc = libsql_wal_insert_frame (db_backup , i , frame , sizeof (frame ));
87- if ( rc != SQLITE_OK ){
88- fprintf (stderr , "Can't inject frame %d: %s\n" , rc , sqlite3_errmsg (db_backup ));
89- return 1 ;
90- }
91- }
92- rc = libsql_wal_insert_end (db_backup );
93- if ( rc != SQLITE_OK ){
94- fprintf (stderr , "Can't end commit: %s\n" , sqlite3_errmsg (db_backup ));
95- return 1 ;
58+ ensure (libsql_wal_get_frame (db_primary , i , frame , sizeof (frame )) == SQLITE_OK , "can't get frame: %s\n" , sqlite3_errmsg (db_primary ));
59+ ensure (libsql_wal_insert_frame (db_backup , i , frame , sizeof (frame )) == SQLITE_OK , "can't inject frame: %s\n" , sqlite3_errmsg (db_backup ));
9660 }
97- return 0 ;
98- }
99-
100- static void gen_data (sqlite3 * db ){
101- sqlite3_exec (db , "CREATE TABLE t (x)" , 0 , 0 , 0 );
102- sqlite3_exec (db , "INSERT INTO t VALUES (randomblob(4 * 1024))" , 0 , 0 , 0 );
103- sqlite3_exec (db , "INSERT INTO t VALUES (randomblob(1 * 1024))" , 0 , 0 , 0 );
104- sqlite3_exec (db , "INSERT INTO t VALUES (randomblob(1 * 1024))" , 0 , 0 , 0 );
61+ ensure (libsql_wal_insert_end (db_backup ) == SQLITE_OK , "can't end commit: %s\n" , sqlite3_errmsg (db_backup ));
10562}
10663
107- int open_db (const char * path , sqlite3 * * db ) {
108- int rc ;
109-
110- rc = sqlite3_open (path , db );
111- if (rc != SQLITE_OK ) {
112- fprintf (stderr , "Can't open database %s: %s\n" , path , sqlite3_errmsg (* db ));
113- return rc ;
114- }
115- rc = sqlite3_exec (* db , "PRAGMA journal_mode=WAL" , NULL , NULL , NULL );
116- if (rc != SQLITE_OK ) {
117- fprintf (stderr , "Can't set journal mode for %s: %s\n" , path , sqlite3_errmsg (* db ));
118- return rc ;
119- }
120- rc = sqlite3_wal_autocheckpoint (* db , 0 );
121- if (rc != SQLITE_OK ) {
122- fprintf (stderr , "Can't disable checkpointing for %s: %s\n" , path , sqlite3_errmsg (* db ));
123- return rc ;
124- }
125- return rc ;
64+ void open_db (const char * path , sqlite3 * * db ) {
65+ ensure (sqlite3_open (path , db ) == SQLITE_OK , "can't open database %s: %s\n" , path , sqlite3_errmsg (* db ));
66+ ensure (sqlite3_exec (* db , "PRAGMA journal_mode=WAL" , NULL , NULL , NULL ) == SQLITE_OK , "can't set journal mode for %s: %s\n" , path , sqlite3_errmsg (* db ));
67+ ensure (sqlite3_wal_autocheckpoint (* db , 0 ) == SQLITE_OK , "can't disable checkpointing for %s: %s\n" , path , sqlite3_errmsg (* db ));
12668}
12769
128- int main (int argc , char * argv [])
129- {
70+ void test_huge_payload () {
13071 sqlite3 * db_primary , * db_backup ;
13172 unsigned int max_frame ;
132- int rc ;
133-
134- rc = open_db ("primary.db" , & db_primary );
135- if (rc != SQLITE_OK ) {
136- return 1 ;
137- }
138- gen_data (db_primary );
139-
140- rc = open_db ("backup.db" , & db_backup );
141- if (rc != SQLITE_OK ) {
142- return 1 ;
143- }
144- rc = libsql_wal_frame_count (db_backup , & max_frame );
145- if (rc != SQLITE_OK ) {
146- fprintf (stderr , "Can't get frame count for backup: %s\n" , sqlite3_errmsg (db_backup ));
147- return 1 ;
148- }
73+ open_db ("primary_test_huge_payload.db" , & db_primary );
74+ ensure (sqlite3_exec (db_primary , "CREATE TABLE t (x)" , 0 , 0 , 0 ) == SQLITE_OK , "failed to insert data\n" );
75+ ensure (sqlite3_exec (db_primary , "INSERT INTO t VALUES (randomblob(4 * 1024))" , 0 , 0 , 0 ) == SQLITE_OK , "failed to insert data\n" );
76+ ensure (sqlite3_exec (db_primary , "INSERT INTO t VALUES (randomblob(1 * 1024))" , 0 , 0 , 0 ) == SQLITE_OK , "failed to insert data\n" );
77+ ensure (sqlite3_exec (db_primary , "INSERT INTO t VALUES (randomblob(1 * 1024))" , 0 , 0 , 0 ) == SQLITE_OK , "failed to insert data\n" );
78+
79+ open_db ("backup_test_huge_payload.db" , & db_backup );
80+ ensure (libsql_wal_frame_count (db_backup , & max_frame ) == SQLITE_OK , "failed to get frames count: %s\n" , sqlite3_errmsg (db_backup ));
14981 assert (max_frame == 0 );
15082
83+ eprintf ("start full sync\n" );
15184 sync_db (db_primary , db_backup );
152-
153- if (cmp_data (db_primary , db_backup )) {
154- return 1 ;
155- }
156-
85+ cmp_data (db_primary , db_backup );
15786 sync_db (db_primary , db_backup );
158- if (cmp_data (db_primary , db_backup )) {
159- return 1 ;
87+ cmp_data (db_primary , db_backup );
88+ }
89+
90+ void test_sync_by_parts () {
91+ sqlite3 * db_primary , * db_backup ;
92+ unsigned int max_frame ;
93+ uint32_t in_commit = 0 ;
94+ open_db ("primary_test_sync_by_parts.db" , & db_primary );
95+ ensure (sqlite3_exec (db_primary , "CREATE TABLE t (x)" , 0 , 0 , 0 ) == SQLITE_OK , "failed to insert data\n" );
96+ ensure (sqlite3_exec (db_primary , "INSERT INTO t VALUES (randomblob(4 * 1024))" , 0 , 0 , 0 ) == SQLITE_OK , "failed to insert data\n" );
97+ ensure (sqlite3_exec (db_primary , "INSERT INTO t VALUES (randomblob(1 * 1024))" , 0 , 0 , 0 ) == SQLITE_OK , "failed to insert data\n" );
98+ ensure (sqlite3_exec (db_primary , "INSERT INTO t VALUES (randomblob(1 * 1024))" , 0 , 0 , 0 ) == SQLITE_OK , "failed to insert data\n" );
99+
100+ open_db ("backup_test_sync_by_parts.db" , & db_backup );
101+
102+ ensure (libsql_wal_frame_count (db_primary , & max_frame ) == SQLITE_OK , "can't get frame count: %s\n" , sqlite3_errmsg (db_primary ));
103+ eprintf ("start sync by parts\n" );
104+ for (int i = 1 ; i <=max_frame ; i ++ ){
105+ char frame [4096 + 24 ];
106+ uint32_t is_commit ;
107+ ensure (libsql_wal_get_frame (db_primary , i , frame , sizeof (frame )) == SQLITE_OK , "can't get frame: %s\n" , sqlite3_errmsg (db_primary ));
108+ is_commit = ((uint32_t )frame [4 ] << 24 ) + ((uint32_t )frame [5 ] << 16 ) + ((uint32_t )frame [6 ] << 8 ) + ((uint32_t )frame [7 ] << 0 );
109+ if (!in_commit ) {
110+ in_commit = 1 ;
111+ ensure (libsql_wal_insert_begin (db_backup ) == SQLITE_OK , "can't begin commit: %s\n" , sqlite3_errmsg (db_backup ));
112+ }
113+ ensure (libsql_wal_insert_frame (db_backup , i , frame , sizeof (frame )) == SQLITE_OK , "can't inject frame: %s\n" , sqlite3_errmsg (db_backup ));
114+ if (is_commit ) {
115+ ensure (libsql_wal_insert_end (db_backup ) == SQLITE_OK , "can't end commit: %s\n" , sqlite3_errmsg (db_backup ));
116+ in_commit = 0 ;
117+ }
160118 }
119+ cmp_data (db_primary , db_backup );
120+ }
161121
162- printf ("OK\n" );
122+ int main (int argc , char * argv [])
123+ {
124+ test_huge_payload ();
125+ printf ("============= OK test_huge_payload\n" );
163126
127+ test_sync_by_parts ();
128+ printf ("============= OK test_sync_by_parts\n" );
164129 return 0 ;
165130}
0 commit comments