X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fjournal%2Fjournal-file.c;h=48c27ee627a503f169697e2bb4f967eeb6e9de62;hb=4a4d89b682d2a8d32e899c4b47950f64df74fb7c;hp=7286e14ddba32a07421a15a7b2c451b74b379c53;hpb=0f99f74a14ef193c1ebde687c5cc76e1d67b85ef;p=elogind.git diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 7286e14dd..48c27ee62 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -26,7 +26,6 @@ #include #include #include -#include #include "journal-def.h" #include "journal-file.h" @@ -136,7 +135,7 @@ void journal_file_close(JournalFile *f) { 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); @@ -374,7 +373,13 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) 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); @@ -391,7 +396,7 @@ static int journal_file_move_to(JournalFile *f, int context, bool keep_always, u 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) { @@ -412,7 +417,7 @@ 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; @@ -425,7 +430,7 @@ int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Objec 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; @@ -441,11 +446,11 @@ int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Objec 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; @@ -482,14 +487,14 @@ static uint64_t journal_file_entry_seqnum(JournalFile *f, uint64_t *seqnum) { 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); @@ -502,7 +507,7 @@ int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object * 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; @@ -1292,7 +1297,7 @@ void journal_file_post_change(JournalFile *f) { __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) { @@ -1366,7 +1371,7 @@ typedef struct ChainCacheItem { } ChainCacheItem; static void chain_cache_put( - Hashmap *h, + OrderedHashmap *h, ChainCacheItem *ci, uint64_t first, uint64_t array, @@ -1380,9 +1385,10 @@ static void chain_cache_put( 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; @@ -1390,7 +1396,7 @@ static void chain_cache_put( ci->first = first; - if (hashmap_put(h, &ci->first, ci) < 0) { + if (ordered_hashmap_put(h, &ci->first, ci) < 0) { free(ci); return; } @@ -1419,7 +1425,7 @@ static int generic_array_get( 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; @@ -1522,7 +1528,7 @@ static int generic_array_bisect( /* 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 @@ -1656,7 +1662,7 @@ static int generic_array_bisect( } } - if (k > n) { + if (k >= n) { if (direction == DIRECTION_UP) { i = n; subtract_one = true; @@ -1792,23 +1798,6 @@ _pure_ static int test_object_offset(JournalFile *f, uint64_t p, uint64_t needle 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; @@ -1938,9 +1927,82 @@ int journal_file_move_to_entry_by_monotonic( 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, + uint64_t p, direction_t direction, Object **ret, uint64_t *offset) { @@ -1948,18 +2010,14 @@ int journal_file_next_entry( int r; assert(f); - assert(p > 0 || !o); n = le64toh(f->header->n_entries); if (n <= 0) return 0; - if (!o) + if (p == 0) i = direction == DIRECTION_DOWN ? 0 : n - 1; else { - if (o->object.type != OBJECT_ENTRY) - return -EINVAL; - r = generic_array_bisect(f, le64toh(f->header->entry_array_offset), le64toh(f->header->n_entries), @@ -2005,55 +2063,6 @@ int journal_file_next_entry( 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, @@ -2288,7 +2297,7 @@ void journal_file_dump(JournalFile *f) { 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; @@ -2498,7 +2507,7 @@ int journal_file_open( goto fail; } - f->chain_cache = hashmap_new(uint64_hash_func, uint64_compare_func); + f->chain_cache = ordered_hashmap_new(&uint64_hash_ops); if (!f->chain_cache) { r = -ENOMEM; goto fail; @@ -2516,8 +2525,6 @@ int journal_file_open( } if (f->last_stat.st_size == 0 && f->writable) { - uint64_t crtime; - /* Let's attach the creation time to the journal file, * so that the vacuuming code knows the age of this * file even if the file might end up corrupted one @@ -2526,10 +2533,9 @@ int journal_file_open( * 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); + fd_setcrtime(f->fd, now(CLOCK_REALTIME)); #ifdef HAVE_GCRYPT /* Try to load the FSPRG state, and if we can't, then