From a2799cc556fa3f8dc0bb3934077ca49e628efed2 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Wed, 15 Dec 2021 18:17:22 +0100 Subject: [PATCH 1/4] journal: Add a minimum hole size for hole punching Let's not bother punching extremely small holes to avoid unnecessary file fragmentation. --- src/journal/journald-file.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/journal/journald-file.c b/src/journal/journald-file.c index 2d263f2cb6e..78580ca84d6 100644 --- a/src/journal/journald-file.c +++ b/src/journal/journald-file.c @@ -15,6 +15,8 @@ #include "stat-util.h" #include "sync-util.h" +#define MINIMUM_HOLE_SIZE (1U * 1024U * 1024U / 2U) + static int journald_file_truncate(JournalFile *f) { uint64_t p; int r; @@ -66,6 +68,9 @@ static int journald_file_entry_array_punch_hole(JournalFile *f, uint64_t p, uint (journal_file_entry_array_n_items(&o) - n_unused) * sizeof(le64_t); sz = p + le64toh(o.object.size) - offset; + if (sz < MINIMUM_HOLE_SIZE) + return 0; + if (fallocate(f->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, offset, sz) < 0) return log_debug_errno(errno, "Failed to punch hole in entry array of %s: %m", f->path); From cdbba4487811bb14714ba462713298b2bda719c7 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Wed, 15 Dec 2021 18:18:25 +0100 Subject: [PATCH 2/4] journal: Correctly advance offset when iterating hash table entries pread() is not guaranteed to completely fill up the given buffer with data which we assumed until now. Instead, only increment the offset by the number of bytes that were actually read. --- src/journal/journald-file.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/journal/journald-file.c b/src/journal/journald-file.c index 78580ca84d6..bf0933189cc 100644 --- a/src/journal/journald-file.c +++ b/src/journal/journald-file.c @@ -81,6 +81,7 @@ static int journald_file_punch_holes(JournalFile *f) { HashItem items[4096 / sizeof(HashItem)]; uint64_t p, sz; size_t to_read; + ssize_t n; int r; r = journald_file_entry_array_punch_hole( @@ -92,14 +93,12 @@ static int journald_file_punch_holes(JournalFile *f) { sz = le64toh(f->header->data_hash_table_size); to_read = MIN((size_t) f->last_stat.st_blksize, sizeof(items)); - for (uint64_t i = p; i < p + sz; i += sizeof(items)) { - ssize_t n_read; + for (uint64_t i = p; i < p + sz; i += n) { + n = pread(f->fd, items, MIN(to_read, p + sz - i), i); + if (n < 0) + return n; - n_read = pread(f->fd, items, MIN(to_read, p + sz - i), i); - if (n_read < 0) - return n_read; - - for (size_t j = 0; j < (size_t) n_read / sizeof(HashItem); j++) { + for (size_t j = 0; j < (size_t) n / sizeof(HashItem); j++) { Object o; for (uint64_t q = le64toh(items[j].head_hash_offset); q != 0; From d951ac5578cafe3d4c0a18e5546b90caf8b01f66 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Wed, 15 Dec 2021 18:22:17 +0100 Subject: [PATCH 3/4] journal: Use 16kb buffer during hole punching Let's use the same buffer size as used in as copy.h. --- src/journal/journald-file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/journal/journald-file.c b/src/journal/journald-file.c index bf0933189cc..64f522a7aa8 100644 --- a/src/journal/journald-file.c +++ b/src/journal/journald-file.c @@ -15,6 +15,7 @@ #include "stat-util.h" #include "sync-util.h" +#define PAYLOAD_BUFFER_SIZE (16U * 1024U) #define MINIMUM_HOLE_SIZE (1U * 1024U * 1024U / 2U) static int journald_file_truncate(JournalFile *f) { @@ -78,7 +79,7 @@ static int journald_file_entry_array_punch_hole(JournalFile *f, uint64_t p, uint } static int journald_file_punch_holes(JournalFile *f) { - HashItem items[4096 / sizeof(HashItem)]; + HashItem items[PAYLOAD_BUFFER_SIZE / sizeof(HashItem)]; uint64_t p, sz; size_t to_read; ssize_t n; From 24040269ee70c2b53bd508646e7de053adfa92df Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Wed, 15 Dec 2021 18:23:15 +0100 Subject: [PATCH 4/4] journal: Stop reading in increments of block size during hole punching Let's not try to be overly clever here. This code path is not overly performance sensitive and we should avoid trying to outsmart the kernel without proper benchmarking. --- src/journal/journald-file.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/journal/journald-file.c b/src/journal/journald-file.c index 64f522a7aa8..503900d5bc2 100644 --- a/src/journal/journald-file.c +++ b/src/journal/journald-file.c @@ -81,7 +81,6 @@ static int journald_file_entry_array_punch_hole(JournalFile *f, uint64_t p, uint static int journald_file_punch_holes(JournalFile *f) { HashItem items[PAYLOAD_BUFFER_SIZE / sizeof(HashItem)]; uint64_t p, sz; - size_t to_read; ssize_t n; int r; @@ -92,10 +91,9 @@ static int journald_file_punch_holes(JournalFile *f) { p = le64toh(f->header->data_hash_table_offset); sz = le64toh(f->header->data_hash_table_size); - to_read = MIN((size_t) f->last_stat.st_blksize, sizeof(items)); for (uint64_t i = p; i < p + sz; i += n) { - n = pread(f->fd, items, MIN(to_read, p + sz - i), i); + n = pread(f->fd, items, MIN(sizeof(items), p + sz - i), i); if (n < 0) return n;