Skip to content

Commit c216e6e

Browse files
committed
recover intermediate
1 parent d694d82 commit c216e6e

File tree

3 files changed

+122
-20
lines changed

3 files changed

+122
-20
lines changed

src/test_ulog_sqlite.c

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ int test_multilevel(char *filename) {
152152

153153
struct tm *t;
154154
struct timeval tv;
155-
uls_write_init(&ctx);
155+
uls_write_init_with_script(&ctx, "tbl_test_log",
156+
"CREATE TABLE test_log (date_time TEXT, int_seq INTEGER, float_seq REAL, float_rand REAL, text_rand TEXT)");
156157

157158
int32_t ival;
158159
double d1, d2;
@@ -204,6 +205,7 @@ int test_multilevel(char *filename) {
204205
}
205206
if (uls_finalize(&ctx)) {
206207
printf("Error during finalize\n");
208+
fclose(fp);
207209
return -6;
208210
}
209211

@@ -270,6 +272,8 @@ void print_usage() {
270272
printf("test_ulog_sqlite -a <db_name.db> <page_size> <col_count> <csv_1> ... <csv_n>\n");
271273
printf(" Appends to a Sqlite database created using -c above\n");
272274
printf(" with records in CSV format (page_size and col_count have to match)\n\n");
275+
printf("test_ulog_sqlite -v <db_name.db>\n");
276+
printf(" Attempts to recover <db_name.db> if not finalized\n\n");
273277
printf("test_ulog_sqlite -r <db_name.db> <rowid>\n");
274278
printf(" Searches <db_name.db> for given row_id and prints result\n\n");
275279
printf("test_ulog_sqlite -b <db_name.db> <col_idx> <value>\n");
@@ -311,6 +315,10 @@ int add_col(struct uls_write_context *ctx, int col_idx, char *data, byte isInt,
311315
}
312316

313317
int append_records(int argc, char *argv[], struct uls_write_context *ctx) {
318+
if (uls_append_empty_row(ctx)) {
319+
printf("Error during add row\n");
320+
return -5;
321+
}
314322
for (int i = 5; i < argc; i++) {
315323
char *col_data = argv[i];
316324
char *chr = col_data;
@@ -388,10 +396,12 @@ int create_db(int argc, char *argv[]) {
388396
fp = fopen(argv[2], "w+b");
389397
if (fp == NULL) {
390398
perror ("Open Error:");
399+
fclose(fp);
391400
return -1;
392401
}
393402
if (uls_write_init(&ctx)) {
394403
printf("Error during init\n");
404+
fclose(fp);
395405
return -3;
396406
}
397407
int ret = append_records(argc, argv, &ctx);
@@ -425,17 +435,53 @@ int append_db(int argc, char *argv[]) {
425435
fp = fopen(argv[2], "w+b");
426436
if (fp == NULL) {
427437
perror ("Open Error:");
438+
fclose(fp);
428439
return -1;
429440
}
430441
if (uls_init_for_append(&ctx)) {
431442
printf("Error during init\n");
443+
fclose(fp);
432444
return -3;
433445
}
434446
int ret = append_records(argc, argv, &ctx);
435447
fclose(fp);
436448
return ret;
437449
}
438450

451+
int recover_db(int argc, char *argv[]) {
452+
byte initial_buf[72];
453+
struct uls_write_context ctx;
454+
ctx.buf = initial_buf;
455+
ctx.read_fn = read_fn;
456+
ctx.flush_fn = flush_fn;
457+
ctx.write_fn = write_fn;
458+
//fd = open(argv[2], O_RDWR | O_SYNC, S_IRUSR | S_IWUSR);
459+
//if (fd == -1) {
460+
// perror("Error");
461+
// return -2;
462+
//}
463+
fp = fopen(argv[2], "r+b");
464+
if (fp == NULL) {
465+
perror ("Open Error:");
466+
return -1;
467+
}
468+
int32_t page_size = uls_read_page_size(&ctx);
469+
if (page_size < 512) {
470+
printf("Error reading page size\n");
471+
fclose(fp);
472+
return -2;
473+
}
474+
byte buf[page_size];
475+
ctx.buf = buf;
476+
if (uls_recover(&ctx)) {
477+
printf("Error during recover\n");
478+
fclose(fp);
479+
return -3;
480+
}
481+
fclose(fp);
482+
return 0;
483+
}
484+
439485
int16_t read_int16(const byte *ptr) {
440486
return (*ptr << 8) | ptr[1];
441487
}
@@ -576,6 +622,7 @@ int bin_srch_db(int argc, char *argv[]) {
576622
}
577623
if (uls_read_init(&ctx)) {
578624
printf("Error during init\n");
625+
fclose(fp);
579626
return -3;
580627
}
581628
byte page_buf[1 << (ctx.page_size_exp == 1 ? 16 : ctx.page_size_exp)];
@@ -612,6 +659,7 @@ int read_db(int argc, char *argv[]) {
612659
}
613660
if (uls_read_init(&ctx)) {
614661
printf("Error during init\n");
662+
fclose(fp);
615663
return -3;
616664
}
617665
byte page_buf[1 << (ctx.page_size_exp == 1 ? 16 : ctx.page_size_exp)];
@@ -635,6 +683,9 @@ int main(int argc, char *argv[]) {
635683
if (argc > 4 && strcmp(argv[1], "-a") == 0) {
636684
append_db(argc, argv);
637685
} else
686+
if (argc == 3 && strcmp(argv[1], "-v") == 0) {
687+
recover_db(argc, argv);
688+
} else
638689
if (argc == 4 && strcmp(argv[1], "-r") == 0) {
639690
read_db(argc, argv);
640691
} else

src/ulog_sqlite.c

Lines changed: 60 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
- header checksum always checked
2+
- no. of records always less than last pos
3+
- optional to write and check page checksum
4+
- record length should not exceed remaining page size
5+
- column length should not exceed remaining record size
16
/*
27
Sqlite Micro Logger
38
@@ -34,6 +39,9 @@
3439
#define LEN_OF_HDR_LEN 2
3540
#define CHKSUM_LEN 3
3641

42+
enum {ULS_ST_NOT_FINAL = 0xA4, ULS_ST_WRITE_PENDING,
43+
ULS_ST_WRITING_IDX, ULS_ST_FINAL};
44+
3745
// Returns how many bytes the given integer will
3846
// occupy if stored as a variable integer
3947
int8_t get_vlen_of_uint16(uint16_t vint) {
@@ -687,7 +695,7 @@ int uls_append_row_with_values(struct uls_write_context *wctx,
687695
write_uint16(ptr + 3, rec_count);
688696
write_uint16(ptr + 5, last_pos);
689697
write_uint16(ptr + 8 - 2 + (rec_count * 2), last_pos);
690-
wctx->flush_flag = 0xA5;
698+
wctx->state = ULS_ST_WRITE_PENDING;
691699

692700
return ULS_RES_OK;
693701
}
@@ -711,7 +719,7 @@ int uls_append_empty_row(struct uls_write_context *wctx) {
711719
write_uint16(ptr + 3, rec_count);
712720
write_uint16(ptr + 5, last_pos);
713721
write_uint16(ptr + 8 - 2 + (rec_count * 2), last_pos);
714-
wctx->flush_flag = 0xA5;
722+
wctx->state = ULS_ST_WRITE_PENDING;
715723

716724
return ULS_RES_OK;
717725
}
@@ -788,7 +796,7 @@ int uls_set_col_val(struct uls_write_context *wctx,
788796
write_uint16(ptr + 5, new_last_pos);
789797
rec_count--;
790798
write_uint16(ptr + 8 + rec_count * 2, new_last_pos);
791-
wctx->flush_flag = 0xA5;
799+
wctx->state = ULS_ST_WRITE_PENDING;
792800

793801
return ULS_RES_OK;
794802
}
@@ -810,28 +818,42 @@ int uls_flush(struct uls_write_context *wctx) {
810818
return res;
811819
int ret = wctx->flush_fn(wctx);
812820
if (!ret)
813-
wctx->flush_flag = 0;
821+
wctx->state = ULS_ST_NOT_FINAL;
814822
return ret;
815823
}
816824

817825
// See .h file for API description
818826
int uls_partial_finalize(struct uls_write_context *wctx) {
819827
int32_t page_size = get_pagesize(wctx->page_size_exp);
820-
if (wctx->flush_flag == 0xA5) {
828+
if (wctx->state == ULS_ST_WRITE_PENDING) {
821829
uls_flush(wctx);
822-
wctx->flush_flag = 0xA5;
830+
wctx->state = ULS_ST_WRITE_PENDING;
823831
}
824832
int res = read_bytes_wctx(wctx, wctx->buf, 0, page_size);
825833
if (res)
826834
return res;
827835
if (memcmp(wctx->buf, sqlite_sig, 16) == 0)
828836
return ULS_RES_OK;
829-
// There was a flush just now, so update the last page in first page
830-
if (wctx->flush_flag == 0xA5) {
831-
write_uint32(wctx->buf + 60, wctx->cur_write_page);
832-
res = write_page(wctx, 0, page_size);
833-
if (res)
834-
return res;
837+
uint32_t last_leaf_page = read_uint32(wctx->buf + 60);
838+
// Update the last page no. in first page
839+
if (last_leaf_page == 0) {
840+
if (!wctx->cur_write_page) {
841+
byte head_buf[8];
842+
do {
843+
res = read_bytes_wctx(wctx, head_buf, (wctx->cur_write_page + 1) * page_size, 8);
844+
if (res)
845+
break;
846+
if (head_buf[0] == 13)
847+
wctx->cur_write_page++;
848+
} while (head_buf[0] == 13);
849+
}
850+
if (wctx->cur_write_page) {
851+
write_uint32(wctx->buf + 60, wctx->cur_write_page);
852+
res = write_page(wctx, 0, page_size);
853+
if (res)
854+
return res;
855+
} else
856+
return ULS_RES_MALFORMED;
835857
}
836858
return ULS_RES_OK;
837859
}
@@ -902,6 +924,31 @@ int uls_not_finalized(struct uls_write_context *wctx) {
902924
return ULS_RES_NOT_FINALIZED;
903925
}
904926

927+
int32_t uls_read_page_size(struct uls_write_context *wctx) {
928+
int res = read_bytes_wctx(wctx, wctx->buf, 0, 72);
929+
if (res)
930+
return res;
931+
if (check_signature(wctx->buf))
932+
return ULS_RES_INVALID_SIG;
933+
int32_t page_size = read_uint16(wctx->buf + 16);
934+
wctx->page_size_exp = get_page_size_exp(page_size);
935+
if (!wctx->page_size_exp)
936+
return ULS_RES_INVALID_SIG;
937+
if (page_size == 1)
938+
return 65536;
939+
return page_size;
940+
}
941+
942+
// See .h file for API description
943+
int uls_recover(struct uls_write_context *wctx) {
944+
wctx->state = ULS_ST_NOT_FINAL;
945+
wctx->cur_write_page = 0;
946+
int res = uls_finalize(wctx);
947+
if (res)
948+
return res;
949+
return ULS_RES_OK;
950+
}
951+
905952
// See .h file for API description
906953
int uls_init_for_append(struct uls_write_context *wctx) {
907954
int res = read_bytes_wctx(wctx, wctx->buf, 0, 72);
@@ -918,7 +965,6 @@ int uls_init_for_append(struct uls_write_context *wctx) {
918965
res = read_bytes_wctx(wctx, wctx->buf, 0, page_size);
919966
if (res)
920967
return res;
921-
wctx->flush_flag = 0;
922968
wctx->cur_write_page = read_uint32(wctx->buf + 60);
923969
if (wctx->cur_write_page == 0)
924970
return ULS_RES_NOT_FINALIZED;
@@ -933,9 +979,7 @@ int uls_init_for_append(struct uls_write_context *wctx) {
933979
res = read_bytes_wctx(wctx, wctx->buf, wctx->cur_write_page * page_size, page_size);
934980
if (res)
935981
return res;
936-
res = uls_append_empty_row(wctx);
937-
if (res)
938-
return res;
982+
wctx->state = ULS_ST_NOT_FINAL;
939983
return ULS_RES_OK;
940984
}
941985

src/ulog_sqlite.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ struct uls_write_context {
6464
// following are running values used internally
6565
uint32_t cur_write_page;
6666
uint32_t cur_write_rowid;
67-
byte flush_flag;
67+
byte state;
6868
int err_no;
6969
};
7070

@@ -113,8 +113,8 @@ const void *uls_get_col_val(struct uls_write_context *wctx, int col_idx, uint32_
113113
// this can be used
114114
int uls_flush(struct uls_write_context *wctx);
115115

116-
// Updates the last leaf page in the first page to enable
117-
// Binary Search
116+
// Flushes data written so far and Updates the last leaf page number
117+
// in the first page to enable Binary Search
118118
int uls_partial_finalize(struct uls_write_context *wctx);
119119

120120
// Based on the data written so far, forms Interior B-Tree pages
@@ -125,6 +125,13 @@ int uls_finalize(struct uls_write_context *wctx);
125125
// Returns 1 if the database is in unfinalized state
126126
int uls_not_finalized(struct uls_write_context *wctx);
127127

128+
// Reads page size from database if not known
129+
int32_t uls_read_page_size(struct uls_write_context *wctx);
130+
131+
// Recovers database pointed by given context
132+
// and finalizes it
133+
int uls_recover(struct uls_write_context *wctx);
134+
128135
// Read context to be passed to read from a database created using this library.
129136
// The running values need not be supplied
130137
struct uls_read_context {

0 commit comments

Comments
 (0)