/* * sophia database * sphia.org * * Copyright (c) Dmitry Simonenko * BSD License */ #include #include #include #include #include "test.h" static char *dbrep = "./rep"; static spa a; static inline int cmp(char *a, size_t asz, char *b, size_t bsz, void *arg) { register uint32_t av = *(uint32_t*)a; register uint32_t bv = *(uint32_t*)b; if (av == bv) return 0; return (av > bv) ? 1 : -1; } static void log_empty(void) { spfile f; sp_fileinit(&f, &a); t( mkdir(dbrep, 0755) == 0 ); t( sp_lognew(&f, dbrep, 1) == 0 ); t( sp_logcomplete(&f) == 0 ); t( sp_logclose(&f) == 0 ); t( exists(dbrep, 1, "log") == 1 ); void *env = sp_env(); t( env != NULL ); t( sp_ctl(env, SPDIR, SPO_CREAT|SPO_RDWR, dbrep) == 0 ); t( sp_ctl(env, SPCMP, cmp, NULL) == 0 ); t( sp_ctl(env, SPMERGE, 0) == 0 ); void *db = sp_open(env); t( db == NULL ); t( sp_error(env) != NULL ); t( sp_destroy(env) == 0 ); t( rmrf(dbrep) == 0 ); } static void log_empty_incomplete(void) { spfile f; sp_fileinit(&f, &a); t( mkdir(dbrep, 0755) == 0 ); t( sp_lognew(&f, dbrep, 1) == 0 ); t( sp_logclose(&f) == 0 ); t( exists(dbrep, 1, "log.incomplete") == 1 ); void *env = sp_env(); t( env != NULL ); t( sp_ctl(env, SPDIR, SPO_CREAT|SPO_RDWR, dbrep) == 0 ); t( sp_ctl(env, SPCMP, cmp, NULL) == 0 ); t( sp_ctl(env, SPMERGE, 0) == 0 ); void *db = sp_open(env); t( db == NULL ); t( sp_error(env) != NULL ); t( sp_destroy(env) == 0 ); t( rmrf(dbrep) == 0 ); } static void log_badrecord(void) { uint32_t k = 123; splogh h = { .magic = SPMAGIC, .version[0] = SP_VERSION_MAJOR, .version[1] = SP_VERSION_MINOR }; spvh vh = { .crc = 0, .size = sizeof(uint32_t), .voffset = 0, .vsize = sizeof(uint32_t), .flags = SPSET }; speofh eof = { SPEOF }; spfile f; spbatch b; sp_fileinit(&f, &a); sp_batchinit(&b); t( mkdir(dbrep, 0755) == 0 ); t( sp_lognew(&f, dbrep, 1) == 0 ); sp_batchadd(&b, &h, sizeof(h)); sp_batchadd(&b, &vh, sizeof(vh)); sp_batchadd(&b, &k, sizeof(k)); sp_batchadd(&b, &k, sizeof(k)); sp_batchadd(&b, &eof, sizeof(eof)); t( sp_logput(&f, &b) == 0 ); t( sp_logcomplete(&f) == 0 ); t( sp_logclose(&f) == 0 ); t( exists(dbrep, 1, "log") == 1 ); void *env = sp_env(); t( env != NULL ); t( sp_ctl(env, SPDIR, SPO_CREAT|SPO_RDWR, dbrep) == 0 ); t( sp_ctl(env, SPCMP, cmp, NULL) == 0 ); t( sp_ctl(env, SPMERGE, 0) == 0 ); void *db = sp_open(env); t( db == NULL ); t( sp_error(env) != NULL ); t( sp_destroy(env) == 0 ); t( rmrf(dbrep) == 0 ); } static void log_badrecord_incomplete(void) { uint32_t k = 123; splogh h = { .magic = SPMAGIC, .version[0] = SP_VERSION_MAJOR, .version[1] = SP_VERSION_MINOR }; spvh vh = { .crc = 0, .size = sizeof(uint32_t), .voffset = 0, .vsize = sizeof(uint32_t), .flags = SPSET }; speofh eof = { SPEOF }; spfile f; spbatch b; sp_fileinit(&f, &a); sp_batchinit(&b); t( mkdir(dbrep, 0755) == 0 ); t( sp_lognew(&f, dbrep, 1) == 0 ); sp_batchadd(&b, &h, sizeof(h)); sp_batchadd(&b, &vh, sizeof(vh)); sp_batchadd(&b, &k, sizeof(k)); sp_batchadd(&b, &k, sizeof(k)); sp_batchadd(&b, &eof, sizeof(eof)); t( sp_logput(&f, &b) == 0 ); t( sp_logclose(&f) == 0 ); t( exists(dbrep, 1, "log.incomplete") == 1 ); void *env = sp_env(); t( env != NULL ); t( sp_ctl(env, SPDIR, SPO_CREAT|SPO_RDWR, dbrep) == 0 ); t( sp_ctl(env, SPCMP, cmp, NULL) == 0 ); t( sp_ctl(env, SPMERGE, 0) == 0 ); void *db = sp_open(env); t( db == NULL ); t( sp_error(env) != NULL ); t( sp_destroy(env) == 0 ); t( exists(dbrep, 1, "log.incomplete") == 1 ); t( rmrf(dbrep) == 0 ); } static void log_1_badrecord_2_goodrecord(void) { uint32_t k = 123; void *env = sp_env(); t( env != NULL ); t( sp_ctl(env, SPDIR, SPO_CREAT|SPO_RDWR, dbrep) == 0 ); t( sp_ctl(env, SPCMP, cmp, NULL) == 0 ); t( sp_ctl(env, SPMERGE, 0) == 0 ); void *db = sp_open(env); t( db != NULL ); t( sp_set(db, &k, sizeof(k), &k, sizeof(k)) == 0 ); t( sp_destroy(db) == 0 ); t( exists(dbrep, 1, "log") == 1 ); splogh h = { .magic = SPMAGIC, .version[0] = SP_VERSION_MAJOR, .version[1] = SP_VERSION_MINOR }; spvh vh = { .crc = 0, .size = sizeof(uint32_t), .voffset = 0, .vsize = sizeof(uint32_t), .flags = SPSET }; speofh eof = { SPEOF }; spfile f; spbatch b; sp_batchinit(&b); sp_fileinit(&f, &a); t( sp_lognew(&f, dbrep, 2) == 0 ); sp_batchadd(&b, &h, sizeof(h)); sp_batchadd(&b, &vh, sizeof(vh)); sp_batchadd(&b, &k, sizeof(k)); sp_batchadd(&b, &k, sizeof(k)); sp_batchadd(&b, &eof, sizeof(eof)); t( sp_logput(&f, &b) == 0 ); t( sp_logcomplete(&f) == 0 ); t( sp_logclose(&f) == 0 ); t( exists(dbrep, 2, "log") == 1 ); db = sp_open(env); t( db == NULL ); t( sp_destroy(env) == 0 ); t( exists(dbrep, 1, "log") == 1 ); t( exists(dbrep, 2, "log") == 1 ); t( rmrf(dbrep) == 0 ); } static void log_noeof(void) { uint32_t k = 123; splogh h = { .magic = SPMAGIC, .version[0] = SP_VERSION_MAJOR, .version[1] = SP_VERSION_MINOR }; spvh vh = { .crc = 0, .size = sizeof(uint32_t), .voffset = 0, .vsize = sizeof(uint32_t), .flags = SPSET }; uint32_t crc; crc = sp_crc32c(0, &k, sizeof(k)); crc = sp_crc32c(crc, &k, sizeof(k)); vh.crc = sp_crc32c(crc, &vh.size, sizeof(spvh) - sizeof(uint32_t)); spfile f; spbatch b; sp_batchinit(&b); sp_fileinit(&f, &a); t( mkdir(dbrep, 0755) == 0 ); t( sp_lognew(&f, dbrep, 1) == 0 ); sp_batchadd(&b, &h, sizeof(h)); sp_batchadd(&b, &vh, sizeof(vh)); sp_batchadd(&b, &k, sizeof(k)); sp_batchadd(&b, &k, sizeof(k)); t( sp_logput(&f, &b) == 0 ); t( sp_logclose(&f) == 0 ); t( exists(dbrep, 1, "log.incomplete") == 1 ); void *env = sp_env(); t( env != NULL ); t( sp_ctl(env, SPDIR, SPO_CREAT|SPO_RDWR, dbrep) == 0 ); t( sp_ctl(env, SPCMP, cmp, NULL) == 0 ); t( sp_ctl(env, SPMERGE, 0) == 0 ); void *db = sp_open(env); t( db != NULL ); size_t vsize = 0; void *vp = NULL; t( sp_get(db, &k, sizeof(k), &vp, &vsize) == 1 ); t( vsize == sizeof(k) ); t( *(uint32_t*)vp == k ); free(vp); t( sp_destroy(db) == 0 ); t( sp_destroy(env) == 0 ); t( rmrf(dbrep) == 0 ); } static void log_noeof_complete(void) { uint32_t k = 123; splogh h = { .magic = SPMAGIC, .version[0] = SP_VERSION_MAJOR, .version[1] = SP_VERSION_MINOR }; spvh vh = { .crc = 0, .size = sizeof(uint32_t), .voffset = 0, .vsize = sizeof(uint32_t), .flags = SPSET }; uint32_t crc; crc = sp_crc32c(0, &k, sizeof(k)); crc = sp_crc32c(crc, &k, sizeof(k)); vh.crc = sp_crc32c(crc, &vh.size, sizeof(spvh) - sizeof(uint32_t)); spfile f; spbatch b; sp_batchinit(&b); sp_fileinit(&f, &a); sp_batchinit(&b); t( mkdir(dbrep, 0755) == 0 ); t( sp_lognew(&f, dbrep, 1) == 0 ); sp_batchadd(&b, &h, sizeof(h)); sp_batchadd(&b, &vh, sizeof(vh)); sp_batchadd(&b, &k, sizeof(k)); sp_batchadd(&b, &k, sizeof(k)); t( sp_logput(&f, &b) == 0 ); t( sp_logcomplete(&f) == 0 ); t( sp_logclose(&f) == 0 ); t( exists(dbrep, 1, "log") == 1 ); void *env = sp_env(); t( env != NULL ); t( sp_ctl(env, SPDIR, SPO_CREAT|SPO_RDWR, dbrep) == 0 ); t( sp_ctl(env, SPCMP, cmp, NULL) == 0 ); t( sp_ctl(env, SPMERGE, 0) == 0 ); void *db = sp_open(env); t( db == NULL ); t( sp_error(env) != NULL ); t( sp_destroy(env) == 0 ); t( rmrf(dbrep) == 0 ); } static void db_empty(void) { spfile f; sp_fileinit(&f, &a); t( mkdir(dbrep, 0755) == 0 ); char path[1024]; snprintf(path, sizeof(path), "%s/%"PRIu32".db", dbrep, 1); int fd = open(path, O_CREAT|O_RDWR, 0644); t( fd != -1 ); t( close(fd) == 0 ); void *env = sp_env(); t( env != NULL ); t( sp_ctl(env, SPDIR, SPO_CREAT|SPO_RDWR, dbrep) == 0 ); t( sp_ctl(env, SPCMP, cmp, NULL) == 0 ); t( sp_ctl(env, SPMERGE, 0) == 0 ); void *db = sp_open(env); t( db == NULL ); t( sp_error(env) != NULL ); t( exists(dbrep, 1, "db") == 1 ); t( sp_destroy(env) == 0 ); t( rmrf(dbrep) == 0 ); } static void db_empty_incomplete(void) { spfile f; sp_fileinit(&f, &a); t( mkdir(dbrep, 0755) == 0 ); char path[1024]; snprintf(path, sizeof(path), "%s/%"PRIu32".db.incomplete", dbrep, 1); int fd = open(path, O_CREAT|O_RDWR, 0644); t( fd != -1 ); t( close(fd) == 0 ); void *env = sp_env(); t( env != NULL ); t( sp_ctl(env, SPDIR, SPO_CREAT|SPO_RDWR, dbrep) == 0 ); t( sp_ctl(env, SPCMP, cmp, NULL) == 0 ); t( sp_ctl(env, SPMERGE, 0) == 0 ); void *db = sp_open(env); t( db == NULL ); t( sp_error(env) != NULL ); t( exists(dbrep, 1, "db.incomplete") == 1 ); t( sp_destroy(env) == 0 ); t( rmrf(dbrep) == 0 ); } static void db_badpage(void) { sppageh h = { .crc = 0, .count = 0, .size = 1234, .bsize = 1234, }; t( mkdir(dbrep, 0755) == 0 ); char path[1024]; snprintf(path, sizeof(path), "%s/%"PRIu32".db", dbrep, 1); int fd = open(path, O_CREAT|O_RDWR, 0644); t( fd != -1 ); t( write(fd, &h, sizeof(h)) == sizeof(h) ); t( close(fd) == 0 ); void *env = sp_env(); t( env != NULL ); t( sp_ctl(env, SPDIR, SPO_CREAT|SPO_RDWR, dbrep) == 0 ); t( sp_ctl(env, SPCMP, cmp, NULL) == 0 ); t( sp_ctl(env, SPMERGE, 0) == 0 ); void *db = sp_open(env); t( db == NULL ); t( sp_error(env) != NULL ); t( sp_destroy(env) == 0 ); t( rmrf(dbrep) == 0 ); } static void log_incomplete_db_incomplete(void) { uint32_t k = 123; splogh h = { .magic = SPMAGIC, .version[0] = SP_VERSION_MAJOR, .version[1] = SP_VERSION_MINOR }; spvh vh = { .crc = 0, .size = sizeof(uint32_t), .voffset = 0, .vsize = sizeof(uint32_t), .flags = SPSET }; speofh eof = { SPEOF }; uint32_t crc; crc = sp_crc32c(0, &k, sizeof(k)); crc = sp_crc32c(crc, &k, sizeof(k)); vh.crc = sp_crc32c(crc, &vh.size, sizeof(spvh) - sizeof(uint32_t)); spfile f; spbatch b; sp_batchinit(&b); sp_fileinit(&f, &a); t( mkdir(dbrep, 0755) == 0 ); t( sp_lognew(&f, dbrep, 1) == 0 ); sp_batchadd(&b, &h, sizeof(h)); sp_batchadd(&b, &vh, sizeof(vh)); sp_batchadd(&b, &k, sizeof(k)); sp_batchadd(&b, &k, sizeof(k)); sp_batchadd(&b, &eof, sizeof(eof)); t( sp_logput(&f, &b) == 0 ); t( sp_logclose(&f) == 0 ); char path[1024]; snprintf(path, sizeof(path), "%s/%"PRIu32".db.incomplete", dbrep, 1); int fd = open(path, O_CREAT|O_RDWR, 0644); t( fd != -1 ); t( write(fd, &h, sizeof(h)) == sizeof(h) ); t( close(fd) == 0 ); void *env = sp_env(); t( env != NULL ); t( sp_ctl(env, SPDIR, SPO_CREAT|SPO_RDWR, dbrep) == 0 ); t( sp_ctl(env, SPCMP, cmp, NULL) == 0 ); t( sp_ctl(env, SPMERGE, 0) == 0 ); void *db = sp_open(env); t( db == NULL ); t( sp_destroy(env) == 0 ); t( rmrf(dbrep) == 0 ); } static void log_db_incomplete(void) { uint32_t k = 123; splogh h = { .magic = SPMAGIC, .version[0] = SP_VERSION_MAJOR, .version[1] = SP_VERSION_MINOR }; spvh vh = { .crc = 0, .size = sizeof(uint32_t), .voffset = 0, .vsize = sizeof(uint32_t), .flags = SPSET }; speofh eof = { SPEOF }; uint32_t crc; crc = sp_crc32c(0, &k, sizeof(k)); crc = sp_crc32c(crc, &k, sizeof(k)); vh.crc = sp_crc32c(crc, &vh.size, sizeof(spvh) - sizeof(uint32_t)); spfile f; spbatch b; sp_batchinit(&b); sp_fileinit(&f, &a); t( mkdir(dbrep, 0755) == 0 ); t( sp_lognew(&f, dbrep, 1) == 0 ); sp_batchadd(&b, &h, sizeof(h)); sp_batchadd(&b, &vh, sizeof(vh)); sp_batchadd(&b, &k, sizeof(k)); sp_batchadd(&b, &k, sizeof(k)); sp_batchadd(&b, &eof, sizeof(eof)); t( sp_logput(&f, &b) == 0 ); t( sp_logcomplete(&f) == 0 ); t( sp_logclose(&f) == 0 ); t( exists(dbrep, 1, "log") == 1 ); char path[1024]; snprintf(path, sizeof(path), "%s/%"PRIu32".db.incomplete", dbrep, 1); int fd = open(path, O_CREAT|O_RDWR, 0644); t( fd != -1 ); t( write(fd, &h, sizeof(h)) == sizeof(h) ); t( close(fd) == 0 ); void *env = sp_env(); t( env != NULL ); t( sp_ctl(env, SPDIR, SPO_CREAT|SPO_RDWR, dbrep) == 0 ); t( sp_ctl(env, SPCMP, cmp, NULL) == 0 ); t( sp_ctl(env, SPMERGE, 0) == 0 ); void *db = sp_open(env); t( db != NULL ); size_t vsize = 0; void *vp = NULL; t( sp_get(db, &k, sizeof(k), &vp, &vsize) == 1 ); t( vsize == sizeof(k) ); t( *(uint32_t*)vp == k ); free(vp); t( sp_destroy(db) == 0 ); t( sp_destroy(env) == 0 ); t( rmrf(dbrep) == 0 ); } int main(int argc, char *argv[]) { sp_allocinit(&a, sp_allocstd, NULL); rmrf(dbrep); test(log_empty); test(log_empty_incomplete); test(log_badrecord); test(log_badrecord_incomplete); test(log_1_badrecord_2_goodrecord); test(log_noeof); test(log_noeof_complete); test(db_empty); test(db_empty_incomplete); test(db_badpage); test(log_db_incomplete); test(log_incomplete_db_incomplete); return 0; }