From 25428cd65656ff69b7e75f86cd10f6d9753ec2e9 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Wed, 7 Oct 2026 19:44:38 +0200 Subject: [PATCH] journal-file: look up the window of an object only once journal_file_move_to_object() maps the object header, reads the object size from it, and then looks up the window again for the whole object. That second lookup finds the same window nearly every time, since windows are 8 MiB and most objects are small. Have mmap_cache_fd_get() return how many bytes the window has after the offset, and skip the second lookup when the object fits in the window and in the file. Reading 1M entries of a real journal takes 10.7% fewer cycles. --- src/libsystemd/sd-journal/journal-file.c | 51 ++++++++++++++++----- src/libsystemd/sd-journal/journal-verify.c | 2 +- src/libsystemd/sd-journal/mmap-cache.c | 5 +- src/libsystemd/sd-journal/mmap-cache.h | 3 +- src/libsystemd/sd-journal/test-mmap-cache.c | 16 +++++-- 5 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c index 950b22f067..9216944e51 100644 --- a/src/libsystemd/sd-journal/journal-file.c +++ b/src/libsystemd/sd-journal/journal-file.c @@ -848,14 +848,16 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) return journal_file_fstat(f); } -static int journal_file_move_to( +static int journal_file_move_to_full( JournalFile *f, ObjectType type, bool keep_always, uint64_t offset, uint64_t size, - void **ret) { + void **ret, + uint64_t *ret_size) { + size_t window_size; int r; assert(f); @@ -884,7 +886,27 @@ static int journal_file_move_to( return -EADDRNOTAVAIL; } - return mmap_cache_fd_get(f->cache_fd, type_to_category(type), keep_always, offset, size, &f->last_stat, ret); + r = mmap_cache_fd_get(f->cache_fd, type_to_category(type), keep_always, offset, size, &f->last_stat, ret, &window_size); + if (r < 0) + return r; + + /* The window is rounded up to whole pages, and may extend beyond the end of the file, which must not + * be accessed */ + if (ret_size) + *ret_size = MIN((uint64_t) window_size, (uint64_t) f->last_stat.st_size - offset); + + return 0; +} + +static int journal_file_move_to( + JournalFile *f, + ObjectType type, + bool keep_always, + uint64_t offset, + uint64_t size, + void **ret) { + + return journal_file_move_to_full(f, type, keep_always, offset, size, ret, /* ret_size= */ NULL); } static uint64_t minimum_header_size(JournalFile *f, Object *o) { @@ -1106,8 +1128,9 @@ static int check_object(JournalFile *f, Object *o, uint64_t offset) { } int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset, Object **ret) { - int r; + uint64_t size, available; Object *o; + int r; assert(f); @@ -1129,7 +1152,7 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset journal_object_type_to_string(type), offset); - r = journal_file_move_to(f, type, false, offset, offsetof(ObjectHeader, payload), (void**) &o); + r = journal_file_move_to_full(f, type, false, offset, offsetof(ObjectHeader, payload), (void**) &o, &available); if (r < 0) return r; @@ -1137,13 +1160,17 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset if (r < 0) return r; - r = journal_file_move_to(f, type, false, offset, le64toh(READ_NOW(o->object.size)), (void**) &o); - if (r < 0) - return r; + /* Usually the window of the header contains the whole object, which then needs no second lookup */ + size = le64toh(READ_NOW(o->object.size)); + if (size > available) { + r = journal_file_move_to(f, type, false, offset, size, (void**) &o); + if (r < 0) + return r; - r = check_object_header(f, o, type, offset); - if (r < 0) - return r; + r = check_object_header(f, o, type, offset); + if (r < 0) + return r; + } r = check_object(f, o, offset); if (r < 0) @@ -4249,7 +4276,7 @@ int journal_file_open( goto fail; } - r = mmap_cache_fd_get(f->cache_fd, MMAP_CACHE_CATEGORY_HEADER, true, 0, PAGE_ALIGN(sizeof(Header)), &f->last_stat, &h); + r = mmap_cache_fd_get(f->cache_fd, MMAP_CACHE_CATEGORY_HEADER, true, 0, PAGE_ALIGN(sizeof(Header)), &f->last_stat, &h, /* ret_size= */ NULL); if (r == -EINVAL) { /* Some file systems (jffs2 or p9fs) don't support mmap() properly (or only read-only * mmap()), and return EINVAL in that case. Let's propagate that as a more recognizable error diff --git a/src/libsystemd/sd-journal/journal-verify.c b/src/libsystemd/sd-journal/journal-verify.c index 79061940b3..d0a7c9eeaf 100644 --- a/src/libsystemd/sd-journal/journal-verify.c +++ b/src/libsystemd/sd-journal/journal-verify.c @@ -404,7 +404,7 @@ static int contains_uint64(MMapFileDescriptor *f, uint64_t n, uint64_t p) { c = (a + b) / 2; - r = mmap_cache_fd_get(f, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z); + r = mmap_cache_fd_get(f, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z, /* ret_size= */ NULL); if (r < 0) return r; diff --git a/src/libsystemd/sd-journal/mmap-cache.c b/src/libsystemd/sd-journal/mmap-cache.c index f49ca12ba4..58d52ff41e 100644 --- a/src/libsystemd/sd-journal/mmap-cache.c +++ b/src/libsystemd/sd-journal/mmap-cache.c @@ -342,7 +342,8 @@ int mmap_cache_fd_get( uint64_t offset, size_t size, struct stat *st, - void **ret) { + void **ret, + size_t *ret_size) { MMapCache *m = mmap_cache_fd_cache(f); Window *w; @@ -386,6 +387,8 @@ found: category_attach_window(m, c, w); *ret = (uint8_t*) w->ptr + (offset - w->offset); + if (ret_size) + *ret_size = w->offset + w->size - offset; return 0; } diff --git a/src/libsystemd/sd-journal/mmap-cache.h b/src/libsystemd/sd-journal/mmap-cache.h index bf690536e9..24f492076e 100644 --- a/src/libsystemd/sd-journal/mmap-cache.h +++ b/src/libsystemd/sd-journal/mmap-cache.h @@ -39,7 +39,8 @@ int mmap_cache_fd_get( uint64_t offset, size_t size, struct stat *st, - void **ret); + void **ret, + size_t *ret_size); int mmap_cache_fd_pin( MMapFileDescriptor *f, diff --git a/src/libsystemd/sd-journal/test-mmap-cache.c b/src/libsystemd/sd-journal/test-mmap-cache.c index b59d5177f6..9fae3dcaa5 100644 --- a/src/libsystemd/sd-journal/test-mmap-cache.c +++ b/src/libsystemd/sd-journal/test-mmap-cache.c @@ -14,6 +14,7 @@ int main(int argc, char *argv[]) { char px[] = "/tmp/testmmapXXXXXXX", py[] = "/tmp/testmmapYXXXXXX", pz[] = "/tmp/testmmapZXXXXXX"; MMapCache *m; void *p, *q; + size_t sp, sq; test_setup_logging(LOG_DEBUG); @@ -30,21 +31,26 @@ int main(int argc, char *argv[]) { ASSERT_OK(z = mkostemp_safe(pz)); (void) unlink(pz); - ASSERT_OK(mmap_cache_fd_get(fx, 0, false, 1, 2, NULL, &p)); + ASSERT_OK(mmap_cache_fd_get(fx, 0, false, 1, 2, NULL, &p, &sp)); + ASSERT_GE(sp, 2U); - ASSERT_OK(mmap_cache_fd_get(fx, 0, false, 2, 2, NULL, &q)); + ASSERT_OK(mmap_cache_fd_get(fx, 0, false, 2, 2, NULL, &q, &sq)); ASSERT_PTR_EQ((uint8_t*) p + 1, (uint8_t*) q); + ASSERT_EQ(sq, sp - 1); - ASSERT_OK(mmap_cache_fd_get(fx, 1, false, 3, 2, NULL, &q)); + ASSERT_OK(mmap_cache_fd_get(fx, 1, false, 3, 2, NULL, &q, &sq)); ASSERT_PTR_EQ((uint8_t*) p + 2, (uint8_t*) q); + ASSERT_EQ(sq, sp - 2); - ASSERT_OK(mmap_cache_fd_get(fx, 0, false, 16ULL*1024ULL*1024ULL, 2, NULL, &p)); + ASSERT_OK(mmap_cache_fd_get(fx, 0, false, 16ULL*1024ULL*1024ULL, 2, NULL, &p, &sp)); + ASSERT_GE(sp, 2U); - ASSERT_OK(mmap_cache_fd_get(fx, 1, false, 16ULL*1024ULL*1024ULL+1, 2, NULL, &q)); + ASSERT_OK(mmap_cache_fd_get(fx, 1, false, 16ULL*1024ULL*1024ULL+1, 2, NULL, &q, &sq)); ASSERT_PTR_EQ((uint8_t*) p + 1, (uint8_t*) q); + ASSERT_EQ(sq, sp - 1); mmap_cache_fd_free(fx); mmap_cache_unref(m);