From c871033a4ddcedb5a3f5e46b53cbc28a53dcb77b Mon Sep 17 00:00:00 2001 From: Vivien Kraus Date: Wed, 10 May 2023 08:29:48 +0200 Subject: Invalidate a whole cache group. --- src/libdisfluid/disfluid-cache-group.h | 47 +++++ src/libdisfluid/disfluid-tests.h | 352 ++++++++++++++++++++++++++++++++- 2 files changed, 398 insertions(+), 1 deletion(-) 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 @@ -298,6 +298,351 @@ START_TEST (test_invalidate_cache_entry) 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"; -- cgit v1.2.3