#include #include #include #include #include #include #include "test.h" #include "storage.h" #define FILENAME "/tmp/tsnif-storage-mmap.tsnif" int test_storage_mmap_init(void) { int rc = 0; struct stat st; struct tsnif_storage_handle handle; struct tsnif_storage_header_mmap *header; struct tsnif_storage_opts opts = { .flags = TSNIF_STORAGE_OPT_WRITE | TSNIF_STORAGE_OPT_WRITE, .size_max = 1024*1024, .term_type = 1, }; TEST_ASSERT(0 == tsnif_storage_init(&handle, &opts, FILENAME), out); TEST_ASSERT(handle.opts == &opts, out_free); TEST_ASSERT(handle.opts->chunk_size == sysconf(_SC_PAGESIZE), out_free); TEST_ASSERT(handle.fd != 0, out_free); TEST_ASSERT(handle.header != NULL, out_free); /* header check before when creating new file */ header = handle.header; TEST_ASSERT(header->common.magic == TSNIF_HEADER_MAGIC, out_free); TEST_ASSERT(header->common.storage_type == TSNIF_STORAGE_TYPE_MMAP, out_free); TEST_ASSERT(header->common.term_type == 1, out_free); TEST_ASSERT(header->common.version == TSNIF_STORAGE_VERSION, out_free); TEST_ASSERT(header->size_max == opts.size_max, out_free); out_free: TEST_ASSERT(0 == tsnif_storage_close(&handle), out); TEST_ASSERT(0 == stat(FILENAME, &st), out); TEST_ASSERT(st.st_size == sysconf(_SC_PAGESIZE), out); out: unlink(FILENAME); return rc; } int test_storage_mmap_open(void) { int rc = 0; struct tsnif_storage_handle handle; struct tsnif_storage_header_mmap *header; struct tsnif_storage_opts opts = { .flags = TSNIF_STORAGE_OPT_WRITE, .size_max = 1024*1024, .term_type = 1, }; TEST_ASSERT(0 == tsnif_storage_init(&handle, &opts, FILENAME), out); TEST_ASSERT(0 == tsnif_storage_close(&handle), out); opts.flags = TSNIF_STORAGE_OPT_READ; TEST_ASSERT(0 == tsnif_storage_init(&handle, &opts, FILENAME), out); /* header check before when opening file */ header = handle.header; TEST_ASSERT(header->common.magic == TSNIF_HEADER_MAGIC, out_free); TEST_ASSERT(header->common.storage_type == TSNIF_STORAGE_TYPE_MMAP, out_free); TEST_ASSERT(header->common.term_type == 1, out_free); TEST_ASSERT(header->common.version == TSNIF_STORAGE_VERSION, out_free); TEST_ASSERT(header->size_max == opts.size_max, out_free); TEST_ASSERT(tsnif_storage_term_type(&handle) == 1, out_free); out_free: TEST_ASSERT(0 == tsnif_storage_close(&handle), out); out: unlink(FILENAME); return rc; } static int get_rec(struct tsnif_storage_rec *rec, char *msg, int i) { sprintf(msg, "krava-%i-", i); memset(rec, 0x0, sizeof(rec)); rec->ptr = msg; rec->len = strlen(msg); return 0; } int test_storage_mmap_write_single_chunk(void) { int rc = 0, i; struct tsnif_storage_handle handle; struct tsnif_storage_opts opts = { .flags = TSNIF_STORAGE_OPT_WRITE | TSNIF_STORAGE_OPT_WRITE, .size_max = 1024*1024, }; TEST_ASSERT(0 == tsnif_storage_init(&handle, &opts, FILENAME), out); for(i = 0; i < 10; i++) { struct tsnif_storage_chunk *chunk = &handle.active_chunk; struct tsnif_storage_chunk_header *header; struct tsnif_storage_rec_mmap *rec_mmap; uint32_t *index; off_t offset; struct tsnif_storage_rec rec; char msg[15]; int free; get_rec(&rec, msg, i); TEST_ASSERT(0 == tsnif_storage_write(&handle, &rec), out_free); TEST_ASSERT(chunk->header, out_free); /* check chunk properties */ header = chunk->header; free = opts.chunk_size - /* chunk header */ sizeof(struct tsnif_storage_chunk_header) - (i + 1) * ( /* record header */ sizeof(struct tsnif_storage_rec_mmap) + /* record data lenght */ rec.len + /* index item */ sizeof(uint32_t) ); TEST_ASSERT(header->cnt == i + 1, out_free); TEST_ASSERT(header->free == free, out_free); /* find current record and check it */ index = chunk->current_index; offset = *(++index); rec_mmap = (void*) chunk->header + offset; TEST_ASSERT(rec_mmap->len == rec.len, out_free); TEST_ASSERT(!memcmp(rec_mmap->data, rec.ptr, rec.len), out_free); } TEST_ASSERT(handle.header->offset_start == sysconf(_SC_PAGESIZE), out_free); TEST_ASSERT(handle.header->cnt == 10, out_free); out_free: TEST_ASSERT(0 == tsnif_storage_close(&handle), out); out: unlink(FILENAME); return rc; } int test_storage_mmap_write_multi_chunks(void) { int rc = 0, i = 0; struct tsnif_storage_handle handle; struct tsnif_storage_chunk *chunk = &handle.active_chunk; struct tsnif_storage_chunk_header *header; struct tsnif_storage_opts opts = { .flags = TSNIF_STORAGE_OPT_WRITE | TSNIF_STORAGE_OPT_WRITE, .size_max = 1024*1024, }; struct tsnif_storage_rec rec; char msg[15]; TEST_ASSERT(0 == tsnif_storage_init(&handle, &opts, FILENAME), out); get_rec(&rec, msg, i++); if (tsnif_storage_write(&handle, &rec)) TEST_ASSERT(1, out_free); header = chunk->header; TEST_ASSERT(header, out_free); do { off_t offset_old, offset_new; int free_threshold = ( /* record header */ sizeof(struct tsnif_storage_rec_mmap) + /* record data */ rec.len + /* safety overhead */ + (4*sizeof(uint32_t))); get_rec(&rec, msg, i++); /* get to the chunk end */ if (header->free > free_threshold) { if (tsnif_storage_write(&handle, &rec)) TEST_ASSERT(1, out_free); continue; } offset_old = chunk->offset; TEST_ASSERT(0 == tsnif_storage_write(&handle, &rec), out_free); offset_new = chunk->offset; TEST_ASSERT(offset_new == (offset_old + opts.chunk_size), out_free); break; } while(1); out_free: TEST_ASSERT(0 == tsnif_storage_close(&handle), out); out: unlink(FILENAME); return rc; } int test_storage_mmap_read_single_chunk(void) { int rc = 0, i = 0; struct tsnif_storage_handle handle; struct tsnif_storage_opts opts = { .flags = TSNIF_STORAGE_OPT_WRITE | TSNIF_STORAGE_OPT_WRITE, .size_max = 1024*1024, }; struct tsnif_storage_rec rec; char msg[15]; if (tsnif_storage_init(&handle, &opts, FILENAME)) TEST_ASSERT(1, out); for(i = 0; i < 10; i++) { get_rec(&rec, msg, i); if (tsnif_storage_write(&handle, &rec)) TEST_ASSERT(1, out_free); } if (tsnif_storage_close(&handle)) TEST_ASSERT(1, out); /* READ mode */ opts.flags = TSNIF_STORAGE_OPT_READ | TSNIF_STORAGE_OPT_READ; opts.size_max = 0; TEST_ASSERT(0 == tsnif_storage_init(&handle, &opts, FILENAME), out); for(i = 0; i < 10; i++) { struct tsnif_storage_rec rec_read; get_rec(&rec, msg, i); TEST_ASSERT(0 == tsnif_storage_read(&handle, TSNIF_STORAGE_READ_NEXT, &rec_read), out_free); TEST_ASSERT(rec.len == rec_read.len, out_free); TEST_ASSERT(rec.flags == rec_read.flags, out_free); TEST_ASSERT(!memcmp(rec_read.ptr, rec.ptr, rec.len), out_free); } /* there should be no other record */ TEST_ASSERT(TSNIF_STORAGE_READ_EOF == tsnif_storage_read(&handle, TSNIF_STORAGE_READ_NEXT, &rec), out_free); for(i = 8; i >= 0; i--) { struct tsnif_storage_rec rec_read; get_rec(&rec, msg, i); TEST_ASSERT(0 == tsnif_storage_read(&handle, TSNIF_STORAGE_READ_PREV, &rec_read), out_free); #if 0 printf("krava:\n"); fwrite(rec_read.ptr, rec_read.len, 1, stdout); fflush(NULL); #endif TEST_ASSERT(rec.len == rec_read.len, out_free); TEST_ASSERT(rec.flags == rec_read.flags, out_free); TEST_ASSERT(!memcmp(rec_read.ptr, rec.ptr, rec.len), out_free); } /* there should be no other record */ TEST_ASSERT(TSNIF_STORAGE_READ_EOF == tsnif_storage_read(&handle, TSNIF_STORAGE_READ_PREV, &rec), out_free); out_free: TEST_ASSERT(0 == tsnif_storage_close(&handle), out); out: unlink(FILENAME); return rc; } int test_storage_mmap_read_multi_chunks(void) { int rc = 0, i = 0; struct tsnif_storage_handle handle; struct tsnif_storage_chunk *chunk = &handle.active_chunk; struct tsnif_storage_opts opts = { .flags = TSNIF_STORAGE_OPT_WRITE | TSNIF_STORAGE_OPT_WRITE, .size_max = 1024*1024, }; struct tsnif_storage_rec rec; char msg[15]; int offset = 0; if (tsnif_storage_init(&handle, &opts, FILENAME)) TEST_ASSERT(1, out_free); /* write whole chunk of data + one record in 2nd chunk */ do { get_rec(&rec, msg, i++); if (tsnif_storage_write(&handle, &rec)) TEST_ASSERT(1, out_free); if (!offset) offset = chunk->offset; } while(chunk->offset == offset); get_rec(&rec, msg, i++); if (tsnif_storage_write(&handle, &rec)) TEST_ASSERT(1, out_free); if (tsnif_storage_close(&handle)) TEST_ASSERT(1, out); opts.flags = TSNIF_STORAGE_OPT_READ | TSNIF_STORAGE_OPT_READ; opts.size_max = 0; TEST_ASSERT(0 == tsnif_storage_init(&handle, &opts, FILENAME), out); for(i = 0; i < handle.header->cnt; i++) { struct tsnif_storage_rec rec_read; get_rec(&rec, msg, i); TEST_ASSERT(0 == tsnif_storage_read(&handle, TSNIF_STORAGE_READ_NEXT, &rec_read), out_free); TEST_ASSERT(rec.len == rec_read.len, out_free); TEST_ASSERT(rec.flags == rec_read.flags, out_free); TEST_ASSERT(!memcmp(rec_read.ptr, rec.ptr, rec.len), out_free); } TEST_ASSERT(TSNIF_STORAGE_READ_EOF == tsnif_storage_read(&handle, TSNIF_STORAGE_READ_NEXT, &rec), out_free); for(i = handle.header->cnt - 2; i >= 0; i--) { struct tsnif_storage_rec rec_read; get_rec(&rec, msg, i); TEST_ASSERT(0 == tsnif_storage_read(&handle, TSNIF_STORAGE_READ_PREV, &rec_read), out_free); TEST_ASSERT(rec.len == rec_read.len, out_free); TEST_ASSERT(rec.flags == rec_read.flags, out_free); TEST_ASSERT(!memcmp(rec_read.ptr, rec.ptr, rec.len), out_free); } out_free: TEST_ASSERT(0 == tsnif_storage_close(&handle), out); out: unlink(FILENAME); return rc; }