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.
This commit is contained in:
Daan De Meyer authored and Daan De Meyer committed 2026-10-09 14:03:41 +02:00
1 parent f992bce2c1
commit 25428cd656
5 files changed
+57 -20

No files matched your search

+39 -12
View File
@@ -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
+1 -1
View File
@@ -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;
+4 -1
View File
@@ -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;
}
+2 -1
View File
@@ -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,
+11 -5
View File
@@ -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);