r9852: Add tridge's Samba4 tdb optimisations.
authorJeremy Allison <jra@samba.org>
Thu, 1 Sep 2005 00:36:46 +0000 (00:36 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 16:03:26 +0000 (11:03 -0500)
Jeremy.
(This used to be commit cfe5a7e5f8eccecf8876c36ddeb0f6e91eb6aac4)

source3/tdb/tdb.c

index d68df037768fa703b17580a5de6426dfbb0ea5ce..908657b355a6747c21214f6ce550f1fa6cdbe7d2 100644 (file)
@@ -1248,6 +1248,54 @@ static int tdb_next_lock(TDB_CONTEXT *tdb, struct tdb_traverse_lock *tlock,
 
        /* Lock each chain from the start one. */
        for (; tlock->hash < tdb->header.hash_size; tlock->hash++) {
+
+               /* this is an optimisation for the common case where
+                  the hash chain is empty, which is particularly
+                  common for the use of tdb with ldb, where large
+                  hashes are used. In that case we spend most of our
+                  time in tdb_brlock(), locking empty hash chains.
+
+                  To avoid this, we do an unlocked pre-check to see
+                  if the hash chain is empty before starting to look
+                  inside it. If it is empty then we can avoid that
+                  hash chain. If it isn't empty then we can't believe
+                  the value we get back, as we read it without a
+                  lock, so instead we get the lock and re-fetch the
+                  value below.
+
+                  Notice that not doing this optimisation on the
+                  first hash chain is critical. We must guarantee
+                  that we have done at least one fcntl lock at the
+                  start of a search to guarantee that memory is
+                  coherent on SMP systems. If records are added by
+                  others during the search then thats OK, and we
+                  could possibly miss those with this trick, but we
+                  could miss them anyway without this trick, so the
+                  semantics don't change.
+
+                  With a non-indexed ldb search this trick gains us a
+                  factor of around 80 in speed on a linux 2.6.x
+                  system (testing using ldbtest).
+                */
+               if (!tlock->off && tlock->hash != 0) {
+                       u32 off;
+                       if (tdb->map_ptr) {
+                               for (;tlock->hash < tdb->header.hash_size;tlock->hash++) {
+                                       if (0 != *(u32 *)(TDB_HASH_TOP(tlock->hash) + (unsigned char *)tdb->map_ptr)) {
+                                               break;
+                                       }
+                               }
+                               if (tlock->hash == tdb->header.hash_size) {
+                                       continue;
+                               }
+                       } else {
+                               if (ofs_read(tdb, TDB_HASH_TOP(tlock->hash), &off) == 0 &&
+                                   off == 0) {
+                                       continue;
+                               }
+                       }
+               }
+
                if (tdb_lock(tdb, tlock->hash, F_WRLCK) == -1)
                        return -1;