-uint64_t journal_file_entry_n_items(Object *o) {
- assert(o);
- assert(o->object.type == htole64(OBJECT_ENTRY));
-
- return (le64toh(o->object.size) - offsetof(Object, entry.items)) / sizeof(EntryItem);
-}
-
-static int journal_file_link_entry_item(JournalFile *f, Object *o, uint64_t offset, uint64_t i) {
- uint64_t p, q;
- int r;
- assert(f);
- assert(o);
- assert(offset > 0);
-
- p = le64toh(o->entry.items[i].object_offset);
- if (p == 0)
- return -EINVAL;
-
- o->entry.items[i].next_entry_offset = 0;
-
- /* Move to the data object */
- r = journal_file_move_to_object(f, p, &o);
- if (r < 0)
- return r;
-
- if (o->object.type != htole64(OBJECT_DATA))
- return -EBADMSG;
-
- q = le64toh(o->data.tail_entry_offset);
- o->data.tail_entry_offset = htole64(offset);
-
- if (q == 0)
- o->data.head_entry_offset = htole64(offset);
- else {
- uint64_t n, j;
-
- /* Move to previous entry */
- r = journal_file_move_to_object(f, q, &o);
- if (r < 0)
- return r;
-
- if (o->object.type != htole64(OBJECT_ENTRY))
- return -EBADMSG;
-
- n = journal_file_entry_n_items(o);
- for (j = 0; j < n; j++)
- if (le64toh(o->entry.items[j].object_offset) == p)
- break;
-
- if (j >= n)
- return -EBADMSG;
-
- o->entry.items[j].next_entry_offset = offset;
- }
-
- /* Move back to original entry */
- r = journal_file_move_to_object(f, offset, &o);
- if (r < 0)
- return r;
-
- o->entry.items[i].prev_entry_offset = q;
- return 0;
-}
-
-static int journal_file_link_entry(JournalFile *f, Object *o, uint64_t offset) {
- uint64_t p, i, n, k, a, b;
- int r;
-
- assert(f);
- assert(o);
- assert(offset > 0);
- assert(o->object.type == htole64(OBJECT_ENTRY));
-
- /* Link up the entry itself */
- p = le64toh(f->header->tail_entry_offset);
-
- o->entry.prev_entry_offset = f->header->tail_entry_offset;
- o->entry.next_entry_offset = 0;
-
- if (p == 0)
- f->header->head_entry_offset = htole64(offset);
- else {
- /* Temporarily move back to the previous entry, to
- * patch in pointer */
-
- r = journal_file_move_to_object(f, p, &o);
- if (r < 0)
- return r;
-
- o->entry.next_entry_offset = htole64(offset);
-
- r = journal_file_move_to_object(f, offset, &o);
- if (r < 0)
- return r;
- }
-
- f->header->tail_entry_offset = htole64(offset);
-
- /* Link up the items */
- n = journal_file_entry_n_items(o);
- for (i = 0; i < n; i++) {
- r = journal_file_link_entry_item(f, o, offset, i);
- if (r < 0)
- return r;
- }
-
- /* Link up the entry in the bisect table */
- n = le64toh(f->header->bisect_table_size) / sizeof(uint64_t);
- k = le64toh(f->header->arena_max_size) / n;
-
- a = (le64toh(f->header->last_bisect_offset) + k - 1) / k;
- b = offset / k;
-
- for (; a <= b; a++)
- f->bisect_table[a] = htole64(offset);
-
- f->header->last_bisect_offset = htole64(offset + le64toh(o->object.size));
-
- return 0;
-}
-
-static int journal_file_append_entry_internal(JournalFile *f, const dual_timestamp *ts, const EntryItem items[], unsigned n_items, Object **ret, uint64_t *offset) {
- uint64_t np;
- uint64_t osize;
- Object *o;
- int r;
-
- assert(f);
- assert(items || n_items == 0);
-
- osize = offsetof(Object, entry.items) + (n_items * sizeof(EntryItem));
-
- r = journal_file_append_object(f, osize, &o, &np);
- if (r < 0)
- return r;
-
- o->object.type = htole64(OBJECT_ENTRY);
- o->entry.seqnum = htole64(journal_file_seqnum(f));
- memcpy(o->entry.items, items, n_items * sizeof(EntryItem));
- o->entry.realtime = htole64(ts->realtime);
- o->entry.monotonic = htole64(ts->monotonic);
-
- r = journal_file_link_entry(f, o, np);
- if (r < 0)
- return r;
-
- if (ret)
- *ret = o;
-
- if (offset)
- *offset = np;
-
- return 0;
-}
-
-int journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const struct iovec iovec[], unsigned n_iovec, Object **ret, uint64_t *offset) {
- unsigned i;
- EntryItem *items;
- int r;
-
- assert(f);
-
- items = new(EntryItem, n_iovec);
- if (!items)
- return -ENOMEM;
-
- for (i = 0; i < n_iovec; i++) {
- uint64_t p;
-
- r = journal_file_append_data(f, iovec[i].iov_base, iovec[i].iov_len, NULL, &p);
- if (r < 0)
- goto finish;
-
- items[i].object_offset = htole64(p);
- }
-
- r = journal_file_append_entry_internal(f, ts, items, n_iovec, ret, offset);
-
-finish:
- free(items);
-
- return r;
-}
-
-int journal_file_move_to_entry(JournalFile *f, uint64_t seqnum, Object **ret, uint64_t *offset) {
- Object *o;
- uint64_t lower, upper, p, n, k;
- int r;
-
- assert(f);
-
- n = le64toh(f->header->bisect_table_size) / sizeof(uint64_t);
- k = le64toh(f->header->arena_max_size) / n;
-
- lower = 0;
- upper = le64toh(f->header->last_bisect_offset)/k+1;
-
- while (lower < upper) {
- k = (upper + lower) / 2;
- p = le64toh(f->bisect_table[k]);
-
- if (p == 0) {
- upper = k;
- continue;
- }
-
- r = journal_file_move_to_object(f, p, &o);
- if (r < 0)
- return r;
-
- if (o->object.type != htole64(OBJECT_ENTRY))
- return -EBADMSG;
-
- if (o->entry.seqnum == seqnum) {
- if (ret)
- *ret = o;
-
- if (offset)
- *offset = p;
-
- return 1;
- } else if (seqnum < o->entry.seqnum)
- upper = k;
- else if (seqnum > o->entry.seqnum)
- lower = k+1;
- }
-
- assert(lower == upper);
-
- if (lower <= 0)
- return 0;
-
- /* The object we are looking for is between
- * bisect_table[lower-1] and bisect_table[lower] */
-
- p = le64toh(f->bisect_table[lower-1]);
-
- for (;;) {
- r = journal_file_move_to_object(f, p, &o);
- if (r < 0)
- return r;
-
- if (o->entry.seqnum == seqnum) {
- if (ret)
- *ret = o;
-
- if (offset)
- *offset = p;
-
- return 1;
-
- } if (seqnum < o->entry.seqnum)
- return 0;
-
- if (o->entry.next_entry_offset == 0)
- return 0;
-
- p = le64toh(o->entry.next_entry_offset);
- }
-
- return 0;
-}
-
-int journal_file_next_entry(JournalFile *f, Object *o, Object **ret, uint64_t *offset) {
- uint64_t np;
- int r;
-
- assert(f);
-
- if (!o)
- np = le64toh(f->header->head_entry_offset);
- else {
- if (le64toh(o->object.type) != OBJECT_ENTRY)
- return -EINVAL;
-
- np = le64toh(o->entry.next_entry_offset);
- }
-
- if (np == 0)
- return 0;
-
- r = journal_file_move_to_object(f, np, &o);
- if (r < 0)
- return r;
-
- if (le64toh(o->object.type) != OBJECT_ENTRY)
- return -EBADMSG;
-
- if (ret)
- *ret = o;
-
- if (offset)
- *offset = np;
-
- return 1;
-}
-
-int journal_file_prev_entry(JournalFile *f, Object *o, Object **ret, uint64_t *offset) {
- uint64_t np;
- int r;
-
- assert(f);
-
- if (!o)
- np = le64toh(f->header->tail_entry_offset);
- else {
- if (le64toh(o->object.type) != OBJECT_ENTRY)
- return -EINVAL;
-
- np = le64toh(o->entry.prev_entry_offset);
- }
-
- if (np == 0)
- return 0;
-
- r = journal_file_move_to_object(f, np, &o);
- if (r < 0)
- return r;
-
- if (le64toh(o->object.type) != OBJECT_ENTRY)
- return -EBADMSG;
-
- if (ret)
- *ret = o;
-
- if (offset)
- *offset = np;