From 6c12a2292884fe79cc6e7d7d30b94cb8d578d046 Mon Sep 17 00:00:00 2001 From: Vivien Kraus Date: Tue, 9 May 2023 20:56:27 +0200 Subject: Save arrays of cache entries to the append-only file. --- src/libdisfluid/Makefile.am | 1 + src/libdisfluid/disfluid-cache-group.h | 130 +++++++++++++++++++++++++++++++++ src/libdisfluid/disfluid-tests.h | 53 ++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 src/libdisfluid/disfluid-cache-group.h diff --git a/src/libdisfluid/Makefile.am b/src/libdisfluid/Makefile.am index 6b919d4..f230a3d 100644 --- a/src/libdisfluid/Makefile.am +++ b/src/libdisfluid/Makefile.am @@ -4,6 +4,7 @@ lib_LTLIBRARIES += %D%/libdisfluid.la %D%/disfluid-authors.h \ %D%/disfluid-append-only-file.h \ %D%/disfluid-cache-entry.h \ + %D%/disfluid-cache-group.h \ %D%/disfluid-cache-entry-key.h \ %D%/disfluid-cache-entry-hash.h \ %D%/disfluid-db.h \ diff --git a/src/libdisfluid/disfluid-cache-group.h b/src/libdisfluid/disfluid-cache-group.h new file mode 100644 index 0000000..6f6b386 --- /dev/null +++ b/src/libdisfluid/disfluid-cache-group.h @@ -0,0 +1,130 @@ +#ifndef DISFLUID_DISFLUID_CACHE_GROUP_INCLUDED +# define DISFLUID_DISFLUID_CACHE_GROUP_INCLUDED + +# include +# include "string-desc.h" +# include + +MAYBE_UNUSED static int +ao_cache_group_read (int fd, size_t offset, + size_t *n_entries, size_t **entry_offsets); + +MAYBE_UNUSED static int +ao_cache_group_push (int fd, size_t *offset, + size_t n_entries, const size_t *entry_offsets); + +# include "disfluid-append-only-file.h" +# include "safe-alloc.h" + +/* The cache group is organized as follows: + + - on 8 bytes, the number of entries, + - on 8 bytes, the offset of the entry array. + */ + +static int +ao_cache_group_read (int fd, + size_t offset, size_t *n_entries, size_t **entry_offsets) +{ + uint8_t header[16]; + string_desc_t header_desc = { + ._nbytes = sizeof (header), + ._data = header + }; + *n_entries = 0; + *entry_offsets = NULL; + size_t array_offset = 0; + if (ao_file_read (fd, offset, header_desc) < 0) + { + return -1; + } + for (size_t i = 0; i < 8; i++) + { + *n_entries *= 256; + *n_entries += header[i]; + } + for (size_t i = 8; i < 16; i++) + { + array_offset *= 256; + array_offset += header[i]; + } + uint8_t *array_data = NULL; + if (ALLOC_N (array_data, *n_entries * 8) < 0 + || ALLOC_N (*entry_offsets, *n_entries) < 0) + { + FREE (array_data); + FREE (*entry_offsets); + return -1; + } + string_desc_t array_desc = { + ._nbytes = *n_entries * 8, + ._data = array_data + }; + if (ao_file_read (fd, array_offset, array_desc) < 0) + { + FREE (array_data); + FREE (*entry_offsets); + return -1; + } + for (size_t i = 0; i < *n_entries; i++) + { + (*entry_offsets)[i] = 0; + for (size_t j = i * 8; j < (i + 1) * 8; j++) + { + (*entry_offsets)[i] *= 256; + (*entry_offsets)[i] += array_data[j]; + } + } + FREE (array_data); + return 0; +} + +static int +ao_cache_group_push (int fd, + size_t *offset, + size_t n_entries, const size_t *entry_offsets) +{ + uint8_t *array_data = NULL; + if (ALLOC_N (array_data, n_entries * 8) < 0) + { + return -1; + } + for (size_t i = 0; i < n_entries; i++) + { + size_t offset = entry_offsets[i]; + for (size_t j = 8 * (i + 1); j-- > 8 * i;) + { + array_data[j] = offset % 256; + offset /= 256; + } + } + string_desc_t array_desc = { + ._nbytes = n_entries * 8, + ._data = array_data + }; + size_t array_offset; + if (ao_file_push_data (fd, array_desc, &array_offset) < 0) + { + FREE (array_data); + return -1; + } + FREE (array_data); + uint8_t header_data[16] = { 0 }; + for (size_t i = 8; i-- > 0;) + { + header_data[i] = n_entries % 256; + n_entries /= 256; + } + for (size_t i = 16; i-- > 8;) + { + header_data[i] = array_offset % 256; + array_offset /= 256; + } + string_desc_t header_desc = { + ._nbytes = 16, + ._data = header_data + }; + return ao_file_push_data (fd, header_desc, offset); +} + +#endif /* DISFLUID_DISFLUID_CACHE_GROUP_INCLUDED */ diff --git a/src/libdisfluid/disfluid-tests.h b/src/libdisfluid/disfluid-tests.h index 0843404..fc16d4c 100644 --- a/src/libdisfluid/disfluid-tests.h +++ b/src/libdisfluid/disfluid-tests.h @@ -21,6 +21,7 @@ static inline int test_append_count (const char *filename, size_t *n); # include "string-desc.h" # include "disfluid-append-only-file.h" # include "disfluid-trie.h" +# include "disfluid-cache-group.h" # define BYTES * 1 @@ -839,6 +840,57 @@ START_TEST (test_aof_trie_fold) END_TEST /* *INDENT-ON* */ +/* *INDENT-OFF* */ +START_TEST (test_aof_cache_group) +/* *INDENT-ON* */ + +{ + /* The group has 2 entries: 8001 and 8002. */ + char filename[] = "/tmp/test-ao-cache-group-XXXXXX"; + int file = mkstemp (filename); + ck_assert_int_ge (file, 0); + static const char *magic_data = "disfluid c.group"; + const string_desc_t file_magic = { + ._data = (char *) magic_data, + ._nbytes = strlen (magic_data) + }; + int error = ao_file_prepare (file, file_magic); + ck_assert_int_eq (error, 0); + size_t top; + error = ao_file_lock_for_writing (file, &top); + ck_assert_int_eq (error, 0); + ck_assert_int_eq (top, 0); + static const size_t expected_offsets[] = { 8001, 8002 }; + size_t final_offset = 42; + error = + ao_cache_group_push (file, &final_offset, + sizeof (expected_offsets) / + sizeof (expected_offsets[0]), expected_offsets); + ck_assert_int_eq (error, 0); + /* The array is 16 bytes, and the header too. */ + ck_assert_int_eq (final_offset, 32); + /* Commit */ + error = ao_file_commit_transaction (file); + ck_assert_int_eq (error, 0); + /* Check */ + size_t actual_n_offsets = 42; + size_t *actual_offsets = NULL; + error = + ao_cache_group_read (file, final_offset, &actual_n_offsets, + &actual_offsets); + ck_assert_int_eq (error, 0); + ck_assert_int_eq (actual_n_offsets, 2); + ck_assert_ptr_nonnull (actual_offsets); + ck_assert_int_eq (actual_offsets[0], 8001); + ck_assert_int_eq (actual_offsets[1], 8002); + FREE (actual_offsets); + remove (filename); + close (file); +} +/* *INDENT-OFF* */ +END_TEST +/* *INDENT-ON* */ + static inline char * tests_read_whole_file (int file) { @@ -896,6 +948,7 @@ run_tests (size_t *n_tests, size_t *n_errors) tcase_add_test (aof, test_aof_recover); tcase_add_test (aof, test_aof_can_read_locked_file); tcase_add_test (aof, test_aof_trie_fold); + tcase_add_test (aof, test_aof_cache_group); suite_add_tcase (suite, aof); SRunner *runner = srunner_create (suite); char log_file_name[] = "/tmp/disfluid-unit-tests-XXXXXX"; -- cgit v1.2.3