PATCHSET: Speed up tdb a bit

Volker Lendecke Volker.Lendecke at SerNet.DE
Tue Mar 18 02:30:54 MDT 2014


On Tue, Mar 18, 2014 at 08:41:58AM +0100, Volker Lendecke wrote:
> On Tue, Mar 18, 2014 at 08:36:36AM +0100, Volker Lendecke wrote:
> > Hi!
> > 
> > Attached find a patchset resulting from a large-scale
> > benchmark.
> > 
> > Review would be appreciated.
> 
> ARGL!
> 
> For more than an hour, tdbtorture went fine with this
> patchset. But in the very moment when I hit "send" it failed
> :-(
> 
> Will re-send something later.

Here it is. The bug was a missed hunk when reshuffling the
patches for presentation. "last_ptr = rec_ptr;" was missing
in the 'tdb: Add "last_ptr" to tdb_find_dead' patch.

Volker

-- 
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de, mailto:kontakt at sernet.de
-------------- next part --------------
From 10c4bdc19dae257f1b1d8f2e89cbe2908752de0f Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 16 Mar 2014 20:08:32 +0000
Subject: [PATCH 1/8] tdb: Fix a tdb corruption

tdb_purge_dead can change the next pointer of "rec" if we purge the record
right behind the current record to be deleted. Just overwrite the magic,
not the whole record with stale data.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/tdb/common/tdb.c |    7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/lib/tdb/common/tdb.c b/lib/tdb/common/tdb.c
index 1e41e84..3aabcfa 100644
--- a/lib/tdb/common/tdb.c
+++ b/lib/tdb/common/tdb.c
@@ -394,6 +394,8 @@ static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
 
 	if (tdb->max_dead_records != 0) {
 
+		uint32_t magic = TDB_DEAD_MAGIC;
+
 		/*
 		 * Allow for some dead records per hash chain, mainly for
 		 * tdb's with a very high create/delete rate like locking.tdb.
@@ -410,8 +412,9 @@ static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
 		/*
 		 * Just mark the record as dead.
 		 */
-		rec.magic = TDB_DEAD_MAGIC;
-		ret = tdb_rec_write(tdb, rec_ptr, &rec);
+		ret = tdb_ofs_write(
+			tdb, rec_ptr + offsetof(struct tdb_record, magic),
+			&magic);
 	}
 	else {
 		ret = tdb_do_delete(tdb, rec_ptr, &rec);
-- 
1.7.9.5


From 44c6bcf17a76107ddb9c390e3d2b9eec05a3f688 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 17 Mar 2014 06:47:11 +0100
Subject: [PATCH 2/8] tdb: Don't purge records to a blocked freelist

If the freelist is heavily contended, we should avoid accessing it

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/tdb/common/tdb.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/lib/tdb/common/tdb.c b/lib/tdb/common/tdb.c
index 3aabcfa..634a552 100644
--- a/lib/tdb/common/tdb.c
+++ b/lib/tdb/common/tdb.c
@@ -351,7 +351,10 @@ static int tdb_purge_dead(struct tdb_context *tdb, uint32_t hash)
 	struct tdb_record rec;
 	tdb_off_t rec_ptr;
 
-	if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
+	if (tdb_lock_nonblock(tdb, -1, F_WRLCK) == -1) {
+		/*
+		 * Don't block the freelist if not strictly necessary
+		 */
 		return -1;
 	}
 
-- 
1.7.9.5


From 15d77dd886154def44492a6a163ed7f3888fb1c3 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 18 Mar 2014 07:46:38 +0100
Subject: [PATCH 3/8] tdb: Do a best fit search for dead records

Hash chains are (or can be made) short enough that a full search for the
best-fitting dead record is feasible. The freelist can become much longer,
there we don't do the full search but accept record which are too large.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/tdb/common/tdb.c |   20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/lib/tdb/common/tdb.c b/lib/tdb/common/tdb.c
index 634a552..8242d2b 100644
--- a/lib/tdb/common/tdb.c
+++ b/lib/tdb/common/tdb.c
@@ -449,6 +449,8 @@ static tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
 			       struct tdb_record *r, tdb_len_t length)
 {
 	tdb_off_t rec_ptr;
+	tdb_off_t best_rec_ptr = 0;
+	struct tdb_record best = { .rec_len = UINT32_MAX };
 
 	/* read in the hash top */
 	if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
@@ -459,16 +461,20 @@ static tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
 		if (tdb_rec_read(tdb, rec_ptr, r) == -1)
 			return 0;
 
-		if (TDB_DEAD(r) && r->rec_len >= length) {
-			/*
-			 * First fit for simple coding, TODO: change to best
-			 * fit
-			 */
-			return rec_ptr;
+		if (TDB_DEAD(r) && (r->rec_len >= length) &&
+		    (r->rec_len < best.rec_len)) {
+			best_rec_ptr = rec_ptr;
+			best = *r;
 		}
 		rec_ptr = r->next;
 	}
-	return 0;
+
+	if (best.rec_len == UINT32_MAX) {
+		return 0;
+	}
+
+	*r = best;
+	return best_rec_ptr;
 }
 
 static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
-- 
1.7.9.5


From a4e3e2fe057b5637e390cad54102c40cfac79969 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 18 Mar 2014 07:52:59 +0100
Subject: [PATCH 4/8] tdb: Move adding tailer space to tdb_find_dead

This aligns the tdb_find_dead API with the tdb_allocate API and thus makes it a
bit easier to understand, at least for me.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/tdb/common/tdb.c |    7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/lib/tdb/common/tdb.c b/lib/tdb/common/tdb.c
index 8242d2b..742680a 100644
--- a/lib/tdb/common/tdb.c
+++ b/lib/tdb/common/tdb.c
@@ -452,6 +452,8 @@ static tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
 	tdb_off_t best_rec_ptr = 0;
 	struct tdb_record best = { .rec_len = UINT32_MAX };
 
+	length += sizeof(tdb_off_t); /* tailer */
+
 	/* read in the hash top */
 	if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
 		return 0;
@@ -518,9 +520,8 @@ static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
 		 * for key, data and tailer. If we find one, we don't have to
 		 * consult the central freelist.
 		 */
-		rec_ptr = tdb_find_dead(
-			tdb, hash, &rec,
-			key.dsize + dbuf.dsize + sizeof(tdb_off_t));
+		rec_ptr = tdb_find_dead(tdb, hash, &rec,
+					key.dsize + dbuf.dsize);
 
 		if (rec_ptr != 0) {
 			rec.key_len = key.dsize;
-- 
1.7.9.5


From 32d7555c8d8af4dfd7d79d78f4d50a9111cc6b3b Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 18 Mar 2014 08:00:45 +0100
Subject: [PATCH 5/8] tdb: Add "last_ptr" to tdb_find_dead

Will be used soon to unlink a dead record from a chain

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/tdb/common/tdb.c |   17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/lib/tdb/common/tdb.c b/lib/tdb/common/tdb.c
index 742680a..b71be98 100644
--- a/lib/tdb/common/tdb.c
+++ b/lib/tdb/common/tdb.c
@@ -446,16 +446,20 @@ _PUBLIC_ int tdb_delete(struct tdb_context *tdb, TDB_DATA key)
  * See if we have a dead record around with enough space
  */
 static tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
-			       struct tdb_record *r, tdb_len_t length)
+			       struct tdb_record *r, tdb_len_t length,
+			       tdb_off_t *p_last_ptr)
 {
-	tdb_off_t rec_ptr;
+	tdb_off_t rec_ptr, last_ptr;
 	tdb_off_t best_rec_ptr = 0;
+	tdb_off_t best_last_ptr = 0;
 	struct tdb_record best = { .rec_len = UINT32_MAX };
 
 	length += sizeof(tdb_off_t); /* tailer */
 
+	last_ptr = TDB_HASH_TOP(hash);
+
 	/* read in the hash top */
-	if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
+	if (tdb_ofs_read(tdb, last_ptr, &rec_ptr) == -1)
 		return 0;
 
 	/* keep looking until we find the right record */
@@ -466,8 +470,10 @@ static tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
 		if (TDB_DEAD(r) && (r->rec_len >= length) &&
 		    (r->rec_len < best.rec_len)) {
 			best_rec_ptr = rec_ptr;
+			best_last_ptr = last_ptr;
 			best = *r;
 		}
+		last_ptr = rec_ptr;
 		rec_ptr = r->next;
 	}
 
@@ -476,6 +482,7 @@ static tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
 	}
 
 	*r = best;
+	*p_last_ptr = best_last_ptr;
 	return best_rec_ptr;
 }
 
@@ -514,6 +521,7 @@ static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
 		tdb_delete_hash(tdb, key, hash);
 
 	if (tdb->max_dead_records != 0) {
+		tdb_off_t last_ptr;
 		/*
 		 * Allow for some dead records per hash chain, look if we can
 		 * find one that can hold the new record. We need enough space
@@ -521,7 +529,8 @@ static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
 		 * consult the central freelist.
 		 */
 		rec_ptr = tdb_find_dead(tdb, hash, &rec,
-					key.dsize + dbuf.dsize);
+					key.dsize + dbuf.dsize,
+					&last_ptr);
 
 		if (rec_ptr != 0) {
 			rec.key_len = key.dsize;
-- 
1.7.9.5


From 766067a7b0446008bfb3a15e28d6ba876be294b6 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 18 Mar 2014 08:01:40 +0100
Subject: [PATCH 6/8] tdb: Make "tdb_find_dead" internally public

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/tdb/common/tdb.c         |    6 +++---
 lib/tdb/common/tdb_private.h |    3 +++
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/lib/tdb/common/tdb.c b/lib/tdb/common/tdb.c
index b71be98..df4dd4d 100644
--- a/lib/tdb/common/tdb.c
+++ b/lib/tdb/common/tdb.c
@@ -445,9 +445,9 @@ _PUBLIC_ int tdb_delete(struct tdb_context *tdb, TDB_DATA key)
 /*
  * See if we have a dead record around with enough space
  */
-static tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
-			       struct tdb_record *r, tdb_len_t length,
-			       tdb_off_t *p_last_ptr)
+tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
+			struct tdb_record *r, tdb_len_t length,
+			tdb_off_t *p_last_ptr)
 {
 	tdb_off_t rec_ptr, last_ptr;
 	tdb_off_t best_rec_ptr = 0;
diff --git a/lib/tdb/common/tdb_private.h b/lib/tdb/common/tdb_private.h
index 7227b43..4c73bb6 100644
--- a/lib/tdb/common/tdb_private.h
+++ b/lib/tdb/common/tdb_private.h
@@ -272,6 +272,9 @@ int tdb_parse_data(struct tdb_context *tdb, TDB_DATA key,
 		   void *private_data);
 tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype,
 			   struct tdb_record *rec);
+tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
+			struct tdb_record *r, tdb_len_t length,
+			tdb_off_t *p_last_ptr);
 void tdb_io_init(struct tdb_context *tdb);
 int tdb_expand(struct tdb_context *tdb, tdb_off_t size);
 tdb_off_t tdb_expand_adjust(tdb_off_t map_size, tdb_off_t size, int page_size);
-- 
1.7.9.5


From 324d86c23765a77c11283d10371c952c358ed759 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 18 Mar 2014 08:03:16 +0100
Subject: [PATCH 7/8] tdb: Make "tdb_purge_dead" internally public

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/tdb/common/tdb.c         |    2 +-
 lib/tdb/common/tdb_private.h |    1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/tdb/common/tdb.c b/lib/tdb/common/tdb.c
index df4dd4d..a7111de 100644
--- a/lib/tdb/common/tdb.c
+++ b/lib/tdb/common/tdb.c
@@ -345,7 +345,7 @@ static int tdb_count_dead(struct tdb_context *tdb, uint32_t hash)
 /*
  * Purge all DEAD records from a hash chain
  */
-static int tdb_purge_dead(struct tdb_context *tdb, uint32_t hash)
+int tdb_purge_dead(struct tdb_context *tdb, uint32_t hash)
 {
 	int res = -1;
 	struct tdb_record rec;
diff --git a/lib/tdb/common/tdb_private.h b/lib/tdb/common/tdb_private.h
index 4c73bb6..f62c0a3 100644
--- a/lib/tdb/common/tdb_private.h
+++ b/lib/tdb/common/tdb_private.h
@@ -275,6 +275,7 @@ tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t has
 tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
 			struct tdb_record *r, tdb_len_t length,
 			tdb_off_t *p_last_ptr);
+int tdb_purge_dead(struct tdb_context *tdb, uint32_t hash);
 void tdb_io_init(struct tdb_context *tdb);
 int tdb_expand(struct tdb_context *tdb, tdb_off_t size);
 tdb_off_t tdb_expand_adjust(tdb_off_t map_size, tdb_off_t size, int page_size);
-- 
1.7.9.5


From 39d35984cff147bee79b3c5a100a53425e2725f9 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 18 Mar 2014 08:04:42 +0100
Subject: [PATCH 8/8] tdb: Reduce freelist contention

In a metadata-intensive benchmark we have seen the locking.tdb freelist to be
one of the central contention points. This patch removes most of the contention
on the freelist. Ages ago we already reduced freelist contention by using the
even much older DEAD records: If TDB_VOLATILE is set, don't directly put
deleted records on the freelist, but just mark a few of them just as DEAD. The
next new record can them re-use that space without consulting the freelist.

This patch builds upon the DEAD records: If we need space and the freelist is
busy, instead of doing a blocking wait on the freelist, start looking into
other chains for DEAD records and steal them from there. This way every hash
chain becomes a small freelist. Just wander around the hash chains as long as
the freelist is still busy.

With this patch and the tdb mutex patch (following hopefully some time soon)
you can see a heavily busy clustered smbd run without locking.tdb futex
syscalls.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 lib/tdb/common/freelist.c    |  100 +++++++++++++++++++++++++++++++++++++-----
 lib/tdb/common/tdb.c         |   20 +--------
 lib/tdb/common/tdb_private.h |    3 +-
 3 files changed, 93 insertions(+), 30 deletions(-)

diff --git a/lib/tdb/common/freelist.c b/lib/tdb/common/freelist.c
index ea14dd0..6f8f812 100644
--- a/lib/tdb/common/freelist.c
+++ b/lib/tdb/common/freelist.c
@@ -273,7 +273,8 @@ static tdb_off_t tdb_allocate_ofs(struct tdb_context *tdb,
 
    0 is returned if the space could not be allocated
  */
-tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct tdb_record *rec)
+static tdb_off_t tdb_allocate_from_freelist(
+	struct tdb_context *tdb, tdb_len_t length, struct tdb_record *rec)
 {
 	tdb_off_t rec_ptr, last_ptr, newrec_ptr;
 	struct {
@@ -282,9 +283,6 @@ tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct tdb_rec
 	} bestfit;
 	float multiplier = 1.0;
 
-	if (tdb_lock(tdb, -1, F_WRLCK) == -1)
-		return 0;
-
 	/* over-allocate to reduce fragmentation */
 	length *= 1.25;
 
@@ -297,7 +295,7 @@ tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct tdb_rec
 
 	/* read in the freelist top */
 	if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1)
-		goto fail;
+		return 0;
 
 	bestfit.rec_ptr = 0;
 	bestfit.last_ptr = 0;
@@ -310,7 +308,7 @@ tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct tdb_rec
 	 */
 	while (rec_ptr) {
 		if (tdb_rec_free_read(tdb, rec_ptr, rec) == -1) {
-			goto fail;
+			return 0;
 		}
 
 		if (rec->rec_len >= length) {
@@ -344,12 +342,11 @@ tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct tdb_rec
 
 	if (bestfit.rec_ptr != 0) {
 		if (tdb_rec_free_read(tdb, bestfit.rec_ptr, rec) == -1) {
-			goto fail;
+			return 0;
 		}
 
 		newrec_ptr = tdb_allocate_ofs(tdb, length, bestfit.rec_ptr,
 					      rec, bestfit.last_ptr);
-		tdb_unlock(tdb, -1, F_WRLCK);
 		return newrec_ptr;
 	}
 
@@ -357,12 +354,95 @@ tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct tdb_rec
 	   database and if we can then try again */
 	if (tdb_expand(tdb, length + sizeof(*rec)) == 0)
 		goto again;
- fail:
-	tdb_unlock(tdb, -1, F_WRLCK);
+
 	return 0;
 }
 
+static bool tdb_alloc_dead(
+	struct tdb_context *tdb, int hash, tdb_len_t length,
+	tdb_off_t *rec_ptr, struct tdb_record *rec)
+{
+	tdb_off_t last_ptr;
+
+	*rec_ptr = tdb_find_dead(tdb, hash, rec, length, &last_ptr);
+	if (*rec_ptr == 0) {
+		return false;
+	}
+	/*
+	 * Unlink the record from the hash chain, it's about to be moved into
+	 * another one.
+	 */
+	return (tdb_ofs_write(tdb, last_ptr, &rec->next) == 0);
+}
+
+/*
+ * Chain "hash" is assumed to be locked
+ */
+
+tdb_off_t tdb_allocate(struct tdb_context *tdb, int hash, tdb_len_t length,
+		       struct tdb_record *rec)
+{
+	tdb_off_t ret;
+	int i;
+
+	if (tdb->max_dead_records == 0) {
+		/*
+		 * No dead records to expect anywhere. Do the blocking
+		 * freelist lock without trying to steal from others
+		 */
+		goto blocking_freelist_allocate;
+	}
+
+	/*
+	 * The following loop tries to get the freelist lock nonblocking. If
+	 * it gets the lock, allocate from there. If the freelist is busy,
+	 * instead of waiting we try to steal dead records from other hash
+	 * chains.
+	 *
+	 * Be aware that we do nonblocking locks on the other hash chains as
+	 * well and fail gracefully. This way we avoid deadlocks (we block two
+	 * hash chains, something which is pretty bad normally)
+	 */
+
+	for (i=1; i<tdb->hash_size; i++) {
+
+		int list;
+
+		if (tdb_lock_nonblock(tdb, -1, F_WRLCK) == 0) {
+			/*
+			 * Under the freelist lock take the chance to give
+			 * back our dead records.
+			 */
+			tdb_purge_dead(tdb, hash);
+
+			ret = tdb_allocate_from_freelist(tdb, length, rec);
+			tdb_unlock(tdb, -1, F_WRLCK);
+			return ret;
+		}
+
+		list = BUCKET(hash+i);
+
+		if (tdb_lock_nonblock(tdb, list, F_WRLCK) == 0) {
+			bool got_dead;
 
+			got_dead = tdb_alloc_dead(tdb, list, length, &ret, rec);
+			tdb_unlock(tdb, list, F_WRLCK);
+
+			if (got_dead) {
+				return ret;
+			}
+		}
+	}
+
+blocking_freelist_allocate:
+
+	if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
+		return 0;
+	}
+	ret = tdb_allocate_from_freelist(tdb, length, rec);
+	tdb_unlock(tdb, -1, F_WRLCK);
+	return ret;
+}
 
 /*
    return the size of the freelist - used to decide if we should repack
diff --git a/lib/tdb/common/tdb.c b/lib/tdb/common/tdb.c
index a7111de..ba1c98e 100644
--- a/lib/tdb/common/tdb.c
+++ b/lib/tdb/common/tdb.c
@@ -550,26 +550,8 @@ static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
 		}
 	}
 
-	/*
-	 * We have to allocate some space from the freelist, so this means we
-	 * have to lock it. Use the chance to purge all the DEAD records from
-	 * the hash chain under the freelist lock.
-	 */
-
-	if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
-		goto fail;
-	}
-
-	if ((tdb->max_dead_records != 0)
-	    && (tdb_purge_dead(tdb, hash) == -1)) {
-		tdb_unlock(tdb, -1, F_WRLCK);
-		goto fail;
-	}
-
 	/* we have to allocate some space */
-	rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize, &rec);
-
-	tdb_unlock(tdb, -1, F_WRLCK);
+	rec_ptr = tdb_allocate(tdb, hash, key.dsize + dbuf.dsize, &rec);
 
 	if (rec_ptr == 0) {
 		goto fail;
diff --git a/lib/tdb/common/tdb_private.h b/lib/tdb/common/tdb_private.h
index f62c0a3..a672159 100644
--- a/lib/tdb/common/tdb_private.h
+++ b/lib/tdb/common/tdb_private.h
@@ -255,7 +255,8 @@ int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
 int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
 void *tdb_convert(void *buf, uint32_t size);
 int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec);
-tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct tdb_record *rec);
+tdb_off_t tdb_allocate(struct tdb_context *tdb, int hash, tdb_len_t length,
+		       struct tdb_record *rec);
 int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
 int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
 int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off);
-- 
1.7.9.5



More information about the samba-technical mailing list