+static ssize_t
+read_all(int fd, void *buf, size_t count)
+{
+ char *in = buf;
+ ssize_t read_ret;
+ size_t done;
+
+ for (done = 0; done < count; done += read_ret) {
+ read_ret = read(fd, in + done, count - done);
+ if (read_ret == -1 || read_ret == 0)
+ return -1;
+ }
+ return done;
+}
+
+static ssize_t
+write_all(int fd, const void *buf, size_t count)
+{
+ const char *out = buf;
+ ssize_t written;
+ size_t done;
+
+ for (done = 0; done < count; done += written) {
+ written = write(fd, out + done, count - done);
+ if (written == -1)
+ return -1;
+ }
+ return done;
+}
+
+/* From the zlib docs:
+ * "If the memory is available, buffers sizes on the order of 128K or 256K
+ * bytes should be used."
+ */
+#define BUFSIZE 256 * 1024
+
+/**
+ * Compresses cache entry in memory and writes it to disk. Returns the size
+ * of the data written to disk.
+ */
+static size_t
+deflate_and_write_to_disk(const void *in_data, size_t in_data_size, int dest,
+ const char *filename)
+{
+#ifdef HAVE_ZSTD
+ /* from the zstd docs (https://facebook.github.io/zstd/zstd_manual.html):
+ * compression runs faster if `dstCapacity` >= `ZSTD_compressBound(srcSize)`.
+ */
+ size_t out_size = ZSTD_compressBound(in_data_size);
+ void * out = malloc(out_size);
+
+ size_t ret = ZSTD_compress(out, out_size, in_data, in_data_size,
+ ZSTD_COMPRESSION_LEVEL);
+ if (ZSTD_isError(ret)) {
+ free(out);
+ return 0;
+ }
+ ssize_t written = write_all(dest, out, ret);
+ if (written == -1) {
+ free(out);
+ return 0;
+ }
+ free(out);
+ return ret;
+#else
+ unsigned char *out;
+
+ /* allocate deflate state */
+ z_stream strm;
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.next_in = (uint8_t *) in_data;
+ strm.avail_in = in_data_size;
+
+ int ret = deflateInit(&strm, Z_BEST_COMPRESSION);
+ if (ret != Z_OK)
+ return 0;
+
+ /* compress until end of in_data */
+ size_t compressed_size = 0;
+ int flush;
+
+ out = malloc(BUFSIZE * sizeof(unsigned char));
+ if (out == NULL)
+ return 0;
+
+ do {
+ int remaining = in_data_size - BUFSIZE;
+ flush = remaining > 0 ? Z_NO_FLUSH : Z_FINISH;
+ in_data_size -= BUFSIZE;
+
+ /* Run deflate() on input until the output buffer is not full (which
+ * means there is no more data to deflate).
+ */
+ do {
+ strm.avail_out = BUFSIZE;
+ strm.next_out = out;
+
+ ret = deflate(&strm, flush); /* no bad return value */
+ assert(ret != Z_STREAM_ERROR); /* state not clobbered */
+
+ size_t have = BUFSIZE - strm.avail_out;
+ compressed_size += have;
+
+ ssize_t written = write_all(dest, out, have);
+ if (written == -1) {
+ (void)deflateEnd(&strm);
+ free(out);
+ return 0;
+ }
+ } while (strm.avail_out == 0);
+
+ /* all input should be used */
+ assert(strm.avail_in == 0);
+
+ } while (flush != Z_FINISH);
+
+ /* stream should be complete */
+ assert(ret == Z_STREAM_END);
+
+ /* clean up and return */
+ (void)deflateEnd(&strm);
+ free(out);
+ return compressed_size;
+# endif
+}
+
+static struct disk_cache_put_job *
+create_put_job(struct disk_cache *cache, const cache_key key,
+ const void *data, size_t size,
+ struct cache_item_metadata *cache_item_metadata)