diff options
author | Vivien Kraus <vivien@planete-kraus.eu> | 2023-03-18 00:04:20 +0100 |
---|---|---|
committer | Vivien Kraus <vivien@planete-kraus.eu> | 2023-03-18 12:02:11 +0100 |
commit | 59011ddd2b058c3797b0eaed2eb3bc01db1e96ea (patch) | |
tree | 4d690b0a8f1def14c73020f4edc01564ed07da58 | |
parent | 13feab587ff754ed0a9e3e93639ecd5c43f3ec40 (diff) |
Avoid memory management where possible.
-rw-r--r-- | include/Makefile.am | 4 | ||||
-rw-r--r-- | include/disfluid.h | 70 | ||||
-rw-r--r-- | include/disfluid/cache_entry.h | 122 | ||||
-rw-r--r-- | src/adwaita/disfluid-cache-entry.c | 2 | ||||
-rw-r--r-- | src/adwaita/disfluid-window.c | 3 | ||||
-rw-r--r-- | src/libdisfluid/disfluid-cache-entry.h | 550 | ||||
-rw-r--r-- | src/libdisfluid/disfluid-tests.h | 374 | ||||
-rw-r--r-- | src/libdisfluid/main.c | 95 |
8 files changed, 745 insertions, 475 deletions
diff --git a/include/Makefile.am b/include/Makefile.am index f935635..044edf6 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1 +1,5 @@ include_HEADERS += %D%/disfluid.h + +pkgincludedir = $(includedir)/disfluid + +dist_pkginclude_HEADERS = %D%/disfluid/cache_entry.h diff --git a/include/disfluid.h b/include/disfluid.h index 51f096a..b117ab7 100644 --- a/include/disfluid.h +++ b/include/disfluid.h @@ -42,6 +42,18 @@ # define LIBDISFLUID_CONST # endif +# ifdef ATTRIBUTE_PURE +# define LIBDISFLUID_PURE ATTRIBUTE_PURE +# else +# define LIBDISFLUID_PURE +# endif + +# ifdef NODISCARD +# define LIBDISFLUID_NODISCARD NODISCARD +# else +# define LIBDISFLUID_NODISCARD +# endif + # ifdef ATTRIBUTE_FD_ARG # define LIBDISFLUID_FD_ARG ATTRIBUTE_FD_ARG # else @@ -60,6 +72,9 @@ # define LIBDISFLUID_FD_ARG_READ_1 \ LIBDISFLUID_FD_ARG_READ (1) +# define LIBDISFLUID_FD_ARG_READ_2 \ + LIBDISFLUID_FD_ARG_READ (2) + # ifdef ATTRIBUTE_FD_ARG_WRITE # define LIBDISFLUID_FD_ARG_WRITE ATTRIBUTE_FD_ARG_WRITE # else @@ -75,6 +90,9 @@ # define LIBDISFLUID_DEALLOC_AS_CACHE_ENTRY \ LIBDISFLUID_DEALLOC_WITH (disfluid_cache_entry_free, 1) +# define LIBDISFLUID_DEALLOC_AS_CACHE \ + LIBDISFLUID_DEALLOC_WITH (disfluid_cache_free, 1) + # ifdef __cplusplus extern "C" { @@ -126,58 +144,10 @@ extern "C" LIBDISFLUID_CONST LIBDISFLUID_API const char *disfluid_translation_credits (void); - struct disfluid_cache_entry; - - LIBDISFLUID_API extern void - disfluid_cache_entry_free (struct disfluid_cache_entry *entry); - - LIBDISFLUID_API LIBDISFLUID_DEALLOC_AS_CACHE_ENTRY - extern struct disfluid_cache_entry *disfluid_cache_entry_alloc (void); - - LIBDISFLUID_API LIBDISFLUID_DEALLOC_AS_CACHE_ENTRY - extern struct disfluid_cache_entry - *disfluid_cache_entry_dup (const struct disfluid_cache_entry *entry); - - LIBDISFLUID_API extern void - disfluid_cache_entry_set_request_date (struct disfluid_cache_entry *entry, - const struct timespec - *request_date); - - LIBDISFLUID_API extern void - disfluid_cache_entry_set_response_date (struct disfluid_cache_entry - *entry, - const struct timespec - *request_date); - - LIBDISFLUID_API extern void - disfluid_cache_entry_invalidate (struct disfluid_cache_entry *entry); - - LIBDISFLUID_API extern void - disfluid_cache_entry_set_invalidated (struct disfluid_cache_entry *entry, - int invalidated); - - LIBDISFLUID_API extern int - disfluid_cache_entry_load (struct disfluid_cache_entry *entry, - const char *filename); - - LIBDISFLUID_API extern void - disfluid_cache_entry_get_request_date (const struct disfluid_cache_entry - *entry, struct timespec *date); - - LIBDISFLUID_API extern void - disfluid_cache_entry_get_response_date (const struct disfluid_cache_entry - *entry, struct timespec *date); - - LIBDISFLUID_API extern int - disfluid_cache_entry_invalidated (const struct disfluid_cache_entry - *entry); - - LIBDISFLUID_API extern int - disfluid_cache_entry_save (const struct disfluid_cache_entry *entry, - const char *filename); - # ifdef __cplusplus } # endif /* __cplusplus */ +# include <disfluid/cache_entry.h> + #endif /* not H_DISFLUID_INCLUDED */ diff --git a/include/disfluid/cache_entry.h b/include/disfluid/cache_entry.h new file mode 100644 index 0000000..fcfb43f --- /dev/null +++ b/include/disfluid/cache_entry.h @@ -0,0 +1,122 @@ +#ifndef H_DISFLUID_CACHE_ENTRY_INCLUDED +# define H_DISFLUID_CACHE_ENTRY_INCLUDED + +# include <disfluid.h> + +# ifdef __cplusplus +extern "C" +{ +# endif /* __cplusplus */ + + struct disfluid_cache_entry; + + LIBDISFLUID_API LIBDISFLUID_CONST extern size_t + disfluid_cache_entry_size (size_t max_key, + size_t max_header, size_t max_body); + + LIBDISFLUID_API LIBDISFLUID_CONST extern size_t + disfluid_cache_entry_alignment (size_t max_key, + size_t max_header, size_t max_body); + + LIBDISFLUID_API extern void + disfluid_cache_entry_init (struct disfluid_cache_entry *entry, + size_t max_key, + size_t max_header, size_t max_body); + + LIBDISFLUID_API extern void + disfluid_cache_entry_minimum_size (const struct disfluid_cache_entry + *entry, size_t *min_key, + size_t *min_header, size_t *min_body); + + /* -1: dest does not have enough allocated for the key, -2: for the + header, -3: for the key and the header, -4: for the body, -5: + for the key and the body, -6: for the header and the body, -7: + for the key, header and body. */ + LIBDISFLUID_API extern int + disfluid_cache_entry_copy (struct disfluid_cache_entry *restrict dest, + const struct disfluid_cache_entry *restrict + src); + + LIBDISFLUID_NODISCARD LIBDISFLUID_API + extern struct disfluid_cache_entry + *disfluid_cache_entry_alloc (size_t max_key, + size_t max_header, size_t max_body); + + LIBDISFLUID_NODISCARD LIBDISFLUID_API + extern struct disfluid_cache_entry + *disfluid_cache_entry_dup (const struct disfluid_cache_entry *entry); + + LIBDISFLUID_API extern void + disfluid_cache_entry_free (struct disfluid_cache_entry *entry); + + LIBDISFLUID_API extern void + disfluid_cache_entry_set_request_date (struct disfluid_cache_entry *entry, + const struct timespec + *request_date); + + LIBDISFLUID_API extern void + disfluid_cache_entry_set_response_date (struct disfluid_cache_entry + *entry, + const struct timespec + *response_date); + + LIBDISFLUID_API extern void + disfluid_cache_entry_set_invalidated (struct disfluid_cache_entry *entry, + int invalidated); + + LIBDISFLUID_API extern void + disfluid_cache_entry_invalidate (struct disfluid_cache_entry *entry); + + LIBDISFLUID_API extern void + disfluid_cache_entry_get_request_date (const struct disfluid_cache_entry + *entry, struct timespec *date); + + LIBDISFLUID_API extern void + disfluid_cache_entry_get_response_date (const struct disfluid_cache_entry + *entry, struct timespec *date); + + LIBDISFLUID_API LIBDISFLUID_PURE extern int + disfluid_cache_entry_is_invalidated (const struct disfluid_cache_entry + *entry); + + LIBDISFLUID_NODISCARD LIBDISFLUID_API extern int + disfluid_cache_entry_load (struct disfluid_cache_entry *entry, + ssize_t (*read_impl) (void *context, + void *buffer, + size_t max_size), + void *context); + + LIBDISFLUID_NODISCARD LIBDISFLUID_FD_ARG_READ_2 LIBDISFLUID_API + extern int disfluid_cache_entry_read (struct disfluid_cache_entry *entry, + int fd); + + LIBDISFLUID_NODISCARD LIBDISFLUID_API extern int + disfluid_cache_entry_fread (struct disfluid_cache_entry *entry, FILE * f); + + LIBDISFLUID_NODISCARD LIBDISFLUID_API extern int + disfluid_cache_entry_save (const struct disfluid_cache_entry *entry, + ssize_t (*write_impl) (void *context, + const void *buffer, + size_t max_size), + void *context); + + LIBDISFLUID_NODISCARD LIBDISFLUID_FD_ARG_WRITE_2 LIBDISFLUID_API + extern int disfluid_cache_entry_write (const struct disfluid_cache_entry + *entry, int fd); + + LIBDISFLUID_NODISCARD LIBDISFLUID_API extern int + disfluid_cache_entry_fwrite (const struct disfluid_cache_entry *entry, + FILE * f); + +# define DISFLUID_CACHE_ENTRY_ALLOC(ptr, max_header, max_body) \ + (ptr = disfluid_cache_entry_alloc (max_header, max_body), \ + ptr == NULL ? -1 : 0) + +# define DISFLUID_CACHE_ENTRY_FREE(ptr) \ + { free (ptr); ptr = NULL; } + +# ifdef __cplusplus +} +# endif /* __cplusplus */ + +#endif /* not H_DISFLUID_CACHE_ENTRY_INCLUDED */ diff --git a/src/adwaita/disfluid-cache-entry.c b/src/adwaita/disfluid-cache-entry.c index d1da6b0..02d7e83 100644 --- a/src/adwaita/disfluid-cache-entry.c +++ b/src/adwaita/disfluid-cache-entry.c @@ -248,7 +248,7 @@ disfluid_adw_cache_entry_set_cache_entry (DisfluidAdwCacheEntry * self, { abort (); } - if (disfluid_cache_entry_invalidated (self->cache_entry)) + if (disfluid_cache_entry_is_invalidated (self->cache_entry)) { if (asprintf (&invalidation_status_title, diff --git a/src/adwaita/disfluid-window.c b/src/adwaita/disfluid-window.c index 8f9d87f..ee8fb16 100644 --- a/src/adwaita/disfluid-window.c +++ b/src/adwaita/disfluid-window.c @@ -53,7 +53,8 @@ disfluid_adw_window_init (DisfluidAdwWindow * self) G_MENU_MODEL (main_menu)); g_object_unref (main_menu); adw_header_bar_pack_end (ADW_HEADER_BAR (header_bar), menu_button); - struct disfluid_cache_entry *cache_entry = disfluid_cache_entry_alloc (); + struct disfluid_cache_entry *cache_entry = + disfluid_cache_entry_alloc (512, 4096, 2097152); if (cache_entry == NULL) { abort (); diff --git a/src/libdisfluid/disfluid-cache-entry.h b/src/libdisfluid/disfluid-cache-entry.h index ae91390..eb09cdf 100644 --- a/src/libdisfluid/disfluid-cache-entry.h +++ b/src/libdisfluid/disfluid-cache-entry.h @@ -1,7 +1,23 @@ #ifndef DISFLUID_DISFLUID_CACHE_ENTRY_INCLUDED # define DISFLUID_DISFLUID_CACHE_ENTRY_INCLUDED -MAYBE_UNUSED static struct disfluid_cache_entry *cache_entry_alloc (void); +MAYBE_UNUSED static size_t +cache_entry_size (size_t max_key, size_t max_header, size_t max_body); + +MAYBE_UNUSED static size_t +cache_entry_alignment (size_t max_key, size_t max_header, size_t max_body); + +MAYBE_UNUSED static void +cache_entry_init (struct disfluid_cache_entry *entry, size_t max_key, + size_t max_header, size_t max_body); + +MAYBE_UNUSED static void +cache_entry_minimum_size (const struct disfluid_cache_entry *entry, + size_t *used_key, size_t *used_header, + size_t *used_body); + +MAYBE_UNUSED static struct disfluid_cache_entry + *cache_entry_alloc (size_t max_key, size_t max_header, size_t max_body); MAYBE_UNUSED static void cache_entry_free (struct disfluid_cache_entry *entry); @@ -24,8 +40,18 @@ MAYBE_UNUSED static void cache_entry_set_invalidated (struct disfluid_cache_entry *entry, bool invalidated); +/* Return value: 0 -> OK, -1 -> read_impl error, -2 -> invalid file, + -3 -> incomplete file. */ +MAYBE_UNUSED static int +cache_entry_load (struct disfluid_cache_entry *entry, + ssize_t (*read_impl) (void *context, void *buffer, + size_t max_size), void *context); + MAYBE_UNUSED static int -cache_entry_load (struct disfluid_cache_entry *entry, const char *filename); +cache_entry_read (struct disfluid_cache_entry *entry, int fd); + +MAYBE_UNUSED static int +cache_entry_fread (struct disfluid_cache_entry *entry, FILE * f); MAYBE_UNUSED static void cache_entry_get_request_date (const struct disfluid_cache_entry *entry, @@ -36,11 +62,19 @@ cache_entry_get_response_date (const struct disfluid_cache_entry *entry, struct timespec *date); MAYBE_UNUSED static bool -cache_entry_invalidated (const struct disfluid_cache_entry *entry); +cache_entry_is_invalidated (const struct disfluid_cache_entry *entry); +/* -1: write_impl failed. 0: OK. */ MAYBE_UNUSED static int cache_entry_save (const struct disfluid_cache_entry *entry, - const char *filename); + ssize_t (*write_impl) (void *context, const void *buffer, + size_t max_size), void *context); + +MAYBE_UNUSED static int +cache_entry_write (const struct disfluid_cache_entry *entry, int fd); + +MAYBE_UNUSED static int +cache_entry_fwrite (const struct disfluid_cache_entry *entry, FILE * f); # include <assert.h> @@ -51,23 +85,151 @@ struct disfluid_cache_entry struct timespec request_date; struct timespec response_date; bool invalidated; + size_t max_key; + size_t max_header; + size_t max_body; }; -static struct disfluid_cache_entry * -cache_entry_alloc (void) +static void * +cache_entry_key (struct disfluid_cache_entry *entry) +{ + size_t entry_offset; + memcpy (&entry_offset, &entry, sizeof (entry)); + size_t key_offset = entry_offset + sizeof (struct disfluid_cache_entry); + void *ret; + memcpy (&ret, &key_offset, sizeof (size_t)); + return ret; +} + +static void * +cache_entry_header (struct disfluid_cache_entry *entry) +{ + size_t entry_offset; + memcpy (&entry_offset, &entry, sizeof (entry)); + size_t header_offset = + entry_offset + sizeof (struct disfluid_cache_entry) + entry->max_key; + void *ret; + memcpy (&ret, &header_offset, sizeof (size_t)); + return ret; +} + +static void * +cache_entry_body (struct disfluid_cache_entry *entry) +{ + size_t entry_offset; + memcpy (&entry_offset, &entry, sizeof (entry)); + size_t body_offset = + entry_offset + sizeof (struct disfluid_cache_entry) + + entry->max_key + entry->max_header; + void *ret; + memcpy (&ret, &body_offset, sizeof (size_t)); + return ret; +} + +static size_t +cache_entry_size (size_t max_key, size_t max_header, size_t max_body) +{ + return sizeof (struct disfluid_cache_entry) + + max_key + max_header + max_body; +} + +static size_t +cache_entry_alignment (size_t max_key, size_t max_header, size_t max_body) +{ + (void) max_key; + (void) max_header; + (void) max_body; + return alignof (struct disfluid_cache_entry); +} + +static void +cache_entry_init (struct disfluid_cache_entry *entry, size_t max_key, + size_t max_header, size_t max_body) { ensure_init (); - struct disfluid_cache_entry *ret = - malloc (sizeof (struct disfluid_cache_entry)); - if (ret == NULL) + entry->request_date.tv_sec = 0; + entry->request_date.tv_nsec = 0; + entry->response_date.tv_sec = 0; + entry->response_date.tv_nsec = 0; + entry->invalidated = false; + entry->max_key = max_key; + entry->max_header = max_header; + entry->max_body = max_body; +} + +static void +cache_entry_minimum_size (const struct disfluid_cache_entry *entry, + size_t *min_key, size_t *min_header, + size_t *min_body) +{ + (void) entry; + *min_key = 0; + *min_header = 0; + *min_body = 0; +} + +static int +cache_entry_copy (struct disfluid_cache_entry *restrict dest, + const struct disfluid_cache_entry *restrict src) +{ + dest->request_date.tv_sec = src->request_date.tv_sec; + dest->request_date.tv_nsec = src->request_date.tv_nsec; + dest->response_date.tv_sec = src->response_date.tv_sec; + dest->response_date.tv_nsec = src->response_date.tv_nsec; + dest->invalidated = src->invalidated; + size_t src_key_size, src_header_size, src_body_size; + cache_entry_minimum_size (src, &src_key_size, &src_header_size, + &src_body_size); + void *dest_key = cache_entry_key (dest); + void *dest_header = cache_entry_header (dest); + void *dest_body = cache_entry_body (dest); + const void *src_key = cache_entry_key ((struct disfluid_cache_entry *) src); + const void *src_header = + cache_entry_header ((struct disfluid_cache_entry *) src); + const void *src_body = + cache_entry_body ((struct disfluid_cache_entry *) src); + int flags = 0; + if (src_key_size > dest->max_key) + { + flags = flags | 1; + } + if (src_header_size > dest->max_header) + { + flags = flags | 2; + } + if (src_body_size > dest->max_body) + { + flags = flags | 4; + } + if (flags == 0) + { + memcpy (dest_key, src_key, src_key_size); + memcpy (dest_header, src_header, src_header_size); + memcpy (dest_body, src_body, src_body_size); + } + return -flags; +} + +static struct disfluid_cache_entry * +cache_entry_alloc (size_t max_key, size_t max_header, size_t max_body) +{ + const size_t size = cache_entry_size (max_key, max_header, max_body); + const size_t alignment = + cache_entry_alignment (max_key, max_header, max_body); + struct disfluid_cache_entry *ret = calloc (1, size); + if (ret != NULL) { - abort (); + size_t address; + assert (sizeof (address) == sizeof (ret)); + memcpy (&address, &ret, sizeof (size_t)); + if ((address % alignment) != 0) + { + /* Calloc alignment is not strict enough. Should not happen + unless disfluid_cache_entry has bizarrely-aligned fields. */ + abort (); + } + cache_entry_init (ret, max_key, max_header, max_body); } - ret->request_date.tv_sec = 0; - ret->request_date.tv_nsec = 0; - ret->response_date.tv_sec = 0; - ret->response_date.tv_nsec = 0; - ret->invalidated = false; return ret; } @@ -80,24 +242,37 @@ cache_entry_free (struct disfluid_cache_entry *entry) static struct disfluid_cache_entry * cache_entry_dup (const struct disfluid_cache_entry *entry) { - struct disfluid_cache_entry *ret = cache_entry_alloc (); + struct disfluid_cache_entry *ret = + cache_entry_alloc (entry->max_key, entry->max_header, entry->max_body); if (ret != NULL) { - ret->request_date.tv_sec = entry->request_date.tv_sec; - ret->request_date.tv_nsec = entry->request_date.tv_nsec; - ret->response_date.tv_sec = entry->response_date.tv_sec; - ret->response_date.tv_nsec = entry->response_date.tv_nsec; - ret->invalidated = entry->invalidated; + int error = cache_entry_copy (ret, entry); + /* There is just as much room in ret as in entry, so the copy + cannot fail. */ + assert (error == 0); } return ret; } static void +cache_entry_normalize_timespec (struct timespec *ts) +{ + static const long billion = 1 * 1000 * 1000 * 1000; + if (ts->tv_nsec >= 1 * billion) + { + time_t additional_seconds = ts->tv_nsec / (1 * billion); + ts->tv_sec += additional_seconds; + ts->tv_nsec = ts->tv_nsec % (1 * billion); + } +} + +static void cache_entry_set_request_date (struct disfluid_cache_entry *entry, const struct timespec *date) { entry->request_date.tv_sec = date->tv_sec; entry->request_date.tv_nsec = date->tv_nsec; + cache_entry_normalize_timespec (&(entry->request_date)); } static void @@ -106,6 +281,7 @@ cache_entry_set_response_date (struct disfluid_cache_entry *entry, { entry->response_date.tv_sec = date->tv_sec; entry->response_date.tv_nsec = date->tv_nsec; + cache_entry_normalize_timespec (&(entry->response_date)); } static void @@ -130,60 +306,59 @@ cache_entry_set_invalidated (struct disfluid_cache_entry *entry, /* The response date on 12 bytes. */ /* On 1 byte: a value >= 128 if invalidated, < 128 if still valid. */ +struct disfluid_cache_entry_loader +{ + ssize_t (*read_impl) (void *, void *, size_t); + void *context; +}; + static int -cache_entry_really_read_n (int fd, size_t n, uint8_t * bytes, - bool *file_incomplete) +cache_entry_really_load_n (struct disfluid_cache_entry_loader *loader, + size_t n, uint8_t * bytes) { - size_t n_read = 0; - *file_incomplete = false; - while (n_read < n) + while (n > 0) { - ssize_t n_this_time = read (fd, &(bytes[n_read]), n - n_read); + ssize_t n_this_time = loader->read_impl (loader->context, bytes, n); if (n_this_time < 0) { - return 1; + return -1; } else if (n_this_time == 0) { - *file_incomplete = true; - return 1; + return -3; } else { assert (n_this_time > 0); - n_read += n_this_time; + bytes = &(bytes[n_this_time]); + n -= n_this_time; } } return 0; } static int -cache_entry_read_magic (int fd, bool *magic_ok, bool *file_incomplete) +cache_entry_load_magic (struct disfluid_cache_entry_loader *loader) { uint8_t magic[16]; - *magic_ok = false; - *file_incomplete = false; - int err = cache_entry_really_read_n (fd, 16, magic, file_incomplete); + int err = cache_entry_really_load_n (loader, 16, magic); if (err) { return err; } if (memcmp (magic, "disfluid c.entry", 16) != 0) { - *magic_ok = false; - return 1; + return -2; } - *magic_ok = true; return 0; } static int -cache_entry_read_timespec (int fd, struct timespec *timespec, - bool *file_incomplete) +cache_entry_load_timespec (struct disfluid_cache_entry_loader *loader, + struct timespec *timespec) { uint8_t data[12]; - *file_incomplete = false; - int err = cache_entry_really_read_n (fd, 12, data, file_incomplete); + int err = cache_entry_really_load_n (loader, 12, data); if (err) { return err; @@ -204,91 +379,89 @@ cache_entry_read_timespec (int fd, struct timespec *timespec, } static int -cache_entry_load_aux (struct disfluid_cache_entry *entry, - const char *filename, bool *file_incomplete) +cache_entry_load_flags (struct disfluid_cache_entry_loader *loader, + bool *invalidated) { - *file_incomplete = false; - int fd = open (filename, O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP); - if (fd < 0) + uint8_t data; + int err = cache_entry_really_load_n (loader, 1, &data); + if (err) { - return -1; + return err; } - bool magic_ok = false; + *invalidated = ((data & 0x80) != 0); + return 0; +} + +static int +cache_entry_load (struct disfluid_cache_entry *entry, + ssize_t (*read_impl) (void *, void *, size_t), + void *context) +{ + struct disfluid_cache_entry_loader loader = { + .read_impl = read_impl, + .context = context + }; + int error = 0; struct timespec request_date, response_date; bool invalidated; - int error = 0; - error = cache_entry_read_magic (fd, &magic_ok, file_incomplete); - if (error) - { - goto cleanup; - } - if (!magic_ok) + if (error == 0) { - error = -1; - goto cleanup; + error = cache_entry_load_magic (&loader); } - error = cache_entry_read_timespec (fd, &request_date, file_incomplete); - if (error) + if (error == 0) { - goto cleanup; + error = cache_entry_load_timespec (&loader, &request_date); } - error = cache_entry_read_timespec (fd, &response_date, file_incomplete); - if (error) + if (error == 0) { - goto cleanup; + error = cache_entry_load_timespec (&loader, &response_date); } - uint8_t flags; - ssize_t n_flags_read = read (fd, &flags, 1); - if (n_flags_read == 0) + if (error == 0) { - *file_incomplete = true; + error = cache_entry_load_flags (&loader, &invalidated); } - if (n_flags_read < 0) + if (error == 0) { - error = -1; - goto cleanup; + cache_entry_set_request_date (entry, &request_date); + cache_entry_set_response_date (entry, &response_date); + cache_entry_set_invalidated (entry, invalidated); } - invalidated = ((flags & 0x80) != 0); - cache_entry_set_request_date (entry, &request_date); - cache_entry_set_response_date (entry, &response_date); - cache_entry_set_invalidated (entry, invalidated); -cleanup: - close (fd); return error; } -static char * -cache_entry_backup_file_name (const char *filename) +static ssize_t +disfluid_cache_entry_loader_read (void *context, void *buffer, size_t max) { - char *backup_file = malloc (strlen (filename) + strlen ("~") + 1); - if (backup_file == NULL) + int *fdp = context; + return read (*fdp, buffer, max); +} + +static ssize_t +disfluid_cache_entry_loader_fread (void *context, void *buffer, size_t max) +{ + assert (max <= SIZE_MAX); + FILE *f = context; + size_t n_read = fread (buffer, 1, max, f); + if (ferror (f)) { - return NULL; + return -1; } - strcpy (backup_file, filename); - strcat (backup_file, "~"); - return backup_file; + assert (n_read <= max); + assert (n_read <= SIZE_MAX); + return n_read; } static int -cache_entry_load (struct disfluid_cache_entry *entry, const char *filename) -{ - /* Try to read from filename. If the file does not exist, do not - even try to read a backup. If the file exists but is incomplete, - read the backup file. */ - bool file_incomplete = false; - int error = cache_entry_load_aux (entry, filename, &file_incomplete); - if (file_incomplete) - { - char *backup_file = cache_entry_backup_file_name (filename); - if (backup_file == NULL) - { - abort (); - } - error = cache_entry_load_aux (entry, backup_file, &file_incomplete); - free (backup_file); - } - return error; +cache_entry_read (struct disfluid_cache_entry *entry, int fd) +{ + int *fdp = &fd; + return cache_entry_load (entry, disfluid_cache_entry_loader_read, fdp); +} + +static int +cache_entry_fread (struct disfluid_cache_entry *entry, FILE * f) +{ + return cache_entry_load (entry, disfluid_cache_entry_loader_fread, f); } static void @@ -308,17 +481,24 @@ cache_entry_get_response_date (const struct disfluid_cache_entry *entry, } static bool -cache_entry_invalidated (const struct disfluid_cache_entry *entry) +cache_entry_is_invalidated (const struct disfluid_cache_entry *entry) { return entry->invalidated; } +struct disfluid_cache_entry_saver +{ + ssize_t (*write_impl) (void *, const void *, size_t); + void *context; +}; + static int -cache_entry_really_write_n (int fd, size_t n, const uint8_t * data) +cache_entry_really_save_n (struct disfluid_cache_entry_saver *saver, size_t n, + const uint8_t * data) { while (n != 0) { - ssize_t n_this_time = write (fd, data, n); + ssize_t n_this_time = saver->write_impl (saver->context, data, n); if (n_this_time < 0) { return -1; @@ -339,14 +519,15 @@ cache_entry_really_write_n (int fd, size_t n, const uint8_t * data) } static int -cache_entry_write_magic (int fd) +cache_entry_save_magic (struct disfluid_cache_entry_saver *saver) { static const uint8_t magic[16] = "disfluid c.entry"; - return cache_entry_really_write_n (fd, 16, magic); + return cache_entry_really_save_n (saver, 16, magic); } static int -cache_entry_write_timespec (int fd, const struct timespec *ts) +cache_entry_save_timespec (struct disfluid_cache_entry_saver *saver, + const struct timespec *ts) { uint8_t data[12]; time_t tv_sec = ts->tv_sec; @@ -362,112 +543,85 @@ cache_entry_write_timespec (int fd, const struct timespec *ts) data[i] = tv_nsec % 256; tv_nsec /= 256; } - return cache_entry_really_write_n (fd, 12, data); + return cache_entry_really_save_n (saver, 12, data); } static int -cache_entry_save (const struct disfluid_cache_entry *entry, - const char *filename) +cache_entry_save_flags (struct disfluid_cache_entry_saver *saver, + bool invalidated) { - /* To save a file: */ - /* 1. Lock it. */ - /* 2. Copy it to `filename~' with copy_file_range. */ - /* 3. Overwrite `filename'. */ - /* 4. Unlock it. */ - int error = 0; - int actual_fd, backup_fd; - actual_fd = open (filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP); - char *backup_file = cache_entry_backup_file_name (filename); - if (backup_file == NULL) - { - abort (); - } - backup_fd = - open (backup_file, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP); - free (backup_file); - if (actual_fd < 0 || backup_fd < 0) + uint8_t value = 0; + if (invalidated) { - error = -1; - goto cleanup; + value = value | 0x80; } - struct flock lock = { - .l_type = F_WRLCK, - .l_whence = SEEK_SET, - .l_start = 0, - .l_len = 0 + return cache_entry_really_save_n (saver, 1, &value); +} + +static int +cache_entry_save (const struct disfluid_cache_entry *entry, + ssize_t (*write_impl) (void *context, const void *buffer, + size_t max_size), void *context) +{ + struct disfluid_cache_entry_saver saver = { + .write_impl = write_impl, + .context = context }; - int lock_error = fcntl (actual_fd, F_SETLKW, &lock); - if (lock_error) - { - error = -2; - goto cleanup; - } - ssize_t n_copied = 0; - do - { - /* Copy by blocks of 2 MiB. I don’t care the size, I don’t have - to allocate it anyway. */ - n_copied = - copy_file_range (actual_fd, NULL, backup_fd, NULL, 2 * 1024 * 1024, - 0); - if (n_copied < 0) - { - error = -3; - goto cleanup; - } - } - while (n_copied != 0); - off_t to_start = lseek (actual_fd, SEEK_SET, 0); - if (to_start != 0) - { - error = -4; - goto cleanup; - } - if (ftruncate (actual_fd, 0) != 0) - { - error = -5; - goto cleanup; - } - assert (error == 0); - error = cache_entry_write_magic (actual_fd); - if (error) - { - error = -6; - goto cleanup; - } - error = cache_entry_write_timespec (actual_fd, &(entry->request_date)); - if (error) - { - error = -7; - goto cleanup; - } - error = cache_entry_write_timespec (actual_fd, &(entry->response_date)); - if (error) + int error = 0; + if (error == 0) { - error = -8; - goto cleanup; + error = cache_entry_save_magic (&saver); } - uint8_t flags = 0; - if (entry->invalidated) + if (error == 0) { - flags = 0x80; + error = cache_entry_save_timespec (&saver, &(entry->request_date)); } - error = cache_entry_really_write_n (actual_fd, 1, &flags); - if (error) + if (error == 0) { - error = -9; - goto cleanup; + error = cache_entry_save_timespec (&saver, &(entry->response_date)); } -cleanup: - if (actual_fd >= 0) + if (error == 0) { - close (actual_fd); + error = cache_entry_save_flags (&saver, entry->invalidated); } - if (backup_fd >= 0) + return error; +} + +static ssize_t +disfluid_cache_entry_saver_write (void *context, const void *buffer, + size_t max) +{ + int *fdp = context; + return write (*fdp, buffer, max); +} + +static ssize_t +disfluid_cache_entry_saver_fwrite (void *context, const void *buffer, + size_t max) +{ + assert (max <= SIZE_MAX); + FILE *f = context; + size_t n_written = fwrite (buffer, 1, max, f); + if (ferror (f)) { - close (backup_fd); + return -1; } - return error; + assert (n_written <= max); + assert (n_written <= SIZE_MAX); + return n_written; +} + +static int +cache_entry_write (const struct disfluid_cache_entry *entry, int fd) +{ + int *fdp = &fd; + return cache_entry_save (entry, disfluid_cache_entry_saver_write, fdp); +} + +static int +cache_entry_fwrite (const struct disfluid_cache_entry *entry, FILE * f) +{ + return cache_entry_save (entry, disfluid_cache_entry_saver_fwrite, f); } #endif /* DISFLUID_DISFLUID_CACHE_ENTRY_INCLUDED */ diff --git a/src/libdisfluid/disfluid-tests.h b/src/libdisfluid/disfluid-tests.h index 0819bb0..21f4f43 100644 --- a/src/libdisfluid/disfluid-tests.h +++ b/src/libdisfluid/disfluid-tests.h @@ -11,11 +11,24 @@ static inline char *run_tests (size_t *n_tests, size_t *n_errors); # include "disfluid-version.h" # include "disfluid-cache-entry.h" -static inline char * -test_tmp_file_name_with_content (size_t n, const uint8_t * content) +# define BYTES * 1 + +# define KILOBYTES * 1024 BYTES + +# define MEGABYTES * 1024 KILOBYTES + +# define THOUSAND * 1000 + +# define MILLION THOUSAND THOUSAND + +# define BILLION THOUSAND MILLION + +static inline int +test_tmp_file_with_content (size_t n, const uint8_t * content) { char name[] = "/tmp/disfluid-cache-entry-test-XXXXXX"; int fd = mkstemp (name); + remove (name); if (fd < 0) { abort (); @@ -40,14 +53,11 @@ test_tmp_file_name_with_content (size_t n, const uint8_t * content) content = &(content[next]); } } - close (fd); - char *ret = malloc (strlen (name) + 1); - if (ret == NULL) + if (lseek (fd, 0, SEEK_SET) != 0) { abort (); } - strcpy (ret, name); - return ret; + return fd; } /* *INDENT-OFF* */ @@ -69,79 +79,22 @@ START_TEST (test_read_invalid_magic_number) { uint8_t data[16 + 12 + 12 + 1] = { 0 }; memcpy (data, "invalid magic no", 16); - char *filename = - test_tmp_file_name_with_content (sizeof (data) / sizeof (data[0]), data); - if (filename == NULL) - { - abort (); - } - struct disfluid_cache_entry *entry = cache_entry_alloc (); - if (entry == NULL) - { - abort (); - } - int error = cache_entry_load (entry, filename); - cache_entry_free (entry); - remove (filename); - free (filename); - ck_assert_int_ne (error, 0); -} -/* *INDENT-OFF* */ -END_TEST -/* *INDENT-ON* */ - -/* *INDENT-OFF* */ -START_TEST (test_read_inexistent_file) -/* *INDENT-ON* */ - -{ - static const char *filename = - "/disfluid-this-file-should-not-exist-to-pass-tests"; - struct disfluid_cache_entry *entry = cache_entry_alloc (); - if (entry == NULL) - { - abort (); - } - int error = cache_entry_load (entry, filename); - cache_entry_free (entry); - ck_assert_int_ne (error, 0); -} -/* *INDENT-OFF* */ -END_TEST -/* *INDENT-ON* */ - -/* *INDENT-OFF* */ -START_TEST (test_read_inexistent_file_with_valid_backup) -/* *INDENT-ON* */ - -{ - uint8_t data[16 + 12 + 12 + 1] = { 0 }; - memcpy (data, "disfluid c.entry", 16); - char *filename = - test_tmp_file_name_with_content (sizeof (data) / sizeof (data[0]), data); - if (filename == NULL) - { - abort (); - } - char *filename_backup = malloc (strlen (filename) + strlen ("~") + 1); - if (filename_backup == NULL) + int fd = + test_tmp_file_with_content (sizeof (data) / sizeof (data[0]), data); + if (fd < 0) { abort (); } - strcpy (filename_backup, filename); - strcat (filename_backup, "~"); - rename (filename, filename_backup); - struct disfluid_cache_entry *entry = cache_entry_alloc (); + struct disfluid_cache_entry *entry = + cache_entry_alloc (512 BYTES, 4 KILOBYTES, 2 MEGABYTES); if (entry == NULL) { abort (); } - int error = cache_entry_load (entry, filename); + int error = cache_entry_read (entry, fd); cache_entry_free (entry); - remove (filename_backup); - free (filename_backup); - free (filename); - ck_assert_int_ne (error, 0); + close (fd); + ck_assert_int_eq (error, -2); } /* *INDENT-OFF* */ END_TEST @@ -152,120 +105,45 @@ test_check_partial_situation (size_t n_partial) { uint8_t data[16 + 12 + 12 + 1] = { 0 }; memcpy (data, "disfluid c.entry", 16); - /* The data is all zeros */ - uint8_t backup_data[16 + 12 + 12 + 1] = { 0 }; - memcpy (backup_data, "disfluid c.entry", 16); - backup_data[16 + 8 - 1] = 1; - backup_data[16 + 12 - 1] = 2; - backup_data[16 + 12 + 8 - 1] = 3; - backup_data[16 + 12 + 12 - 1] = 4; - backup_data[16 + 12 + 12 + 1 - 1] = 0x80; - /* The backup has a request date of 1s + 2ns, response of 3s + 4ns, + data[16 + 8 - 1] = 1; + data[16 + 12 - 1] = 2; + data[16 + 12 + 8 - 1] = 3; + data[16 + 12 + 12 - 1] = 4; + data[16 + 12 + 12 + 1 - 1] = 0x80; + /* The data has a request date of 1s + 2ns, response of 3s + 4ns, and is invalidated. */ assert (n_partial <= sizeof (data) / sizeof (data[0])); - char *filename = test_tmp_file_name_with_content (n_partial, data); - if (filename == NULL) - { - abort (); - } - char *filename_backup = malloc (strlen (filename) + strlen ("~") + 1); - if (filename_backup == NULL) - { - abort (); - } - strcpy (filename_backup, filename); - strcat (filename_backup, "~"); - char *backup_content_filename = - test_tmp_file_name_with_content (sizeof (backup_data) / - sizeof (backup_data[0]), backup_data); - if (backup_content_filename == NULL) + int fd = test_tmp_file_with_content (n_partial, data); + if (fd < 0) { abort (); } - rename (backup_content_filename, filename_backup); - /* Now, filename is a partial file, and filename~ is a valid - backup. */ - struct disfluid_cache_entry *entry = cache_entry_alloc (); + struct disfluid_cache_entry *entry = + cache_entry_alloc (512 BYTES, 4 KILOBYTES, 2 MEGABYTES); if (entry == NULL) { abort (); } - int error = cache_entry_load (entry, filename); - ck_assert_int_eq (error, 0); + int error = cache_entry_read (entry, fd); if (n_partial < sizeof (data) / sizeof (data[0])) { - /* This should be the content of the backup file. */ + ck_assert_int_eq (error, -3); + } + else + { + ck_assert_int_eq (error, 0); struct timespec request, response; cache_entry_get_request_date (entry, &request); cache_entry_get_response_date (entry, &response); - bool invalidated = cache_entry_invalidated (entry); + bool invalidated = cache_entry_is_invalidated (entry); ck_assert_int_eq (request.tv_sec, 1); ck_assert_int_eq (request.tv_nsec, 2); ck_assert_int_eq (response.tv_sec, 3); ck_assert_int_eq (response.tv_nsec, 4); ck_assert (invalidated); } - else - { - /* This should be the content of the full file. */ - struct timespec request, response; - cache_entry_get_request_date (entry, &request); - cache_entry_get_response_date (entry, &response); - bool invalidated = cache_entry_invalidated (entry); - ck_assert_int_eq (request.tv_sec, 0); - ck_assert_int_eq (request.tv_nsec, 0); - ck_assert_int_eq (response.tv_sec, 0); - ck_assert_int_eq (response.tv_nsec, 0); - ck_assert (!invalidated); - } - cache_entry_free (entry); - free (backup_content_filename); - free (filename_backup); - free (filename); -} - -/* *INDENT-OFF* */ -START_TEST (test_read_file_with_valid_backup) -/* *INDENT-ON* */ - -{ - uint8_t data[16 + 12 + 12 + 1] = { 0 }; - memcpy (data, "disfluid c.entry", 16); - /* The data is all zeros */ - uint8_t backup_data[16 + 12 + 12 + 1] = { 0 }; - memcpy (backup_data, "disfluid c.entry", 16); - backup_data[16 + 8 - 1] = 1; - backup_data[16 + 12 - 1] = 2; - backup_data[16 + 12 + 8 - 1] = 3; - backup_data[16 + 12 + 12 - 1] = 4; - backup_data[16 + 12 + 12 + 1 - 1] = 0x80; - /* The backup has a request date of 1s + 2ns, response of 3s + 4ns, - and is invalidated. */ - char *filename = - test_tmp_file_name_with_content (sizeof (data) / sizeof (data[0]), data); - if (filename == NULL) - { - abort (); - } - char *filename_backup = malloc (strlen (filename) + strlen ("~") + 1); - if (filename_backup == NULL) - { - abort (); - } - strcpy (filename_backup, filename); - strcat (filename_backup, "~"); - rename (filename, filename_backup); - struct disfluid_cache_entry *entry = cache_entry_alloc (); - if (entry == NULL) - { - abort (); - } - int error = cache_entry_load (entry, filename); - remove (filename_backup); - free (filename_backup); - free (filename); cache_entry_free (entry); - ck_assert_int_ne (error, 0); + close (fd); } /* *INDENT-OFF* */ END_TEST @@ -374,6 +252,90 @@ START_TEST (test_read_cache_file_partial_41) END_TEST /* *INDENT-ON* */ +/* *INDENT-ON* */ +START_TEST (test_load_and_shrink) +/* *INDENT-ON* */ +{ + /* This pattern lets you load a cache entry on the stack, with a + maximum size, but not knowing the required size beforehand. The + resulting entry will not waste any room on the stack (except for + alignment and padding…). */ + /* 1. Create a large entry. */ + /* 2. Load data into the large entry. */ + /* 3. Push a minimal entry on the stack. */ + /* 4. Copy the contents to the minimal entry. */ + /* 5. Reinitialize the initial entry. */ + /* 6. Copy the second entry to the initial entry. */ + /* 7. Shrink the stack. */ + /* No copy operation can fail here. */ + size_t default_key_size = 512; + size_t default_header_size = 4096; + size_t default_body_size = 2 * 1024 * 1024; + struct disfluid_cache_entry *entry; + assert (sizeof (entry) == sizeof (size_t)); + const size_t required_size = + cache_entry_size (default_key_size, default_header_size, + default_body_size); + const size_t required_alignment = + cache_entry_alignment (default_key_size, default_header_size, + default_body_size); + entry = calloc (1, required_size); + if (entry == NULL) + { + abort (); + } + size_t address; + memcpy (&address, &entry, sizeof (entry)); + ck_assert_int_eq (address % required_alignment, 0); + cache_entry_init (entry, default_key_size, default_header_size, + default_body_size); + struct timespec request_date, response_date; + request_date.tv_sec = 42; + request_date.tv_nsec = 69; + response_date.tv_sec = 118; + response_date.tv_nsec = 218; + cache_entry_set_request_date (entry, &request_date); + cache_entry_set_response_date (entry, &response_date); + cache_entry_set_invalidated (entry, true); + size_t really_used_key_size, really_used_header_size, really_used_body_size; + cache_entry_minimum_size (entry, &really_used_key_size, + &really_used_header_size, &really_used_body_size); + struct disfluid_cache_entry *best_fit; + const size_t really_used_size = + cache_entry_size (really_used_key_size, really_used_header_size, + really_used_body_size); + best_fit = calloc (1, really_used_size); + if (best_fit == NULL) + { + abort (); + } + cache_entry_init (best_fit, really_used_key_size, really_used_header_size, + really_used_body_size); + int copy_error = cache_entry_copy (best_fit, entry); + ck_assert_int_eq (copy_error, 0); + cache_entry_init (entry, really_used_key_size, really_used_header_size, + really_used_body_size); + copy_error = cache_entry_copy (entry, best_fit); + ck_assert_int_eq (copy_error, 0); + struct disfluid_cache_entry *shrinked = realloc (entry, really_used_size); + assert (shrinked != NULL); + entry = shrinked; + free (best_fit); + struct timespec check_request_date, check_response_date; + cache_entry_get_request_date (entry, &check_request_date); + cache_entry_get_response_date (entry, &check_response_date); + bool check_invalidated = cache_entry_is_invalidated (entry); + ck_assert_int_eq (check_request_date.tv_sec, 42); + ck_assert_int_eq (check_request_date.tv_nsec, 69); + ck_assert_int_eq (check_response_date.tv_sec, 118); + ck_assert_int_eq (check_response_date.tv_nsec, 218); + ck_assert (check_invalidated); + free (entry); +} +/* *INDENT-OFF* */ +END_TEST +/* *INDENT-ON* */ + /* *INDENT-OFF* */ START_TEST (test_write_cache_entry) /* *INDENT-ON* */ @@ -388,21 +350,15 @@ START_TEST (test_write_cache_entry) old_data[16 + 12 + 12 + 1 - 1] = 0x80; /* The old data has a request date of 1s + 2ns, response of 3s + 4ns, and is invalidated. */ - char *filename = - test_tmp_file_name_with_content (sizeof (old_data) / sizeof (old_data[0]), - old_data); - if (filename == NULL) - { - abort (); - } - char *filename_backup = malloc (strlen (filename) + strlen ("~") + 1); - if (filename_backup == NULL) + int fd = + test_tmp_file_with_content (sizeof (old_data) / sizeof (old_data[0]), + old_data); + if (fd < 0) { abort (); } - strcpy (filename_backup, filename); - strcat (filename_backup, "~"); - struct disfluid_cache_entry *entry = cache_entry_alloc (); + struct disfluid_cache_entry *entry = + cache_entry_alloc (512 BYTES, 4 KILOBYTES, 2 MEGABYTES); if (entry == NULL) { abort (); @@ -415,53 +371,52 @@ START_TEST (test_write_cache_entry) cache_entry_set_request_date (entry, &request); cache_entry_set_response_date (entry, &response); cache_entry_set_invalidated (entry, false); - int error = cache_entry_save (entry, filename); + int error = cache_entry_write (entry, fd); ck_assert_int_eq (error, 0); - uint8_t check_backup_data[16 + 12 + 12 + 1]; uint8_t check_data[16 + 12 + 12 + 1]; assert (sizeof (check_data) == sizeof (old_data)); - assert (sizeof (check_backup_data) == sizeof (old_data)); - bool file_incomplete, backup_file_incomplete; - int fd = open (filename, O_RDONLY, 0); - int fd_backup = open (filename_backup, O_RDONLY, 0); - if (fd < 0 || fd_backup < 0) - { - abort (); - } + error = lseek (fd, 0, SEEK_SET); + ck_assert_int_eq (error, 0); + struct disfluid_cache_entry_loader read_loader = { + .read_impl = disfluid_cache_entry_loader_read, + .context = &fd + }; int check_error = - (cache_entry_really_read_n - (fd, sizeof (check_data) / sizeof (check_data[0]), check_data, - &file_incomplete) != 0); - int check_backup_error = - (cache_entry_really_read_n - (fd_backup, sizeof (check_backup_data) / sizeof (check_backup_data[0]), - check_backup_data, &backup_file_incomplete) != 0); + (cache_entry_really_load_n + (&read_loader, (sizeof (check_data) / sizeof (check_data[0])), + check_data)); ck_assert_int_eq (check_error, 0); - ck_assert_int_eq (check_backup_error, 0); - ck_assert (!file_incomplete); - ck_assert (!backup_file_incomplete); ck_assert_int_eq (memcmp (check_data, "disfluid c.entry", 16), 0); ck_assert_int_eq (check_data[16 + 8 - 1], 10); ck_assert_int_eq (check_data[16 + 12 - 1], 11); ck_assert_int_eq (check_data[16 + 12 + 8 - 1], 12); ck_assert_int_eq (check_data[16 + 12 + 12 - 1], 13); ck_assert_int_eq (check_data[16 + 12 + 12 + 1 - 1], 0); - ck_assert_int_eq (memcmp - (check_backup_data, old_data, - sizeof (check_backup_data) / - sizeof (check_backup_data[0])), 0); close (fd); - close (fd_backup); - remove (filename); - remove (filename_backup); cache_entry_free (entry); - free (filename_backup); - free (filename); } /* *INDENT-OFF* */ END_TEST /* *INDENT-ON* */ +/* *INDENT-OFF* */ +START_TEST (test_normalize_timespec) +/* *INDENT-ON* */ + +{ + struct timespec ts = { + .tv_sec = 42, + .tv_nsec = 2 BILLION + 123 MILLION + 456 THOUSAND + 789 + }; + cache_entry_normalize_timespec (&ts); + ck_assert_int_eq (ts.tv_sec, 44); + ck_assert_int_eq (ts.tv_nsec, 123 MILLION + 456 THOUSAND + 789); +} +/* *INDENT-OFF* */ +END_TEST +/* *INDENT-ON* */ + + static inline char * tests_read_whole_file (int file) { @@ -495,11 +450,11 @@ run_tests (size_t *n_tests, size_t *n_errors) TCase *general = tcase_create (_("disfluid general tests")); tcase_add_test (general, test_check_version); suite_add_tcase (suite, general); + TCase *time_functions = tcase_create (_("disfluid time functions")); + tcase_add_test (time_functions, test_normalize_timespec); + suite_add_tcase (suite, time_functions); TCase *cache_entry = tcase_create (_("disfluid cache entry files")); tcase_add_test (cache_entry, test_read_invalid_magic_number); - tcase_add_test (cache_entry, test_read_inexistent_file); - tcase_add_test (cache_entry, test_read_inexistent_file_with_valid_backup); - tcase_add_test (cache_entry, test_read_file_with_valid_backup); tcase_add_test (cache_entry, test_read_cache_file_partial_0); tcase_add_test (cache_entry, test_read_cache_file_partial_1); tcase_add_test (cache_entry, test_read_cache_file_partial_16); @@ -510,6 +465,7 @@ run_tests (size_t *n_tests, size_t *n_errors) tcase_add_test (cache_entry, test_read_cache_file_partial_37); tcase_add_test (cache_entry, test_read_cache_file_partial_40); tcase_add_test (cache_entry, test_read_cache_file_partial_41); + tcase_add_test (cache_entry, test_load_and_shrink); tcase_add_test (cache_entry, test_write_cache_entry); suite_add_tcase (suite, cache_entry); SRunner *runner = srunner_create (suite); diff --git a/src/libdisfluid/main.c b/src/libdisfluid/main.c index 24efb51..a898079 100644 --- a/src/libdisfluid/main.c +++ b/src/libdisfluid/main.c @@ -115,16 +115,46 @@ disfluid_translation_credits (void) return translation_credits (); } -struct disfluid_cache_entry * -disfluid_cache_entry_alloc (void) +size_t +disfluid_cache_entry_size (size_t max_key, size_t max_header, size_t max_body) { - return cache_entry_alloc (); + return cache_entry_size (max_key, max_header, max_body); +} + +size_t +disfluid_cache_entry_alignment (size_t max_key, size_t max_header, + size_t max_body) +{ + return cache_entry_alignment (max_key, max_header, max_body); } void -disfluid_cache_entry_free (struct disfluid_cache_entry *entry) +disfluid_cache_entry_init (struct disfluid_cache_entry *entry, + size_t max_key, size_t max_header, size_t max_body) { - return cache_entry_free (entry); + cache_entry_init (entry, max_key, max_header, max_body); +} + +void +disfluid_cache_entry_minimum_size (const struct disfluid_cache_entry *entry, + size_t *min_key, size_t *min_header, + size_t *min_body) +{ + cache_entry_minimum_size (entry, min_key, min_header, min_body); +} + +int +disfluid_cache_entry_copy (struct disfluid_cache_entry *restrict dest, + const struct disfluid_cache_entry *restrict src) +{ + return cache_entry_copy (dest, src); +} + +struct disfluid_cache_entry * +disfluid_cache_entry_alloc (size_t max_key, size_t max_header, + size_t max_body) +{ + return cache_entry_alloc (max_key, max_header, max_body); } struct disfluid_cache_entry * @@ -134,6 +164,12 @@ disfluid_cache_entry_dup (const struct disfluid_cache_entry *entry) } void +disfluid_cache_entry_free (struct disfluid_cache_entry *entry) +{ + return cache_entry_free (entry); +} + +void disfluid_cache_entry_set_request_date (struct disfluid_cache_entry *entry, const struct timespec *date) { @@ -160,13 +196,6 @@ disfluid_cache_entry_set_invalidated (struct disfluid_cache_entry *entry, cache_entry_set_invalidated (entry, invalidated); } -int -disfluid_cache_entry_load (struct disfluid_cache_entry *entry, - const char *filename) -{ - return cache_entry_load (entry, filename); -} - void disfluid_cache_entry_get_request_date (const struct disfluid_cache_entry *entry, struct timespec *date) @@ -182,14 +211,48 @@ disfluid_cache_entry_get_response_date (const struct disfluid_cache_entry } int -disfluid_cache_entry_invalidated (const struct disfluid_cache_entry *entry) +disfluid_cache_entry_is_invalidated (const struct disfluid_cache_entry *entry) { - return cache_entry_invalidated (entry); + return cache_entry_is_invalidated (entry); +} + +int +disfluid_cache_entry_load (struct disfluid_cache_entry *entry, + ssize_t (*read_impl) (void *, void *, size_t), + void *context) +{ + return cache_entry_load (entry, read_impl, context); } int disfluid_cache_entry_save (const struct disfluid_cache_entry *entry, - const char *filename) + ssize_t (*write_impl) (void *, const void *, + size_t), void *context) +{ + return cache_entry_save (entry, write_impl, context); +} + +int +disfluid_cache_entry_read (struct disfluid_cache_entry *entry, int fd) +{ + return cache_entry_read (entry, fd); +} + +int +disfluid_cache_entry_fread (struct disfluid_cache_entry *entry, FILE * f) +{ + return cache_entry_fread (entry, f); +} + +int +disfluid_cache_entry_write (const struct disfluid_cache_entry *entry, int fd) +{ + return cache_entry_write (entry, fd); +} + +int +disfluid_cache_entry_fwrite (const struct disfluid_cache_entry *entry, + FILE * f) { - return cache_entry_save (entry, filename); + return cache_entry_fwrite (entry, f); } |