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