git » libjio » commit c205c0d

libjio: Internal journal API cleanup

author Alberto Bertogli
2009-07-11 03:33:07 UTC
committer Alberto Bertogli
2009-07-11 03:34:13 UTC
parent 31cc89586bb819134113ea47a3053021f83cf9ea

libjio: Internal journal API cleanup

This patch cleans the internal journal API up, mostly by making a clear
distinction between struct jtrans and struct journal_op. Now, the latter
does not know about the former, and jtrans only uses the exported journal
functions.

Signed-off-by: Alberto Bertogli <albertito@blitiri.com.ar>

libjio/journal.c +25 -60
libjio/journal.h +5 -3
libjio/trans.c +72 -25

diff --git a/libjio/journal.c b/libjio/journal.c
index 324a8f9..b823b5d 100644
--- a/libjio/journal.c
+++ b/libjio/journal.c
@@ -205,7 +205,7 @@ static int fsync_dir(int fd)
 
 /** Create a new transaction in the journal. Returns a pointer to an opaque
  * jop_t (that is freed using journal_free), or NULL if there was an error. */
-struct journal_op *journal_new(struct jtrans *ts)
+struct journal_op *journal_new(struct jfs *fs, unsigned int flags)
 {
 	int fd, id;
 	ssize_t rv;
@@ -221,35 +221,33 @@ struct journal_op *journal_new(struct jtrans *ts)
 	if (name == NULL)
 		goto error;
 
-	id = get_tid(ts->fs);
+	id = get_tid(fs);
 	if (id == 0)
 		goto error;
 
 	/* open the transaction file */
-	get_jtfile(ts->fs, id, name);
+	get_jtfile(fs, id, name);
 	fd = open(name, O_RDWR | O_CREAT | O_TRUNC, 0600);
 	if (fd < 0)
 		goto error;
 
 	jop->id = id;
 	jop->fd = fd;
+	jop->numops = 0;
 	jop->name = name;
 	jop->curpos = 0;
 	jop->csum = 0;
-	jop->ts = ts;
-	jop->fs = ts->fs;
+	jop->fs = fs;
 
 	fiu_exit_on("jio/commit/created_tf");
 
 	/* and lock it, just in case */
 	plockf(fd, F_LOCKW, 0, 0);
 
-	ts->id = id;
-
 	/* save the header */
 	hdr.ver = 1;
 	hdr.trans_id = id;
-	hdr.flags = ts->flags;
+	hdr.flags = flags;
 
 	hdr_hton(&hdr);
 	rv = spwrite(fd, &hdr, sizeof(hdr), 0);
@@ -266,7 +264,7 @@ struct journal_op *journal_new(struct jtrans *ts)
 
 unlink_error:
 	unlink(name);
-	free_tid(ts->fs, ts->id);
+	free_tid(fs, id);
 	close(fd);
 
 error:
@@ -276,38 +274,16 @@ error:
 	return NULL;
 }
 
-/** Saves a single joper in the journal file */
-static int save_joper(struct journal_op *jop, const struct jtrans *ts,
-		struct joper *op)
+/** Save a single operation in the journal file */
+int journal_add_op(struct journal_op *jop, unsigned char *buf, size_t len,
+		off_t offset)
 {
 	ssize_t rv;
 	struct on_disk_ophdr ophdr;
 
-	/* read the current content only if the transaction is not
-	 * marked as NOROLLBACK, and if the data is not there yet,
-	 * which is the normal case, but for rollbacking we fill it
-	 * ourselves */
-	if (!(ts->flags & J_NOROLLBACK) && (op->pdata == NULL)) {
-		op->pdata = malloc(op->len);
-		if (op->pdata == NULL)
-			goto error;
-
-		op->plen = op->len;
-
-		rv = spread(ts->fs->fd, op->pdata, op->len,
-				op->offset);
-		if (rv < 0)
-			goto error;
-		if (rv < op->len) {
-			/* we are extending the file! */
-			/* ftruncate(ts->fs->fd, op->offset + op->len); */
-			op->plen = rv;
-		}
-	}
-
-	/* save the operation's header */
-	ophdr.len = op->len;
-	ophdr.offset = op->offset;
+	/* save the operation's header, */
+	ophdr.len = len;
+	ophdr.offset = offset;
 
 	ophdr_hton(&ophdr);
 	rv = spwrite(jop->fd, &ophdr, sizeof(ophdr), jop->curpos);
@@ -321,12 +297,14 @@ static int save_joper(struct journal_op *jop, const struct jtrans *ts,
 			sizeof(ophdr));
 
 	/* and save it to the disk */
-	rv = spwrite(jop->fd, op->buf, op->len, jop->curpos);
-	if (rv != op->len)
+	rv = spwrite(jop->fd, buf, len, jop->curpos);
+	if (rv != len)
 		goto error;
 
-	jop->curpos += op->len;
-	jop->csum = checksum_buf(jop->csum, op->buf, op->len);
+	jop->curpos += len;
+	jop->csum = checksum_buf(jop->csum, buf, len);
+
+	jop->numops++;
 
 	return 0;
 
@@ -334,26 +312,13 @@ error:
 	return -1;
 }
 
-/** Save the given transaction in the journal */
-int journal_save(struct journal_op *jop)
+/** Commit the journal operation */
+int journal_commit(struct journal_op *jop)
 {
 	ssize_t rv;
-	struct joper *op;
-	const struct jtrans *ts = jop->ts;
 	struct on_disk_ophdr ophdr;
 	struct on_disk_trailer trailer;
 
-	/* save each transacion in the file */
-	for (op = ts->op; op != NULL; op = op->next) {
-		rv = save_joper(jop, ts, op);
-		if (rv != 0)
-			goto error;
-
-		fiu_exit_on("jio/commit/tf_opdata");
-	}
-
-	fiu_exit_on("jio/commit/tf_data");
-
 	/* write the the empty ophdr to mark there are no more operations, and
 	 * then the trailer */
 	ophdr.len = 0;
@@ -369,7 +334,7 @@ int journal_save(struct journal_op *jop)
 			sizeof(ophdr));
 
 	trailer.checksum = jop->csum;
-	trailer.numops = ts->numops;
+	trailer.numops = jop->numops;
 
 	trailer_hton(&trailer);
 	rv = spwrite(jop->fd, &trailer, sizeof(trailer), jop->curpos);
@@ -383,7 +348,7 @@ int journal_save(struct journal_op *jop)
 	 * point) so we only flush here (both data and metadata) */
 	if (fsync(jop->fd) != 0)
 		goto error;
-	if (fsync_dir(ts->fs->jdirfd) != 0)
+	if (fsync_dir(jop->fs->jdirfd) != 0)
 		goto error;
 
 	fiu_exit_on("jio/commit/tf_sync");
@@ -444,7 +409,7 @@ int fill_trans(unsigned char *map, off_t len, struct jtrans *ts)
 {
 	int rv, numops;
 	unsigned char *p;
-	struct joper *op, *tmp;
+	struct operation *op, *tmp;
 	struct on_disk_hdr hdr;
 	struct on_disk_ophdr ophdr;
 	struct on_disk_trailer trailer;
@@ -484,7 +449,7 @@ int fill_trans(unsigned char *map, off_t len, struct jtrans *ts)
 		if (p + ophdr.len > map + len)
 			goto error;
 
-		op = malloc(sizeof(struct joper));
+		op = malloc(sizeof(struct operation));
 		if (op == NULL)
 			goto error;
 
diff --git a/libjio/journal.h b/libjio/journal.h
index 765571b..648fcb9 100644
--- a/libjio/journal.h
+++ b/libjio/journal.h
@@ -9,17 +9,19 @@
 struct journal_op {
 	int id;
 	int fd;
+	int numops;
 	char *name;
 	off_t curpos;
 	uint32_t csum;
-	struct jtrans *ts;
 	struct jfs *fs;
 };
 
 typedef struct journal_op jop_t;
 
-struct journal_op *journal_new(struct jtrans *ts);
-int journal_save(struct journal_op *jop);
+struct journal_op *journal_new(struct jfs *fs, unsigned int flags);
+int journal_add_op(struct journal_op *jop, unsigned char *buf, size_t len,
+		off_t offset);
+int journal_commit(struct journal_op *jop);
 int journal_free(struct journal_op *jop);
 
 int fill_trans(unsigned char *map, off_t len, struct jtrans *ts);
diff --git a/libjio/trans.c b/libjio/trans.c
index b4ffc42..1d5c1ba 100644
--- a/libjio/trans.c
+++ b/libjio/trans.c
@@ -43,9 +43,10 @@ struct jtrans *jtrans_new(struct jfs *fs, unsigned int flags)
 	ts->op = NULL;
 	ts->numops = 0;
 	ts->len = 0;
+
 	pthread_mutexattr_init(&attr);
 	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
-	pthread_mutex_init( &(ts->lock), &attr);
+	pthread_mutex_init(&(ts->lock), &attr);
 	pthread_mutexattr_destroy(&attr);
 
 	return ts;
@@ -74,6 +75,34 @@ void jtrans_free(struct jtrans *ts)
 	free(ts);
 }
 
+/** Read the previous information from the disk into the given operation
+ * structure. Returns 0 on success, -1 on error. */
+static int operation_read_prev(struct jtrans *ts, struct operation *op)
+{
+	ssize_t rv;
+
+	op->pdata = malloc(op->len);
+	if (op->pdata == NULL)
+		return -1;
+
+	rv = spread(ts->fs->fd, op->pdata, op->len,
+			op->offset);
+	if (rv < 0) {
+		free(op->pdata);
+		op->pdata = NULL;
+		return -1;
+	}
+
+	op->plen = op->len;
+	if (rv < op->len) {
+		/* we are extending the file! */
+		/* ftruncate(ts->fs->fd, op->offset + op->len); */
+		op->plen = rv;
+	}
+
+	return 0;
+}
+
 /* Add an operation to a transaction */
 int jtrans_add(struct jtrans *ts, const void *buf, size_t count, off_t offset)
 {
@@ -87,7 +116,7 @@ int jtrans_add(struct jtrans *ts, const void *buf, size_t count, off_t offset)
 		return -1;
 	}
 
-	/* fail for 0 length transactions */
+	/* fail for 0 length operations */
 	if (count == 0) {
 		pthread_mutex_unlock(&(ts->lock));
 		return 1;
@@ -106,8 +135,8 @@ int jtrans_add(struct jtrans *ts, const void *buf, size_t count, off_t offset)
 			pthread_mutex_unlock(&(ts->lock));
 			return -1;
 		}
-		jop = ts->op;
-		jop->prev = NULL;
+		op = ts->op;
+		op->prev = NULL;
 	} else {
 		for (tmpop = ts->op; tmpop->next != NULL; tmpop = tmpop->next)
 			;
@@ -117,34 +146,34 @@ int jtrans_add(struct jtrans *ts, const void *buf, size_t count, off_t offset)
 			return -1;
 		}
 		tmpop->next->prev = tmpop;
-		jop = tmpop->next;
+		op = tmpop->next;
 	}
 
-	jop->buf = malloc(count);
-	if (jop->buf == NULL) {
+	op->buf = malloc(count);
+	if (op->buf == NULL) {
 		/* remove from the list and fail */
-		if (jop->prev == NULL) {
+		if (op->prev == NULL) {
 			ts->op = NULL;
 		} else {
-			jop->prev->next = jop->next;
+			op->prev->next = op->next;
 		}
-		free(jop);
+		free(op);
 		pthread_mutex_unlock(&(ts->lock));
 		return -1;
 	}
 
 	ts->numops++;
 	ts->len += count;
+
 	pthread_mutex_unlock(&(ts->lock));
 
-	/* we copy the buffer because then the caller can reuse it */
-	memcpy(jop->buf, buf, count);
-	jop->len = count;
-	jop->offset = offset;
-	jop->next = NULL;
-	jop->plen = 0;
-	jop->pdata = NULL;
-	jop->locked = 0;
+	memcpy(op->buf, buf, count);
+	op->len = count;
+	op->offset = offset;
+	op->next = NULL;
+	op->plen = 0;
+	op->pdata = NULL;
+	op->locked = 0;
 
 	if (!(ts->flags & J_NOROLLBACK)) {
 		/* jtrans_commit() will want to read the current data, so we
@@ -161,7 +190,7 @@ ssize_t jtrans_commit(struct jtrans *ts)
 	ssize_t r, retval = -1;
 	struct operation *op;
 	struct jlinger *linger;
-	jop_t *jop;
+	jop_t *jop = NULL;
 	size_t written = 0;
 
 	pthread_mutex_lock(&(ts->lock));
@@ -189,16 +218,33 @@ ssize_t jtrans_commit(struct jtrans *ts)
 		}
 	}
 
-	jop = journal_new(ts);
+	/* create and fill the transaction file */
+	jop = journal_new(ts->fs, ts->flags);
 	if (jop == NULL)
 		goto unlock_exit;
 
-	r = journal_save(jop);
-	if (r < 0) {
-		journal_free(jop);
-		goto unlock_exit;
+	if (!(ts->flags & J_NOROLLBACK)) {
+		for (op = ts->op; op != NULL; op = op->next) {
+			 r = operation_read_prev(ts, op);
+			 if (r < 0)
+				 goto unlink_exit;
+		}
 	}
 
+	for (op = ts->op; op != NULL; op = op->next) {
+		r = journal_add_op(jop, op->buf, op->len, op->offset);
+		if (r != 0)
+			goto unlink_exit;
+
+		fiu_exit_on("jio/commit/tf_opdata");
+	}
+
+	fiu_exit_on("jio/commit/tf_data");
+
+	r = journal_commit(jop);
+	if (r < 0)
+		goto unlink_exit;
+
 	/* now that we have a safe transaction file, let's apply it */
 	written = 0;
 	for (op = ts->op; op != NULL; op = op->next) {
@@ -275,13 +321,14 @@ rollback_exit:
 		}
 	}
 
+unlink_exit:
 	/* If the journal operation is no longer needed, we remove it from the
 	 * disk.
 	 *
 	 * Extreme conditions (filesystem just got read-only, for example) can
 	 * cause journal_free() to fail, but there's not much left to do at
 	 * that point, and the caller will have to be careful and stop its
-	 * operations. In that case, we will return -1, but the transaction
+	 * operations. In that case, we will return -2, and the transaction
 	 * will be marked as J_COMMITTED to indicate that the data was
 	 * effectively written to disk. */
 	if (jop) {