
This patch implement lingering transactions.

It allows you to trade performance with recovery time, by using a different
approach to journaling.

Normally, you would open the file O_SYNC, and when commiting a transaction
data gets written twice: once in the transaction file, and once in the real
file. Then, after the last write, the transaction file is removed.

What this patch do is allow you to avoid opening the file O_SYNC, and thus
writing the data synchronously only once, speeding up operations. The OS will
do the writeouts asynchronous when it think the time is right.

In this mode, the transaction file is written synchronously, but instead of
then writing to the real file with O_SYNC and then removing the transaction
file, we do the write _without_ O_SYNC and leave the transaction file.

In case of a crash, the transaction files will still be there for recovery, so
there's no risk of losing data.



---

 cur-root/libjio.h |   10 ++++++++++
 cur-root/trans.c  |   46 +++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 51 insertions(+), 5 deletions(-)

diff -puN trans.c~lingering_transactions trans.c
--- cur/trans.c~lingering_transactions	2004-07-13 18:16:43.582327120 -0300
+++ cur-root/trans.c	2004-07-13 18:16:43.585326664 -0300
@@ -45,7 +45,7 @@ static unsigned int get_tid(struct jfs *
 	/* increment it and handle overflows */
 	rv = curid + 1;
 	if (rv == 0)
-		rv = 1;
+		goto exit;
 
 	/* write to the file descriptor */
 	r = spwrite(fs->jfd, &rv, sizeof(rv), 0);
@@ -197,6 +197,7 @@ int jtrans_commit(struct jtrans *ts)
 	char *name;
 	unsigned char *buf_init, *bufp;
 	struct joper *op;
+	struct jlinger *linger;
 	off_t curpos = 0;
 	size_t written = 0;
 
@@ -355,10 +356,22 @@ int jtrans_commit(struct jtrans *ts)
 		written += rv;
 	}
 
-	/* the transaction has been applied, so we cleanup and remove it from
-	 * the disk */
-	free_tid(ts->fs, ts->id);
-	unlink(name);
+	if (ts->flags & J_LINGER) {
+		linger = malloc(sizeof(struct jlinger));
+		if (linger == NULL)
+			goto exit;
+
+		linger->id = id;
+		linger->name = strdup(name);
+		linger->next = ts->fs->ltrans;
+
+		ts->fs->ltrans = linger;
+	} else {
+		/* the transaction has been applied, so we cleanup and remove
+		 * it from the disk */
+		free_tid(ts->fs, ts->id);
+		unlink(name);
+	}
 
 	/* mark the transaction as commited, _after_ it was removed */
 	ts->flags = ts->flags | J_COMMITED;
@@ -466,6 +479,7 @@ int jopen(struct jfs *fs, const char *na
 	fs->fd = fd;
 	fs->name = strdup(name);
 	fs->flags = jflags;
+	fs->ltrans = NULL;
 
 	/* Note on fs->lock usage: this lock is used only inside the wrappers,
 	 * and exclusively to protect the file pointer. This means that it
@@ -519,9 +533,31 @@ int jopen(struct jfs *fs, const char *na
 	return fd;
 }
 
+/* sync a file (makes sense only if using lingering transactions) */
+void jsync(struct jfs *fs)
+{
+	struct jlinger *linger, *ltmp;
+
+	fsync(fs->fd);
+
+	linger = fs->ltrans;
+	while (linger != NULL) {
+		free_tid(fs, linger->id);
+		unlink(linger->name);
+		free(linger->name);
+
+		ltmp = linger->next;
+		free(linger);
+
+		linger = ltmp;
+	}
+}
+
 /* close a file */
 int jclose(struct jfs *fs)
 {
+	jsync(fs);
+
 	if (close(fs->fd))
 		return -1;
 	if (close(fs->jfd))
diff -puN libjio.h~lingering_transactions libjio.h
--- cur/libjio.h~lingering_transactions	2004-07-13 18:16:43.583326968 -0300
+++ cur-root/libjio.h	2004-07-13 18:16:43.585326664 -0300
@@ -27,6 +27,7 @@ struct jfs {
 	int jdirfd;		/* journal directory file descriptor */
 	int jfd;		/* journal's lock file descriptor */
 	int flags;		/* journal flags */
+	struct jlinger *ltrans;	/* lingered transactions */
 	pthread_mutex_t lock;	/* a soft lock used in some operations */
 };
 
@@ -53,6 +54,13 @@ struct jtrans {
 	struct joper *op;	/* list of operations */
 };
 
+/* lingered transaction */
+struct jlinger {
+	int id;			/* transaction id */
+	char *name;		/* name of the transaction file */
+	struct jlinger *next;
+};
+
 struct jfsck_result {
 	int total;		/* total transactions files we looked at */
 	int invalid;		/* invalid files in the journal directory */
@@ -88,6 +96,7 @@ int jtrans_add(struct jtrans *ts, const 
 int jtrans_commit(struct jtrans *ts);
 int jtrans_rollback(struct jtrans *ts);
 void jtrans_free(struct jtrans *ts);
+void jsync(struct jfs *fs);
 int jclose(struct jfs *fs);
 
 
@@ -123,6 +132,7 @@ FILE *jfsopen(struct jfs *stream, const 
 /* jfs constants */
 #define J_NOLOCK	1	/* don't lock the file before operating on it */
 #define J_NOROLLBACK	2	/* no need to read rollback information */
+#define J_LINGER	3	/* use lingering transactions */
 
 /* jtrans constants */
 #define J_COMMITED	1	/* mark a transaction as commited */

_
