diff options
-rw-r--r-- | source4/lib/tdb/common/tdb.c | 54 | ||||
-rw-r--r-- | source4/lib/tdb/common/tdb_private.h | 4 | ||||
-rw-r--r-- | source4/lib/tdb/common/transaction.c | 6 | ||||
-rw-r--r-- | source4/lib/tdb/include/tdb.h | 2 |
4 files changed, 65 insertions, 1 deletions
diff --git a/source4/lib/tdb/common/tdb.c b/source4/lib/tdb/common/tdb.c index 4b0d4a31c5..b0411601eb 100644 --- a/source4/lib/tdb/common/tdb.c +++ b/source4/lib/tdb/common/tdb.c @@ -30,6 +30,33 @@ TDB_DATA tdb_null; +/* + increment the tdb sequence number if the tdb has been opened using + the TDB_SEQNUM flag +*/ +static void tdb_increment_seqnum(struct tdb_context *tdb) +{ + tdb_off_t seqnum=0; + + if (!(tdb->flags & TDB_SEQNUM)) { + return; + } + + if (tdb_brlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, F_SETLKW, 1) != 0) { + return; + } + + /* we ignore errors from this, as we have no sane way of + dealing with them. + */ + tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum); + seqnum++; + tdb_ofs_write(tdb, TDB_SEQNUM_OFS, &seqnum); + + tdb_brlock(tdb, TDB_SEQNUM_OFS, F_UNLCK, F_SETLKW, 1); +} + + /* Returns 0 on fail. On success, return offset of record, and fills in rec */ static tdb_off_t tdb_find(struct tdb_context *tdb, TDB_DATA key, u32 hash, @@ -203,6 +230,11 @@ static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, u32 hash) if (!(rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK, &rec))) return -1; ret = tdb_do_delete(tdb, rec_ptr, &rec); + + if (ret == 0) { + tdb_increment_seqnum(tdb); + } + if (tdb_unlock(tdb, BUCKET(rec.full_hash), F_WRLCK) != 0) TDB_LOG((tdb, 0, "tdb_delete: WARNING tdb_unlock failed!\n")); return ret; @@ -295,6 +327,9 @@ int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag) /* Need to tdb_unallocate() here */ goto fail; } + + tdb_increment_seqnum(tdb); + out: SAFE_FREE(p); tdb_unlock(tdb, BUCKET(hash), F_WRLCK); @@ -369,3 +404,22 @@ tdb_log_func tdb_log_fn(struct tdb_context *tdb) { return tdb->log_fn; } + + +/* + get the tdb sequence number. Only makes sense if the writers opened + with TDB_SEQNUM set. Note that this sequence number will wrap quite + quickly, so it should only be used for a 'has something changed' + test, not for code that relies on the count of the number of changes + made. If you want a counter then use a tdb record. + + The aim of this sequence number is to allow for a very lightweight + test of a possible tdb change. +*/ +int tdb_get_seqnum(struct tdb_context *tdb) +{ + tdb_off_t seqnum=0; + + tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum); + return seqnum; +} diff --git a/source4/lib/tdb/common/tdb_private.h b/source4/lib/tdb/common/tdb_private.h index d7193b2b67..d01a88695d 100644 --- a/source4/lib/tdb/common/tdb_private.h +++ b/source4/lib/tdb/common/tdb_private.h @@ -94,6 +94,7 @@ typedef u32 tdb_off_t; #define TDB_HASHTABLE_SIZE(tdb) ((tdb->header.hash_size+1)*sizeof(tdb_off_t)) #define TDB_DATA_START(hash_size) TDB_HASH_TOP(hash_size-1) #define TDB_RECOVERY_HEAD offsetof(struct tdb_header, recovery_start) +#define TDB_SEQNUM_OFS offsetof(struct tdb_header, sequence_number) #define TDB_PAD_BYTE 0x42 #define TDB_PAD_U32 0x42424242 @@ -155,7 +156,8 @@ struct tdb_header { u32 hash_size; /* number of hash entries */ tdb_off_t rwlocks; /* obsolete - kept to detect old formats */ tdb_off_t recovery_start; /* offset of transaction recovery region */ - tdb_off_t reserved[30]; + tdb_off_t sequence_number; /* used when TDB_SEQNUM is set */ + tdb_off_t reserved[29]; }; struct tdb_lock_type { diff --git a/source4/lib/tdb/common/transaction.c b/source4/lib/tdb/common/transaction.c index ace4aa51a6..6960a02ad8 100644 --- a/source4/lib/tdb/common/transaction.c +++ b/source4/lib/tdb/common/transaction.c @@ -892,6 +892,12 @@ int tdb_transaction_commit(struct tdb_context *tdb) tdb_brlock_len(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1); + /* + TODO: maybe write to some dummy hdr field, or write to magic + offset without mmap, before the last sync, instead of the + utime() call + */ + /* on some systems (like Linux 2.6.x) changes via mmap/msync don't change the mtime of the file, this means the file may not be backed up (as tdb rounding to block sizes means that diff --git a/source4/lib/tdb/include/tdb.h b/source4/lib/tdb/include/tdb.h index c116f29fc1..ddde17850b 100644 --- a/source4/lib/tdb/include/tdb.h +++ b/source4/lib/tdb/include/tdb.h @@ -46,6 +46,7 @@ extern "C" { #define TDB_CONVERT 16 /* convert endian (internal use) */ #define TDB_BIGENDIAN 32 /* header is big-endian (internal use) */ #define TDB_NOSYNC 64 /* don't use synchronous transactions */ +#define TDB_SEQNUM 128 /* maintain a sequence number */ #define TDB_ERRCODE(code, ret) ((tdb->ecode = (code)), ret) @@ -109,6 +110,7 @@ int tdb_transaction_start(struct tdb_context *tdb); int tdb_transaction_commit(struct tdb_context *tdb); int tdb_transaction_cancel(struct tdb_context *tdb); int tdb_transaction_recover(struct tdb_context *tdb); +int tdb_get_seqnum(struct tdb_context *tdb); /* Low level locking functions: use with care */ int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key); |