Browse Source

tdb2: handle non-transaction-page-aligned sizes in recovery.

tdb1 always makes the tdb a multiple of the transaction page size,
tdb2 doesn't.  This means that if a transaction hits the exact end of
the file, we might need to save off a partial page.

So that we don't have to rewrite tdb_recovery_size() too, we simply do
a short read and memset the unused section to 0 (to keep valgrind
happy).
Rusty Russell 15 years ago
parent
commit
ba7740e689
1 changed files with 14 additions and 3 deletions
  1. 14 3
      ccan/tdb2/transaction.c

+ 14 - 3
ccan/tdb2/transaction.c

@@ -815,6 +815,7 @@ static enum TDB_ERROR transaction_setup_recovery(struct tdb_context *tdb,
 		if (offset >= old_map_size) {
 		if (offset >= old_map_size) {
 			continue;
 			continue;
 		}
 		}
+
 		if (offset + length > tdb->file->map_size) {
 		if (offset + length > tdb->file->map_size) {
 			free(data);
 			free(data);
 			return tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
 			return tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
@@ -829,9 +830,19 @@ static enum TDB_ERROR transaction_setup_recovery(struct tdb_context *tdb,
 		/* the recovery area contains the old data, not the
 		/* the recovery area contains the old data, not the
 		   new data, so we have to call the original tdb_read
 		   new data, so we have to call the original tdb_read
 		   method to get it */
 		   method to get it */
-		ecode = methods->tread(tdb, offset,
-				       p + sizeof(offset) + sizeof(length),
-				       length);
+		if (offset + length > old_map_size) {
+			/* Short read at EOF, and zero fill. */
+			unsigned int len = old_map_size - offset;
+			ecode = methods->tread(tdb, offset,
+					       p + sizeof(offset) + sizeof(length),
+					       len);
+			memset(p + sizeof(offset) + sizeof(length) + len, 0,
+			       length - len);
+		} else {
+			ecode = methods->tread(tdb, offset,
+					       p + sizeof(offset) + sizeof(length),
+					       length);
+		}
 		if (ecode != TDB_SUCCESS) {
 		if (ecode != TDB_SUCCESS) {
 			free(data);
 			free(data);
 			return ecode;
 			return ecode;