summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVivien Kraus <vivien@planete-kraus.eu>2023-05-10 08:29:48 +0200
committerVivien Kraus <vivien@planete-kraus.eu>2023-05-10 08:46:45 +0200
commitc871033a4ddcedb5a3f5e46b53cbc28a53dcb77b (patch)
tree9e70aae453d5720eeaeb3e0f9ef45485a9294c0e
parent4d5a3614821ce74e418bb3c9b8eae8667edccaf0 (diff)
Invalidate a whole cache group.
-rw-r--r--src/libdisfluid/disfluid-cache-group.h47
-rw-r--r--src/libdisfluid/disfluid-tests.h352
2 files changed, 398 insertions, 1 deletions
diff --git a/src/libdisfluid/disfluid-cache-group.h b/src/libdisfluid/disfluid-cache-group.h
index 6f6b386..b0a94af 100644
--- a/src/libdisfluid/disfluid-cache-group.h
+++ b/src/libdisfluid/disfluid-cache-group.h
@@ -13,6 +13,9 @@ MAYBE_UNUSED static int
ao_cache_group_push (int fd, size_t *offset,
size_t n_entries, const size_t *entry_offsets);
+MAYBE_UNUSED static int
+ao_cache_group_invalidate (int fd, size_t offset, size_t *invalidated_offset);
+
# include "disfluid-append-only-file.h"
# include "safe-alloc.h"
@@ -127,4 +130,48 @@ ao_cache_group_push (int fd,
return ao_file_push_data (fd, header_desc, offset);
}
+MAYBE_UNUSED static int
+ao_cache_group_invalidate (int fd, size_t offset, size_t *invalidated_offset)
+{
+ size_t n_entries = 42;
+ size_t *offsets = NULL;
+ int error = ao_cache_group_read (fd, offset, &n_entries, &offsets);
+ if (error != 0)
+ {
+ FREE (offsets);
+ return -1;
+ }
+ bool changed = false;
+ for (size_t i = 0; i < n_entries; i++)
+ {
+ size_t old_offset = offsets[i];
+ size_t new_offset = 42;
+ if (ao_cache_entry_invalidate (fd, old_offset, &new_offset) < 0)
+ {
+ FREE (offsets);
+ return -1;
+ }
+ if (old_offset != new_offset)
+ {
+ changed = true;
+ }
+ offsets[i] = new_offset;
+ }
+ if (changed)
+ {
+ if (ao_cache_group_push (fd, invalidated_offset, n_entries, offsets) <
+ 0)
+ {
+ FREE (offsets);
+ return -1;
+ }
+ }
+ else
+ {
+ *invalidated_offset = offset;
+ }
+ FREE (offsets);
+ return 0;
+}
+
#endif /* DISFLUID_DISFLUID_CACHE_GROUP_INCLUDED */
diff --git a/src/libdisfluid/disfluid-tests.h b/src/libdisfluid/disfluid-tests.h
index 4ec4569..9ebbeb9 100644
--- a/src/libdisfluid/disfluid-tests.h
+++ b/src/libdisfluid/disfluid-tests.h
@@ -299,6 +299,351 @@ END_TEST
/* *INDENT-ON* */
/* *INDENT-OFF* */
+START_TEST (test_invalidate_cache_group_noop)
+/* *INDENT-ON* */
+
+{
+ /* There are 2 entries in the group. Both are already invalidated,
+ so invalidating the group is a no-op. */
+ static const char *key_1_value = "GET http://example.com\r\n";
+ static const char *key_2_value = "GET http://example.com\r\nlater\r\n";
+ static const char *header_1_value =
+ "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n";
+ static const char *header_2_value =
+ "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nLast-Modified: later\r\n\r\n";
+ static const char *body_1_value = "Hello, world!";
+ static const char *body_2_value = "Hello, world 2!";
+ const string_desc_t key_1 = {._nbytes = strlen (key_1_value),._data =
+ (char *) key_1_value
+ };
+ const string_desc_t key_2 = {._nbytes = strlen (key_2_value),._data =
+ (char *) key_2_value
+ };
+ const string_desc_t header_1 = {._nbytes = strlen (header_1_value),._data =
+ (char *) header_1_value
+ };
+ const string_desc_t header_2 = {._nbytes = strlen (header_2_value),._data =
+ (char *) header_2_value
+ };
+ const string_desc_t body_1 = {._nbytes = strlen (body_1_value),._data =
+ (char *) body_1_value
+ };
+ const string_desc_t body_2 = {._nbytes = strlen (body_2_value),._data =
+ (char *) body_2_value
+ };
+ const struct timespec request_date_1 = {.tv_sec = 12345,.tv_nsec = 678910 };
+ const struct timespec response_date_1 = {.tv_sec = 111213,.tv_nsec = 141516
+ };
+ const struct timespec request_date_2 = {.tv_sec = 22345,.tv_nsec = 678920 };
+ const struct timespec response_date_2 = {.tv_sec = 222223,.tv_nsec = 242526
+ };
+ char filename[] = "/tmp/test-ao-cache-entry-XXXXXX";
+ int file = mkstemp (filename);
+ ck_assert_int_ge (file, 0);
+ static const char *magic_data = "disfluid c.entry";
+ const string_desc_t file_magic = {
+ ._data = (char *) magic_data,
+ ._nbytes = strlen (magic_data)
+ };
+ int error = 0;
+ size_t top;
+ error = ao_file_prepare (file, file_magic);
+ error = ao_file_lock_for_writing (file, &top);
+ ck_assert_int_eq (error, 0);
+ size_t offset_1, offset_2;
+ error =
+ /* Notice the "true" here. */
+ ao_cache_entry_push (file, &offset_1, &request_date_1, &response_date_1,
+ true, key_1, header_1, body_1);
+ ck_assert_int_eq (error, 0);
+ error =
+ /* Notice the "true" here too. */
+ ao_cache_entry_push (file, &offset_2, &request_date_2, &response_date_2,
+ true, key_2, header_2, body_2);
+ ck_assert_int_eq (error, 0);
+ size_t offsets[] = { offset_1, offset_2 };
+ error =
+ ao_cache_group_push (file, &top, sizeof (offsets) / sizeof (offsets[0]),
+ offsets);
+ ck_assert_int_eq (error, 0);
+ error = ao_file_commit_transaction (file);
+ ck_assert_int_eq (error, 0);
+ size_t invalidated_offset = 42;
+ error = ao_cache_group_invalidate (file, top, &invalidated_offset);
+ ck_assert_int_eq (error, 0);
+ ck_assert_int_eq (invalidated_offset, top);
+ remove (filename);
+ close (file);
+}
+/* *INDENT-OFF* */
+END_TEST
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+START_TEST (test_invalidate_cache_group_partial)
+/* *INDENT-ON* */
+
+{
+ /* There are 2 entries in the group. The first one is invalidated,
+ but not the second one. */
+ static const char *key_1_value = "GET http://example.com\r\n";
+ static const char *key_2_value = "GET http://example.com\r\nlater\r\n";
+ static const char *header_1_value =
+ "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n";
+ static const char *header_2_value =
+ "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nLast-Modified: later\r\n\r\n";
+ static const char *body_1_value = "Hello, world!";
+ static const char *body_2_value = "Hello, world 2!";
+ const string_desc_t key_1 = {._nbytes = strlen (key_1_value),._data =
+ (char *) key_1_value
+ };
+ const string_desc_t key_2 = {._nbytes = strlen (key_2_value),._data =
+ (char *) key_2_value
+ };
+ const string_desc_t header_1 = {._nbytes = strlen (header_1_value),._data =
+ (char *) header_1_value
+ };
+ const string_desc_t header_2 = {._nbytes = strlen (header_2_value),._data =
+ (char *) header_2_value
+ };
+ const string_desc_t body_1 = {._nbytes = strlen (body_1_value),._data =
+ (char *) body_1_value
+ };
+ const string_desc_t body_2 = {._nbytes = strlen (body_2_value),._data =
+ (char *) body_2_value
+ };
+ const struct timespec request_date_1 = {.tv_sec = 12345,.tv_nsec = 678910 };
+ const struct timespec response_date_1 = {.tv_sec = 111213,.tv_nsec = 141516
+ };
+ const struct timespec request_date_2 = {.tv_sec = 22345,.tv_nsec = 678920 };
+ const struct timespec response_date_2 = {.tv_sec = 222223,.tv_nsec = 242526
+ };
+ char filename[] = "/tmp/test-ao-cache-entry-XXXXXX";
+ int file = mkstemp (filename);
+ ck_assert_int_ge (file, 0);
+ static const char *magic_data = "disfluid c.entry";
+ const string_desc_t file_magic = {
+ ._data = (char *) magic_data,
+ ._nbytes = strlen (magic_data)
+ };
+ int error = 0;
+ size_t top;
+ error = ao_file_prepare (file, file_magic);
+ error = ao_file_lock_for_writing (file, &top);
+ ck_assert_int_eq (error, 0);
+ size_t offset_1, offset_2;
+ error =
+ /* Notice the "true" here. */
+ ao_cache_entry_push (file, &offset_1, &request_date_1, &response_date_1,
+ true, key_1, header_1, body_1);
+ ck_assert_int_eq (error, 0);
+ error =
+ /* However, notice the "false" here. */
+ ao_cache_entry_push (file, &offset_2, &request_date_2, &response_date_2,
+ false, key_2, header_2, body_2);
+ ck_assert_int_eq (error, 0);
+ size_t offsets[] = { offset_1, offset_2 };
+ error =
+ ao_cache_group_push (file, &top, sizeof (offsets) / sizeof (offsets[0]),
+ offsets);
+ ck_assert_int_eq (error, 0);
+ error = ao_file_commit_transaction (file);
+ ck_assert_int_eq (error, 0);
+ size_t invalidated_offset = 42;
+ error = ao_cache_group_invalidate (file, top, &invalidated_offset);
+ ck_assert_int_eq (error, 0);
+ ck_assert_int_gt (invalidated_offset, top);
+ size_t *final_offsets = NULL;
+ size_t n_entries = 42;
+ error =
+ ao_cache_group_read (file, invalidated_offset, &n_entries,
+ &final_offsets);
+ ck_assert_int_eq (error, 0);
+ ck_assert_int_eq (n_entries, 2);
+ ck_assert_int_eq (final_offsets[0], offset_1);
+ ck_assert_int_gt (final_offsets[1], offset_2);
+ string_desc_t check_key = { 0 };
+ string_desc_t check_header = { 0 };
+ string_desc_t check_body = { 0 };
+ struct timespec check_request_date, check_response_date;
+ bool check_invalidated;
+ error =
+ ao_cache_entry_read (file, final_offsets[1], &check_request_date,
+ &check_response_date, &check_invalidated, true, true,
+ true, &check_key, &check_header, &check_body);
+ ck_assert_int_eq (error, 0);
+ ck_assert_int_eq (check_request_date.tv_sec, 22345);
+ ck_assert_int_eq (check_request_date.tv_nsec, 678920);
+ ck_assert_int_eq (check_response_date.tv_sec, 222223);
+ ck_assert_int_eq (check_response_date.tv_nsec, 242526);
+ ck_assert (check_invalidated);
+ ck_assert_int_eq (check_key._nbytes, strlen (key_2_value));
+ ck_assert_int_eq (check_header._nbytes, strlen (header_2_value));
+ ck_assert_int_eq (check_body._nbytes, strlen (body_2_value));
+ ck_assert_int_eq (memcmp
+ (check_key._data, key_2_value, strlen (key_2_value)), 0);
+ ck_assert_int_eq (memcmp
+ (check_header._data, header_2_value,
+ strlen (header_2_value)), 0);
+ ck_assert_int_eq (memcmp
+ (check_body._data, body_2_value, strlen (body_2_value)),
+ 0);
+ FREE (check_key._data);
+ FREE (check_header._data);
+ FREE (check_body._data);
+ FREE (final_offsets);
+ remove (filename);
+ close (file);
+}
+/* *INDENT-OFF* */
+END_TEST
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+START_TEST (test_invalidate_cache_group_all)
+/* *INDENT-ON* */
+
+{
+ /* There are 2 entries in the group. The first one is invalidated,
+ but not the second one. */
+ static const char *key_1_value = "GET http://example.com\r\n";
+ static const char *key_2_value = "GET http://example.com\r\nlater\r\n";
+ static const char *header_1_value =
+ "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n";
+ static const char *header_2_value =
+ "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nLast-Modified: later\r\n\r\n";
+ static const char *body_1_value = "Hello, world!";
+ static const char *body_2_value = "Hello, world 2!";
+ const string_desc_t key_1 = {._nbytes = strlen (key_1_value),._data =
+ (char *) key_1_value
+ };
+ const string_desc_t key_2 = {._nbytes = strlen (key_2_value),._data =
+ (char *) key_2_value
+ };
+ const string_desc_t header_1 = {._nbytes = strlen (header_1_value),._data =
+ (char *) header_1_value
+ };
+ const string_desc_t header_2 = {._nbytes = strlen (header_2_value),._data =
+ (char *) header_2_value
+ };
+ const string_desc_t body_1 = {._nbytes = strlen (body_1_value),._data =
+ (char *) body_1_value
+ };
+ const string_desc_t body_2 = {._nbytes = strlen (body_2_value),._data =
+ (char *) body_2_value
+ };
+ const struct timespec request_date_1 = {.tv_sec = 12345,.tv_nsec = 678910 };
+ const struct timespec response_date_1 = {.tv_sec = 111213,.tv_nsec = 141516
+ };
+ const struct timespec request_date_2 = {.tv_sec = 22345,.tv_nsec = 678920 };
+ const struct timespec response_date_2 = {.tv_sec = 222223,.tv_nsec = 242526
+ };
+ char filename[] = "/tmp/test-ao-cache-entry-XXXXXX";
+ int file = mkstemp (filename);
+ ck_assert_int_ge (file, 0);
+ static const char *magic_data = "disfluid c.entry";
+ const string_desc_t file_magic = {
+ ._data = (char *) magic_data,
+ ._nbytes = strlen (magic_data)
+ };
+ int error = 0;
+ size_t top;
+ error = ao_file_prepare (file, file_magic);
+ error = ao_file_lock_for_writing (file, &top);
+ ck_assert_int_eq (error, 0);
+ size_t offset_1, offset_2;
+ error =
+ /* Notice the "false" here. */
+ ao_cache_entry_push (file, &offset_1, &request_date_1, &response_date_1,
+ false, key_1, header_1, body_1);
+ ck_assert_int_eq (error, 0);
+ error =
+ /* Notice the "false" here too. */
+ ao_cache_entry_push (file, &offset_2, &request_date_2, &response_date_2,
+ false, key_2, header_2, body_2);
+ ck_assert_int_eq (error, 0);
+ size_t offsets[] = { offset_1, offset_2 };
+ error =
+ ao_cache_group_push (file, &top, sizeof (offsets) / sizeof (offsets[0]),
+ offsets);
+ ck_assert_int_eq (error, 0);
+ error = ao_file_commit_transaction (file);
+ ck_assert_int_eq (error, 0);
+ size_t invalidated_offset = 42;
+ error = ao_cache_group_invalidate (file, top, &invalidated_offset);
+ ck_assert_int_eq (error, 0);
+ ck_assert_int_gt (invalidated_offset, top);
+ size_t *final_offsets = NULL;
+ size_t n_entries = 42;
+ error =
+ ao_cache_group_read (file, invalidated_offset, &n_entries,
+ &final_offsets);
+ ck_assert_int_eq (error, 0);
+ ck_assert_int_eq (n_entries, 2);
+ ck_assert_int_gt (final_offsets[0], offset_1);
+ ck_assert_int_gt (final_offsets[1], offset_2);
+ string_desc_t check_key = { 0 };
+ string_desc_t check_header = { 0 };
+ string_desc_t check_body = { 0 };
+ struct timespec check_request_date, check_response_date;
+ bool check_invalidated;
+ error =
+ ao_cache_entry_read (file, final_offsets[0], &check_request_date,
+ &check_response_date, &check_invalidated, true, true,
+ true, &check_key, &check_header, &check_body);
+ ck_assert_int_eq (error, 0);
+ ck_assert_int_eq (check_request_date.tv_sec, 12345);
+ ck_assert_int_eq (check_request_date.tv_nsec, 678910);
+ ck_assert_int_eq (check_response_date.tv_sec, 111213);
+ ck_assert_int_eq (check_response_date.tv_nsec, 141516);
+ ck_assert (check_invalidated);
+ ck_assert_int_eq (check_key._nbytes, strlen (key_1_value));
+ ck_assert_int_eq (check_header._nbytes, strlen (header_1_value));
+ ck_assert_int_eq (check_body._nbytes, strlen (body_1_value));
+ ck_assert_int_eq (memcmp
+ (check_key._data, key_1_value, strlen (key_1_value)), 0);
+ ck_assert_int_eq (memcmp
+ (check_header._data, header_1_value,
+ strlen (header_1_value)), 0);
+ ck_assert_int_eq (memcmp
+ (check_body._data, body_1_value, strlen (body_1_value)),
+ 0);
+ FREE (check_key._data);
+ FREE (check_header._data);
+ FREE (check_body._data);
+ error =
+ ao_cache_entry_read (file, final_offsets[1], &check_request_date,
+ &check_response_date, &check_invalidated, true, true,
+ true, &check_key, &check_header, &check_body);
+ ck_assert_int_eq (error, 0);
+ ck_assert_int_eq (check_request_date.tv_sec, 22345);
+ ck_assert_int_eq (check_request_date.tv_nsec, 678920);
+ ck_assert_int_eq (check_response_date.tv_sec, 222223);
+ ck_assert_int_eq (check_response_date.tv_nsec, 242526);
+ ck_assert (check_invalidated);
+ ck_assert_int_eq (check_key._nbytes, strlen (key_2_value));
+ ck_assert_int_eq (check_header._nbytes, strlen (header_2_value));
+ ck_assert_int_eq (check_body._nbytes, strlen (body_2_value));
+ ck_assert_int_eq (memcmp
+ (check_key._data, key_2_value, strlen (key_2_value)), 0);
+ ck_assert_int_eq (memcmp
+ (check_header._data, header_2_value,
+ strlen (header_2_value)), 0);
+ ck_assert_int_eq (memcmp
+ (check_body._data, body_2_value, strlen (body_2_value)),
+ 0);
+ FREE (check_key._data);
+ FREE (check_header._data);
+ FREE (check_body._data);
+ FREE (final_offsets);
+ remove (filename);
+ close (file);
+}
+/* *INDENT-OFF* */
+END_TEST
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
START_TEST (test_cache_key_no_host)
/* *INDENT-ON* */
@@ -1065,6 +1410,12 @@ run_tests (size_t *n_tests, size_t *n_errors)
tcase_add_test (cache_entry, test_invalidate_cache_entry_noop);
tcase_add_test (cache_entry, test_invalidate_cache_entry);
suite_add_tcase (suite, cache_entry);
+ TCase *cache_group = tcase_create (_("disfluid cache group files"));
+ tcase_add_test (cache_group, test_aof_cache_group);
+ tcase_add_test (cache_group, test_invalidate_cache_group_noop);
+ tcase_add_test (cache_group, test_invalidate_cache_group_partial);
+ tcase_add_test (cache_group, test_invalidate_cache_group_all);
+ suite_add_tcase (suite, cache_group);
TCase *cache_key = tcase_create (_("disfluid cache key"));
tcase_add_test (cache_key, test_cache_key_no_host);
tcase_add_test (cache_key, test_cache_key_invalid_request_line);
@@ -1086,7 +1437,6 @@ 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";