From 7072ca1ebdd9a6a3a4691eb282143f8eedfc0e8e Mon Sep 17 00:00:00 2001 From: Vivien Kraus Date: Tue, 9 May 2023 21:39:46 +0200 Subject: Add a function to invalidate a cache entry. The function reuses the memory for the key, response header and body, so it adds at most 80 bytes to the file. --- src/libdisfluid/disfluid-cache-entry.h | 38 +++++++++ src/libdisfluid/disfluid-tests.h | 138 +++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+) diff --git a/src/libdisfluid/disfluid-cache-entry.h b/src/libdisfluid/disfluid-cache-entry.h index ca4f743..1c06537 100644 --- a/src/libdisfluid/disfluid-cache-entry.h +++ b/src/libdisfluid/disfluid-cache-entry.h @@ -26,6 +26,9 @@ ao_cache_entry_push (int fd, size_t *offset, const string_desc_t response_header, const string_desc_t response_body); +MAYBE_UNUSED static int +ao_cache_entry_invalidate (int fd, size_t offset, size_t *invalidated_offset); + # include "disfluid-append-only-file.h" # include "safe-alloc.h" @@ -355,4 +358,39 @@ ao_cache_entry_push (int fd, size_t *offset, } return 0; } + +static int +ao_cache_entry_invalidate (int fd, size_t offset, size_t *invalidated_offset) +{ + struct cache_entry_header header; + uint8_t header_bytes[12 * 2 + 16 * 3 + 1 + 7] = { 0 }; + string_desc_t data = {._nbytes = sizeof (header_bytes),._data = header_bytes + }; + *invalidated_offset = offset; + if (ao_file_read (fd, offset, data) < 0) + { + return -1; + } + if (ao_cache_entry_from_bytes (header_bytes, &header) < 0) + { + return -1; + } + if (header.invalidated) + { + return 0; + } + header.invalidated = true; + /* Push just the header, reuse the memory for key, response header + and body. */ + if (ao_cache_entry_to_bytes (&header, header_bytes) < 0) + { + return -1; + } + if (ao_file_push_data (fd, data, invalidated_offset) < 0) + { + return -1; + } + return 0; +} + #endif /* DISFLUID_DISFLUID_CACHE_ENTRY_INCLUDED */ diff --git a/src/libdisfluid/disfluid-tests.h b/src/libdisfluid/disfluid-tests.h index fc16d4c..4ec4569 100644 --- a/src/libdisfluid/disfluid-tests.h +++ b/src/libdisfluid/disfluid-tests.h @@ -162,6 +162,142 @@ START_TEST (test_read_normal) END_TEST /* *INDENT-ON* */ +/* *INDENT-OFF* */ +START_TEST (test_invalidate_cache_entry_noop) +/* *INDENT-ON* */ + +{ + /* Add a single cache entry to the file. It is already invalidated, + so invalidating it again does not do anything. */ + static const char *key_value = "GET http://example.com\r\n"; + static const char *header_value = + "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n"; + static const char *body_value = "Hello, world!"; + const string_desc_t key = {._nbytes = strlen (key_value),._data = + (char *) key_value + }; + const string_desc_t header = {._nbytes = strlen (header_value),._data = + (char *) header_value + }; + const string_desc_t body = {._nbytes = strlen (body_value),._data = + (char *) body_value + }; + const struct timespec request_date = {.tv_sec = 12345,.tv_nsec = 678910 }; + const struct timespec response_date = {.tv_sec = 111213,.tv_nsec = 141516 }; + 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); + error = + /* Notice the "true" here. */ + ao_cache_entry_push (file, &top, &request_date, &response_date, true, key, + header, body); + 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_entry_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_entry) +/* *INDENT-ON* */ + +{ + /* Add a single cache entry to the file. It is not invalidated, so + invalidating it again pushes a new cache entry. The cache entry + reuses storage for the key, header and body, so it is just 80 + bytes after the existing entry. */ + static const char *key_value = "GET http://example.com\r\n"; + static const char *header_value = + "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n"; + static const char *body_value = "Hello, world!"; + const string_desc_t key = {._nbytes = strlen (key_value),._data = + (char *) key_value + }; + const string_desc_t header = {._nbytes = strlen (header_value),._data = + (char *) header_value + }; + const string_desc_t body = {._nbytes = strlen (body_value),._data = + (char *) body_value + }; + const struct timespec request_date = {.tv_sec = 12345,.tv_nsec = 678910 }; + const struct timespec response_date = {.tv_sec = 111213,.tv_nsec = 141516 }; + 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); + error = + /* Notice the "false" here. */ + ao_cache_entry_push (file, &top, &request_date, &response_date, false, + key, header, body); + 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_entry_invalidate (file, top, &invalidated_offset); + ck_assert_int_eq (error, 0); + ck_assert_int_eq (invalidated_offset, top + 80); + 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, invalidated_offset, &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_value)); + ck_assert_int_eq (check_header._nbytes, strlen (header_value)); + ck_assert_int_eq (check_body._nbytes, strlen (body_value)); + ck_assert_int_eq (memcmp (check_key._data, key_value, strlen (key_value)), + 0); + ck_assert_int_eq (memcmp + (check_header._data, header_value, strlen (header_value)), + 0); + ck_assert_int_eq (memcmp + (check_body._data, body_value, strlen (body_value)), 0); + FREE (check_key._data); + FREE (check_header._data); + FREE (check_body._data); + remove (filename); + close (file); +} +/* *INDENT-OFF* */ +END_TEST +/* *INDENT-ON* */ + /* *INDENT-OFF* */ START_TEST (test_cache_key_no_host) /* *INDENT-ON* */ @@ -926,6 +1062,8 @@ run_tests (size_t *n_tests, size_t *n_errors) suite_add_tcase (suite, general); TCase *cache_entry = tcase_create (_("disfluid cache entry files")); tcase_add_test (cache_entry, test_read_normal); + 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_key = tcase_create (_("disfluid cache key")); tcase_add_test (cache_key, test_cache_key_no_host); -- cgit v1.2.3