]> git.ozlabs.org Git - ccan/commitdiff
tdb2: TDB_ATTRIBUTE_STATS access via tdb_get_attribute.
authorRusty Russell <rusty@rustcorp.com.au>
Wed, 27 Apr 2011 13:51:32 +0000 (23:21 +0930)
committerRusty Russell <rusty@rustcorp.com.au>
Wed, 27 Apr 2011 13:51:32 +0000 (23:21 +0930)
Now we have tdb_get_attribute, it makes sense to make that the method
of accessing statistics.  That way they are always available, and it's
probably cheaper doing the direct increment than even the unlikely()
branch.

12 files changed:
ccan/tdb2/free.c
ccan/tdb2/hash.c
ccan/tdb2/io.c
ccan/tdb2/lock.c
ccan/tdb2/open.c
ccan/tdb2/private.h
ccan/tdb2/tdb.c
ccan/tdb2/tdb2.h
ccan/tdb2/test/failtest_helper.h
ccan/tdb2/test/run-91-get-stats.c [new file with mode: 0644]
ccan/tdb2/tools/speed.c
ccan/tdb2/transaction.c

index c78d138943b108550dbf886f4aa599e5310a1e7c..e2b9cb18c5043a98a173eca52fecab4c22ad3dae 100644 (file)
@@ -342,7 +342,7 @@ static tdb_bool_err coalesce(struct tdb_context *tdb,
        struct tdb_free_record rec;
        enum TDB_ERROR ecode;
 
        struct tdb_free_record rec;
        enum TDB_ERROR ecode;
 
-       add_stat(tdb, alloc_coalesce_tried, 1);
+       tdb->stats.alloc_coalesce_tried++;
        end = off + sizeof(struct tdb_used_record) + data_len;
 
        while (end < tdb->file->map_size) {
        end = off + sizeof(struct tdb_used_record) + data_len;
 
        while (end < tdb->file->map_size) {
@@ -376,7 +376,7 @@ static tdb_bool_err coalesce(struct tdb_context *tdb,
                /* We may be violating lock order here, so best effort. */
                if (tdb_lock_free_bucket(tdb, nb_off, TDB_LOCK_NOWAIT)
                    != TDB_SUCCESS) {
                /* We may be violating lock order here, so best effort. */
                if (tdb_lock_free_bucket(tdb, nb_off, TDB_LOCK_NOWAIT)
                    != TDB_SUCCESS) {
-                       add_stat(tdb, alloc_coalesce_lockfail, 1);
+                       tdb->stats.alloc_coalesce_lockfail++;
                        break;
                }
 
                        break;
                }
 
@@ -388,14 +388,14 @@ static tdb_bool_err coalesce(struct tdb_context *tdb,
                }
 
                if (unlikely(frec_magic(&rec) != TDB_FREE_MAGIC)) {
                }
 
                if (unlikely(frec_magic(&rec) != TDB_FREE_MAGIC)) {
-                       add_stat(tdb, alloc_coalesce_race, 1);
+                       tdb->stats.alloc_coalesce_race++;
                        tdb_unlock_free_bucket(tdb, nb_off);
                        break;
                }
 
                if (unlikely(frec_ftable(&rec) != ftable)
                    || unlikely(size_to_bucket(frec_len(&rec)) != bucket)) {
                        tdb_unlock_free_bucket(tdb, nb_off);
                        break;
                }
 
                if (unlikely(frec_ftable(&rec) != ftable)
                    || unlikely(size_to_bucket(frec_len(&rec)) != bucket)) {
-                       add_stat(tdb, alloc_coalesce_race, 1);
+                       tdb->stats.alloc_coalesce_race++;
                        tdb_unlock_free_bucket(tdb, nb_off);
                        break;
                }
                        tdb_unlock_free_bucket(tdb, nb_off);
                        break;
                }
@@ -409,7 +409,7 @@ static tdb_bool_err coalesce(struct tdb_context *tdb,
 
                end += sizeof(struct tdb_used_record) + frec_len(&rec);
                tdb_unlock_free_bucket(tdb, nb_off);
 
                end += sizeof(struct tdb_used_record) + frec_len(&rec);
                tdb_unlock_free_bucket(tdb, nb_off);
-               add_stat(tdb, alloc_coalesce_num_merged, 1);
+               tdb->stats.alloc_coalesce_num_merged++;
        }
 
        /* Didn't find any adjacent free? */
        }
 
        /* Didn't find any adjacent free? */
@@ -446,7 +446,7 @@ static tdb_bool_err coalesce(struct tdb_context *tdb,
                goto err;
        }
 
                goto err;
        }
 
-       add_stat(tdb, alloc_coalesce_succeeded, 1);
+       tdb->stats.alloc_coalesce_succeeded++;
        tdb_unlock_free_bucket(tdb, b_off);
 
        ecode = add_free_record(tdb, off, end - off);
        tdb_unlock_free_bucket(tdb, b_off);
 
        ecode = add_free_record(tdb, off, end - off);
@@ -476,7 +476,7 @@ static tdb_off_t lock_and_alloc(struct tdb_context *tdb,
        size_t size = adjust_size(keylen, datalen);
        enum TDB_ERROR ecode;
 
        size_t size = adjust_size(keylen, datalen);
        enum TDB_ERROR ecode;
 
-       add_stat(tdb, allocs, 1);
+       tdb->stats.allocs++;
 again:
        b_off = bucket_off(ftable_off, bucket);
 
 again:
        b_off = bucket_off(ftable_off, bucket);
 
@@ -596,7 +596,7 @@ again:
                /* Bucket of leftover will be <= current bucket, so nested
                 * locking is allowed. */
                if (leftover) {
                /* Bucket of leftover will be <= current bucket, so nested
                 * locking is allowed. */
                if (leftover) {
-                       add_stat(tdb, alloc_leftover, 1);
+                       tdb->stats.alloc_leftover++;
                        ecode = add_free_record(tdb,
                                                best_off + sizeof(rec)
                                                + frec_len(&best) - leftover,
                        ecode = add_free_record(tdb,
                                                best_off + sizeof(rec)
                                                + frec_len(&best) - leftover,
@@ -649,9 +649,9 @@ static tdb_off_t get_free(struct tdb_context *tdb,
                                return off;
                        if (off != 0) {
                                if (b == start_b)
                                return off;
                        if (off != 0) {
                                if (b == start_b)
-                                       add_stat(tdb, alloc_bucket_exact, 1);
+                                       tdb->stats.alloc_bucket_exact++;
                                if (b == TDB_FREE_BUCKETS - 1)
                                if (b == TDB_FREE_BUCKETS - 1)
-                                       add_stat(tdb, alloc_bucket_max, 1);
+                                       tdb->stats.alloc_bucket_max++;
                                /* Worked?  Stay using this list. */
                                tdb->ftable_off = ftable_off;
                                tdb->ftable = ftable;
                                /* Worked?  Stay using this list. */
                                tdb->ftable_off = ftable_off;
                                tdb->ftable = ftable;
@@ -758,7 +758,7 @@ static enum TDB_ERROR tdb_expand(struct tdb_context *tdb, tdb_len_t size)
        /* We need to drop this lock before adding free record. */
        tdb_unlock_expand(tdb, F_WRLCK);
 
        /* We need to drop this lock before adding free record. */
        tdb_unlock_expand(tdb, F_WRLCK);
 
-       add_stat(tdb, expands, 1);
+       tdb->stats.expands++;
        return add_free_record(tdb, old_size, wanted);
 }
 
        return add_free_record(tdb, old_size, wanted);
 }
 
index 745f04c87e5574f50719b3018b4a78f7167fbbd6..1359cfecd66dc6280e3314e78fd2e7e5ea91c8bd 100644 (file)
@@ -72,7 +72,7 @@ static tdb_bool_err key_matches(struct tdb_context *tdb,
        const char *rkey;
 
        if (rec_key_length(rec) != key->dsize) {
        const char *rkey;
 
        if (rec_key_length(rec) != key->dsize) {
-               add_stat(tdb, compare_wrong_keylen, 1);
+               tdb->stats.compare_wrong_keylen++;
                return ret;
        }
 
                return ret;
        }
 
@@ -83,7 +83,7 @@ static tdb_bool_err key_matches(struct tdb_context *tdb,
        if (memcmp(rkey, key->dptr, key->dsize) == 0)
                ret = true;
        else
        if (memcmp(rkey, key->dptr, key->dsize) == 0)
                ret = true;
        else
-               add_stat(tdb, compare_wrong_keycmp, 1);
+               tdb->stats.compare_wrong_keycmp++;
        tdb_access_release(tdb, rkey);
        return ret;
 }
        tdb_access_release(tdb, rkey);
        return ret;
 }
@@ -98,10 +98,10 @@ static tdb_bool_err match(struct tdb_context *tdb,
        tdb_off_t off;
        enum TDB_ERROR ecode;
 
        tdb_off_t off;
        enum TDB_ERROR ecode;
 
-       add_stat(tdb, compares, 1);
+       tdb->stats.compares++;
        /* Desired bucket must match. */
        if (h->home_bucket != (val & TDB_OFF_HASH_GROUP_MASK)) {
        /* Desired bucket must match. */
        if (h->home_bucket != (val & TDB_OFF_HASH_GROUP_MASK)) {
-               add_stat(tdb, compare_wrong_bucket, 1);
+               tdb->stats.compare_wrong_bucket++;
                return false;
        }
 
                return false;
        }
 
@@ -109,7 +109,7 @@ static tdb_bool_err match(struct tdb_context *tdb,
        if (bits_from(val, TDB_OFF_HASH_EXTRA_BIT, TDB_OFF_UPPER_STEAL_EXTRA)
            != bits_from(h->h, 64 - h->hash_used - TDB_OFF_UPPER_STEAL_EXTRA,
                    TDB_OFF_UPPER_STEAL_EXTRA)) {
        if (bits_from(val, TDB_OFF_HASH_EXTRA_BIT, TDB_OFF_UPPER_STEAL_EXTRA)
            != bits_from(h->h, 64 - h->hash_used - TDB_OFF_UPPER_STEAL_EXTRA,
                    TDB_OFF_UPPER_STEAL_EXTRA)) {
-               add_stat(tdb, compare_wrong_offsetbits, 1);
+               tdb->stats.compare_wrong_offsetbits++;
                return false;
        }
 
                return false;
        }
 
@@ -120,7 +120,7 @@ static tdb_bool_err match(struct tdb_context *tdb,
        }
 
        if ((h->h & ((1 << 11)-1)) != rec_hash(rec)) {
        }
 
        if ((h->h & ((1 << 11)-1)) != rec_hash(rec)) {
-               add_stat(tdb, compare_wrong_rechash, 1);
+               tdb->stats.compare_wrong_rechash++;
                return false;
        }
 
                return false;
        }
 
@@ -492,11 +492,11 @@ static enum TDB_ERROR expand_group(struct tdb_context *tdb, struct hash_info *h)
        bucket = fullest_bucket(tdb, h->group, h->home_bucket);
 
        if (h->hash_used == 64) {
        bucket = fullest_bucket(tdb, h->group, h->home_bucket);
 
        if (h->hash_used == 64) {
-               add_stat(tdb, alloc_chain, 1);
+               tdb->stats.alloc_chain++;
                subsize = sizeof(struct tdb_chain);
                magic = TDB_CHAIN_MAGIC;
        } else {
                subsize = sizeof(struct tdb_chain);
                magic = TDB_CHAIN_MAGIC;
        } else {
-               add_stat(tdb, alloc_subhash, 1);
+               tdb->stats.alloc_subhash++;
                subsize = (sizeof(tdb_off_t) << TDB_SUBLEVEL_HASH_BITS);
                magic = TDB_HTABLE_MAGIC;
        }
                subsize = (sizeof(tdb_off_t) << TDB_SUBLEVEL_HASH_BITS);
                magic = TDB_HTABLE_MAGIC;
        }
index bb3d2192829dc504a885e06176f6a2e275c2bcd8..240a1c038da368c274363cb3cfcd37945a517a0e 100644 (file)
@@ -592,12 +592,6 @@ void tdb_inc_seqnum(struct tdb_context *tdb)
        }
 }
 
        }
 }
 
-void add_stat_(struct tdb_context *tdb, uint64_t *s, size_t val)
-{
-       if ((uintptr_t)s < (uintptr_t)tdb->stats + tdb->stats->size)
-               *s += val;
-}
-
 static const struct tdb_methods io_methods = {
        tdb_read,
        tdb_write,
 static const struct tdb_methods io_methods = {
        tdb_read,
        tdb_write,
index 2878eaeee5e98a9a034005a9dd0e626fa733ffc0..8a338cbe188c1f954ada8f701c2f7de6aeec5257 100644 (file)
@@ -104,9 +104,9 @@ static int lock(struct tdb_context *tdb,
                tdb->file->locker = getpid();
        }
 
                tdb->file->locker = getpid();
        }
 
-       add_stat(tdb, lock_lowlevel, 1);
+       tdb->stats.lock_lowlevel++;
        if (!waitflag)
        if (!waitflag)
-               add_stat(tdb, lock_nonblock, 1);
+               tdb->stats.lock_nonblock++;
        return tdb->lock_fn(tdb->file->fd, rw, off, len, waitflag,
                            tdb->lock_data);
 }
        return tdb->lock_fn(tdb->file->fd, rw, off, len, waitflag,
                            tdb->lock_data);
 }
@@ -359,7 +359,7 @@ static enum TDB_ERROR tdb_nest_lock(struct tdb_context *tdb,
                return TDB_ERR_LOCK;
        }
 
                return TDB_ERR_LOCK;
        }
 
-       add_stat(tdb, locks, 1);
+       tdb->stats.locks++;
 
        new_lck = find_nestlock(tdb, offset, NULL);
        if (new_lck) {
 
        new_lck = find_nestlock(tdb, offset, NULL);
        if (new_lck) {
@@ -567,7 +567,7 @@ enum TDB_ERROR tdb_allrecord_lock(struct tdb_context *tdb, int ltype,
                                  " can't upgrade a write lock");
        }
 
                                  " can't upgrade a write lock");
        }
 
-       add_stat(tdb, locks, 1);
+       tdb->stats.locks++;
 again:
        /* Lock hashes, gradually. */
        ecode = tdb_lock_gradual(tdb, ltype, flags, TDB_HASH_LOCK_START,
 again:
        /* Lock hashes, gradually. */
        ecode = tdb_lock_gradual(tdb, ltype, flags, TDB_HASH_LOCK_START,
index 37e20907fedfc1a9f512c449dea8b8e727ebcf9a..1292fcc1ee32ee59431284527706461696096211 100644 (file)
@@ -203,6 +203,12 @@ enum TDB_ERROR tdb_set_attribute(struct tdb_context *tdb,
                                     : attr->base.attr == TDB_ATTRIBUTE_SEED
                                     ? "TDB_ATTRIBUTE_SEED"
                                     : "TDB_ATTRIBUTE_OPENHOOK");
                                     : attr->base.attr == TDB_ATTRIBUTE_SEED
                                     ? "TDB_ATTRIBUTE_SEED"
                                     : "TDB_ATTRIBUTE_OPENHOOK");
+       case TDB_ATTRIBUTE_STATS:
+               return tdb->last_error
+                       = tdb_logerr(tdb, TDB_ERR_EINVAL,
+                                    TDB_LOG_USE_ERROR,
+                                    "tdb_set_attribute:"
+                                    " cannot set TDB_ATTRIBUTE_STATS");
        case TDB_ATTRIBUTE_FLOCK:
                tdb->lock_fn = attr->flock.lock;
                tdb->unlock_fn = attr->flock.unlock;
        case TDB_ATTRIBUTE_FLOCK:
                tdb->lock_fn = attr->flock.lock;
                tdb->unlock_fn = attr->flock.unlock;
@@ -252,9 +258,13 @@ enum TDB_ERROR tdb_get_attribute(struct tdb_context *tdb,
                                     TDB_LOG_USE_ERROR,
                                     "tdb_get_attribute:"
                                     " cannot get TDB_ATTRIBUTE_OPENHOOK");
                                     TDB_LOG_USE_ERROR,
                                     "tdb_get_attribute:"
                                     " cannot get TDB_ATTRIBUTE_OPENHOOK");
-       case TDB_ATTRIBUTE_STATS:
-               /* FIXME */
-               return TDB_ERR_EINVAL;
+       case TDB_ATTRIBUTE_STATS: {
+               size_t size = attr->stats.size;
+               if (size > tdb->stats.size)
+                       size = tdb->stats.size;
+               memcpy(&attr->stats, &tdb->stats, size);
+               break;
+       }
        case TDB_ATTRIBUTE_FLOCK:
                attr->flock.lock = tdb->lock_fn;
                attr->flock.unlock = tdb->unlock_fn;
        case TDB_ATTRIBUTE_FLOCK:
                attr->flock.lock = tdb->lock_fn;
                attr->flock.unlock = tdb->unlock_fn;
@@ -291,7 +301,10 @@ void tdb_unset_attribute(struct tdb_context *tdb,
                           : "TDB_ATTRIBUTE_OPENHOOK");
                break;
        case TDB_ATTRIBUTE_STATS:
                           : "TDB_ATTRIBUTE_OPENHOOK");
                break;
        case TDB_ATTRIBUTE_STATS:
-               /* FIXME */
+               tdb_logerr(tdb, TDB_ERR_EINVAL,
+                          TDB_LOG_USE_ERROR,
+                          "tdb_unset_attribute:"
+                          "cannot unset TDB_ATTRIBUTE_STATS");
                break;
        case TDB_ATTRIBUTE_FLOCK:
                tdb->lock_fn = tdb_fcntl_lock;
                break;
        case TDB_ATTRIBUTE_FLOCK:
                tdb->lock_fn = tdb_fcntl_lock;
@@ -337,13 +350,15 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
        tdb->flags = tdb_flags;
        tdb->log_fn = NULL;
        tdb->transaction = NULL;
        tdb->flags = tdb_flags;
        tdb->log_fn = NULL;
        tdb->transaction = NULL;
-       tdb->stats = NULL;
        tdb->access = NULL;
        tdb->last_error = TDB_SUCCESS;
        tdb->file = NULL;
        tdb->lock_fn = tdb_fcntl_lock;
        tdb->unlock_fn = tdb_fcntl_unlock;
        tdb->hash_fn = jenkins_hash;
        tdb->access = NULL;
        tdb->last_error = TDB_SUCCESS;
        tdb->file = NULL;
        tdb->lock_fn = tdb_fcntl_lock;
        tdb->unlock_fn = tdb_fcntl_unlock;
        tdb->hash_fn = jenkins_hash;
+       memset(&tdb->stats, 0, sizeof(tdb->stats));
+       tdb->stats.base.attr = TDB_ATTRIBUTE_STATS;
+       tdb->stats.size = sizeof(tdb->stats);
        tdb_io_init(tdb);
 
        while (attr) {
        tdb_io_init(tdb);
 
        while (attr) {
@@ -355,12 +370,6 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
                case TDB_ATTRIBUTE_SEED:
                        seed = &attr->seed;
                        break;
                case TDB_ATTRIBUTE_SEED:
                        seed = &attr->seed;
                        break;
-               case TDB_ATTRIBUTE_STATS:
-                       tdb->stats = &attr->stats;
-                       /* They have stats we don't know about?  Tell them. */
-                       if (tdb->stats->size > sizeof(attr->stats))
-                               tdb->stats->size = sizeof(attr->stats);
-                       break;
                case TDB_ATTRIBUTE_OPENHOOK:
                        openhook = &attr->openhook;
                        break;
                case TDB_ATTRIBUTE_OPENHOOK:
                        openhook = &attr->openhook;
                        break;
@@ -407,16 +416,6 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
                if (ecode != TDB_SUCCESS) {
                        goto fail;
                }
                if (ecode != TDB_SUCCESS) {
                        goto fail;
                }
-               if (name) {
-                       tdb->name = strdup(name);
-                       if (!tdb->name) {
-                               ecode = tdb_logerr(tdb, TDB_ERR_OOM,
-                                                  TDB_LOG_ERROR,
-                                                  "tdb_open: failed to"
-                                                  " allocate name");
-                               goto fail;
-                       }
-               }
                tdb_convert(tdb, &hdr.hash_seed, sizeof(hdr.hash_seed));
                tdb->hash_seed = hdr.hash_seed;
                tdb_ftable_init(tdb);
                tdb_convert(tdb, &hdr.hash_seed, sizeof(hdr.hash_seed));
                tdb->hash_seed = hdr.hash_seed;
                tdb_ftable_init(tdb);
@@ -525,13 +524,6 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
                goto fail;
        }
 
                goto fail;
        }
 
-       tdb->name = strdup(name);
-       if (!tdb->name) {
-               ecode = tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
-                                  "tdb_open: failed to allocate name");
-               goto fail;
-       }
-
        /* Clear any features we don't understand. */
        if ((open_flags & O_ACCMODE) != O_RDONLY) {
                hdr.features_used &= TDB_FEATURE_MASK;
        /* Clear any features we don't understand. */
        if ((open_flags & O_ACCMODE) != O_RDONLY) {
                hdr.features_used &= TDB_FEATURE_MASK;
index 306cb3ff467f70397fbcd91709a285c34e9e9de8..cc791b0bb4e3da3226c22862b21d03e32304e931 100644 (file)
@@ -358,9 +358,6 @@ struct tdb_context {
        /* mmap read only? */
        int mmap_flags;
 
        /* mmap read only? */
        int mmap_flags;
 
-       /* Error code for last tdb error. */
-       enum TDB_ERROR ecode;
-
        /* the flags passed to tdb_open, for tdb_reopen. */
        uint32_t flags;
 
        /* the flags passed to tdb_open, for tdb_reopen. */
        uint32_t flags;
 
@@ -391,7 +388,8 @@ struct tdb_context {
        /* IO methods: changes for transactions. */
        const struct tdb_methods *methods;
 
        /* IO methods: changes for transactions. */
        const struct tdb_methods *methods;
 
-       struct tdb_attribute_stats *stats;
+       /* Our statistics. */
+       struct tdb_attribute_stats stats;
 
        /* Direct access information */
        struct tdb_access_hdr *access;
 
        /* Direct access information */
        struct tdb_access_hdr *access;
@@ -535,14 +533,6 @@ enum TDB_ERROR tdb_read_convert(struct tdb_context *tdb, tdb_off_t off,
 /* Bump the seqnum (caller checks for tdb->flags & TDB_SEQNUM) */
 void tdb_inc_seqnum(struct tdb_context *tdb);
 
 /* Bump the seqnum (caller checks for tdb->flags & TDB_SEQNUM) */
 void tdb_inc_seqnum(struct tdb_context *tdb);
 
-/* Adds a stat, if it's in range. */
-void add_stat_(struct tdb_context *tdb, uint64_t *stat, size_t val);
-#define add_stat(tdb, statname, val)                                   \
-       do {                                                            \
-               if (unlikely((tdb)->stats))                             \
-                       add_stat_((tdb), &(tdb)->stats->statname, (val)); \
-       } while (0)
-
 /* lock.c: */
 /* Lock/unlock a range of hashes. */
 enum TDB_ERROR tdb_lock_hashes(struct tdb_context *tdb,
 /* lock.c: */
 /* Lock/unlock a range of hashes. */
 enum TDB_ERROR tdb_lock_hashes(struct tdb_context *tdb,
index 2a37f13063a4f094162ce3cb6bcd919c342d782e..18cf2e93a598ea7c3f742bcb3e445a5985686d55 100644 (file)
@@ -38,7 +38,7 @@ static enum TDB_ERROR replace_data(struct tdb_context *tdb,
 
        /* We didn't like the existing one: remove it. */
        if (old_off) {
 
        /* We didn't like the existing one: remove it. */
        if (old_off) {
-               add_stat(tdb, frees, 1);
+               tdb->stats.frees++;
                ecode = add_free_record(tdb, old_off,
                                        sizeof(struct tdb_used_record)
                                        + key.dsize + old_room);
                ecode = add_free_record(tdb, old_off,
                                        sizeof(struct tdb_used_record)
                                        + key.dsize + old_room);
@@ -285,7 +285,7 @@ enum TDB_ERROR tdb_delete(struct tdb_context *tdb, struct tdb_data key)
        }
 
        /* Free the deleted entry. */
        }
 
        /* Free the deleted entry. */
-       add_stat(tdb, frees, 1);
+       tdb->stats.frees++;
        ecode = add_free_record(tdb, off,
                                sizeof(struct tdb_used_record)
                                + rec_key_length(&rec)
        ecode = add_free_record(tdb, off,
                                sizeof(struct tdb_used_record)
                                + rec_key_length(&rec)
index 296410e74196573a955470b78c422daa870f8be5..d9194a5eccce54629595966d277cefa0cb7cf8c5 100644 (file)
@@ -729,13 +729,13 @@ struct tdb_attribute_seed {
  * struct tdb_attribute_stats - tdb operational statistics
  *
  * This attribute records statistics of various low-level TDB operations.
  * struct tdb_attribute_stats - tdb operational statistics
  *
  * This attribute records statistics of various low-level TDB operations.
- * This can be used to assist performance evaluation.
+ * This can be used to assist performance evaluation.  This is only
+ * useful for tdb_get_attribute().
  *
  * New fields will be added at the end, hence the "size" argument which
  *
  * New fields will be added at the end, hence the "size" argument which
- * indicates how large your structure is.  If your size is larger than
- * that known about by this version of tdb, the size will be reduced to
- * the known structure size.  Thus you can detect older versions, and
- * thus know that newer stats will not be updated.
+ * indicates how large your structure is: it must be filled in before
+ * calling tdb_get_attribute(), which will overwrite it with the size
+ * tdb knows about.
  */
 struct tdb_attribute_stats {
        struct tdb_attribute_base base; /* .attr = TDB_ATTRIBUTE_STATS */
  */
 struct tdb_attribute_stats {
        struct tdb_attribute_base base; /* .attr = TDB_ATTRIBUTE_STATS */
index 214fcfa1dec3fcd3e0b47203457ecbc3cdaac292..af0ee9b7db678b946ff0510e05f4067c2b757468 100644 (file)
@@ -4,7 +4,7 @@
 #include <stdbool.h>
 
 /* FIXME: Check these! */
 #include <stdbool.h>
 
 /* FIXME: Check these! */
-#define INITIAL_TDB_MALLOC     "open.c", 324, FAILTEST_MALLOC
+#define INITIAL_TDB_MALLOC     "open.c", 337, FAILTEST_MALLOC
 #define URANDOM_OPEN           "open.c", 45, FAILTEST_OPEN
 #define URANDOM_READ           "open.c", 25, FAILTEST_READ
 
 #define URANDOM_OPEN           "open.c", 45, FAILTEST_OPEN
 #define URANDOM_READ           "open.c", 25, FAILTEST_READ
 
diff --git a/ccan/tdb2/test/run-91-get-stats.c b/ccan/tdb2/test/run-91-get-stats.c
new file mode 100644 (file)
index 0000000..795dfd6
--- /dev/null
@@ -0,0 +1,59 @@
+#include <ccan/tdb2/tdb.c>
+#include <ccan/tdb2/open.c>
+#include <ccan/tdb2/free.c>
+#include <ccan/tdb2/lock.c>
+#include <ccan/tdb2/io.c>
+#include <ccan/tdb2/hash.c>
+#include <ccan/tdb2/check.c>
+#include <ccan/tdb2/transaction.c>
+#include <ccan/tdb2/traverse.c>
+#include <ccan/tap/tap.h>
+#include "logging.h"
+
+int main(int argc, char *argv[])
+{
+       unsigned int i;
+       struct tdb_context *tdb;
+       int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
+                       TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT };
+
+       plan_tests(sizeof(flags) / sizeof(flags[0]) * 11);
+
+       for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+               union tdb_attribute *attr;
+               struct tdb_data key = tdb_mkdata("key", 3);
+
+               tdb = tdb_open("run-91-get-stats.tdb", flags[i],
+                              O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
+               ok1(tdb);
+               ok1(tdb_store(tdb, key, key, TDB_REPLACE) == 0);
+
+               /* Use malloc so valgrind will catch overruns. */
+               attr = malloc(sizeof *attr);
+               attr->stats.base.attr = TDB_ATTRIBUTE_STATS;
+               attr->stats.size = sizeof(*attr);
+
+               ok1(tdb_get_attribute(tdb, attr) == 0);
+               ok1(attr->stats.size == sizeof(*attr));
+               ok1(attr->stats.allocs > 0);
+               ok1(attr->stats.expands > 0);
+               ok1(attr->stats.locks > 0);
+               free(attr);
+
+               /* Try short one. */
+               attr = malloc(offsetof(struct tdb_attribute_stats, allocs)
+                             + sizeof(attr->stats.allocs));
+               attr->stats.base.attr = TDB_ATTRIBUTE_STATS;
+               attr->stats.size = offsetof(struct tdb_attribute_stats, allocs)
+                       + sizeof(attr->stats.allocs);
+               ok1(tdb_get_attribute(tdb, attr) == 0);
+               ok1(attr->stats.size == sizeof(*attr));
+               ok1(attr->stats.allocs > 0);
+               free(attr);
+               ok1(tap_log_messages == 0);
+
+               tdb_close(tdb);
+
+       }
+       return exit_status();
+}
index 487c056ae3ddc156651b0ab58513bc5eba24298c..86c36ed809aee3c43f54a2a803b328bf5c79772c 100644 (file)
@@ -43,55 +43,67 @@ static int count_record(struct tdb_context *tdb,
        return 0;
 }
 
        return 0;
 }
 
-static void dump_and_clear_stats(struct tdb_attribute_stats *stats)
+static void dump_and_clear_stats(struct tdb_context **tdb,
+                                int flags,
+                                union tdb_attribute *attr)
 {
 {
+       union tdb_attribute stats;
+       enum TDB_ERROR ecode;
+
+       stats.base.attr = TDB_ATTRIBUTE_STATS;
+       stats.stats.size = sizeof(stats.stats);
+       ecode = tdb_get_attribute(*tdb, &stats);
+       if (ecode != TDB_SUCCESS)
+               errx(1, "Getting stats: %s", tdb_errorstr(ecode));
+
        printf("allocs = %llu\n",
        printf("allocs = %llu\n",
-              (unsigned long long)stats->allocs);
+              (unsigned long long)stats.stats.allocs);
        printf("  alloc_subhash = %llu\n",
        printf("  alloc_subhash = %llu\n",
-              (unsigned long long)stats->alloc_subhash);
+              (unsigned long long)stats.stats.alloc_subhash);
        printf("  alloc_chain = %llu\n",
        printf("  alloc_chain = %llu\n",
-              (unsigned long long)stats->alloc_chain);
+              (unsigned long long)stats.stats.alloc_chain);
        printf("  alloc_bucket_exact = %llu\n",
        printf("  alloc_bucket_exact = %llu\n",
-              (unsigned long long)stats->alloc_bucket_exact);
+              (unsigned long long)stats.stats.alloc_bucket_exact);
        printf("  alloc_bucket_max = %llu\n",
        printf("  alloc_bucket_max = %llu\n",
-              (unsigned long long)stats->alloc_bucket_max);
+              (unsigned long long)stats.stats.alloc_bucket_max);
        printf("  alloc_leftover = %llu\n",
        printf("  alloc_leftover = %llu\n",
-              (unsigned long long)stats->alloc_leftover);
+              (unsigned long long)stats.stats.alloc_leftover);
        printf("  alloc_coalesce_tried = %llu\n",
        printf("  alloc_coalesce_tried = %llu\n",
-              (unsigned long long)stats->alloc_coalesce_tried);
+              (unsigned long long)stats.stats.alloc_coalesce_tried);
        printf("    alloc_coalesce_lockfail = %llu\n",
        printf("    alloc_coalesce_lockfail = %llu\n",
-              (unsigned long long)stats->alloc_coalesce_lockfail);
+              (unsigned long long)stats.stats.alloc_coalesce_lockfail);
        printf("    alloc_coalesce_race = %llu\n",
        printf("    alloc_coalesce_race = %llu\n",
-              (unsigned long long)stats->alloc_coalesce_race);
+              (unsigned long long)stats.stats.alloc_coalesce_race);
        printf("    alloc_coalesce_succeeded = %llu\n",
        printf("    alloc_coalesce_succeeded = %llu\n",
-              (unsigned long long)stats->alloc_coalesce_succeeded);
+              (unsigned long long)stats.stats.alloc_coalesce_succeeded);
        printf("       alloc_coalesce_num_merged = %llu\n",
        printf("       alloc_coalesce_num_merged = %llu\n",
-              (unsigned long long)stats->alloc_coalesce_num_merged);
+              (unsigned long long)stats.stats.alloc_coalesce_num_merged);
        printf("compares = %llu\n",
        printf("compares = %llu\n",
-              (unsigned long long)stats->compares);
+              (unsigned long long)stats.stats.compares);
        printf("  compare_wrong_bucket = %llu\n",
        printf("  compare_wrong_bucket = %llu\n",
-              (unsigned long long)stats->compare_wrong_bucket);
+              (unsigned long long)stats.stats.compare_wrong_bucket);
        printf("  compare_wrong_offsetbits = %llu\n",
        printf("  compare_wrong_offsetbits = %llu\n",
-              (unsigned long long)stats->compare_wrong_offsetbits);
+              (unsigned long long)stats.stats.compare_wrong_offsetbits);
        printf("  compare_wrong_keylen = %llu\n",
        printf("  compare_wrong_keylen = %llu\n",
-              (unsigned long long)stats->compare_wrong_keylen);
+              (unsigned long long)stats.stats.compare_wrong_keylen);
        printf("  compare_wrong_rechash = %llu\n",
        printf("  compare_wrong_rechash = %llu\n",
-              (unsigned long long)stats->compare_wrong_rechash);
+              (unsigned long long)stats.stats.compare_wrong_rechash);
        printf("  compare_wrong_keycmp = %llu\n",
        printf("  compare_wrong_keycmp = %llu\n",
-              (unsigned long long)stats->compare_wrong_keycmp);
+              (unsigned long long)stats.stats.compare_wrong_keycmp);
        printf("expands = %llu\n",
        printf("expands = %llu\n",
-              (unsigned long long)stats->expands);
+              (unsigned long long)stats.stats.expands);
        printf("frees = %llu\n",
        printf("frees = %llu\n",
-              (unsigned long long)stats->frees);
+              (unsigned long long)stats.stats.frees);
        printf("locks = %llu\n",
        printf("locks = %llu\n",
-              (unsigned long long)stats->locks);
+              (unsigned long long)stats.stats.locks);
        printf("   lock_lowlevel = %llu\n",
        printf("   lock_lowlevel = %llu\n",
-              (unsigned long long)stats->lock_lowlevel);
+              (unsigned long long)stats.stats.lock_lowlevel);
        printf("   lock_nonblock = %llu\n",
        printf("   lock_nonblock = %llu\n",
-              (unsigned long long)stats->lock_nonblock);
+              (unsigned long long)stats.stats.lock_nonblock);
 
        /* Now clear. */
 
        /* Now clear. */
-       memset(&stats->allocs, 0, (char *)(stats+1) - (char *)&stats->allocs);
+       tdb_close(*tdb);
+       *tdb = tdb_open("/tmp/speed.tdb", flags, O_RDWR, 0, attr);
 }
 
 static void tdb_log(struct tdb_context *tdb, enum tdb_log_level level,
 }
 
 static void tdb_log(struct tdb_context *tdb, enum tdb_log_level level,
@@ -109,7 +121,8 @@ int main(int argc, char *argv[])
        TDB_DATA key, data;
        struct tdb_context *tdb;
        struct timeval start, stop;
        TDB_DATA key, data;
        struct tdb_context *tdb;
        struct timeval start, stop;
-       union tdb_attribute seed, stats, log;
+       union tdb_attribute seed, log;
+       bool do_stats = false;
        enum TDB_ERROR ecode;
 
        /* Try to keep benchmarks even. */
        enum TDB_ERROR ecode;
 
        /* Try to keep benchmarks even. */
@@ -121,11 +134,6 @@ int main(int argc, char *argv[])
        log.base.next = &seed;
        log.log.fn = tdb_log;
 
        log.base.next = &seed;
        log.log.fn = tdb_log;
 
-       memset(&stats, 0, sizeof(stats));
-       stats.base.attr = TDB_ATTRIBUTE_STATS;
-       stats.base.next = NULL;
-       stats.stats.size = sizeof(stats);
-
        if (argv[1] && strcmp(argv[1], "--internal") == 0) {
                flags = TDB_INTERNAL;
                argc--;
        if (argv[1] && strcmp(argv[1], "--internal") == 0) {
                flags = TDB_INTERNAL;
                argc--;
@@ -147,7 +155,7 @@ int main(int argc, char *argv[])
                argv++;
        }
        if (argv[1] && strcmp(argv[1], "--stats") == 0) {
                argv++;
        }
        if (argv[1] && strcmp(argv[1], "--stats") == 0) {
-               seed.base.next = &stats;
+               do_stats = true;
                argc--;
                argv++;
        }
                argc--;
                argv++;
        }
@@ -196,8 +204,8 @@ int main(int argc, char *argv[])
                printf("%s\n", sumstr);
                free(sumstr);
        }
                printf("%s\n", sumstr);
                free(sumstr);
        }
-       if (seed.base.next)
-               dump_and_clear_stats(&stats.stats);
+       if (do_stats)
+               dump_and_clear_stats(&tdb, flags, &log);
 
        if (++stage == stopat)
                exit(0);
 
        if (++stage == stopat)
                exit(0);
@@ -228,8 +236,8 @@ int main(int argc, char *argv[])
                printf("%s\n", sumstr);
                free(sumstr);
        }
                printf("%s\n", sumstr);
                free(sumstr);
        }
-       if (seed.base.next)
-               dump_and_clear_stats(&stats.stats);
+       if (do_stats)
+               dump_and_clear_stats(&tdb, flags, &log);
        if (++stage == stopat)
                exit(0);
 
        if (++stage == stopat)
                exit(0);
 
@@ -258,8 +266,8 @@ int main(int argc, char *argv[])
                printf("%s\n", sumstr);
                free(sumstr);
        }
                printf("%s\n", sumstr);
                free(sumstr);
        }
-       if (seed.base.next)
-               dump_and_clear_stats(&stats.stats);
+       if (do_stats)
+               dump_and_clear_stats(&tdb, flags, &log);
        if (++stage == stopat)
                exit(0);
 
        if (++stage == stopat)
                exit(0);
 
@@ -286,8 +294,8 @@ int main(int argc, char *argv[])
                printf("%s\n", sumstr);
                free(sumstr);
        }
                printf("%s\n", sumstr);
                free(sumstr);
        }
-       if (seed.base.next)
-               dump_and_clear_stats(&stats.stats);
+       if (do_stats)
+               dump_and_clear_stats(&tdb, flags, &log);
        if (++stage == stopat)
                exit(0);
 
        if (++stage == stopat)
                exit(0);
 
@@ -315,8 +323,8 @@ int main(int argc, char *argv[])
                printf("%s\n", sumstr);
                free(sumstr);
        }
                printf("%s\n", sumstr);
                free(sumstr);
        }
-       if (seed.base.next)
-               dump_and_clear_stats(&stats.stats);
+       if (do_stats)
+               dump_and_clear_stats(&tdb, flags, &log);
        if (++stage == stopat)
                exit(0);
 
        if (++stage == stopat)
                exit(0);
 
@@ -344,8 +352,8 @@ int main(int argc, char *argv[])
                printf("%s\n", sumstr);
                free(sumstr);
        }
                printf("%s\n", sumstr);
                free(sumstr);
        }
-       if (seed.base.next)
-               dump_and_clear_stats(&stats.stats);
+       if (do_stats)
+               dump_and_clear_stats(&tdb, flags, &log);
        if (++stage == stopat)
                exit(0);
 
        if (++stage == stopat)
                exit(0);
 
@@ -403,8 +411,8 @@ int main(int argc, char *argv[])
                printf("%s\n", sumstr);
                free(sumstr);
        }
                printf("%s\n", sumstr);
                free(sumstr);
        }
-       if (seed.base.next)
-               dump_and_clear_stats(&stats.stats);
+       if (do_stats)
+               dump_and_clear_stats(&tdb, flags, &log);
        if (++stage == stopat)
                exit(0);
 
        if (++stage == stopat)
                exit(0);
 
index d15db10691eb7d17c489a54d4211ccaa5cb16535..68ae234d2f90ccbe4fb993dd27476df7c89afba2 100644 (file)
@@ -682,7 +682,7 @@ static enum TDB_ERROR tdb_recovery_allocate(struct tdb_context *tdb,
           us an area that is being currently used (as of the start of
           the transaction) */
        if (recovery_head != 0) {
           us an area that is being currently used (as of the start of
           the transaction) */
        if (recovery_head != 0) {
-               add_stat(tdb, frees, 1);
+               tdb->stats.frees++;
                ecode = add_free_record(tdb, recovery_head,
                                        sizeof(rec) + rec.max_len);
                if (ecode != TDB_SUCCESS) {
                ecode = add_free_record(tdb, recovery_head,
                                        sizeof(rec) + rec.max_len);
                if (ecode != TDB_SUCCESS) {