#include "system/wait.h"
#else
#define _XOPEN_SOURCE 500
+#define _FILE_OFFSET_BITS 64
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
/* #define TDB_TRACE 1 */
-#if HAVE_GETPAGESIZE
+#ifndef __STRING
+#define __STRING(x) #x
+#endif
+
+#ifndef __STRINGSTRING
+#define __STRINGSTRING(x) __STRING(x)
+#endif
+
+#ifndef __location__
+#define __location__ __FILE__ ":" __STRINGSTRING(__LINE__)
+#endif
+
+#if !HAVE_GETPAGESIZE
#define getpagesize() 0x2000
#endif
typedef uint32_t tdb_off_t;
#ifndef offsetof
-#define offsetof(t,f) ((unsigned int)&((t *)0)->f)
+#define offsetof(t,f) ((size_t)&((t *)0)->f)
#endif
#define TDB_MAGIC_FOOD "TDB file\n"
#define TDB_FREE_MAGIC (~TDB_MAGIC)
#define TDB_DEAD_MAGIC (0xFEE1DEAD)
#define TDB_RECOVERY_MAGIC (0xf53bc0e7U)
+#define TDB_RECOVERY_INVALID_MAGIC (0x0)
+#define TDB_HASH_RWLOCK_MAGIC (0xbad1a51U)
#define TDB_ALIGNMENT 4
#define DEFAULT_HASH_SIZE 131
#define FREELIST_TOP (sizeof(struct tdb_header))
#ifdef TDB_TRACE
void tdb_trace(struct tdb_context *tdb, const char *op);
+void tdb_trace_seqnum(struct tdb_context *tdb, uint32_t seqnum, const char *op);
void tdb_trace_open(struct tdb_context *tdb, const char *op,
unsigned hash_size, unsigned tdb_flags, unsigned open_flags);
void tdb_trace_ret(struct tdb_context *tdb, const char *op, int ret);
TDB_DATA rec1, TDB_DATA rec2, TDB_DATA ret);
#else
#define tdb_trace(tdb, op)
+#define tdb_trace_seqnum(tdb, seqnum, op)
#define tdb_trace_open(tdb, op, hash_size, tdb_flags, open_flags)
#define tdb_trace_ret(tdb, op, ret)
#define tdb_trace_retrec(tdb, op, ret)
#endif /* !TDB_TRACE */
/* lock offsets */
-#define GLOBAL_LOCK 0
+#define OPEN_LOCK 0
#define ACTIVE_LOCK 4
#define TRANSACTION_LOCK 8
#define CONVERT(x) (DOCONV() ? tdb_convert(&x, sizeof(x)) : &x)
-/* the body of the database is made of one list_struct for the free space
+/* the body of the database is made of one tdb_record for the free space
plus a separate data list for each hash value */
-struct list_struct {
+struct tdb_record {
tdb_off_t next; /* offset of the next record in the list */
tdb_len_t rec_len; /* total byte length of record */
tdb_len_t key_len; /* byte length of key */
tdb_off_t rwlocks; /* obsolete - kept to detect old formats */
tdb_off_t recovery_start; /* offset of transaction recovery region */
tdb_off_t sequence_number; /* used when TDB_SEQNUM is set */
- tdb_off_t reserved[29];
+ uint32_t magic1_hash; /* hash of TDB_MAGIC_FOOD. */
+ uint32_t magic2_hash; /* hash of TDB_MAGIC. */
+ tdb_off_t reserved[27];
};
struct tdb_lock_type {
- int list;
+ uint32_t off;
uint32_t count;
uint32_t ltype;
};
int lock_rw;
};
+enum tdb_lock_flags {
+ /* WAIT == F_SETLKW, NOWAIT == F_SETLK */
+ TDB_LOCK_NOWAIT = 0,
+ TDB_LOCK_WAIT = 1,
+ /* If set, don't log an error on failure. */
+ TDB_LOCK_PROBE = 2,
+ /* If set, don't actually lock at all. */
+ TDB_LOCK_MARK_ONLY = 4,
+};
struct tdb_methods {
int (*tdb_read)(struct tdb_context *, tdb_off_t , void *, tdb_len_t , int );
void (*next_hash_chain)(struct tdb_context *, uint32_t *);
int (*tdb_oob)(struct tdb_context *, tdb_off_t , int );
int (*tdb_expand_file)(struct tdb_context *, tdb_off_t , tdb_off_t );
- int (*tdb_brlock)(struct tdb_context *, tdb_off_t , int, int, int, size_t);
};
struct tdb_context {
int read_only; /* opened read-only */
int traverse_read; /* read-only traversal */
int traverse_write; /* read-write traversal */
- struct tdb_lock_type global_lock;
+ struct tdb_lock_type allrecord_lock; /* .offset == upgradable */
int num_lockrecs;
struct tdb_lock_type *lockrecs; /* only real locks, all with count>0 */
enum TDB_ERROR ecode; /* error code for last tdb error */
struct tdb_logging_context log;
unsigned int (*hash_fn)(TDB_DATA *key);
int open_flags; /* flags used in the open - needed by reopen */
- unsigned int num_locks; /* number of chain locks held */
const struct tdb_methods *methods;
struct tdb_transaction *transaction;
int page_size;
int max_dead_records;
- int have_transaction_lock;
+#ifdef TDB_TRACE
int tracefd;
+#endif
volatile sig_atomic_t *interrupt_sig_ptr;
};
void tdb_mmap(struct tdb_context *tdb);
int tdb_lock(struct tdb_context *tdb, int list, int ltype);
int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype);
+int tdb_nest_lock(struct tdb_context *tdb, uint32_t offset, int ltype,
+ enum tdb_lock_flags flags);
+int tdb_nest_unlock(struct tdb_context *tdb, uint32_t offset, int ltype,
+ bool mark_lock);
+bool tdb_have_locks(struct tdb_context *tdb);
int tdb_unlock(struct tdb_context *tdb, int list, int ltype);
-int tdb_brlock(struct tdb_context *tdb, tdb_off_t offset, int rw_type, int lck_type, int probe, size_t len);
+int tdb_brlock(struct tdb_context *tdb,
+ int rw_type, tdb_off_t offset, size_t len,
+ enum tdb_lock_flags flags);
+int tdb_brunlock(struct tdb_context *tdb,
+ int rw_type, tdb_off_t offset, size_t len);
+bool tdb_have_extra_locks(struct tdb_context *tdb);
+void tdb_release_extra_locks(struct tdb_context *tdb);
int tdb_transaction_lock(struct tdb_context *tdb, int ltype);
-int tdb_transaction_unlock(struct tdb_context *tdb);
-int tdb_brlock_upgrade(struct tdb_context *tdb, tdb_off_t offset, size_t len);
+int tdb_transaction_unlock(struct tdb_context *tdb, int ltype);
+int tdb_allrecord_lock(struct tdb_context *tdb, int ltype,
+ enum tdb_lock_flags flags, bool upgradable);
+int tdb_allrecord_unlock(struct tdb_context *tdb, int ltype, bool mark_lock);
+int tdb_allrecord_upgrade(struct tdb_context *tdb);
int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off);
int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off);
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 list_struct *rec);
-tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct list_struct *rec);
+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);
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);
int tdb_unlock_record(struct tdb_context *tdb, tdb_off_t off);
-int tdb_transaction_cancel_internal(struct tdb_context *tdb);
-int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec);
-int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec);
-int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct list_struct *rec);
+bool tdb_needs_recovery(struct tdb_context *tdb);
+int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec);
+int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec);
+int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct tdb_record *rec);
unsigned char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len);
int tdb_parse_data(struct tdb_context *tdb, TDB_DATA key,
tdb_off_t offset, tdb_len_t len,
void *private_data),
void *private_data);
tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype,
- struct list_struct *rec);
+ struct tdb_record *rec);
void tdb_io_init(struct tdb_context *tdb);
int tdb_expand(struct tdb_context *tdb, tdb_off_t size);
int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off,
- struct list_struct *rec);
-
-
+ struct tdb_record *rec);
+void tdb_header_hash(struct tdb_context *tdb,
+ uint32_t *magic1_hash, uint32_t *magic2_hash);
+unsigned int tdb_old_hash(TDB_DATA *key);
+size_t tdb_dead_space(struct tdb_context *tdb, tdb_off_t off);
#endif