[SCM] Samba Shared Repository - branch master updated

Rusty Russell rusty at samba.org
Wed Oct 21 07:32:52 MDT 2009


The branch, master has been updated
       via  7030043... lib/tdb: TDB_TRACE support (for developers)
      from  1467e5e... s4-ldb: allow for non-null terminated ldb_val in ldb_dn_from_ldb_val

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 703004340c3e0f43f741bd368d2525cfd187d590
Author: Rusty Russell <rusty at rustcorp.com.au>
Date:   Tue Oct 20 12:19:41 2009 +1030

    lib/tdb: TDB_TRACE support (for developers)
    
    When TDB_TRACE is defined (in tdb_private.h), verbose tracing of tdb operations is enabled.
    This can be replayed using "replay_trace" from http://ccan.ozlabs.org/info/tdb.
    
    The majority of this patch comes from moving internal functions to _<funcname> to
    avoid double-tracing.  There should be no additional overhead for the normal (!TDB_TRACE)
    case.
    
    Note that the verbose traces compress really well with rzip.
    
    Signed-off-by: Rusty Russell <rusty at rustcorp.com.au>

-----------------------------------------------------------------------

Summary of changes:
 lib/tdb/common/lock.c        |   34 +++++-
 lib/tdb/common/open.c        |   31 +++++-
 lib/tdb/common/tdb.c         |  232 +++++++++++++++++++++++++++++++++++++----
 lib/tdb/common/tdb_private.h |   36 +++++++
 lib/tdb/common/transaction.c |   55 +++++++----
 lib/tdb/common/traverse.c    |   23 ++++-
 lib/tdb/docs/tracing.txt     |   46 ++++++++
 7 files changed, 402 insertions(+), 55 deletions(-)
 create mode 100644 lib/tdb/docs/tracing.txt


Changeset truncated at 500 lines:

diff --git a/lib/tdb/common/lock.c b/lib/tdb/common/lock.c
index 2c72ae1..3414049 100644
--- a/lib/tdb/common/lock.c
+++ b/lib/tdb/common/lock.c
@@ -422,48 +422,58 @@ static int _tdb_unlockall(struct tdb_context *tdb, int ltype)
 /* lock entire database with write lock */
 int tdb_lockall(struct tdb_context *tdb)
 {
+	tdb_trace(tdb, "tdb_lockall");
 	return _tdb_lockall(tdb, F_WRLCK, F_SETLKW);
 }
 
 /* lock entire database with write lock - mark only */
 int tdb_lockall_mark(struct tdb_context *tdb)
 {
+	tdb_trace(tdb, "tdb_lockall_mark");
 	return _tdb_lockall(tdb, F_WRLCK | TDB_MARK_LOCK, F_SETLKW);
 }
 
 /* unlock entire database with write lock - unmark only */
 int tdb_lockall_unmark(struct tdb_context *tdb)
 {
+	tdb_trace(tdb, "tdb_lockall_unmark");
 	return _tdb_unlockall(tdb, F_WRLCK | TDB_MARK_LOCK);
 }
 
 /* lock entire database with write lock - nonblocking varient */
 int tdb_lockall_nonblock(struct tdb_context *tdb)
 {
-	return _tdb_lockall(tdb, F_WRLCK, F_SETLK);
+	int ret = _tdb_lockall(tdb, F_WRLCK, F_SETLK);
+	tdb_trace_ret(tdb, "tdb_lockall_nonblock", ret);
+	return ret;
 }
 
 /* unlock entire database with write lock */
 int tdb_unlockall(struct tdb_context *tdb)
 {
+	tdb_trace(tdb, "tdb_unlockall");
 	return _tdb_unlockall(tdb, F_WRLCK);
 }
 
 /* lock entire database with read lock */
 int tdb_lockall_read(struct tdb_context *tdb)
 {
+	tdb_trace(tdb, "tdb_lockall_read");
 	return _tdb_lockall(tdb, F_RDLCK, F_SETLKW);
 }
 
 /* lock entire database with read lock - nonblock varient */
 int tdb_lockall_read_nonblock(struct tdb_context *tdb)
 {
-	return _tdb_lockall(tdb, F_RDLCK, F_SETLK);
+	int ret = _tdb_lockall(tdb, F_RDLCK, F_SETLK);
+	tdb_trace_ret(tdb, "tdb_lockall_read_nonblock", ret);
+	return ret;
 }
 
 /* unlock entire database with read lock */
 int tdb_unlockall_read(struct tdb_context *tdb)
 {
+	tdb_trace(tdb, "tdb_unlockall_read");
 	return _tdb_unlockall(tdb, F_RDLCK);
 }
 
@@ -471,7 +481,9 @@ int tdb_unlockall_read(struct tdb_context *tdb)
    contention - it cannot guarantee how many records will be locked */
 int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key)
 {
-	return tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
+	int ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
+	tdb_trace_1rec(tdb, "tdb_chainlock", key);
+	return ret;
 }
 
 /* lock/unlock one hash chain, non-blocking. This is meant to be used
@@ -479,33 +491,43 @@ int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key)
    locked */
 int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key)
 {
-	return tdb_lock_nonblock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
+	int ret = tdb_lock_nonblock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
+	tdb_trace_1rec_ret(tdb, "tdb_chainlock_nonblock", key, ret);
+	return ret;
 }
 
 /* mark a chain as locked without actually locking it. Warning! use with great caution! */
 int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key)
 {
-	return tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK | TDB_MARK_LOCK);
+	int ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK | TDB_MARK_LOCK);
+	tdb_trace_1rec(tdb, "tdb_chainlock_mark", key);
+	return ret;
 }
 
 /* unmark a chain as locked without actually locking it. Warning! use with great caution! */
 int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key)
 {
+	tdb_trace_1rec(tdb, "tdb_chainlock_unmark", key);
 	return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK | TDB_MARK_LOCK);
 }
 
 int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key)
 {
+	tdb_trace_1rec(tdb, "tdb_chainunlock", key);
 	return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK);
 }
 
 int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key)
 {
-	return tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK);
+	int ret;
+	ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK);
+	tdb_trace_1rec(tdb, "tdb_chainlock_read", key);
+	return ret;
 }
 
 int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key)
 {
+	tdb_trace_1rec(tdb, "tdb_chainunlock_read", key);
 	return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK);
 }
 
diff --git a/lib/tdb/common/open.c b/lib/tdb/common/open.c
index 141e6fe..f0061d7 100644
--- a/lib/tdb/common/open.c
+++ b/lib/tdb/common/open.c
@@ -205,6 +205,10 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
 			TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: tdb_new_database failed!"));
 			goto fail;
 		}
+#ifdef TDB_TRACE
+		/* All tracing will fail.  That's ok. */
+		tdb->tracefd = -1;
+#endif
 		goto internal;
 	}
 
@@ -315,6 +319,22 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
 		goto fail;
 	}
 
+#ifdef TDB_TRACE
+	{
+		char tracefile[strlen(name) + 32];
+
+		snprintf(tracefile, sizeof(tracefile),
+			 "%s.trace.%li", name, (long)getpid());
+		tdb->tracefd = open(tracefile, O_WRONLY|O_CREAT|O_EXCL, 0600);
+		if (tdb->tracefd >= 0) {
+			tdb_enable_seqnum(tdb);
+			tdb_trace_open(tdb, "tdb_open", hash_size, tdb_flags,
+				       open_flags);
+		} else
+			TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to open trace file %s!\n", tracefile));
+	}
+#endif
+
  internal:
 	/* Internal (memory-only) databases skip all the code above to
 	 * do with disk files, and resume here by releasing their
@@ -330,7 +350,10 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
 
 	if (!tdb)
 		return NULL;
-	
+
+#ifdef TDB_TRACE
+	close(tdb->tracefd);
+#endif
 	if (tdb->map_ptr) {
 		if (tdb->flags & TDB_INTERNAL)
 			SAFE_FREE(tdb->map_ptr);
@@ -366,8 +389,9 @@ int tdb_close(struct tdb_context *tdb)
 	struct tdb_context **i;
 	int ret = 0;
 
+	tdb_trace(tdb, "tdb_close");
 	if (tdb->transaction) {
-		tdb_transaction_cancel(tdb);
+		_tdb_transaction_cancel(tdb);
 	}
 
 	if (tdb->map_ptr) {
@@ -389,6 +413,9 @@ int tdb_close(struct tdb_context *tdb)
 		}
 	}
 
+#ifdef TDB_TRACE
+	close(tdb->tracefd);
+#endif
 	memset(tdb, 0, sizeof(*tdb));
 	SAFE_FREE(tdb);
 
diff --git a/lib/tdb/common/tdb.c b/lib/tdb/common/tdb.c
index 9b4b9c4..7acc111 100644
--- a/lib/tdb/common/tdb.c
+++ b/lib/tdb/common/tdb.c
@@ -158,7 +158,7 @@ static int tdb_update_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash,
  * then the TDB_DATA will have zero length but
  * a non-zero pointer
  */
-TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
+static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
 {
 	tdb_off_t rec_ptr;
 	struct list_struct rec;
@@ -177,6 +177,14 @@ TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
 	return ret;
 }
 
+TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
+{
+	TDB_DATA ret = _tdb_fetch(tdb, key);
+
+	tdb_trace_1rec_retrec(tdb, "tdb_fetch", key, ret);
+	return ret;
+}
+
 /*
  * Find an entry in the database and hand the record's data to a parsing
  * function. The parsing function is executed under the chain read lock, so it
@@ -207,8 +215,10 @@ int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
 	hash = tdb->hash_fn(&key);
 
 	if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) {
+		tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, -1);
 		return TDB_ERRCODE(TDB_ERR_NOEXIST, 0);
 	}
+	tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, 0);
 
 	ret = tdb_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len,
 			     rec.data_len, parser, private_data);
@@ -237,7 +247,11 @@ static int tdb_exists_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
 int tdb_exists(struct tdb_context *tdb, TDB_DATA key)
 {
 	uint32_t hash = tdb->hash_fn(&key);
-	return tdb_exists_hash(tdb, key, hash);
+	int ret;
+
+	ret = tdb_exists_hash(tdb, key, hash);
+	tdb_trace_1rec_ret(tdb, "tdb_exists", key, ret);
+	return ret;
 }
 
 /* actually delete an entry in the database given the offset */
@@ -392,7 +406,11 @@ static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
 int tdb_delete(struct tdb_context *tdb, TDB_DATA key)
 {
 	uint32_t hash = tdb->hash_fn(&key);
-	return tdb_delete_hash(tdb, key, hash);
+	int ret;
+
+	ret = tdb_delete_hash(tdb, key, hash);
+	tdb_trace_1rec_ret(tdb, "tdb_delete", key, ret);
+	return ret;
 }
 
 /*
@@ -424,29 +442,14 @@ static tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
 	return 0;
 }
 
-/* store an element in the database, replacing any existing element
-   with the same key 
-
-   return 0 on success, -1 on failure
-*/
-int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
+static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
+		       TDB_DATA dbuf, int flag, uint32_t hash)
 {
 	struct list_struct rec;
-	uint32_t hash;
 	tdb_off_t rec_ptr;
 	char *p = NULL;
 	int ret = -1;
 
-	if (tdb->read_only || tdb->traverse_read) {
-		tdb->ecode = TDB_ERR_RDONLY;
-		return -1;
-	}
-
-	/* find which hash bucket it is in */
-	hash = tdb->hash_fn(&key);
-	if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
-		return -1;
-
 	/* check for it existing, on insert. */
 	if (flag == TDB_INSERT) {
 		if (tdb_exists_hash(tdb, key, hash)) {
@@ -562,10 +565,35 @@ int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
 	}
 
 	SAFE_FREE(p); 
-	tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
 	return ret;
 }
 
+/* store an element in the database, replacing any existing element
+   with the same key
+
+   return 0 on success, -1 on failure
+*/
+int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
+{
+	uint32_t hash;
+	int ret;
+
+	if (tdb->read_only || tdb->traverse_read) {
+		tdb->ecode = TDB_ERR_RDONLY;
+		tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, -1);
+		return -1;
+	}
+
+	/* find which hash bucket it is in */
+	hash = tdb->hash_fn(&key);
+	if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
+		return -1;
+
+	ret = _tdb_store(tdb, key, dbuf, flag, hash);
+	tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, ret);
+	tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
+	return ret;
+}
 
 /* Append to an entry. Create if not exist. */
 int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
@@ -579,7 +607,7 @@ int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
 	if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
 		return -1;
 
-	dbuf = tdb_fetch(tdb, key);
+	dbuf = _tdb_fetch(tdb, key);
 
 	if (dbuf.dptr == NULL) {
 		dbuf.dptr = (unsigned char *)malloc(new_dbuf.dsize);
@@ -605,7 +633,8 @@ int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
 	memcpy(dbuf.dptr + dbuf.dsize, new_dbuf.dptr, new_dbuf.dsize);
 	dbuf.dsize += new_dbuf.dsize;
 
-	ret = tdb_store(tdb, key, dbuf, 0);
+	ret = _tdb_store(tdb, key, dbuf, 0, hash);
+	tdb_trace_2rec_retrec(tdb, "tdb_append", key, new_dbuf, dbuf);
 	
 failed:
 	tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
@@ -739,6 +768,8 @@ int tdb_wipe_all(struct tdb_context *tdb)
 		return -1;
 	}
 
+	tdb_trace(tdb, "tdb_wipe_all");
+
 	/* see if the tdb has a recovery area, and remember its size
 	   if so. We don't want to lose this as otherwise each
 	   tdb_wipe_all() in a transaction will increase the size of
@@ -837,6 +868,8 @@ int tdb_repack(struct tdb_context *tdb)
 	struct tdb_context *tmp_db;
 	struct traverse_state state;
 
+	tdb_trace(tdb, "tdb_repack");
+
 	if (tdb_transaction_start(tdb) != 0) {
 		TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to start transaction\n"));
 		return -1;
@@ -899,3 +932,156 @@ int tdb_repack(struct tdb_context *tdb)
 
 	return 0;
 }
+
+#ifdef TDB_TRACE
+static void tdb_trace_write(struct tdb_context *tdb, const char *str)
+{
+	if (write(tdb->tracefd, str, strlen(str)) != strlen(str)) {
+		close(tdb->tracefd);
+		tdb->tracefd = -1;
+	}
+}
+
+static void tdb_trace_start(struct tdb_context *tdb)
+{
+	tdb_off_t seqnum=0;
+	char msg[sizeof(tdb_off_t) * 4 + 1];
+
+	tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
+	snprintf(msg, sizeof(msg), "%u ", seqnum);
+	tdb_trace_write(tdb, msg);
+}
+
+static void tdb_trace_end(struct tdb_context *tdb)
+{
+	tdb_trace_write(tdb, "\n");
+}
+
+static void tdb_trace_end_ret(struct tdb_context *tdb, int ret)
+{
+	char msg[sizeof(ret) * 4 + 4];
+	snprintf(msg, sizeof(msg), " = %i\n", ret);
+	tdb_trace_write(tdb, msg);
+}
+
+static void tdb_trace_record(struct tdb_context *tdb, TDB_DATA rec)
+{
+	char msg[20 + rec.dsize*2], *p;
+	unsigned int i;
+
+	/* We differentiate zero-length records from non-existent ones. */
+	if (rec.dptr == NULL) {
+		tdb_trace_write(tdb, " NULL");
+		return;
+	}
+
+	/* snprintf here is purely cargo-cult programming. */
+	p = msg;
+	p += snprintf(p, sizeof(msg), " %zu:", rec.dsize);
+	for (i = 0; i < rec.dsize; i++)
+		p += snprintf(p, 2, "%02x", rec.dptr[i]);
+
+	tdb_trace_write(tdb, msg);
+}
+
+void tdb_trace(struct tdb_context *tdb, const char *op)
+{
+	tdb_trace_start(tdb);
+	tdb_trace_write(tdb, op);
+	tdb_trace_end(tdb);
+}
+
+void tdb_trace_seqnum(struct tdb_context *tdb, uint32_t seqnum, const char *op)
+{
+	char msg[sizeof(tdb_off_t) * 4 + 1];
+
+	snprintf(msg, sizeof(msg), "%u ", seqnum);
+	tdb_trace_write(tdb, msg);
+	tdb_trace_write(tdb, op);
+	tdb_trace_end(tdb);
+}
+
+void tdb_trace_open(struct tdb_context *tdb, const char *op,
+		    unsigned hash_size, unsigned tdb_flags, unsigned open_flags)
+{
+	char msg[128];
+
+	snprintf(msg, sizeof(msg),
+		 "%s %u 0x%x 0x%x", op, hash_size, tdb_flags, open_flags);
+	tdb_trace_start(tdb);
+	tdb_trace_write(tdb, msg);
+	tdb_trace_end(tdb);
+}
+
+void tdb_trace_ret(struct tdb_context *tdb, const char *op, int ret)
+{
+	tdb_trace_start(tdb);
+	tdb_trace_write(tdb, op);
+	tdb_trace_end_ret(tdb, ret);
+}
+
+void tdb_trace_retrec(struct tdb_context *tdb, const char *op, TDB_DATA ret)
+{
+	tdb_trace_start(tdb);
+	tdb_trace_write(tdb, op);
+	tdb_trace_write(tdb, " =");
+	tdb_trace_record(tdb, ret);
+	tdb_trace_end(tdb);
+}
+
+void tdb_trace_1rec(struct tdb_context *tdb, const char *op,
+		    TDB_DATA rec)
+{
+	tdb_trace_start(tdb);
+	tdb_trace_write(tdb, op);
+	tdb_trace_record(tdb, rec);
+	tdb_trace_end(tdb);
+}
+
+void tdb_trace_1rec_ret(struct tdb_context *tdb, const char *op,
+			TDB_DATA rec, int ret)
+{
+	tdb_trace_start(tdb);
+	tdb_trace_write(tdb, op);
+	tdb_trace_record(tdb, rec);
+	tdb_trace_end_ret(tdb, ret);
+}
+
+void tdb_trace_1rec_retrec(struct tdb_context *tdb, const char *op,
+			   TDB_DATA rec, TDB_DATA ret)
+{
+	tdb_trace_start(tdb);
+	tdb_trace_write(tdb, op);
+	tdb_trace_record(tdb, rec);
+	tdb_trace_write(tdb, " =");
+	tdb_trace_record(tdb, ret);
+	tdb_trace_end(tdb);
+}
+
+void tdb_trace_2rec_flag_ret(struct tdb_context *tdb, const char *op,
+			     TDB_DATA rec1, TDB_DATA rec2, unsigned flag,
+			     int ret)
+{
+	char msg[1 + sizeof(ret) * 4];


-- 
Samba Shared Repository


More information about the samba-cvs mailing list