From c74e2960dc4fd8e25db21ffed3bb7f35c10576c8 Mon Sep 17 00:00:00 2001 From: Jan Vcelak <jan.vcelak@nic.cz> Date: Wed, 3 Dec 2014 14:57:16 +0100 Subject: [PATCH] backport: journal file end check Correct detection of journal end position. 4a21001 Merge branch 'journal_file_end_check' into 'master' 1b07a79 journal: correct file end position detection fbc4690 tests: journal, added 10x rollover, random item size --- src/knot/server/journal.c | 18 +++++----- tests/journal.c | 74 +++++++++++++++++++++++++-------------- 2 files changed, 56 insertions(+), 36 deletions(-) diff --git a/src/knot/server/journal.c b/src/knot/server/journal.c index 1a8194bcef..455e792c7d 100644 --- a/src/knot/server/journal.c +++ b/src/knot/server/journal.c @@ -547,10 +547,10 @@ int journal_write_in(journal_t *j, journal_node_t **rn, uint64_t id, size_t len) dbg_journal("journal: will write id=%llu, node=%u, size=%zu, fsize=%zu\n", (unsigned long long)id, j->qtail, len, j->fsize); - /* Calculate remaining bytes to reach file size limit. */ - size_t fs_remaining = 0; - if (j->fsize < j->fslimit) { - fs_remaining = j->fslimit - j->fsize; + /* Calculate file end position (with imposed limits). */ + size_t file_end = j->fsize; + if (file_end > j->fslimit) { + file_end = j->fslimit; } int seek_ret = 0; @@ -559,12 +559,12 @@ int journal_write_in(journal_t *j, journal_node_t **rn, uint64_t id, size_t len) dbg_journal("journal: free.pos = %u free.len = %u\n", j->free.pos, j->free.len); journal_node_t *n = j->nodes + j->qtail; - if (j->free.pos + j->free.len == j->fsize) { + if (j->free.pos + len >= file_end) { dbg_journal_verb("journal: * is last node\n"); /* Grow journal file until the size limit. */ - if(j->free.len < len && len <= fs_remaining) { + if(j->free.pos + len < j->fslimit) { size_t diff = len - j->free.len; dbg_journal("journal: * growing by +%zu, pos=%u, " "new fsize=%zu\n", @@ -573,10 +573,8 @@ int journal_write_in(journal_t *j, journal_node_t **rn, uint64_t id, size_t len) j->fsize += diff; /* Appending increases file size. */ j->free.len += diff; - } - - /* Rewind if resize is needed, but the limit is reached. */ - if(j->free.len < len && len > fs_remaining) { + } else { + /* Rewind if resize is needed, but the limit is reached. */ journal_node_t *head = j->nodes + j->qhead; j->fsize = j->free.pos; j->free.pos = head->pos; diff --git a/tests/journal.c b/tests/journal.c index eaf58ef41e..8aba457e64 100644 --- a/tests/journal.c +++ b/tests/journal.c @@ -23,7 +23,6 @@ #include <tap/basic.h> #include "knot/server/journal.h" -#include "knot/knot.h" /*! \brief Generate random string with given length. */ static int randstr(char* dst, size_t len) @@ -36,12 +35,45 @@ static int randstr(char* dst, size_t len) return 0; } +/*! \brief Journal fillup test with size check. */ +static void test_fillup(journal_t *journal, size_t fsize, unsigned iter) +{ + const unsigned chunk = 512 + rand() % 512; + int ret = KNOT_EOK; + char *mptr = NULL; + size_t large_entry_len = chunk * 1024; + char *large_entry = malloc(chunk * 1024); + assert(large_entry); + randstr(large_entry, large_entry_len); + unsigned i = 0; + for (; i < 512; ++i) { + uint64_t chk_key = 0xBEBE + (iter * 512) + i; + ret = journal_map(journal, chk_key, &mptr, large_entry_len, false); + if (ret != KNOT_EOK) { + break; + } + + memcpy(mptr, large_entry, large_entry_len); + journal_unmap(journal, chk_key, mptr, 1); + } + is_int(KNOT_EBUSY, ret, "journal: fillup #%u (%d entries)", iter, i); + free(large_entry); + + /* Check file size. */ + struct stat st; + fstat(journal->fd, &st); + ok(st.st_size < fsize + large_entry_len, "journal: fillup / size check #%u", iter); + if (st.st_size > fsize + large_entry_len) { + diag("journal: fillup / size check #%u fsize(%zu) > max(%zu)", iter, st.st_size, fsize + large_entry_len); + } +} + int main(int argc, char *argv[]) { plan_lazy(); /* Create tmpdir */ - int fsize = 10 * 1024 * 1024; + size_t fsize = 10 * 1024 * 1024; char *tmpdir = test_tmpdir(); char jfilename[256]; snprintf(jfilename, sizeof(jfilename), "%s/%s", tmpdir, "journal.XXXXXX"); @@ -97,10 +129,9 @@ int main(int argc, char *argv[]) is_int(KNOT_EOK, ret, "journal: data integrity check after close/open"); /* Write random data. */ - ret = 0; - uint64_t tskey = 0xDEAD0000; + ret = KNOT_EOK; for (int i = 0; i < 512; ++i) { - chk_key = tskey + i; + chk_key = 0xDEAD0000 + i; ret = journal_map(journal, chk_key, &mptr, sizeof(chk_buf), false); if (ret != KNOT_EOK) { diag("journal_map failed: %s", knot_strerror(ret)); @@ -119,28 +150,19 @@ int main(int argc, char *argv[]) is_int(KNOT_ESPACE, ret, "journal: overfill"); /* Fillup */ - tskey = 0xBEEF0000; - size_t large_entry_len = 512 * 1024; - char *large_entry = malloc(512 * 1024); - assert(large_entry); - randstr(large_entry, large_entry_len); - for (int i = 0; i < 512; ++i) { - chk_key = tskey + i; - ret = journal_map(journal, chk_key, &mptr, large_entry_len, false); - if (ret != KNOT_EOK) { - break; - } - - journal_unmap(journal, chk_key, mptr, 1); + unsigned iterations = 10; + for (unsigned i = 0; i < iterations; ++i) { + /* Journal flush. */ + journal_close(journal); + ret = journal_mark_synced(jfilename); + is_int(KNOT_EOK, ret, "journal: flush after fillup #%u", i); + journal = journal_open(jfilename, fsize); + ok(journal != NULL, "journal: reopen after flush #%u", i); + /* Journal fillup. */ + test_fillup(journal, fsize, i); } - is_int(KNOT_EBUSY, ret, "journal: fillup"); - free(large_entry); - - /* Check file size. */ - struct stat st; - stat(journal->path, &st); - ok(st.st_size < fsize + large_entry_len, "journal: fillup file size check"); - + + /* Close journal. */ journal_close(journal); -- GitLab