+
+ header.magic = GUINT32_TO_LE(HEADER_MAGIC);
+ header.offset = GUINT64_TO_LE(offset);
+ header.size = GUINT32_TO_LE(item->data->len);
+ header.id = item->id;
+ footer.magic = GUINT32_TO_LE(FOOTER_MAGIC);
+
+ uint32_t crc = BLUESKY_CRC32C_SEED;
+
+ writebuf(log->fd, (const char *)&header, sizeof(header));
+ crc = crc32c(crc, (const char *)&header, sizeof(header));
+
+ writebuf(log->fd, item->data->data, item->data->len);
+ crc = crc32c(crc, item->data->data, item->data->len);
+
+ crc = crc32c(crc, (const char *)&footer,
+ sizeof(footer) - sizeof(uint32_t));
+ footer.crc = crc32c_finalize(crc);
+ writebuf(log->fd, (const char *)&footer, sizeof(footer));
+
+ item->log_seq = log->seq_num;
+ item->log_offset = offset + sizeof(header);
+ item->log_size = item->data->len;
+
+ offset += sizeof(header) + sizeof(footer) + item->data->len;
+
+ /* Replace the log item's string data with a memory-mapped copy of the
+ * data, now that it has been written to the log file. (Even if it
+ * isn't yet on disk, it should at least be in the page cache and so
+ * available to memory map.) */
+ bluesky_string_unref(item->data);
+ item->data = NULL;
+ bluesky_cloudlog_fetch(item);
+
+ log->committed = g_slist_prepend(log->committed, item);
+ g_atomic_int_add(&item->data_lock_count, -1);
+ g_mutex_unlock(item->lock);
+
+ /* Force an if there are no other log items currently waiting to be
+ * written. */
+ if (g_async_queue_length(log->queue) <= 0)
+ log_commit(log);