summaryrefslogtreecommitdiff
path: root/lib/tdb
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2011-12-21 14:17:25 +1030
committerRusty Russell <rusty@rustcorp.com.au>2011-12-21 06:25:40 +0100
commit5767224b7f4703c3195aa69eef4352d80980f95e (patch)
tree9a53b804f37279797758dbdab87a10f455ac502f /lib/tdb
parent3a2a755e3380a8f81374009d463cd06161352507 (diff)
downloadsamba-5767224b7f4703c3195aa69eef4352d80980f95e.tar.gz
samba-5767224b7f4703c3195aa69eef4352d80980f95e.tar.bz2
samba-5767224b7f4703c3195aa69eef4352d80980f95e.zip
tdb: don't free old recovery area when expanding if already at EOF.
We allocate a new recovery area by expanding the file. But if the recovery area is already at the end of file (as shown in at least one client case), we can simply expand the record, rather than freeing it and creating a new one. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Autobuild-User: Rusty Russell <rusty@rustcorp.com.au> Autobuild-Date: Wed Dec 21 06:25:40 CET 2011 on sn-devel-104
Diffstat (limited to 'lib/tdb')
-rw-r--r--lib/tdb/common/transaction.c47
1 files changed, 30 insertions, 17 deletions
diff --git a/lib/tdb/common/transaction.c b/lib/tdb/common/transaction.c
index f7d56a05a3..c3477eb80c 100644
--- a/lib/tdb/common/transaction.c
+++ b/lib/tdb/common/transaction.c
@@ -698,7 +698,7 @@ static int tdb_recovery_allocate(struct tdb_context *tdb,
{
struct tdb_record rec;
const struct tdb_methods *methods = tdb->transaction->io_methods;
- tdb_off_t recovery_head;
+ tdb_off_t recovery_head, new_end;
if (tdb_recovery_area(tdb, methods, &recovery_head, &rec) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery head\n"));
@@ -707,6 +707,7 @@ static int tdb_recovery_allocate(struct tdb_context *tdb,
*recovery_size = tdb_recovery_size(tdb);
+ /* Existing recovery area? */
if (recovery_head != 0 && *recovery_size <= rec.rec_len) {
/* it fits in the existing area */
*recovery_max_size = rec.rec_len;
@@ -714,33 +715,45 @@ static int tdb_recovery_allocate(struct tdb_context *tdb,
return 0;
}
- /* we need to free up the old recovery area, then allocate a
- new one at the end of the file. Note that we cannot use
- tdb_allocate() to allocate the new one as that might return
- us an area that is being currently used (as of the start of
- the transaction) */
- if (recovery_head != 0) {
- if (tdb_free(tdb, recovery_head, &rec) == -1) {
- TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to free previous recovery area\n"));
- return -1;
+ /* If recovery area in middle of file, we need a new one. */
+ if (recovery_head == 0
+ || recovery_head + sizeof(rec) + rec.rec_len != tdb->map_size) {
+ /* we need to free up the old recovery area, then allocate a
+ new one at the end of the file. Note that we cannot use
+ tdb_allocate() to allocate the new one as that might return
+ us an area that is being currently used (as of the start of
+ the transaction) */
+ if (recovery_head) {
+ if (tdb_free(tdb, recovery_head, &rec) == -1) {
+ TDB_LOG((tdb, TDB_DEBUG_FATAL,
+ "tdb_recovery_allocate: failed to"
+ " free previous recovery area\n"));
+ return -1;
+ }
+
+ /* the tdb_free() call might have increased
+ * the recovery size */
+ *recovery_size = tdb_recovery_size(tdb);
}
+
+ /* New head will be at end of file. */
+ recovery_head = tdb->map_size;
}
- /* the tdb_free() call might have increased the recovery size */
- *recovery_size = tdb_recovery_size(tdb);
+ /* Now we know where it will be. */
+ *recovery_offset = recovery_head;
- /* round up to a multiple of page size */
+ /* Expand by more than we need, so we don't do it often. */
*recovery_max_size = tdb_expand_adjust(tdb->map_size,
*recovery_size,
tdb->page_size)
- sizeof(rec);
- *recovery_offset = tdb->map_size;
- recovery_head = *recovery_offset;
+ new_end = recovery_head + sizeof(rec) + *recovery_max_size;
if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size,
- (tdb->map_size - tdb->transaction->old_map_size) +
- sizeof(rec) + *recovery_max_size) == -1) {
+ new_end - tdb->transaction->old_map_size)
+ == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to create recovery area\n"));
return -1;
}