git » libjio » commit 4e2b2db

This patch changes the commit procedure (and thus jfsck()) to avoid writing the data we're about to commit into the transaction file.

author Alberto Bertogli
2004-04-30 13:40:34 UTC
committer Alberto Bertogli
2007-07-15 12:43:37 UTC
parent c892113cddaa81ae06f1abb3bf14d3c47f994bd4

This patch changes the commit procedure (and thus jfsck()) to avoid writing the data we're about to commit into the transaction file.

This patch changes the commit procedure (and thus jfsck()) to avoid writing
the data we're about to commit into the transaction file.

The reason behind this is that it slows things down and doesn't provide any
real warantees: a crash is as likely to happen when we're writing the
transaction file as it is when we're writing the real file.

So by writing only the previous data (to be able to rollback it in the case of
a crash) we provide the same warantees, improve performance and reduce code.

doc/libjio.lyx +3 -13
jiofsck.c +1 -1
libjio.c +43 -68
libjio.h +4 -4

diff --git a/doc/libjio.lyx b/doc/libjio.lyx
index 645caff..0503ecd 100644
--- a/doc/libjio.lyx
+++ b/doc/libjio.lyx
@@ -112,9 +112,6 @@ This impose some restrictions to the kind of operations you can perform
  over a file while it's currently being used: you can't move it (because
  the journal directory name depends on the filename) and you can't unlink
  it (for similar reasons).
- Some other operations, like truncating, are also done outside the library
- and the user is expected to do them atomically when no transactions are
- currently being done.
  
 \layout Standard
 
@@ -214,9 +211,6 @@ Read the previous data from the file
 Write the previous data in the transaction
 \layout Itemize
 
-Write the data to commit to the transaction file
-\layout Itemize
-
 Write the data to the file
 \layout Itemize
 
@@ -316,11 +310,11 @@ jiofsck
  which is just a simple invocation to that function), which opens the file
  and goes through all transactions in the journal (remember that transactions
  are removed from the journal directory after they're applied), loading
- and recommiting them if possible.
+ and rollbacking them if necessary.
  There are several steps where it can fail: there could be no journal, a
  given transaction file might be corrupted, incomplete, and so on; but in
  the end, there are two cases regarding each transaction: either it's complete
- and can be reapplied, or not.
+ and can be rollbacked, or not.
 \layout Standard
 
 In the case the transaction is not complete, there is no possibility that
@@ -330,11 +324,7 @@ In the case the transaction is not complete, there is no possibility that
 after
 \emph default 
  saving it in the journal, so there is really nothing left to be done.
-\layout Standard
-
-If the transaction is complete, we only need to recommit: if the transaction
- was either not applied at all, partially applied or completely applied,
- it makes no difference as we are now capable of completing it, and do so.
+ So if the transaction is complete, we only need to rollback.
 \layout Standard
 
 In any case, after making the recovery you can simply remove the journal
diff --git a/jiofsck.c b/jiofsck.c
index 062dd3a..b48600d 100644
--- a/jiofsck.c
+++ b/jiofsck.c
@@ -55,7 +55,7 @@ int main(int argc, char **argv)
 	printf("Broken body:\t %d\n", res.broken_body);
 	printf("Load error:\t %d\n", res.load_error);
 	printf("Apply error:\t %d\n", res.apply_error);
-	printf("Reapplied:\t %d\n", res.reapplied);
+	printf("Rollbacked:\t %d\n", res.rollbacked);
 	printf("\n");
 	
 	printf("You can now safely remove the journal directory completely\n"
diff --git a/libjio.c b/libjio.c
index 17f9eac..c6b446c 100644
--- a/libjio.c
+++ b/libjio.c
@@ -294,7 +294,23 @@ int jtrans_commit(struct jtrans *ts)
 	if (!(ts->fs->flags & J_NOLOCK))
 		plockf(ts->fs->fd, F_LOCK, ts->offset, ts->len);
 	
-	/* first the static data */
+	/* read the current content and fill in the transaction structure */
+	ts->pdata = malloc(ts->len);
+	if (ts->pdata == NULL)
+		goto exit;
+	
+	ts->plen = ts->len;
+
+	rv = spread(ts->fs->fd, ts->pdata, ts->len, ts->offset);
+	if (rv < 0)
+		goto exit;
+	if (rv < ts->len) {
+		/* we are extending the file! use ftruncate() to do it */
+		ftruncate(ts->fs->fd, ts->offset + ts->len);
+		ts->plen = rv;
+	}
+
+	/* now save the transaction to the file, static data first */
 	
 	buf_init = malloc(J_DISKTFIXSIZE);
 	if (buf_init == NULL)
@@ -311,6 +327,9 @@ int jtrans_commit(struct jtrans *ts)
 	memcpy(bufp, (void *) &(ts->len), sizeof(ts->len));
 	bufp += 4;
 	
+	memcpy(bufp, (void *) &(ts->plen), sizeof(ts->plen));
+	bufp += 4;
+	
 	memcpy(bufp, (void *) &(ts->ulen), sizeof(ts->ulen));
 	bufp += 4;
 	
@@ -324,7 +343,7 @@ int jtrans_commit(struct jtrans *ts)
 	free(buf_init);
 	
 	
-	/* and now the variable part */
+	/* and now the variable data */
 
 	if (ts->udata) {
 		rv = spwrite(fd, ts->udata, ts->ulen, J_DISKTFIXSIZE);
@@ -332,33 +351,9 @@ int jtrans_commit(struct jtrans *ts)
 			goto exit;
 	}
 	
-	ts->pdata = malloc(ts->len);
-	if (ts->pdata == NULL)
-		goto exit;
-	
-	ts->plen = ts->len;
-
-	/* copy the current content into the transaction file */
-	rv = spread(ts->fs->fd, ts->pdata, ts->len, ts->offset);
-	if (rv < 0)
-		goto exit;
-	if (rv < ts->len) {
-		/* we are extending the file! use ftruncate() to do it */
-		ftruncate(ts->fs->fd, ts->offset + ts->len);
-
-		ts->plen = rv;
-
-	}
-	
 	t = J_DISKTFIXSIZE + ts->ulen;
-	rv = spwrite(fd, ts->pdata, ts->len, t);
-	if (rv != ts->len)
-		goto exit;
-	
-	/* save the new data in the transaction file */
-	t = J_DISKTFIXSIZE + ts->ulen + ts->plen;
-	rv = spwrite(fd, ts->buf, ts->len, t);
-	if (rv != ts->len)
+	rv = spwrite(fd, ts->pdata, ts->plen, t);
+	if (rv != ts->plen)
 		goto exit;
 	
 	/* this is a simple but efficient optimization: instead of doing
@@ -373,13 +368,14 @@ int jtrans_commit(struct jtrans *ts)
 	if (rv != ts->len)
 		goto exit;
 	
-	/* mark the transaction as commited */
-	ts->flags = ts->flags | J_COMMITED;
-
 	/* 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;
+
 	
 exit:
 	close(fd);
@@ -404,11 +400,6 @@ int jtrans_rollback(struct jtrans *ts)
 	/* copy the old transaction to the new one */
 	jtrans_init(ts->fs, &newts);
 
-	newts.name = malloc(strlen(ts->name));
-	if (newts.name == NULL)
-		return -1;
-	
-	strcpy(newts.name, ts->name);
 	newts.flags = ts->flags;
 	newts.offset = ts->offset;
 
@@ -427,8 +418,8 @@ int jtrans_rollback(struct jtrans *ts)
 		
 	}
 	
-	newts.pdata = ts->buf;
-	newts.plen = ts->len;
+	newts.pdata = ts->pdata;
+	newts.plen = ts->plen;
 
 	newts.udata = ts->udata;
 	newts.ulen = ts->ulen;
@@ -691,7 +682,7 @@ int jfsck(char *name, struct jfsck_result *res)
 {
 	int fd, tfd, rv, i, maxtid;
 	char jdir[PATH_MAX], jlockfile[PATH_MAX], tname[PATH_MAX];
-	char *buf = NULL;
+	unsigned char *buf = NULL;
 	struct stat sinfo;
 	struct jfs fs;
 	struct jtrans *curts;
@@ -780,20 +771,22 @@ int jfsck(char *name, struct jfsck_result *res)
 			free(buf);
 			goto loop;
 		}
-		
-		curts->flags = (int) *(buf + 4);
-		curts->len = (size_t) *(buf + 8);
-		curts->ulen = (size_t) *(buf + 16);
-		curts->offset = (off_t) *(buf + 20);
+
+		curts->flags = *( (uint32_t *) (buf + 4));
+		curts->len = *( (uint32_t *) (buf + 8));
+		curts->plen = *( (uint32_t *) (buf + 12));
+		curts->ulen = *( (uint32_t *) (buf + 16));
+		curts->offset = *( (uint64_t *) (buf + 20));
 
 		free(buf);
 
 		/* if we got here, the transaction was not applied, so we
 		 * check if the transaction file is complete (we only need to
-		 * apply it) or not (so we can't do anything but ignore it) */
+		 * rollback it) or not (so we can't do anything but ignore it)
+		 */
 
 		lstat(tname, &sinfo);
-		rv = J_DISKTFIXSIZE + curts->len + curts->ulen + curts->plen;
+		rv = J_DISKTFIXSIZE + curts->ulen + curts->plen;
 		if (sinfo.st_size != rv) {
 			/* the transaction file is incomplete, some of the
 			 * body is missing */
@@ -803,13 +796,7 @@ int jfsck(char *name, struct jfsck_result *res)
 
 		/* we have a complete transaction file which commit was not
 		 * successful, so we read it to complete the transaction
-		 * structure and apply it again */
-		curts->buf = malloc(curts->len);
-		if (curts->buf == NULL) {
-			res->load_error++;
-			goto loop;
-		}
-		
+		 * structure and rollback it */
 		curts->pdata = malloc(curts->plen);
 		if (curts->pdata == NULL) {
 			res->load_error++;
@@ -838,27 +825,15 @@ int jfsck(char *name, struct jfsck_result *res)
 			goto loop;
 		}
 
-		/* real data */
-		offset = J_DISKTFIXSIZE + curts->ulen + curts->plen;
-		rv = spread(tfd, curts->buf, curts->len, offset);
-		if (rv != curts->len) {
-			res->load_error++;
-			goto loop;
-		}
-
-		/* apply */
-		rv = jtrans_commit(curts);
+		/* rollback */
+		rv = jtrans_rollback(curts);
 		if (rv < 0) {
 			res->apply_error++;
 			goto loop;
 		}
-		res->reapplied++;
+		res->rollbacked++;
 
 		/* free the data we just allocated */
-		if (curts->len) {
-			free(curts->buf);
-			curts->buf = NULL;
-		}
 		if (curts->plen) {
 			free(curts->pdata);
 			curts->pdata = NULL;
diff --git a/libjio.h b/libjio.h
index 23f5296..6f04871 100644
--- a/libjio.h
+++ b/libjio.h
@@ -44,7 +44,7 @@ struct jfsck_result {
 	int broken_body;	/* transactions broken (body missing) */
 	int load_error;		/* errors loading the transaction */
 	int apply_error;	/* errors applying the transaction */
-	int reapplied;		/* transactions that were re-applied */
+	int rollbacked;		/* transactions that were rollbacked */
 };
 
 /* on-disk structure */
@@ -54,13 +54,13 @@ struct disk_trans {
 	uint32_t id;		/* id */
 	uint32_t flags;		/* flags about this transaction */
 	uint32_t len;		/* data lenght */
+	uint32_t plen;		/* previous data lenght */
 	uint32_t ulen;		/* user-supplied information lenght */
 	uint64_t offset;	/* offset relative to the BOF */
 	
 	/* payload (variable lenght) */
 	char *udata;		/* user-supplied data */
-	char *prevdata;		/* previous data, optional, for rollback */
-	char *data;		/* data */
+	char *prevdata;		/* previous data for rollback */
 };
 
 
@@ -93,7 +93,7 @@ int jfsck(char *name, struct jfsck_result *res);
 #define J_ROLLBACKED	2	/* mark a transaction as rollbacked */
 
 /* disk_trans constants */
-#define J_DISKTFIXSIZE	 24	/* lenght of disk_trans' header */ 
+#define J_DISKTFIXSIZE	 28	/* lenght of disk_trans' header */ 
 
 /* jfsck constants (return values) */
 #define J_ESUCCESS	0	/* success - shouldn't be used */