*/
#include "private.h"
#include <ccan/likely/likely.h>
+#include <ccan/ilog/ilog.h>
#include <time.h>
#include <assert.h>
#include <limits.h>
static unsigned fls64(uint64_t val)
{
-#if HAVE_BUILTIN_CLZL
- if (val <= ULONG_MAX) {
- /* This is significantly faster! */
- return val ? sizeof(long) * CHAR_BIT - __builtin_clzl(val) : 0;
- } else {
-#endif
- uint64_t r = 64;
-
- if (!val)
- return 0;
- if (!(val & 0xffffffff00000000ull)) {
- val <<= 32;
- r -= 32;
- }
- if (!(val & 0xffff000000000000ull)) {
- val <<= 16;
- r -= 16;
- }
- if (!(val & 0xff00000000000000ull)) {
- val <<= 8;
- r -= 8;
- }
- if (!(val & 0xf000000000000000ull)) {
- val <<= 4;
- r -= 4;
- }
- if (!(val & 0xc000000000000000ull)) {
- val <<= 2;
- r -= 2;
- }
- if (!(val & 0x8000000000000000ull)) {
- val <<= 1;
- r -= 1;
- }
- return r;
-#if HAVE_BUILTIN_CLZL
- }
-#endif
+ return ilog64(val);
}
/* In which bucket would we find a particular record size? (ignoring header) */
/* Remove from free bucket. */
static int remove_from_list(struct tdb_context *tdb,
- tdb_off_t b_off, struct tdb_free_record *r)
+ tdb_off_t b_off, tdb_off_t r_off,
+ struct tdb_free_record *r)
{
tdb_off_t off;
} else {
off = r->prev + offsetof(struct tdb_free_record, next);
}
+
+#ifdef DEBUG
+ if (tdb_read_off(tdb, off) != r_off) {
+ tdb->log(tdb, TDB_DEBUG_FATAL, tdb->log_priv,
+ "remove_from_list: %llu bad prev in list %llu\n",
+ (long long)r_off, (long long)b_off);
+ return -1;
+ }
+#endif
+
/* r->prev->next = r->next */
if (tdb_write_off(tdb, off, r->next)) {
return -1;
if (r->next != 0) {
off = r->next + offsetof(struct tdb_free_record, prev);
/* r->next->prev = r->prev */
+
+#ifdef DEBUG
+ if (tdb_read_off(tdb, off) != r_off) {
+ tdb->log(tdb, TDB_DEBUG_FATAL, tdb->log_priv,
+ "remove_from_list: %llu bad list %llu\n",
+ (long long)r_off, (long long)b_off);
+ return -1;
+ }
+#endif
+
if (tdb_write_off(tdb, off, r->prev)) {
return -1;
}
return -1;
if (new->next) {
+#ifdef DEBUG
+ if (tdb_read_off(tdb,
+ new->next
+ + offsetof(struct tdb_free_record, prev))
+ != 0) {
+ tdb->log(tdb, TDB_DEBUG_FATAL, tdb->log_priv,
+ "enqueue_in_free: %llu bad head prev %llu\n",
+ (long long)new->next, (long long)b_off);
+ return -1;
+ }
+#endif
/* next->prev = new. */
if (tdb_write_off(tdb, new->next
+ offsetof(struct tdb_free_record, prev),
break;
}
- if (remove_from_list(tdb, nb_off, r) == -1) {
+ if (remove_from_list(tdb, nb_off, end, r) == -1) {
tdb_unlock_free_bucket(tdb, nb_off);
goto err;
}
goto err;
}
- if (remove_from_list(tdb, b_off, r) == -1)
+ if (remove_from_list(tdb, b_off, off, r) == -1)
goto err;
/* We have to drop this to avoid deadlocks. */
if (best_off) {
use_best:
/* We're happy with this size: take it. */
- if (remove_from_list(tdb, b_off, &best) != 0)
+ if (remove_from_list(tdb, b_off, best_off, &best) != 0)
goto unlock_err;
tdb_unlock_free_bucket(tdb, b_off);