summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVivien Kraus <vivien@planete-kraus.eu>2023-05-09 20:56:27 +0200
committerVivien Kraus <vivien@planete-kraus.eu>2023-05-10 00:01:20 +0200
commit6c12a2292884fe79cc6e7d7d30b94cb8d578d046 (patch)
tree6af61cd5eb0b6e44fd6a21ded50c546c9fd1609f
parent5f3a6dc02bb49d1c49ad8b198ee3147d0691b888 (diff)
Save arrays of cache entries to the append-only file.
-rw-r--r--src/libdisfluid/Makefile.am1
-rw-r--r--src/libdisfluid/disfluid-cache-group.h130
-rw-r--r--src/libdisfluid/disfluid-tests.h53
3 files changed, 184 insertions, 0 deletions
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 <config.h>
+# include "string-desc.h"
+# include <stdbool.h>
+
+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";