summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVivien Kraus <vivien@planete-kraus.eu>2023-03-18 00:04:20 +0100
committerVivien Kraus <vivien@planete-kraus.eu>2023-03-18 12:02:11 +0100
commit59011ddd2b058c3797b0eaed2eb3bc01db1e96ea (patch)
tree4d690b0a8f1def14c73020f4edc01564ed07da58
parent13feab587ff754ed0a9e3e93639ecd5c43f3ec40 (diff)
Avoid memory management where possible.
-rw-r--r--include/Makefile.am4
-rw-r--r--include/disfluid.h70
-rw-r--r--include/disfluid/cache_entry.h122
-rw-r--r--src/adwaita/disfluid-cache-entry.c2
-rw-r--r--src/adwaita/disfluid-window.c3
-rw-r--r--src/libdisfluid/disfluid-cache-entry.h550
-rw-r--r--src/libdisfluid/disfluid-tests.h374
-rw-r--r--src/libdisfluid/main.c95
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);
}