if (f->mmap)
mmap_cache_unref(f->mmap);
- hashmap_free_free(f->chain_cache);
+ ordered_hashmap_free_free(f->chain_cache);
#if defined(HAVE_XZ) || defined(HAVE_LZ4)
free(f->compress_buffer);
return 0;
}
-static int journal_file_move_to(JournalFile *f, int context, bool keep_always, uint64_t offset, uint64_t size, void **ret) {
+static unsigned type_to_context(ObjectType type) {
+ /* One context for each type, plus one catch-all for the rest */
+ assert_cc(_OBJECT_TYPE_MAX <= MMAP_CACHE_MAX_CONTEXTS);
+ return type > OBJECT_UNUSED && type < _OBJECT_TYPE_MAX ? type : 0;
+}
+
+static int journal_file_move_to(JournalFile *f, ObjectType type, bool keep_always, uint64_t offset, uint64_t size, void **ret) {
assert(f);
assert(ret);
return -EADDRNOTAVAIL;
}
- return mmap_cache_get(f->mmap, f->fd, f->prot, context, keep_always, offset, size, &f->last_stat, ret);
+ return mmap_cache_get(f->mmap, f->fd, f->prot, type_to_context(type), keep_always, offset, size, &f->last_stat, ret);
}
static uint64_t minimum_header_size(Object *o) {
return table[o->object.type];
}
-int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Object **ret) {
+int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset, Object **ret) {
int r;
void *t;
Object *o;
if (!VALID64(offset))
return -EFAULT;
- r = journal_file_move_to(f, type_to_context(type), false, offset, sizeof(ObjectHeader), &t);
+ r = journal_file_move_to(f, type, false, offset, sizeof(ObjectHeader), &t);
if (r < 0)
return r;
if (s < minimum_header_size(o))
return -EBADMSG;
- if (type > 0 && o->object.type != type)
+ if (type > OBJECT_UNUSED && o->object.type != type)
return -EBADMSG;
if (s > sizeof(ObjectHeader)) {
- r = journal_file_move_to(f, o->object.type, false, offset, s, &t);
+ r = journal_file_move_to(f, type, false, offset, s, &t);
if (r < 0)
return r;
return r;
}
-int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object **ret, uint64_t *offset) {
+int journal_file_append_object(JournalFile *f, ObjectType type, uint64_t size, Object **ret, uint64_t *offset) {
int r;
uint64_t p;
Object *tail, *o;
void *t;
assert(f);
- assert(type > 0 && type < _OBJECT_TYPE_MAX);
+ assert(type > OBJECT_UNUSED && type < _OBJECT_TYPE_MAX);
assert(size >= sizeof(ObjectHeader));
assert(offset);
assert(ret);
if (p == 0)
p = le64toh(f->header->header_size);
else {
- r = journal_file_move_to_object(f, -1, p, &tail);
+ r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &tail);
if (r < 0)
return r;
__sync_synchronize();
if (ftruncate(f->fd, f->last_stat.st_size) < 0)
- log_error("Failed to truncate file to its own size: %m");
+ log_error_errno(errno, "Failed to truncate file to its own size: %m");
}
static int entry_item_cmp(const void *_a, const void *_b) {
} ChainCacheItem;
static void chain_cache_put(
- Hashmap *h,
+ OrderedHashmap *h,
ChainCacheItem *ci,
uint64_t first,
uint64_t array,
if (array == first)
return;
- if (hashmap_size(h) >= CHAIN_CACHE_MAX)
- ci = hashmap_steal_first(h);
- else {
+ if (ordered_hashmap_size(h) >= CHAIN_CACHE_MAX) {
+ ci = ordered_hashmap_steal_first(h);
+ assert(ci);
+ } else {
ci = new(ChainCacheItem, 1);
if (!ci)
return;
ci->first = first;
- if (hashmap_put(h, &ci->first, ci) < 0) {
+ if (ordered_hashmap_put(h, &ci->first, ci) < 0) {
free(ci);
return;
}
a = first;
/* Try the chain cache first */
- ci = hashmap_get(f->chain_cache, &first);
+ ci = ordered_hashmap_get(f->chain_cache, &first);
if (ci && i > ci->total) {
a = ci->array;
i -= ci->total;
/* Start with the first array in the chain */
a = first;
- ci = hashmap_get(f->chain_cache, &first);
+ ci = ordered_hashmap_get(f->chain_cache, &first);
if (ci && n > ci->total) {
/* Ah, we have iterated this bisection array chain
* previously! Let's see if we can skip ahead in the
}
}
- if (k > n) {
+ if (k >= n) {
if (direction == DIRECTION_UP) {
i = n;
subtract_one = true;
return TEST_RIGHT;
}
-int journal_file_move_to_entry_by_offset(
- JournalFile *f,
- uint64_t p,
- direction_t direction,
- Object **ret,
- uint64_t *offset) {
-
- return generic_array_bisect(f,
- le64toh(f->header->entry_array_offset),
- le64toh(f->header->n_entries),
- p,
- test_object_offset,
- direction,
- ret, offset, NULL);
-}
-
-
static int test_object_seqnum(JournalFile *f, uint64_t p, uint64_t needle) {
Object *o;
int r;
ret, offset, NULL);
}
+void journal_file_reset_location(JournalFile *f) {
+ f->location_type = LOCATION_HEAD;
+ f->current_offset = 0;
+ f->current_seqnum = 0;
+ f->current_realtime = 0;
+ f->current_monotonic = 0;
+ zero(f->current_boot_id);
+ f->current_xor_hash = 0;
+}
+
+void journal_file_save_location(JournalFile *f, direction_t direction, Object *o, uint64_t offset) {
+ f->last_direction = direction;
+ f->location_type = LOCATION_SEEK;
+ f->current_offset = offset;
+ f->current_seqnum = le64toh(o->entry.seqnum);
+ f->current_realtime = le64toh(o->entry.realtime);
+ f->current_monotonic = le64toh(o->entry.monotonic);
+ f->current_boot_id = o->entry.boot_id;
+ f->current_xor_hash = le64toh(o->entry.xor_hash);
+}
+
+int journal_file_compare_locations(JournalFile *af, JournalFile *bf) {
+ assert(af);
+ assert(bf);
+ assert(af->location_type == LOCATION_SEEK);
+ assert(bf->location_type == LOCATION_SEEK);
+
+ /* If contents and timestamps match, these entries are
+ * identical, even if the seqnum does not match */
+ if (sd_id128_equal(af->current_boot_id, bf->current_boot_id) &&
+ af->current_monotonic == bf->current_monotonic &&
+ af->current_realtime == bf->current_realtime &&
+ af->current_xor_hash == bf->current_xor_hash)
+ return 0;
+
+ if (sd_id128_equal(af->header->seqnum_id, bf->header->seqnum_id)) {
+
+ /* If this is from the same seqnum source, compare
+ * seqnums */
+ if (af->current_seqnum < bf->current_seqnum)
+ return -1;
+ if (af->current_seqnum > bf->current_seqnum)
+ return 1;
+
+ /* Wow! This is weird, different data but the same
+ * seqnums? Something is borked, but let's make the
+ * best of it and compare by time. */
+ }
+
+ if (sd_id128_equal(af->current_boot_id, bf->current_boot_id)) {
+
+ /* If the boot id matches, compare monotonic time */
+ if (af->current_monotonic < bf->current_monotonic)
+ return -1;
+ if (af->current_monotonic > bf->current_monotonic)
+ return 1;
+ }
+
+ /* Otherwise, compare UTC time */
+ if (af->current_realtime < bf->current_realtime)
+ return -1;
+ if (af->current_realtime > bf->current_realtime)
+ return 1;
+
+ /* Finally, compare by contents */
+ if (af->current_xor_hash < bf->current_xor_hash)
+ return -1;
+ if (af->current_xor_hash > bf->current_xor_hash)
+ return 1;
+
+ return 0;
+}
+
int journal_file_next_entry(
JournalFile *f,
Object *o, uint64_t p,
return 1;
}
-int journal_file_skip_entry(
- JournalFile *f,
- Object *o, uint64_t p,
- int64_t skip,
- Object **ret, uint64_t *offset) {
-
- uint64_t i, n;
- int r;
-
- assert(f);
- assert(o);
- assert(p > 0);
-
- if (o->object.type != OBJECT_ENTRY)
- return -EINVAL;
-
- r = generic_array_bisect(f,
- le64toh(f->header->entry_array_offset),
- le64toh(f->header->n_entries),
- p,
- test_object_offset,
- DIRECTION_DOWN,
- NULL, NULL,
- &i);
- if (r <= 0)
- return r;
-
- /* Calculate new index */
- if (skip < 0) {
- if ((uint64_t) -skip >= i)
- i = 0;
- else
- i = i - (uint64_t) -skip;
- } else
- i += (uint64_t) skip;
-
- n = le64toh(f->header->n_entries);
- if (n <= 0)
- return -EBADMSG;
-
- if (i >= n)
- i = n-1;
-
- return generic_array_get(f,
- le64toh(f->header->entry_array_offset),
- i,
- ret, offset);
-}
-
int journal_file_next_entry_for_data(
JournalFile *f,
Object *o, uint64_t p,
p = le64toh(f->header->header_size);
while (p != 0) {
- r = journal_file_move_to_object(f, -1, p, &o);
+ r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o);
if (r < 0)
goto fail;
goto fail;
}
- f->chain_cache = hashmap_new(&uint64_hash_ops);
+ f->chain_cache = ordered_hashmap_new(&uint64_hash_ops);
if (!f->chain_cache) {
r = -ENOMEM;
goto fail;
* currently no usable API to query this, hence let's
* emulate this via extended attributes. If extended
* attributes are not supported we'll just skip this,
- * and rely solely on mtime/atime/ctime of the file.*/
+ * and rely solely on mtime/atime/ctime of the file. */
crtime = htole64((uint64_t) now(CLOCK_REALTIME));
fsetxattr(f->fd, "user.crtime_usec", &crtime, sizeof(crtime), XATTR_CREATE);