tdb: Make tdb_find circular-safe
[samba.git] / lib / tdb / common / tdb_private.h
index de8d9e68fb55c310a76fe8bf644a9f8b5fe245c0..307cad92c2ab55a0c6ffeeea8624432ca948e9b2 100644 (file)
@@ -96,6 +96,10 @@ void tdb_trace_1rec_retrec(struct tdb_context *tdb, const char *op,
 void tdb_trace_2rec_flag_ret(struct tdb_context *tdb, const char *op,
                             TDB_DATA rec1, TDB_DATA rec2, unsigned flag,
                             int ret);
+void tdb_trace_1plusn_rec_flag_ret(struct tdb_context *tdb, const char *op,
+                                  TDB_DATA rec,
+                                  const TDB_DATA *recs, int num_recs,
+                                  unsigned flag, int ret);
 void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op,
                           TDB_DATA rec1, TDB_DATA rec2, TDB_DATA ret);
 #else
@@ -108,6 +112,7 @@ void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op,
 #define tdb_trace_1rec_ret(tdb, op, rec, ret)
 #define tdb_trace_1rec_retrec(tdb, op, rec, ret)
 #define tdb_trace_2rec_flag_ret(tdb, op, rec1, rec2, flag, ret)
+#define tdb_trace_1plusn_rec_flag_ret(tdb, op, rec, recs, num_recs, flag, ret);
 #define tdb_trace_2rec_retrec(tdb, op, rec1, rec2, ret)
 #endif /* !TDB_TRACE */
 
@@ -121,6 +126,22 @@ void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op,
 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
 #endif
 
+/*
+ * Note: the BUCKET macro is broken as it returns an unexpected result when
+ * called as BUCKET(-1) for the freelist:
+ *
+ * -1 is sign converted to an unsigned int 4294967295 and then the modulo
+ * tdb->hashtable_size is computed. So with a hashtable_size of 10 the result
+ * is
+ *
+ *   4294967295 % hashtable_size = 5.
+ *
+ * where it should be -1 (C uses symmetric modulo).
+ *
+ * As all callers will lock the same wrong list consistently locking is still
+ * consistent. We can not change this without an incompatible on-disk format
+ * change, otherwise different tdb versions would use incompatible locking.
+ */
 #define BUCKET(hash) ((hash) % tdb->hash_size)
 
 #define DOCONV() (tdb->flags & TDB_CONVERT)
@@ -170,13 +191,23 @@ struct tdb_lock_type {
        uint32_t ltype;
 };
 
+struct tdb_chainwalk_ctx {
+       tdb_off_t slow_ptr;
+       bool slow_chase;
+};
+
 struct tdb_traverse_lock {
        struct tdb_traverse_lock *next;
        uint32_t off;
-       uint32_t hash;
+       uint32_t list;
        int lock_rw;
 };
 
+void tdb_chainwalk_init(struct tdb_chainwalk_ctx *ctx, tdb_off_t ptr);
+bool tdb_chainwalk_check(struct tdb_context *tdb,
+                        struct tdb_chainwalk_ctx *ctx,
+                        tdb_off_t next_ptr);
+
 enum tdb_lock_flags {
        /* WAIT == F_SETLKW, NOWAIT == F_SETLK */
        TDB_LOCK_NOWAIT = 0,