summaryrefslogtreecommitdiff
path: root/lib/tdb/common/transaction.c
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2010-02-24 13:23:58 +1030
committerRusty Russell <rusty@rustcorp.com.au>2010-02-24 13:23:58 +1030
commitec96ea690edbe3398d690b4a953d487ca1773f1c (patch)
tree24346da6a7faddd3b04478e58b08d8b809994ce1 /lib/tdb/common/transaction.c
parent1bf482b9ef9ec73dd7ee4387d7087aa3955503dd (diff)
downloadsamba-ec96ea690edbe3398d690b4a953d487ca1773f1c.tar.gz
samba-ec96ea690edbe3398d690b4a953d487ca1773f1c.tar.bz2
samba-ec96ea690edbe3398d690b4a953d487ca1773f1c.zip
tdb: handle processes dying during transaction commit.
tdb transactions were designed to be robust against the machine powering off, but interestingly were never designed to handle the case where an administrator kill -9's a process during commit. Because recovery is only done on tdb_open, processes with the tdb already mapped will simply use it despite it being corrupt and needing recovery. The solution to this is to check for recovery every time we grab a data lock: we could have gained the lock because a process just died. This has no measurable cost: here is the time for tdbtorture -s 0 -n 1 -l 10000: Before: 2.75 2.50 2.81 3.19 2.91 2.53 2.72 2.50 2.78 2.77 = Avg 2.75 After: 2.81 2.57 3.42 2.49 3.02 2.49 2.84 2.48 2.80 2.43 = Avg 2.74 Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'lib/tdb/common/transaction.c')
-rw-r--r--lib/tdb/common/transaction.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/lib/tdb/common/transaction.c b/lib/tdb/common/transaction.c
index 3d267af2b0..4f1cc708ef 100644
--- a/lib/tdb/common/transaction.c
+++ b/lib/tdb/common/transaction.c
@@ -1192,3 +1192,28 @@ int tdb_transaction_recover(struct tdb_context *tdb)
/* all done */
return 0;
}
+
+/* Any I/O failures we say "needs recovery". */
+bool tdb_needs_recovery(struct tdb_context *tdb)
+{
+ tdb_off_t recovery_head;
+ struct tdb_record rec;
+
+ /* find the recovery area */
+ if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
+ return true;
+ }
+
+ if (recovery_head == 0) {
+ /* we have never allocated a recovery record */
+ return false;
+ }
+
+ /* read the recovery record */
+ if (tdb->methods->tdb_read(tdb, recovery_head, &rec,
+ sizeof(rec), DOCONV()) == -1) {
+ return true;
+ }
+
+ return (rec.magic == TDB_RECOVERY_MAGIC);
+}