From: Amitay Isaacs Date: Thu, 15 May 2014 14:05:43 +0000 (+1000) Subject: ctdb-build: Remove duplicate tdb library X-Git-Url: http://git.samba.org/?a=commitdiff_plain;h=400cb4d031cea3bece77571eab16db7791ce7dd0;p=metze%2Fsamba%2Fwip.git ctdb-build: Remove duplicate tdb library Signed-off-by: Amitay Isaacs Reviewed-by: Michael Adam --- diff --git a/ctdb/lib/tdb/ABI/tdb-1.2.1.sigs b/ctdb/lib/tdb/ABI/tdb-1.2.1.sigs deleted file mode 100644 index 84f200745e2d..000000000000 --- a/ctdb/lib/tdb/ABI/tdb-1.2.1.sigs +++ /dev/null @@ -1,95 +0,0 @@ -tdb_add_flags: void (struct tdb_context *, unsigned int) -tdb_alloc_read: unsigned char *(struct tdb_context *, tdb_off_t, tdb_len_t) -tdb_allocate: tdb_off_t (struct tdb_context *, tdb_len_t, struct tdb_record *) -tdb_allrecord_lock: int (struct tdb_context *, int, enum tdb_lock_flags, bool) -tdb_allrecord_unlock: int (struct tdb_context *, int, bool) -tdb_allrecord_upgrade: int (struct tdb_context *) -tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA) -tdb_brlock: int (struct tdb_context *, int, tdb_off_t, size_t, enum tdb_lock_flags) -tdb_brunlock: int (struct tdb_context *, int, tdb_off_t, size_t) -tdb_chainlock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_read: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA) -tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_close: int (struct tdb_context *) -tdb_convert: void *(void *, uint32_t) -tdb_delete: int (struct tdb_context *, TDB_DATA) -tdb_do_delete: int (struct tdb_context *, tdb_off_t, struct tdb_record *) -tdb_dump_all: void (struct tdb_context *) -tdb_enable_seqnum: void (struct tdb_context *) -tdb_error: enum TDB_ERROR (struct tdb_context *) -tdb_errorstr: const char *(struct tdb_context *) -tdb_exists: int (struct tdb_context *, TDB_DATA) -tdb_expand: int (struct tdb_context *, tdb_off_t) -tdb_fd: int (struct tdb_context *) -tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_find_lock_hash: tdb_off_t (struct tdb_context *, TDB_DATA, uint32_t, int, struct tdb_record *) -tdb_firstkey: TDB_DATA (struct tdb_context *) -tdb_free: int (struct tdb_context *, tdb_off_t, struct tdb_record *) -tdb_freelist_size: int (struct tdb_context *) -tdb_get_flags: int (struct tdb_context *) -tdb_get_logging_private: void *(struct tdb_context *) -tdb_get_seqnum: int (struct tdb_context *) -tdb_hash_size: int (struct tdb_context *) -tdb_have_extra_locks: bool (struct tdb_context *) -tdb_increment_seqnum_nonblock: void (struct tdb_context *) -tdb_io_init: void (struct tdb_context *) -tdb_lock: int (struct tdb_context *, int, int) -tdb_lock_nonblock: int (struct tdb_context *, int, int) -tdb_lock_record: int (struct tdb_context *, tdb_off_t) -tdb_lockall: int (struct tdb_context *) -tdb_lockall_mark: int (struct tdb_context *) -tdb_lockall_nonblock: int (struct tdb_context *) -tdb_lockall_read: int (struct tdb_context *) -tdb_lockall_read_nonblock: int (struct tdb_context *) -tdb_lockall_unmark: int (struct tdb_context *) -tdb_log_fn: tdb_log_func (struct tdb_context *) -tdb_map_size: size_t (struct tdb_context *) -tdb_mmap: void (struct tdb_context *) -tdb_munmap: int (struct tdb_context *) -tdb_name: const char *(struct tdb_context *) -tdb_needs_recovery: bool (struct tdb_context *) -tdb_nest_lock: int (struct tdb_context *, uint32_t, int, enum tdb_lock_flags) -tdb_nest_unlock: int (struct tdb_context *, uint32_t, int, bool) -tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_ofs_read: int (struct tdb_context *, tdb_off_t, tdb_off_t *) -tdb_ofs_write: int (struct tdb_context *, tdb_off_t, tdb_off_t *) -tdb_open: struct tdb_context *(const char *, int, int, int, mode_t) -tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func) -tdb_parse_data: int (struct tdb_context *, TDB_DATA, tdb_off_t, tdb_len_t, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_printfreelist: int (struct tdb_context *) -tdb_rec_free_read: int (struct tdb_context *, tdb_off_t, struct tdb_record *) -tdb_rec_read: int (struct tdb_context *, tdb_off_t, struct tdb_record *) -tdb_rec_write: int (struct tdb_context *, tdb_off_t, struct tdb_record *) -tdb_release_transaction_locks: void (struct tdb_context *) -tdb_remove_flags: void (struct tdb_context *, unsigned int) -tdb_reopen: int (struct tdb_context *) -tdb_reopen_all: int (int) -tdb_repack: int (struct tdb_context *) -tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *) -tdb_set_max_dead: void (struct tdb_context *, int) -tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *) -tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int) -tdb_transaction_cancel: int (struct tdb_context *) -tdb_transaction_commit: int (struct tdb_context *) -tdb_transaction_lock: int (struct tdb_context *, int, enum tdb_lock_flags) -tdb_transaction_prepare_commit: int (struct tdb_context *) -tdb_transaction_recover: int (struct tdb_context *) -tdb_transaction_start: int (struct tdb_context *) -tdb_transaction_start_nonblock: int (struct tdb_context *) -tdb_transaction_unlock: int (struct tdb_context *, int) -tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_unlock: int (struct tdb_context *, int, int) -tdb_unlock_record: int (struct tdb_context *, tdb_off_t) -tdb_unlockall: int (struct tdb_context *) -tdb_unlockall_read: int (struct tdb_context *) -tdb_validate_freelist: int (struct tdb_context *, int *) -tdb_wipe_all: int (struct tdb_context *) -tdb_write_lock_record: int (struct tdb_context *, tdb_off_t) -tdb_write_unlock_record: int (struct tdb_context *, tdb_off_t) diff --git a/ctdb/lib/tdb/ABI/tdb-1.2.10.sigs b/ctdb/lib/tdb/ABI/tdb-1.2.10.sigs deleted file mode 100644 index 61f6c19ee36d..000000000000 --- a/ctdb/lib/tdb/ABI/tdb-1.2.10.sigs +++ /dev/null @@ -1,66 +0,0 @@ -tdb_add_flags: void (struct tdb_context *, unsigned int) -tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA) -tdb_chainlock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_read: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA) -tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_close: int (struct tdb_context *) -tdb_delete: int (struct tdb_context *, TDB_DATA) -tdb_dump_all: void (struct tdb_context *) -tdb_enable_seqnum: void (struct tdb_context *) -tdb_error: enum TDB_ERROR (struct tdb_context *) -tdb_errorstr: const char *(struct tdb_context *) -tdb_exists: int (struct tdb_context *, TDB_DATA) -tdb_fd: int (struct tdb_context *) -tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_firstkey: TDB_DATA (struct tdb_context *) -tdb_freelist_size: int (struct tdb_context *) -tdb_get_flags: int (struct tdb_context *) -tdb_get_logging_private: void *(struct tdb_context *) -tdb_get_seqnum: int (struct tdb_context *) -tdb_hash_size: int (struct tdb_context *) -tdb_increment_seqnum_nonblock: void (struct tdb_context *) -tdb_jenkins_hash: unsigned int (TDB_DATA *) -tdb_lock_nonblock: int (struct tdb_context *, int, int) -tdb_lockall: int (struct tdb_context *) -tdb_lockall_mark: int (struct tdb_context *) -tdb_lockall_nonblock: int (struct tdb_context *) -tdb_lockall_read: int (struct tdb_context *) -tdb_lockall_read_nonblock: int (struct tdb_context *) -tdb_lockall_unmark: int (struct tdb_context *) -tdb_log_fn: tdb_log_func (struct tdb_context *) -tdb_map_size: size_t (struct tdb_context *) -tdb_name: const char *(struct tdb_context *) -tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_null: dptr = 0xXXXX, dsize = 0 -tdb_open: struct tdb_context *(const char *, int, int, int, mode_t) -tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func) -tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_printfreelist: int (struct tdb_context *) -tdb_remove_flags: void (struct tdb_context *, unsigned int) -tdb_reopen: int (struct tdb_context *) -tdb_reopen_all: int (int) -tdb_repack: int (struct tdb_context *) -tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *) -tdb_set_max_dead: void (struct tdb_context *, int) -tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *) -tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int) -tdb_summary: char *(struct tdb_context *) -tdb_transaction_cancel: int (struct tdb_context *) -tdb_transaction_commit: int (struct tdb_context *) -tdb_transaction_prepare_commit: int (struct tdb_context *) -tdb_transaction_start: int (struct tdb_context *) -tdb_transaction_start_nonblock: int (struct tdb_context *) -tdb_transaction_write_lock_mark: int (struct tdb_context *) -tdb_transaction_write_lock_unmark: int (struct tdb_context *) -tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_unlock: int (struct tdb_context *, int, int) -tdb_unlockall: int (struct tdb_context *) -tdb_unlockall_read: int (struct tdb_context *) -tdb_validate_freelist: int (struct tdb_context *, int *) -tdb_wipe_all: int (struct tdb_context *) diff --git a/ctdb/lib/tdb/ABI/tdb-1.2.11.sigs b/ctdb/lib/tdb/ABI/tdb-1.2.11.sigs deleted file mode 100644 index d727f2163dd2..000000000000 --- a/ctdb/lib/tdb/ABI/tdb-1.2.11.sigs +++ /dev/null @@ -1,67 +0,0 @@ -tdb_add_flags: void (struct tdb_context *, unsigned int) -tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA) -tdb_chainlock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_read: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA) -tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_close: int (struct tdb_context *) -tdb_delete: int (struct tdb_context *, TDB_DATA) -tdb_dump_all: void (struct tdb_context *) -tdb_enable_seqnum: void (struct tdb_context *) -tdb_error: enum TDB_ERROR (struct tdb_context *) -tdb_errorstr: const char *(struct tdb_context *) -tdb_exists: int (struct tdb_context *, TDB_DATA) -tdb_fd: int (struct tdb_context *) -tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_firstkey: TDB_DATA (struct tdb_context *) -tdb_freelist_size: int (struct tdb_context *) -tdb_get_flags: int (struct tdb_context *) -tdb_get_logging_private: void *(struct tdb_context *) -tdb_get_seqnum: int (struct tdb_context *) -tdb_hash_size: int (struct tdb_context *) -tdb_increment_seqnum_nonblock: void (struct tdb_context *) -tdb_jenkins_hash: unsigned int (TDB_DATA *) -tdb_lock_nonblock: int (struct tdb_context *, int, int) -tdb_lockall: int (struct tdb_context *) -tdb_lockall_mark: int (struct tdb_context *) -tdb_lockall_nonblock: int (struct tdb_context *) -tdb_lockall_read: int (struct tdb_context *) -tdb_lockall_read_nonblock: int (struct tdb_context *) -tdb_lockall_unmark: int (struct tdb_context *) -tdb_log_fn: tdb_log_func (struct tdb_context *) -tdb_map_size: size_t (struct tdb_context *) -tdb_name: const char *(struct tdb_context *) -tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_null: dptr = 0xXXXX, dsize = 0 -tdb_open: struct tdb_context *(const char *, int, int, int, mode_t) -tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func) -tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_printfreelist: int (struct tdb_context *) -tdb_remove_flags: void (struct tdb_context *, unsigned int) -tdb_reopen: int (struct tdb_context *) -tdb_reopen_all: int (int) -tdb_repack: int (struct tdb_context *) -tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *) -tdb_set_max_dead: void (struct tdb_context *, int) -tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *) -tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int) -tdb_summary: char *(struct tdb_context *) -tdb_transaction_cancel: int (struct tdb_context *) -tdb_transaction_commit: int (struct tdb_context *) -tdb_transaction_prepare_commit: int (struct tdb_context *) -tdb_transaction_start: int (struct tdb_context *) -tdb_transaction_start_nonblock: int (struct tdb_context *) -tdb_transaction_write_lock_mark: int (struct tdb_context *) -tdb_transaction_write_lock_unmark: int (struct tdb_context *) -tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_unlock: int (struct tdb_context *, int, int) -tdb_unlockall: int (struct tdb_context *) -tdb_unlockall_read: int (struct tdb_context *) -tdb_validate_freelist: int (struct tdb_context *, int *) -tdb_wipe_all: int (struct tdb_context *) diff --git a/ctdb/lib/tdb/ABI/tdb-1.2.2.sigs b/ctdb/lib/tdb/ABI/tdb-1.2.2.sigs deleted file mode 100644 index 043790d27e6c..000000000000 --- a/ctdb/lib/tdb/ABI/tdb-1.2.2.sigs +++ /dev/null @@ -1,60 +0,0 @@ -tdb_add_flags: void (struct tdb_context *, unsigned int) -tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA) -tdb_chainlock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_read: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA) -tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_close: int (struct tdb_context *) -tdb_delete: int (struct tdb_context *, TDB_DATA) -tdb_dump_all: void (struct tdb_context *) -tdb_enable_seqnum: void (struct tdb_context *) -tdb_error: enum TDB_ERROR (struct tdb_context *) -tdb_errorstr: const char *(struct tdb_context *) -tdb_exists: int (struct tdb_context *, TDB_DATA) -tdb_fd: int (struct tdb_context *) -tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_firstkey: TDB_DATA (struct tdb_context *) -tdb_freelist_size: int (struct tdb_context *) -tdb_get_flags: int (struct tdb_context *) -tdb_get_logging_private: void *(struct tdb_context *) -tdb_get_seqnum: int (struct tdb_context *) -tdb_hash_size: int (struct tdb_context *) -tdb_increment_seqnum_nonblock: void (struct tdb_context *) -tdb_lockall: int (struct tdb_context *) -tdb_lockall_mark: int (struct tdb_context *) -tdb_lockall_nonblock: int (struct tdb_context *) -tdb_lockall_read: int (struct tdb_context *) -tdb_lockall_read_nonblock: int (struct tdb_context *) -tdb_lockall_unmark: int (struct tdb_context *) -tdb_log_fn: tdb_log_func (struct tdb_context *) -tdb_map_size: size_t (struct tdb_context *) -tdb_name: const char *(struct tdb_context *) -tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_null: dptr = 0xXXXX, dsize = 0 -tdb_open: struct tdb_context *(const char *, int, int, int, mode_t) -tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func) -tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_printfreelist: int (struct tdb_context *) -tdb_remove_flags: void (struct tdb_context *, unsigned int) -tdb_reopen: int (struct tdb_context *) -tdb_reopen_all: int (int) -tdb_repack: int (struct tdb_context *) -tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *) -tdb_set_max_dead: void (struct tdb_context *, int) -tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *) -tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int) -tdb_transaction_cancel: int (struct tdb_context *) -tdb_transaction_commit: int (struct tdb_context *) -tdb_transaction_prepare_commit: int (struct tdb_context *) -tdb_transaction_start: int (struct tdb_context *) -tdb_transaction_start_nonblock: int (struct tdb_context *) -tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_unlockall: int (struct tdb_context *) -tdb_unlockall_read: int (struct tdb_context *) -tdb_validate_freelist: int (struct tdb_context *, int *) -tdb_wipe_all: int (struct tdb_context *) diff --git a/ctdb/lib/tdb/ABI/tdb-1.2.3.sigs b/ctdb/lib/tdb/ABI/tdb-1.2.3.sigs deleted file mode 100644 index 043790d27e6c..000000000000 --- a/ctdb/lib/tdb/ABI/tdb-1.2.3.sigs +++ /dev/null @@ -1,60 +0,0 @@ -tdb_add_flags: void (struct tdb_context *, unsigned int) -tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA) -tdb_chainlock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_read: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA) -tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_close: int (struct tdb_context *) -tdb_delete: int (struct tdb_context *, TDB_DATA) -tdb_dump_all: void (struct tdb_context *) -tdb_enable_seqnum: void (struct tdb_context *) -tdb_error: enum TDB_ERROR (struct tdb_context *) -tdb_errorstr: const char *(struct tdb_context *) -tdb_exists: int (struct tdb_context *, TDB_DATA) -tdb_fd: int (struct tdb_context *) -tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_firstkey: TDB_DATA (struct tdb_context *) -tdb_freelist_size: int (struct tdb_context *) -tdb_get_flags: int (struct tdb_context *) -tdb_get_logging_private: void *(struct tdb_context *) -tdb_get_seqnum: int (struct tdb_context *) -tdb_hash_size: int (struct tdb_context *) -tdb_increment_seqnum_nonblock: void (struct tdb_context *) -tdb_lockall: int (struct tdb_context *) -tdb_lockall_mark: int (struct tdb_context *) -tdb_lockall_nonblock: int (struct tdb_context *) -tdb_lockall_read: int (struct tdb_context *) -tdb_lockall_read_nonblock: int (struct tdb_context *) -tdb_lockall_unmark: int (struct tdb_context *) -tdb_log_fn: tdb_log_func (struct tdb_context *) -tdb_map_size: size_t (struct tdb_context *) -tdb_name: const char *(struct tdb_context *) -tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_null: dptr = 0xXXXX, dsize = 0 -tdb_open: struct tdb_context *(const char *, int, int, int, mode_t) -tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func) -tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_printfreelist: int (struct tdb_context *) -tdb_remove_flags: void (struct tdb_context *, unsigned int) -tdb_reopen: int (struct tdb_context *) -tdb_reopen_all: int (int) -tdb_repack: int (struct tdb_context *) -tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *) -tdb_set_max_dead: void (struct tdb_context *, int) -tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *) -tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int) -tdb_transaction_cancel: int (struct tdb_context *) -tdb_transaction_commit: int (struct tdb_context *) -tdb_transaction_prepare_commit: int (struct tdb_context *) -tdb_transaction_start: int (struct tdb_context *) -tdb_transaction_start_nonblock: int (struct tdb_context *) -tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_unlockall: int (struct tdb_context *) -tdb_unlockall_read: int (struct tdb_context *) -tdb_validate_freelist: int (struct tdb_context *, int *) -tdb_wipe_all: int (struct tdb_context *) diff --git a/ctdb/lib/tdb/ABI/tdb-1.2.4.sigs b/ctdb/lib/tdb/ABI/tdb-1.2.4.sigs deleted file mode 100644 index 043790d27e6c..000000000000 --- a/ctdb/lib/tdb/ABI/tdb-1.2.4.sigs +++ /dev/null @@ -1,60 +0,0 @@ -tdb_add_flags: void (struct tdb_context *, unsigned int) -tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA) -tdb_chainlock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_read: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA) -tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_close: int (struct tdb_context *) -tdb_delete: int (struct tdb_context *, TDB_DATA) -tdb_dump_all: void (struct tdb_context *) -tdb_enable_seqnum: void (struct tdb_context *) -tdb_error: enum TDB_ERROR (struct tdb_context *) -tdb_errorstr: const char *(struct tdb_context *) -tdb_exists: int (struct tdb_context *, TDB_DATA) -tdb_fd: int (struct tdb_context *) -tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_firstkey: TDB_DATA (struct tdb_context *) -tdb_freelist_size: int (struct tdb_context *) -tdb_get_flags: int (struct tdb_context *) -tdb_get_logging_private: void *(struct tdb_context *) -tdb_get_seqnum: int (struct tdb_context *) -tdb_hash_size: int (struct tdb_context *) -tdb_increment_seqnum_nonblock: void (struct tdb_context *) -tdb_lockall: int (struct tdb_context *) -tdb_lockall_mark: int (struct tdb_context *) -tdb_lockall_nonblock: int (struct tdb_context *) -tdb_lockall_read: int (struct tdb_context *) -tdb_lockall_read_nonblock: int (struct tdb_context *) -tdb_lockall_unmark: int (struct tdb_context *) -tdb_log_fn: tdb_log_func (struct tdb_context *) -tdb_map_size: size_t (struct tdb_context *) -tdb_name: const char *(struct tdb_context *) -tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_null: dptr = 0xXXXX, dsize = 0 -tdb_open: struct tdb_context *(const char *, int, int, int, mode_t) -tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func) -tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_printfreelist: int (struct tdb_context *) -tdb_remove_flags: void (struct tdb_context *, unsigned int) -tdb_reopen: int (struct tdb_context *) -tdb_reopen_all: int (int) -tdb_repack: int (struct tdb_context *) -tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *) -tdb_set_max_dead: void (struct tdb_context *, int) -tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *) -tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int) -tdb_transaction_cancel: int (struct tdb_context *) -tdb_transaction_commit: int (struct tdb_context *) -tdb_transaction_prepare_commit: int (struct tdb_context *) -tdb_transaction_start: int (struct tdb_context *) -tdb_transaction_start_nonblock: int (struct tdb_context *) -tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_unlockall: int (struct tdb_context *) -tdb_unlockall_read: int (struct tdb_context *) -tdb_validate_freelist: int (struct tdb_context *, int *) -tdb_wipe_all: int (struct tdb_context *) diff --git a/ctdb/lib/tdb/ABI/tdb-1.2.5.sigs b/ctdb/lib/tdb/ABI/tdb-1.2.5.sigs deleted file mode 100644 index 1e01f3ba24bf..000000000000 --- a/ctdb/lib/tdb/ABI/tdb-1.2.5.sigs +++ /dev/null @@ -1,61 +0,0 @@ -tdb_add_flags: void (struct tdb_context *, unsigned int) -tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA) -tdb_chainlock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_read: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA) -tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_close: int (struct tdb_context *) -tdb_delete: int (struct tdb_context *, TDB_DATA) -tdb_dump_all: void (struct tdb_context *) -tdb_enable_seqnum: void (struct tdb_context *) -tdb_error: enum TDB_ERROR (struct tdb_context *) -tdb_errorstr: const char *(struct tdb_context *) -tdb_exists: int (struct tdb_context *, TDB_DATA) -tdb_fd: int (struct tdb_context *) -tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_firstkey: TDB_DATA (struct tdb_context *) -tdb_freelist_size: int (struct tdb_context *) -tdb_get_flags: int (struct tdb_context *) -tdb_get_logging_private: void *(struct tdb_context *) -tdb_get_seqnum: int (struct tdb_context *) -tdb_hash_size: int (struct tdb_context *) -tdb_increment_seqnum_nonblock: void (struct tdb_context *) -tdb_jenkins_hash: unsigned int (TDB_DATA *) -tdb_lockall: int (struct tdb_context *) -tdb_lockall_mark: int (struct tdb_context *) -tdb_lockall_nonblock: int (struct tdb_context *) -tdb_lockall_read: int (struct tdb_context *) -tdb_lockall_read_nonblock: int (struct tdb_context *) -tdb_lockall_unmark: int (struct tdb_context *) -tdb_log_fn: tdb_log_func (struct tdb_context *) -tdb_map_size: size_t (struct tdb_context *) -tdb_name: const char *(struct tdb_context *) -tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_null: dptr = 0xXXXX, dsize = 0 -tdb_open: struct tdb_context *(const char *, int, int, int, mode_t) -tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func) -tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_printfreelist: int (struct tdb_context *) -tdb_remove_flags: void (struct tdb_context *, unsigned int) -tdb_reopen: int (struct tdb_context *) -tdb_reopen_all: int (int) -tdb_repack: int (struct tdb_context *) -tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *) -tdb_set_max_dead: void (struct tdb_context *, int) -tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *) -tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int) -tdb_transaction_cancel: int (struct tdb_context *) -tdb_transaction_commit: int (struct tdb_context *) -tdb_transaction_prepare_commit: int (struct tdb_context *) -tdb_transaction_start: int (struct tdb_context *) -tdb_transaction_start_nonblock: int (struct tdb_context *) -tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_unlockall: int (struct tdb_context *) -tdb_unlockall_read: int (struct tdb_context *) -tdb_validate_freelist: int (struct tdb_context *, int *) -tdb_wipe_all: int (struct tdb_context *) diff --git a/ctdb/lib/tdb/ABI/tdb-1.2.6.sigs b/ctdb/lib/tdb/ABI/tdb-1.2.6.sigs deleted file mode 100644 index 1e01f3ba24bf..000000000000 --- a/ctdb/lib/tdb/ABI/tdb-1.2.6.sigs +++ /dev/null @@ -1,61 +0,0 @@ -tdb_add_flags: void (struct tdb_context *, unsigned int) -tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA) -tdb_chainlock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_read: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA) -tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_close: int (struct tdb_context *) -tdb_delete: int (struct tdb_context *, TDB_DATA) -tdb_dump_all: void (struct tdb_context *) -tdb_enable_seqnum: void (struct tdb_context *) -tdb_error: enum TDB_ERROR (struct tdb_context *) -tdb_errorstr: const char *(struct tdb_context *) -tdb_exists: int (struct tdb_context *, TDB_DATA) -tdb_fd: int (struct tdb_context *) -tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_firstkey: TDB_DATA (struct tdb_context *) -tdb_freelist_size: int (struct tdb_context *) -tdb_get_flags: int (struct tdb_context *) -tdb_get_logging_private: void *(struct tdb_context *) -tdb_get_seqnum: int (struct tdb_context *) -tdb_hash_size: int (struct tdb_context *) -tdb_increment_seqnum_nonblock: void (struct tdb_context *) -tdb_jenkins_hash: unsigned int (TDB_DATA *) -tdb_lockall: int (struct tdb_context *) -tdb_lockall_mark: int (struct tdb_context *) -tdb_lockall_nonblock: int (struct tdb_context *) -tdb_lockall_read: int (struct tdb_context *) -tdb_lockall_read_nonblock: int (struct tdb_context *) -tdb_lockall_unmark: int (struct tdb_context *) -tdb_log_fn: tdb_log_func (struct tdb_context *) -tdb_map_size: size_t (struct tdb_context *) -tdb_name: const char *(struct tdb_context *) -tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_null: dptr = 0xXXXX, dsize = 0 -tdb_open: struct tdb_context *(const char *, int, int, int, mode_t) -tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func) -tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_printfreelist: int (struct tdb_context *) -tdb_remove_flags: void (struct tdb_context *, unsigned int) -tdb_reopen: int (struct tdb_context *) -tdb_reopen_all: int (int) -tdb_repack: int (struct tdb_context *) -tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *) -tdb_set_max_dead: void (struct tdb_context *, int) -tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *) -tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int) -tdb_transaction_cancel: int (struct tdb_context *) -tdb_transaction_commit: int (struct tdb_context *) -tdb_transaction_prepare_commit: int (struct tdb_context *) -tdb_transaction_start: int (struct tdb_context *) -tdb_transaction_start_nonblock: int (struct tdb_context *) -tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_unlockall: int (struct tdb_context *) -tdb_unlockall_read: int (struct tdb_context *) -tdb_validate_freelist: int (struct tdb_context *, int *) -tdb_wipe_all: int (struct tdb_context *) diff --git a/ctdb/lib/tdb/ABI/tdb-1.2.7.sigs b/ctdb/lib/tdb/ABI/tdb-1.2.7.sigs deleted file mode 100644 index 1e01f3ba24bf..000000000000 --- a/ctdb/lib/tdb/ABI/tdb-1.2.7.sigs +++ /dev/null @@ -1,61 +0,0 @@ -tdb_add_flags: void (struct tdb_context *, unsigned int) -tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA) -tdb_chainlock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_read: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA) -tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_close: int (struct tdb_context *) -tdb_delete: int (struct tdb_context *, TDB_DATA) -tdb_dump_all: void (struct tdb_context *) -tdb_enable_seqnum: void (struct tdb_context *) -tdb_error: enum TDB_ERROR (struct tdb_context *) -tdb_errorstr: const char *(struct tdb_context *) -tdb_exists: int (struct tdb_context *, TDB_DATA) -tdb_fd: int (struct tdb_context *) -tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_firstkey: TDB_DATA (struct tdb_context *) -tdb_freelist_size: int (struct tdb_context *) -tdb_get_flags: int (struct tdb_context *) -tdb_get_logging_private: void *(struct tdb_context *) -tdb_get_seqnum: int (struct tdb_context *) -tdb_hash_size: int (struct tdb_context *) -tdb_increment_seqnum_nonblock: void (struct tdb_context *) -tdb_jenkins_hash: unsigned int (TDB_DATA *) -tdb_lockall: int (struct tdb_context *) -tdb_lockall_mark: int (struct tdb_context *) -tdb_lockall_nonblock: int (struct tdb_context *) -tdb_lockall_read: int (struct tdb_context *) -tdb_lockall_read_nonblock: int (struct tdb_context *) -tdb_lockall_unmark: int (struct tdb_context *) -tdb_log_fn: tdb_log_func (struct tdb_context *) -tdb_map_size: size_t (struct tdb_context *) -tdb_name: const char *(struct tdb_context *) -tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_null: dptr = 0xXXXX, dsize = 0 -tdb_open: struct tdb_context *(const char *, int, int, int, mode_t) -tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func) -tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_printfreelist: int (struct tdb_context *) -tdb_remove_flags: void (struct tdb_context *, unsigned int) -tdb_reopen: int (struct tdb_context *) -tdb_reopen_all: int (int) -tdb_repack: int (struct tdb_context *) -tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *) -tdb_set_max_dead: void (struct tdb_context *, int) -tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *) -tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int) -tdb_transaction_cancel: int (struct tdb_context *) -tdb_transaction_commit: int (struct tdb_context *) -tdb_transaction_prepare_commit: int (struct tdb_context *) -tdb_transaction_start: int (struct tdb_context *) -tdb_transaction_start_nonblock: int (struct tdb_context *) -tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_unlockall: int (struct tdb_context *) -tdb_unlockall_read: int (struct tdb_context *) -tdb_validate_freelist: int (struct tdb_context *, int *) -tdb_wipe_all: int (struct tdb_context *) diff --git a/ctdb/lib/tdb/ABI/tdb-1.2.8.sigs b/ctdb/lib/tdb/ABI/tdb-1.2.8.sigs deleted file mode 100644 index 1e01f3ba24bf..000000000000 --- a/ctdb/lib/tdb/ABI/tdb-1.2.8.sigs +++ /dev/null @@ -1,61 +0,0 @@ -tdb_add_flags: void (struct tdb_context *, unsigned int) -tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA) -tdb_chainlock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_read: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA) -tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_close: int (struct tdb_context *) -tdb_delete: int (struct tdb_context *, TDB_DATA) -tdb_dump_all: void (struct tdb_context *) -tdb_enable_seqnum: void (struct tdb_context *) -tdb_error: enum TDB_ERROR (struct tdb_context *) -tdb_errorstr: const char *(struct tdb_context *) -tdb_exists: int (struct tdb_context *, TDB_DATA) -tdb_fd: int (struct tdb_context *) -tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_firstkey: TDB_DATA (struct tdb_context *) -tdb_freelist_size: int (struct tdb_context *) -tdb_get_flags: int (struct tdb_context *) -tdb_get_logging_private: void *(struct tdb_context *) -tdb_get_seqnum: int (struct tdb_context *) -tdb_hash_size: int (struct tdb_context *) -tdb_increment_seqnum_nonblock: void (struct tdb_context *) -tdb_jenkins_hash: unsigned int (TDB_DATA *) -tdb_lockall: int (struct tdb_context *) -tdb_lockall_mark: int (struct tdb_context *) -tdb_lockall_nonblock: int (struct tdb_context *) -tdb_lockall_read: int (struct tdb_context *) -tdb_lockall_read_nonblock: int (struct tdb_context *) -tdb_lockall_unmark: int (struct tdb_context *) -tdb_log_fn: tdb_log_func (struct tdb_context *) -tdb_map_size: size_t (struct tdb_context *) -tdb_name: const char *(struct tdb_context *) -tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_null: dptr = 0xXXXX, dsize = 0 -tdb_open: struct tdb_context *(const char *, int, int, int, mode_t) -tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func) -tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_printfreelist: int (struct tdb_context *) -tdb_remove_flags: void (struct tdb_context *, unsigned int) -tdb_reopen: int (struct tdb_context *) -tdb_reopen_all: int (int) -tdb_repack: int (struct tdb_context *) -tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *) -tdb_set_max_dead: void (struct tdb_context *, int) -tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *) -tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int) -tdb_transaction_cancel: int (struct tdb_context *) -tdb_transaction_commit: int (struct tdb_context *) -tdb_transaction_prepare_commit: int (struct tdb_context *) -tdb_transaction_start: int (struct tdb_context *) -tdb_transaction_start_nonblock: int (struct tdb_context *) -tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_unlockall: int (struct tdb_context *) -tdb_unlockall_read: int (struct tdb_context *) -tdb_validate_freelist: int (struct tdb_context *, int *) -tdb_wipe_all: int (struct tdb_context *) diff --git a/ctdb/lib/tdb/ABI/tdb-1.2.9.sigs b/ctdb/lib/tdb/ABI/tdb-1.2.9.sigs deleted file mode 100644 index 9e4149b4e5e7..000000000000 --- a/ctdb/lib/tdb/ABI/tdb-1.2.9.sigs +++ /dev/null @@ -1,62 +0,0 @@ -tdb_add_flags: void (struct tdb_context *, unsigned int) -tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA) -tdb_chainlock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_read: int (struct tdb_context *, TDB_DATA) -tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock: int (struct tdb_context *, TDB_DATA) -tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA) -tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_close: int (struct tdb_context *) -tdb_delete: int (struct tdb_context *, TDB_DATA) -tdb_dump_all: void (struct tdb_context *) -tdb_enable_seqnum: void (struct tdb_context *) -tdb_error: enum TDB_ERROR (struct tdb_context *) -tdb_errorstr: const char *(struct tdb_context *) -tdb_exists: int (struct tdb_context *, TDB_DATA) -tdb_fd: int (struct tdb_context *) -tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_firstkey: TDB_DATA (struct tdb_context *) -tdb_freelist_size: int (struct tdb_context *) -tdb_get_flags: int (struct tdb_context *) -tdb_get_logging_private: void *(struct tdb_context *) -tdb_get_seqnum: int (struct tdb_context *) -tdb_hash_size: int (struct tdb_context *) -tdb_increment_seqnum_nonblock: void (struct tdb_context *) -tdb_jenkins_hash: unsigned int (TDB_DATA *) -tdb_lockall: int (struct tdb_context *) -tdb_lockall_mark: int (struct tdb_context *) -tdb_lockall_nonblock: int (struct tdb_context *) -tdb_lockall_read: int (struct tdb_context *) -tdb_lockall_read_nonblock: int (struct tdb_context *) -tdb_lockall_unmark: int (struct tdb_context *) -tdb_log_fn: tdb_log_func (struct tdb_context *) -tdb_map_size: size_t (struct tdb_context *) -tdb_name: const char *(struct tdb_context *) -tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA) -tdb_null: dptr = 0xXXXX, dsize = 0 -tdb_open: struct tdb_context *(const char *, int, int, int, mode_t) -tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func) -tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *) -tdb_printfreelist: int (struct tdb_context *) -tdb_remove_flags: void (struct tdb_context *, unsigned int) -tdb_reopen: int (struct tdb_context *) -tdb_reopen_all: int (int) -tdb_repack: int (struct tdb_context *) -tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *) -tdb_set_max_dead: void (struct tdb_context *, int) -tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *) -tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int) -tdb_summary: char *(struct tdb_context *) -tdb_transaction_cancel: int (struct tdb_context *) -tdb_transaction_commit: int (struct tdb_context *) -tdb_transaction_prepare_commit: int (struct tdb_context *) -tdb_transaction_start: int (struct tdb_context *) -tdb_transaction_start_nonblock: int (struct tdb_context *) -tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *) -tdb_unlockall: int (struct tdb_context *) -tdb_unlockall_read: int (struct tdb_context *) -tdb_validate_freelist: int (struct tdb_context *, int *) -tdb_wipe_all: int (struct tdb_context *) diff --git a/ctdb/lib/tdb/common/check.c b/ctdb/lib/tdb/common/check.c deleted file mode 100644 index 313f55cbb05e..000000000000 --- a/ctdb/lib/tdb/common/check.c +++ /dev/null @@ -1,472 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Rusty Russell 2009 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ -#include "tdb_private.h" - -/* Since we opened it, these shouldn't fail unless it's recent corruption. */ -static bool tdb_check_header(struct tdb_context *tdb, tdb_off_t *recovery) -{ - struct tdb_header hdr; - uint32_t h1, h2; - - if (tdb->methods->tdb_read(tdb, 0, &hdr, sizeof(hdr), 0) == -1) - return false; - if (strcmp(hdr.magic_food, TDB_MAGIC_FOOD) != 0) - goto corrupt; - - CONVERT(hdr); - if (hdr.version != TDB_VERSION) - goto corrupt; - - if (hdr.rwlocks != 0 && hdr.rwlocks != TDB_HASH_RWLOCK_MAGIC) - goto corrupt; - - tdb_header_hash(tdb, &h1, &h2); - if (hdr.magic1_hash && hdr.magic2_hash && - (hdr.magic1_hash != h1 || hdr.magic2_hash != h2)) - goto corrupt; - - if (hdr.hash_size == 0) - goto corrupt; - - if (hdr.hash_size != tdb->header.hash_size) - goto corrupt; - - if (hdr.recovery_start != 0 && - hdr.recovery_start < TDB_DATA_START(tdb->header.hash_size)) - goto corrupt; - - *recovery = hdr.recovery_start; - return true; - -corrupt: - tdb->ecode = TDB_ERR_CORRUPT; - TDB_LOG((tdb, TDB_DEBUG_ERROR, "Header is corrupt\n")); - return false; -} - -/* Generic record header check. */ -static bool tdb_check_record(struct tdb_context *tdb, - tdb_off_t off, - const struct tdb_record *rec) -{ - tdb_off_t tailer; - - /* Check rec->next: 0 or points to record offset, aligned. */ - if (rec->next > 0 && rec->next < TDB_DATA_START(tdb->header.hash_size)){ - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Record offset %d too small next %d\n", - off, rec->next)); - goto corrupt; - } - if (rec->next + sizeof(*rec) < rec->next) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Record offset %d too large next %d\n", - off, rec->next)); - goto corrupt; - } - if ((rec->next % TDB_ALIGNMENT) != 0) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Record offset %d misaligned next %d\n", - off, rec->next)); - goto corrupt; - } - if (tdb->methods->tdb_oob(tdb, rec->next, sizeof(*rec), 0)) - goto corrupt; - - /* Check rec_len: similar to rec->next, implies next record. */ - if ((rec->rec_len % TDB_ALIGNMENT) != 0) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Record offset %d misaligned length %d\n", - off, rec->rec_len)); - goto corrupt; - } - /* Must fit tailer. */ - if (rec->rec_len < sizeof(tailer)) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Record offset %d too short length %d\n", - off, rec->rec_len)); - goto corrupt; - } - /* OOB allows "right at the end" access, so this works for last rec. */ - if (tdb->methods->tdb_oob(tdb, off, sizeof(*rec)+rec->rec_len, 0)) - goto corrupt; - - /* Check tailer. */ - if (tdb_ofs_read(tdb, off+sizeof(*rec)+rec->rec_len-sizeof(tailer), - &tailer) == -1) - goto corrupt; - if (tailer != sizeof(*rec) + rec->rec_len) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Record offset %d invalid tailer\n", off)); - goto corrupt; - } - - return true; - -corrupt: - tdb->ecode = TDB_ERR_CORRUPT; - return false; -} - -/* Grab some bytes: may copy if can't use mmap. - Caller has already done bounds check. */ -static TDB_DATA get_bytes(struct tdb_context *tdb, - tdb_off_t off, tdb_len_t len) -{ - TDB_DATA d; - - d.dsize = len; - - if (tdb->transaction == NULL && tdb->map_ptr != NULL) - d.dptr = (unsigned char *)tdb->map_ptr + off; - else - d.dptr = tdb_alloc_read(tdb, off, d.dsize); - return d; -} - -/* Frees data if we're not able to simply use mmap. */ -static void put_bytes(struct tdb_context *tdb, TDB_DATA d) -{ - if (tdb->transaction == NULL && tdb->map_ptr != NULL) - return; - free(d.dptr); -} - -/* We use the excellent Jenkins lookup3 hash; this is based on hash_word2. - * See: http://burtleburtle.net/bob/c/lookup3.c - */ -#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) -static void hash(uint32_t key, uint32_t *pc, uint32_t *pb) -{ - uint32_t a,b,c; - - /* Set up the internal state */ - a = b = c = 0xdeadbeef + *pc; - c += *pb; - a += key; - c ^= b; c -= rot(b,14); - a ^= c; a -= rot(c,11); - b ^= a; b -= rot(a,25); - c ^= b; c -= rot(b,16); - a ^= c; a -= rot(c,4); - b ^= a; b -= rot(a,14); - c ^= b; c -= rot(b,24); - *pc=c; *pb=b; -} - -/* - We want to check that all free records are in the free list - (only once), and all free list entries are free records. Similarly - for each hash chain of used records. - - Doing that naively (without walking hash chains, since we want to be - linear) means keeping a list of records which have been seen in each - hash chain, and another of records pointed to (ie. next pointers - from records and the initial hash chain heads). These two lists - should be equal. This will take 8 bytes per record, and require - sorting at the end. - - So instead, we record each offset in a bitmap such a way that - recording it twice will cancel out. Since each offset should appear - exactly twice, the bitmap should be zero at the end. - - The approach was inspired by Bloom Filters (see Wikipedia). For - each value, we flip K bits in a bitmap of size N. The number of - distinct arrangements is: - - N! / (K! * (N-K)!) - - Of course, not all arrangements are actually distinct, but testing - shows this formula to be close enough. - - So, if K == 8 and N == 256, the probability of two things flipping the same - bits is 1 in 409,663,695,276,000. - - Given that ldb uses a hash size of 10000, using 32 bytes per hash chain - (320k) seems reasonable. -*/ -#define NUM_HASHES 8 -#define BITMAP_BITS 256 - -static void bit_flip(unsigned char bits[], unsigned int idx) -{ - bits[idx / CHAR_BIT] ^= (1 << (idx % CHAR_BIT)); -} - -/* We record offsets in a bitmap for the particular chain it should be in. */ -static void record_offset(unsigned char bits[], tdb_off_t off) -{ - uint32_t h1 = off, h2 = 0; - unsigned int i; - - /* We get two good hash values out of jhash2, so we use both. Then - * we keep going to produce further hash values. */ - for (i = 0; i < NUM_HASHES / 2; i++) { - hash(off, &h1, &h2); - bit_flip(bits, h1 % BITMAP_BITS); - bit_flip(bits, h2 % BITMAP_BITS); - h2++; - } -} - -/* Check that an in-use record is valid. */ -static bool tdb_check_used_record(struct tdb_context *tdb, - tdb_off_t off, - const struct tdb_record *rec, - unsigned char **hashes, - int (*check)(TDB_DATA, TDB_DATA, void *), - void *private_data) -{ - TDB_DATA key, data; - - if (!tdb_check_record(tdb, off, rec)) - return false; - - /* key + data + tailer must fit in record */ - if (rec->key_len + rec->data_len + sizeof(tdb_off_t) > rec->rec_len) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Record offset %d too short for contents\n", off)); - return false; - } - - key = get_bytes(tdb, off + sizeof(*rec), rec->key_len); - if (!key.dptr) - return false; - - if (tdb->hash_fn(&key) != rec->full_hash) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Record offset %d has incorrect hash\n", off)); - goto fail_put_key; - } - - /* Mark this offset as a known value for this hash bucket. */ - record_offset(hashes[BUCKET(rec->full_hash)+1], off); - /* And similarly if the next pointer is valid. */ - if (rec->next) - record_offset(hashes[BUCKET(rec->full_hash)+1], rec->next); - - /* If they supply a check function and this record isn't dead, - get data and feed it. */ - if (check && rec->magic != TDB_DEAD_MAGIC) { - data = get_bytes(tdb, off + sizeof(*rec) + rec->key_len, - rec->data_len); - if (!data.dptr) - goto fail_put_key; - - if (check(key, data, private_data) == -1) - goto fail_put_data; - put_bytes(tdb, data); - } - - put_bytes(tdb, key); - return true; - -fail_put_data: - put_bytes(tdb, data); -fail_put_key: - put_bytes(tdb, key); - return false; -} - -/* Check that an unused record is valid. */ -static bool tdb_check_free_record(struct tdb_context *tdb, - tdb_off_t off, - const struct tdb_record *rec, - unsigned char **hashes) -{ - if (!tdb_check_record(tdb, off, rec)) - return false; - - /* Mark this offset as a known value for the free list. */ - record_offset(hashes[0], off); - /* And similarly if the next pointer is valid. */ - if (rec->next) - record_offset(hashes[0], rec->next); - return true; -} - -/* Slow, but should be very rare. */ -size_t tdb_dead_space(struct tdb_context *tdb, tdb_off_t off) -{ - size_t len; - - for (len = 0; off + len < tdb->map_size; len++) { - char c; - if (tdb->methods->tdb_read(tdb, off, &c, 1, 0)) - return 0; - if (c != 0 && c != 0x42) - break; - } - return len; -} - -_PUBLIC_ int tdb_check(struct tdb_context *tdb, - int (*check)(TDB_DATA key, TDB_DATA data, void *private_data), - void *private_data) -{ - unsigned int h; - unsigned char **hashes; - tdb_off_t off, recovery_start; - struct tdb_record rec; - bool found_recovery = false; - tdb_len_t dead; - bool locked; - - /* Read-only databases use no locking at all: it's best-effort. - * We may have a write lock already, so skip that case too. */ - if (tdb->read_only || tdb->allrecord_lock.count != 0) { - locked = false; - } else { - if (tdb_lockall_read(tdb) == -1) - return -1; - locked = true; - } - - /* Make sure we know true size of the underlying file. */ - tdb->methods->tdb_oob(tdb, tdb->map_size, 1, 1); - - /* Header must be OK: also gets us the recovery ptr, if any. */ - if (!tdb_check_header(tdb, &recovery_start)) - goto unlock; - - /* We should have the whole header, too. */ - if (tdb->map_size < TDB_DATA_START(tdb->header.hash_size)) { - tdb->ecode = TDB_ERR_CORRUPT; - TDB_LOG((tdb, TDB_DEBUG_ERROR, "File too short for hashes\n")); - goto unlock; - } - - /* One big malloc: pointers then bit arrays. */ - hashes = (unsigned char **)calloc( - 1, sizeof(hashes[0]) * (1+tdb->header.hash_size) - + BITMAP_BITS / CHAR_BIT * (1+tdb->header.hash_size)); - if (!hashes) { - tdb->ecode = TDB_ERR_OOM; - goto unlock; - } - - /* Initialize pointers */ - hashes[0] = (unsigned char *)(&hashes[1+tdb->header.hash_size]); - for (h = 1; h < 1+tdb->header.hash_size; h++) - hashes[h] = hashes[h-1] + BITMAP_BITS / CHAR_BIT; - - /* Freelist and hash headers are all in a row: read them. */ - for (h = 0; h < 1+tdb->header.hash_size; h++) { - if (tdb_ofs_read(tdb, FREELIST_TOP + h*sizeof(tdb_off_t), - &off) == -1) - goto free; - if (off) - record_offset(hashes[h], off); - } - - /* For each record, read it in and check it's ok. */ - for (off = TDB_DATA_START(tdb->header.hash_size); - off < tdb->map_size; - off += sizeof(rec) + rec.rec_len) { - if (tdb->methods->tdb_read(tdb, off, &rec, sizeof(rec), - DOCONV()) == -1) - goto free; - switch (rec.magic) { - case TDB_MAGIC: - case TDB_DEAD_MAGIC: - if (!tdb_check_used_record(tdb, off, &rec, hashes, - check, private_data)) - goto free; - break; - case TDB_FREE_MAGIC: - if (!tdb_check_free_record(tdb, off, &rec, hashes)) - goto free; - break; - /* If we crash after ftruncate, we can get zeroes or fill. */ - case TDB_RECOVERY_INVALID_MAGIC: - case 0x42424242: - if (recovery_start == off) { - found_recovery = true; - break; - } - dead = tdb_dead_space(tdb, off); - if (dead < sizeof(rec)) - goto corrupt; - - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Dead space at %d-%d (of %u)\n", - off, off + dead, tdb->map_size)); - rec.rec_len = dead - sizeof(rec); - break; - case TDB_RECOVERY_MAGIC: - if (recovery_start != off) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Unexpected recovery record at offset %d\n", - off)); - goto free; - } - found_recovery = true; - break; - default: ; - corrupt: - tdb->ecode = TDB_ERR_CORRUPT; - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Bad magic 0x%x at offset %d\n", - rec.magic, off)); - goto free; - } - } - - /* Now, hashes should all be empty: each record exists and is referred - * to by one other. */ - for (h = 0; h < 1+tdb->header.hash_size; h++) { - unsigned int i; - for (i = 0; i < BITMAP_BITS / CHAR_BIT; i++) { - if (hashes[h][i] != 0) { - tdb->ecode = TDB_ERR_CORRUPT; - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Hashes do not match records\n")); - goto free; - } - } - } - - /* We must have found recovery area if there was one. */ - if (recovery_start != 0 && !found_recovery) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Expected a recovery area at %u\n", - recovery_start)); - goto free; - } - - free(hashes); - if (locked) { - tdb_unlockall_read(tdb); - } - return 0; - -free: - free(hashes); -unlock: - if (locked) { - tdb_unlockall_read(tdb); - } - return -1; -} diff --git a/ctdb/lib/tdb/common/dump.c b/ctdb/lib/tdb/common/dump.c deleted file mode 100644 index 67de04e37c65..000000000000 --- a/ctdb/lib/tdb/common/dump.c +++ /dev/null @@ -1,137 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 1999-2005 - Copyright (C) Paul `Rusty' Russell 2000 - Copyright (C) Jeremy Allison 2000-2003 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ - -#include "tdb_private.h" - -static tdb_off_t tdb_dump_record(struct tdb_context *tdb, int hash, - tdb_off_t offset) -{ - struct tdb_record rec; - tdb_off_t tailer_ofs, tailer; - - if (tdb->methods->tdb_read(tdb, offset, (char *)&rec, - sizeof(rec), DOCONV()) == -1) { - printf("ERROR: failed to read record at %u\n", offset); - return 0; - } - - printf(" rec: hash=%d offset=0x%08x next=0x%08x rec_len=%d " - "key_len=%d data_len=%d full_hash=0x%x magic=0x%x\n", - hash, offset, rec.next, rec.rec_len, rec.key_len, rec.data_len, - rec.full_hash, rec.magic); - - tailer_ofs = offset + sizeof(rec) + rec.rec_len - sizeof(tdb_off_t); - - if (tdb_ofs_read(tdb, tailer_ofs, &tailer) == -1) { - printf("ERROR: failed to read tailer at %u\n", tailer_ofs); - return rec.next; - } - - if (tailer != rec.rec_len + sizeof(rec)) { - printf("ERROR: tailer does not match record! tailer=%u totalsize=%u\n", - (unsigned int)tailer, (unsigned int)(rec.rec_len + sizeof(rec))); - } - return rec.next; -} - -static int tdb_dump_chain(struct tdb_context *tdb, int i) -{ - tdb_off_t rec_ptr, top; - - top = TDB_HASH_TOP(i); - - if (tdb_lock(tdb, i, F_WRLCK) != 0) - return -1; - - if (tdb_ofs_read(tdb, top, &rec_ptr) == -1) - return tdb_unlock(tdb, i, F_WRLCK); - - if (rec_ptr) - printf("hash=%d\n", i); - - while (rec_ptr) { - rec_ptr = tdb_dump_record(tdb, i, rec_ptr); - } - - return tdb_unlock(tdb, i, F_WRLCK); -} - -_PUBLIC_ void tdb_dump_all(struct tdb_context *tdb) -{ - int i; - for (i=0;iheader.hash_size;i++) { - tdb_dump_chain(tdb, i); - } - printf("freelist:\n"); - tdb_dump_chain(tdb, -1); -} - -_PUBLIC_ int tdb_printfreelist(struct tdb_context *tdb) -{ - int ret; - long total_free = 0; - tdb_off_t offset, rec_ptr; - struct tdb_record rec; - - if ((ret = tdb_lock(tdb, -1, F_WRLCK)) != 0) - return ret; - - offset = FREELIST_TOP; - - /* read in the freelist top */ - if (tdb_ofs_read(tdb, offset, &rec_ptr) == -1) { - tdb_unlock(tdb, -1, F_WRLCK); - return 0; - } - - printf("freelist top=[0x%08x]\n", rec_ptr ); - while (rec_ptr) { - if (tdb->methods->tdb_read(tdb, rec_ptr, (char *)&rec, - sizeof(rec), DOCONV()) == -1) { - tdb_unlock(tdb, -1, F_WRLCK); - return -1; - } - - if (rec.magic != TDB_FREE_MAGIC) { - printf("bad magic 0x%08x in free list\n", rec.magic); - tdb_unlock(tdb, -1, F_WRLCK); - return -1; - } - - printf("entry offset=[0x%08x], rec.rec_len = [0x%08x (%d)] (end = 0x%08x)\n", - rec_ptr, rec.rec_len, rec.rec_len, rec_ptr + rec.rec_len); - total_free += rec.rec_len; - - /* move to the next record */ - rec_ptr = rec.next; - } - printf("total rec_len = [0x%08x (%d)]\n", (int)total_free, - (int)total_free); - - return tdb_unlock(tdb, -1, F_WRLCK); -} - diff --git a/ctdb/lib/tdb/common/error.c b/ctdb/lib/tdb/common/error.c deleted file mode 100644 index 2aaaa8134e4c..000000000000 --- a/ctdb/lib/tdb/common/error.c +++ /dev/null @@ -1,57 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 1999-2005 - Copyright (C) Paul `Rusty' Russell 2000 - Copyright (C) Jeremy Allison 2000-2003 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ - -#include "tdb_private.h" - -_PUBLIC_ enum TDB_ERROR tdb_error(struct tdb_context *tdb) -{ - return tdb->ecode; -} - -static struct tdb_errname { - enum TDB_ERROR ecode; const char *estring; -} emap[] = { {TDB_SUCCESS, "Success"}, - {TDB_ERR_CORRUPT, "Corrupt database"}, - {TDB_ERR_IO, "IO Error"}, - {TDB_ERR_LOCK, "Locking error"}, - {TDB_ERR_OOM, "Out of memory"}, - {TDB_ERR_EXISTS, "Record exists"}, - {TDB_ERR_NOLOCK, "Lock exists on other keys"}, - {TDB_ERR_EINVAL, "Invalid parameter"}, - {TDB_ERR_NOEXIST, "Record does not exist"}, - {TDB_ERR_RDONLY, "write not permitted"} }; - -/* Error string for the last tdb error */ -_PUBLIC_ const char *tdb_errorstr(struct tdb_context *tdb) -{ - uint32_t i; - for (i = 0; i < sizeof(emap) / sizeof(struct tdb_errname); i++) - if (tdb->ecode == emap[i].ecode) - return emap[i].estring; - return "Invalid error code"; -} - diff --git a/ctdb/lib/tdb/common/freelist.c b/ctdb/lib/tdb/common/freelist.c deleted file mode 100644 index 6358f64a04ab..000000000000 --- a/ctdb/lib/tdb/common/freelist.c +++ /dev/null @@ -1,386 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 1999-2005 - Copyright (C) Paul `Rusty' Russell 2000 - Copyright (C) Jeremy Allison 2000-2003 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ - -#include "tdb_private.h" - -/* 'right' merges can involve O(n^2) cost when combined with a - traverse, so they are disabled until we find a way to do them in - O(1) time -*/ -#define USE_RIGHT_MERGES 0 - -/* read a freelist record and check for simple errors */ -int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off, struct tdb_record *rec) -{ - if (tdb->methods->tdb_read(tdb, off, rec, sizeof(*rec),DOCONV()) == -1) - return -1; - - if (rec->magic == TDB_MAGIC) { - /* this happens when a app is showdown while deleting a record - we should - not completely fail when this happens */ - TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read non-free magic 0x%x at offset=%d - fixing\n", - rec->magic, off)); - rec->magic = TDB_FREE_MAGIC; - if (tdb->methods->tdb_write(tdb, off, rec, sizeof(*rec)) == -1) - return -1; - } - - if (rec->magic != TDB_FREE_MAGIC) { - /* Ensure ecode is set for log fn. */ - tdb->ecode = TDB_ERR_CORRUPT; - TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read bad magic 0x%x at offset=%d\n", - rec->magic, off)); - return -1; - } - if (tdb->methods->tdb_oob(tdb, rec->next, sizeof(*rec), 0) != 0) - return -1; - return 0; -} - - -#if USE_RIGHT_MERGES -/* Remove an element from the freelist. Must have alloc lock. */ -static int remove_from_freelist(struct tdb_context *tdb, tdb_off_t off, tdb_off_t next) -{ - tdb_off_t last_ptr, i; - - /* read in the freelist top */ - last_ptr = FREELIST_TOP; - while (tdb_ofs_read(tdb, last_ptr, &i) != -1 && i != 0) { - if (i == off) { - /* We've found it! */ - return tdb_ofs_write(tdb, last_ptr, &next); - } - /* Follow chain (next offset is at start of record) */ - last_ptr = i; - } - tdb->ecode = TDB_ERR_CORRUPT; - TDB_LOG((tdb, TDB_DEBUG_FATAL,"remove_from_freelist: not on list at off=%d\n", off)); - return -1; -} -#endif - - -/* update a record tailer (must hold allocation lock) */ -static int update_tailer(struct tdb_context *tdb, tdb_off_t offset, - const struct tdb_record *rec) -{ - tdb_off_t totalsize; - - /* Offset of tailer from record header */ - totalsize = sizeof(*rec) + rec->rec_len; - return tdb_ofs_write(tdb, offset + totalsize - sizeof(tdb_off_t), - &totalsize); -} - -/* Add an element into the freelist. Merge adjacent records if - necessary. */ -int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec) -{ - /* Allocation and tailer lock */ - if (tdb_lock(tdb, -1, F_WRLCK) != 0) - return -1; - - /* set an initial tailer, so if we fail we don't leave a bogus record */ - if (update_tailer(tdb, offset, rec) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed!\n")); - goto fail; - } - -#if USE_RIGHT_MERGES - /* Look right first (I'm an Australian, dammit) */ - if (offset + sizeof(*rec) + rec->rec_len + sizeof(*rec) <= tdb->map_size) { - tdb_off_t right = offset + sizeof(*rec) + rec->rec_len; - struct tdb_record r; - - if (tdb->methods->tdb_read(tdb, right, &r, sizeof(r), DOCONV()) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: right read failed at %u\n", right)); - goto left; - } - - /* If it's free, expand to include it. */ - if (r.magic == TDB_FREE_MAGIC) { - if (remove_from_freelist(tdb, right, r.next) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: right free failed at %u\n", right)); - goto left; - } - rec->rec_len += sizeof(r) + r.rec_len; - if (update_tailer(tdb, offset, rec) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed at %u\n", offset)); - goto fail; - } - } - } -left: -#endif - - /* Look left */ - if (offset - sizeof(tdb_off_t) > TDB_DATA_START(tdb->header.hash_size)) { - tdb_off_t left = offset - sizeof(tdb_off_t); - struct tdb_record l; - tdb_off_t leftsize; - - /* Read in tailer and jump back to header */ - if (tdb_ofs_read(tdb, left, &leftsize) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left offset read failed at %u\n", left)); - goto update; - } - - /* it could be uninitialised data */ - if (leftsize == 0 || leftsize == TDB_PAD_U32) { - goto update; - } - - left = offset - leftsize; - - if (leftsize > offset || - left < TDB_DATA_START(tdb->header.hash_size)) { - goto update; - } - - /* Now read in the left record */ - if (tdb->methods->tdb_read(tdb, left, &l, sizeof(l), DOCONV()) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left read failed at %u (%u)\n", left, leftsize)); - goto update; - } - - /* If it's free, expand to include it. */ - if (l.magic == TDB_FREE_MAGIC) { - /* we now merge the new record into the left record, rather than the other - way around. This makes the operation O(1) instead of O(n). This change - prevents traverse from being O(n^2) after a lot of deletes */ - l.rec_len += sizeof(*rec) + rec->rec_len; - if (tdb_rec_write(tdb, left, &l) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_left failed at %u\n", left)); - goto fail; - } - if (update_tailer(tdb, left, &l) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed at %u\n", offset)); - goto fail; - } - tdb_unlock(tdb, -1, F_WRLCK); - return 0; - } - } - -update: - - /* Now, prepend to free list */ - rec->magic = TDB_FREE_MAGIC; - - if (tdb_ofs_read(tdb, FREELIST_TOP, &rec->next) == -1 || - tdb_rec_write(tdb, offset, rec) == -1 || - tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free record write failed at offset=%d\n", offset)); - goto fail; - } - - /* And we're done. */ - tdb_unlock(tdb, -1, F_WRLCK); - return 0; - - fail: - tdb_unlock(tdb, -1, F_WRLCK); - return -1; -} - - - -/* - the core of tdb_allocate - called when we have decided which - free list entry to use - - Note that we try to allocate by grabbing data from the end of an existing record, - not the beginning. This is so the left merge in a free is more likely to be - able to free up the record without fragmentation - */ -static tdb_off_t tdb_allocate_ofs(struct tdb_context *tdb, - tdb_len_t length, tdb_off_t rec_ptr, - struct tdb_record *rec, tdb_off_t last_ptr) -{ -#define MIN_REC_SIZE (sizeof(struct tdb_record) + sizeof(tdb_off_t) + 8) - - if (rec->rec_len < length + MIN_REC_SIZE) { - /* we have to grab the whole record */ - - /* unlink it from the previous record */ - if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1) { - return 0; - } - - /* mark it not free */ - rec->magic = TDB_MAGIC; - if (tdb_rec_write(tdb, rec_ptr, rec) == -1) { - return 0; - } - return rec_ptr; - } - - /* we're going to just shorten the existing record */ - rec->rec_len -= (length + sizeof(*rec)); - if (tdb_rec_write(tdb, rec_ptr, rec) == -1) { - return 0; - } - if (update_tailer(tdb, rec_ptr, rec) == -1) { - return 0; - } - - /* and setup the new record */ - rec_ptr += sizeof(*rec) + rec->rec_len; - - memset(rec, '\0', sizeof(*rec)); - rec->rec_len = length; - rec->magic = TDB_MAGIC; - - if (tdb_rec_write(tdb, rec_ptr, rec) == -1) { - return 0; - } - - if (update_tailer(tdb, rec_ptr, rec) == -1) { - return 0; - } - - return rec_ptr; -} - -/* allocate some space from the free list. The offset returned points - to a unconnected tdb_record within the database with room for at - least length bytes of total data - - 0 is returned if the space could not be allocated - */ -tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct tdb_record *rec) -{ - tdb_off_t rec_ptr, last_ptr, newrec_ptr; - struct { - tdb_off_t rec_ptr, last_ptr; - tdb_len_t rec_len; - } bestfit; - float multiplier = 1.0; - - if (tdb_lock(tdb, -1, F_WRLCK) == -1) - return 0; - - /* over-allocate to reduce fragmentation */ - length *= 1.25; - - /* Extra bytes required for tailer */ - length += sizeof(tdb_off_t); - length = TDB_ALIGN(length, TDB_ALIGNMENT); - - again: - last_ptr = FREELIST_TOP; - - /* read in the freelist top */ - if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1) - goto fail; - - bestfit.rec_ptr = 0; - bestfit.last_ptr = 0; - bestfit.rec_len = 0; - - /* - this is a best fit allocation strategy. Originally we used - a first fit strategy, but it suffered from massive fragmentation - issues when faced with a slowly increasing record size. - */ - while (rec_ptr) { - if (tdb_rec_free_read(tdb, rec_ptr, rec) == -1) { - goto fail; - } - - if (rec->rec_len >= length) { - if (bestfit.rec_ptr == 0 || - rec->rec_len < bestfit.rec_len) { - bestfit.rec_len = rec->rec_len; - bestfit.rec_ptr = rec_ptr; - bestfit.last_ptr = last_ptr; - } - } - - /* move to the next record */ - last_ptr = rec_ptr; - rec_ptr = rec->next; - - /* if we've found a record that is big enough, then - stop searching if its also not too big. The - definition of 'too big' changes as we scan - through */ - if (bestfit.rec_len > 0 && - bestfit.rec_len < length * multiplier) { - break; - } - - /* this multiplier means we only extremely rarely - search more than 50 or so records. At 50 records we - accept records up to 11 times larger than what we - want */ - multiplier *= 1.05; - } - - if (bestfit.rec_ptr != 0) { - if (tdb_rec_free_read(tdb, bestfit.rec_ptr, rec) == -1) { - goto fail; - } - - newrec_ptr = tdb_allocate_ofs(tdb, length, bestfit.rec_ptr, - rec, bestfit.last_ptr); - tdb_unlock(tdb, -1, F_WRLCK); - return newrec_ptr; - } - - /* we didn't find enough space. See if we can expand the - database and if we can then try again */ - if (tdb_expand(tdb, length + sizeof(*rec)) == 0) - goto again; - fail: - tdb_unlock(tdb, -1, F_WRLCK); - return 0; -} - - - -/* - return the size of the freelist - used to decide if we should repack -*/ -_PUBLIC_ int tdb_freelist_size(struct tdb_context *tdb) -{ - tdb_off_t ptr; - int count=0; - - if (tdb_lock(tdb, -1, F_RDLCK) == -1) { - return -1; - } - - ptr = FREELIST_TOP; - while (tdb_ofs_read(tdb, ptr, &ptr) == 0 && ptr != 0) { - count++; - } - - tdb_unlock(tdb, -1, F_RDLCK); - return count; -} diff --git a/ctdb/lib/tdb/common/freelistcheck.c b/ctdb/lib/tdb/common/freelistcheck.c deleted file mode 100644 index ab6e78f02dbb..000000000000 --- a/ctdb/lib/tdb/common/freelistcheck.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Jeremy Allison 2006 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ - -#include "tdb_private.h" - -/* Check the freelist is good and contains no loops. - Very memory intensive - only do this as a consistency - checker. Heh heh - uses an in memory tdb as the storage - for the "seen" record list. For some reason this strikes - me as extremely clever as I don't have to write another tree - data structure implementation :-). - */ - -static int seen_insert(struct tdb_context *mem_tdb, tdb_off_t rec_ptr) -{ - TDB_DATA key, data; - - memset(&data, '\0', sizeof(data)); - key.dptr = (unsigned char *)&rec_ptr; - key.dsize = sizeof(rec_ptr); - return tdb_store(mem_tdb, key, data, TDB_INSERT); -} - -_PUBLIC_ int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries) -{ - struct tdb_context *mem_tdb = NULL; - struct tdb_record rec; - tdb_off_t rec_ptr, last_ptr; - int ret = -1; - - *pnum_entries = 0; - - mem_tdb = tdb_open("flval", tdb->header.hash_size, - TDB_INTERNAL, O_RDWR, 0600); - if (!mem_tdb) { - return -1; - } - - if (tdb_lock(tdb, -1, F_WRLCK) == -1) { - tdb_close(mem_tdb); - return 0; - } - - last_ptr = FREELIST_TOP; - - /* Store the FREELIST_TOP record. */ - if (seen_insert(mem_tdb, last_ptr) == -1) { - tdb->ecode = TDB_ERR_CORRUPT; - ret = -1; - goto fail; - } - - /* read in the freelist top */ - if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1) { - goto fail; - } - - while (rec_ptr) { - - /* If we can't store this record (we've seen it - before) then the free list has a loop and must - be corrupt. */ - - if (seen_insert(mem_tdb, rec_ptr)) { - tdb->ecode = TDB_ERR_CORRUPT; - ret = -1; - goto fail; - } - - if (tdb_rec_free_read(tdb, rec_ptr, &rec) == -1) { - goto fail; - } - - /* move to the next record */ - last_ptr = rec_ptr; - rec_ptr = rec.next; - *pnum_entries += 1; - } - - ret = 0; - - fail: - - tdb_close(mem_tdb); - tdb_unlock(tdb, -1, F_WRLCK); - return ret; -} diff --git a/ctdb/lib/tdb/common/hash.c b/ctdb/lib/tdb/common/hash.c deleted file mode 100644 index 1eed7221d2ab..000000000000 --- a/ctdb/lib/tdb/common/hash.c +++ /dev/null @@ -1,345 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Rusty Russell 2010 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ -#include "tdb_private.h" - -/* This is based on the hash algorithm from gdbm */ -unsigned int tdb_old_hash(TDB_DATA *key) -{ - uint32_t value; /* Used to compute the hash value. */ - uint32_t i; /* Used to cycle through random values. */ - - /* Set the initial value from the key size. */ - for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++) - value = (value + (key->dptr[i] << (i*5 % 24))); - - return (1103515243 * value + 12345); -} - -#ifndef WORDS_BIGENDIAN -# define HASH_LITTLE_ENDIAN 1 -# define HASH_BIG_ENDIAN 0 -#else -# define HASH_LITTLE_ENDIAN 0 -# define HASH_BIG_ENDIAN 1 -#endif - -/* -------------------------------------------------------------------------------- -lookup3.c, by Bob Jenkins, May 2006, Public Domain. - -These are functions for producing 32-bit hashes for hash table lookup. -hash_word(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() -are externally useful functions. Routines to test the hash are included -if SELF_TEST is defined. You can use this free for any purpose. It's in -the public domain. It has no warranty. - -You probably want to use hashlittle(). hashlittle() and hashbig() -hash byte arrays. hashlittle() is is faster than hashbig() on -little-endian machines. Intel and AMD are little-endian machines. -On second thought, you probably want hashlittle2(), which is identical to -hashlittle() except it returns two 32-bit hashes for the price of one. -You could implement hashbig2() if you wanted but I haven't bothered here. - -If you want to find a hash of, say, exactly 7 integers, do - a = i1; b = i2; c = i3; - mix(a,b,c); - a += i4; b += i5; c += i6; - mix(a,b,c); - a += i7; - final(a,b,c); -then use c as the hash value. If you have a variable length array of -4-byte integers to hash, use hash_word(). If you have a byte array (like -a character string), use hashlittle(). If you have several byte arrays, or -a mix of things, see the comments above hashlittle(). - -Why is this so big? I read 12 bytes at a time into 3 4-byte integers, -then mix those integers. This is fast (you can do a lot more thorough -mixing with 12*3 instructions on 3 integers than you can with 3 instructions -on 1 byte), but shoehorning those bytes into integers efficiently is messy. -*/ - -#define hashsize(n) ((uint32_t)1<<(n)) -#define hashmask(n) (hashsize(n)-1) -#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) - -/* -------------------------------------------------------------------------------- -mix -- mix 3 32-bit values reversibly. - -This is reversible, so any information in (a,b,c) before mix() is -still in (a,b,c) after mix(). - -If four pairs of (a,b,c) inputs are run through mix(), or through -mix() in reverse, there are at least 32 bits of the output that -are sometimes the same for one pair and different for another pair. -This was tested for: -* pairs that differed by one bit, by two bits, in any combination - of top bits of (a,b,c), or in any combination of bottom bits of - (a,b,c). -* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed - the output delta to a Gray code (a^(a>>1)) so a string of 1's (as - is commonly produced by subtraction) look like a single 1-bit - difference. -* the base values were pseudorandom, all zero but one bit set, or - all zero plus a counter that starts at zero. - -Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that -satisfy this are - 4 6 8 16 19 4 - 9 15 3 18 27 15 - 14 9 3 7 17 3 -Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing -for "differ" defined as + with a one-bit base and a two-bit delta. I -used http://burtleburtle.net/bob/hash/avalanche.html to choose -the operations, constants, and arrangements of the variables. - -This does not achieve avalanche. There are input bits of (a,b,c) -that fail to affect some output bits of (a,b,c), especially of a. The -most thoroughly mixed value is c, but it doesn't really even achieve -avalanche in c. - -This allows some parallelism. Read-after-writes are good at doubling -the number of bits affected, so the goal of mixing pulls in the opposite -direction as the goal of parallelism. I did what I could. Rotates -seem to cost as much as shifts on every machine I could lay my hands -on, and rotates are much kinder to the top and bottom bits, so I used -rotates. -------------------------------------------------------------------------------- -*/ -#define mix(a,b,c) \ -{ \ - a -= c; a ^= rot(c, 4); c += b; \ - b -= a; b ^= rot(a, 6); a += c; \ - c -= b; c ^= rot(b, 8); b += a; \ - a -= c; a ^= rot(c,16); c += b; \ - b -= a; b ^= rot(a,19); a += c; \ - c -= b; c ^= rot(b, 4); b += a; \ -} - -/* -------------------------------------------------------------------------------- -final -- final mixing of 3 32-bit values (a,b,c) into c - -Pairs of (a,b,c) values differing in only a few bits will usually -produce values of c that look totally different. This was tested for -* pairs that differed by one bit, by two bits, in any combination - of top bits of (a,b,c), or in any combination of bottom bits of - (a,b,c). -* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed - the output delta to a Gray code (a^(a>>1)) so a string of 1's (as - is commonly produced by subtraction) look like a single 1-bit - difference. -* the base values were pseudorandom, all zero but one bit set, or - all zero plus a counter that starts at zero. - -These constants passed: - 14 11 25 16 4 14 24 - 12 14 25 16 4 14 24 -and these came close: - 4 8 15 26 3 22 24 - 10 8 15 26 3 22 24 - 11 8 15 26 3 22 24 -------------------------------------------------------------------------------- -*/ -#define final(a,b,c) \ -{ \ - c ^= b; c -= rot(b,14); \ - a ^= c; a -= rot(c,11); \ - b ^= a; b -= rot(a,25); \ - c ^= b; c -= rot(b,16); \ - a ^= c; a -= rot(c,4); \ - b ^= a; b -= rot(a,14); \ - c ^= b; c -= rot(b,24); \ -} - - -/* -------------------------------------------------------------------------------- -hashlittle() -- hash a variable-length key into a 32-bit value - k : the key (the unaligned variable-length array of bytes) - length : the length of the key, counting by bytes - val2 : IN: can be any 4-byte value OUT: second 32 bit hash. -Returns a 32-bit value. Every bit of the key affects every bit of -the return value. Two keys differing by one or two bits will have -totally different hash values. Note that the return value is better -mixed than val2, so use that first. - -The best hash table sizes are powers of 2. There is no need to do -mod a prime (mod is sooo slow!). If you need less than 32 bits, -use a bitmask. For example, if you need only 10 bits, do - h = (h & hashmask(10)); -In which case, the hash table should have hashsize(10) elements. - -If you are hashing n strings (uint8_t **)k, do it like this: - for (i=0, h=0; i 12) - { - a += k[0]; - b += k[1]; - c += k[2]; - mix(a,b,c); - length -= 12; - k += 3; - } - - /*----------------------------- handle the last (probably partial) block */ - k8 = (const uint8_t *)k; - switch(length) - { - case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; - case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ - case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ - case 9 : c+=k8[8]; /* fall through */ - case 8 : b+=k[1]; a+=k[0]; break; - case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ - case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ - case 5 : b+=k8[4]; /* fall through */ - case 4 : a+=k[0]; break; - case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ - case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ - case 1 : a+=k8[0]; break; - case 0 : return c; - } - } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { - const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ - const uint8_t *k8; - - /*--------------- all but last block: aligned reads and different mixing */ - while (length > 12) - { - a += k[0] + (((uint32_t)k[1])<<16); - b += k[2] + (((uint32_t)k[3])<<16); - c += k[4] + (((uint32_t)k[5])<<16); - mix(a,b,c); - length -= 12; - k += 6; - } - - /*----------------------------- handle the last (probably partial) block */ - k8 = (const uint8_t *)k; - switch(length) - { - case 12: c+=k[4]+(((uint32_t)k[5])<<16); - b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ - case 10: c+=k[4]; - b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 9 : c+=k8[8]; /* fall through */ - case 8 : b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ - case 6 : b+=k[2]; - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 5 : b+=k8[4]; /* fall through */ - case 4 : a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ - case 2 : a+=k[0]; - break; - case 1 : a+=k8[0]; - break; - case 0 : return c; /* zero length requires no mixing */ - } - - } else { /* need to read the key one byte at a time */ - const uint8_t *k = (const uint8_t *)key; - - /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ - while (length > 12) - { - a += k[0]; - a += ((uint32_t)k[1])<<8; - a += ((uint32_t)k[2])<<16; - a += ((uint32_t)k[3])<<24; - b += k[4]; - b += ((uint32_t)k[5])<<8; - b += ((uint32_t)k[6])<<16; - b += ((uint32_t)k[7])<<24; - c += k[8]; - c += ((uint32_t)k[9])<<8; - c += ((uint32_t)k[10])<<16; - c += ((uint32_t)k[11])<<24; - mix(a,b,c); - length -= 12; - k += 12; - } - - /*-------------------------------- last block: affect all 32 bits of (c) */ - switch(length) /* all the case statements fall through */ - { - case 12: c+=((uint32_t)k[11])<<24; - case 11: c+=((uint32_t)k[10])<<16; - case 10: c+=((uint32_t)k[9])<<8; - case 9 : c+=k[8]; - case 8 : b+=((uint32_t)k[7])<<24; - case 7 : b+=((uint32_t)k[6])<<16; - case 6 : b+=((uint32_t)k[5])<<8; - case 5 : b+=k[4]; - case 4 : a+=((uint32_t)k[3])<<24; - case 3 : a+=((uint32_t)k[2])<<16; - case 2 : a+=((uint32_t)k[1])<<8; - case 1 : a+=k[0]; - break; - case 0 : return c; - } - } - - final(a,b,c); - return c; -} - -_PUBLIC_ unsigned int tdb_jenkins_hash(TDB_DATA *key) -{ - return hashlittle(key->dptr, key->dsize); -} diff --git a/ctdb/lib/tdb/common/io.c b/ctdb/lib/tdb/common/io.c deleted file mode 100644 index 25968bfef2db..000000000000 --- a/ctdb/lib/tdb/common/io.c +++ /dev/null @@ -1,534 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 1999-2005 - Copyright (C) Paul `Rusty' Russell 2000 - Copyright (C) Jeremy Allison 2000-2003 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ - - -#include "tdb_private.h" - -/* check for an out of bounds access - if it is out of bounds then - see if the database has been expanded by someone else and expand - if necessary -*/ -static int tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, - int probe) -{ - struct stat st; - if (len + off < len) { - if (!probe) { - /* Ensure ecode is set for log fn. */ - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob off %d len %d wrap\n", - (int)off, (int)len)); - } - return -1; - } - - if (off + len <= tdb->map_size) - return 0; - if (tdb->flags & TDB_INTERNAL) { - if (!probe) { - /* Ensure ecode is set for log fn. */ - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %u beyond internal malloc size %u\n", - (int)(off + len), (int)tdb->map_size)); - } - return -1; - } - - if (fstat(tdb->fd, &st) == -1) { - tdb->ecode = TDB_ERR_IO; - return -1; - } - - /* Beware >4G files! */ - if ((tdb_off_t)st.st_size != st.st_size) { - /* Ensure ecode is set for log fn. */ - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_oob len %llu too large!\n", - (long long)st.st_size)); - return -1; - } - - /* Unmap, update size, remap. We do this unconditionally, to handle - * the unusual case where the db is truncated. - * - * This can happen to a child using tdb_reopen_all(true) on a - * TDB_CLEAR_IF_FIRST tdb whose parent crashes: the next - * opener will truncate the database. */ - if (tdb_munmap(tdb) == -1) { - tdb->ecode = TDB_ERR_IO; - return -1; - } - tdb->map_size = st.st_size; - if (tdb_mmap(tdb) != 0) { - return - 1; - } - - if (st.st_size < (size_t)off + len) { - if (!probe) { - /* Ensure ecode is set for log fn. */ - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %u beyond eof at %u\n", - (int)(off + len), (int)st.st_size)); - } - return -1; - } - return 0; -} - -/* write a lump of data at a specified offset */ -static int tdb_write(struct tdb_context *tdb, tdb_off_t off, - const void *buf, tdb_len_t len) -{ - if (len == 0) { - return 0; - } - - if (tdb->read_only || tdb->traverse_read) { - tdb->ecode = TDB_ERR_RDONLY; - return -1; - } - - if (tdb->methods->tdb_oob(tdb, off, len, 0) != 0) - return -1; - - if (tdb->map_ptr) { - memcpy(off + (char *)tdb->map_ptr, buf, len); - } else { -#ifdef HAVE_INCOHERENT_MMAP - tdb->ecode = TDB_ERR_IO; - return -1; -#else - ssize_t written = pwrite(tdb->fd, buf, len, off); - if ((written != (ssize_t)len) && (written != -1)) { - /* try once more */ - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: wrote only " - "%d of %d bytes at %d, trying once more\n", - (int)written, len, off)); - written = pwrite(tdb->fd, (const char *)buf+written, - len-written, - off+written); - } - if (written == -1) { - /* Ensure ecode is set for log fn. */ - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_write failed at %d " - "len=%d (%s)\n", off, len, strerror(errno))); - return -1; - } else if (written != (ssize_t)len) { - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: failed to " - "write %d bytes at %d in two attempts\n", - len, off)); - return -1; - } -#endif - } - return 0; -} - -/* Endian conversion: we only ever deal with 4 byte quantities */ -void *tdb_convert(void *buf, uint32_t size) -{ - uint32_t i, *p = (uint32_t *)buf; - for (i = 0; i < size / 4; i++) - p[i] = TDB_BYTEREV(p[i]); - return buf; -} - - -/* read a lump of data at a specified offset, maybe convert */ -static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf, - tdb_len_t len, int cv) -{ - if (tdb->methods->tdb_oob(tdb, off, len, 0) != 0) { - return -1; - } - - if (tdb->map_ptr) { - memcpy(buf, off + (char *)tdb->map_ptr, len); - } else { -#ifdef HAVE_INCOHERENT_MMAP - tdb->ecode = TDB_ERR_IO; - return -1; -#else - ssize_t ret = pread(tdb->fd, buf, len, off); - if (ret != (ssize_t)len) { - /* Ensure ecode is set for log fn. */ - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_read failed at %d " - "len=%d ret=%d (%s) map_size=%d\n", - (int)off, (int)len, (int)ret, strerror(errno), - (int)tdb->map_size)); - return -1; - } -#endif - } - if (cv) { - tdb_convert(buf, len); - } - return 0; -} - - - -/* - do an unlocked scan of the hash table heads to find the next non-zero head. The value - will then be confirmed with the lock held -*/ -static void tdb_next_hash_chain(struct tdb_context *tdb, uint32_t *chain) -{ - uint32_t h = *chain; - if (tdb->map_ptr) { - for (;h < tdb->header.hash_size;h++) { - if (0 != *(uint32_t *)(TDB_HASH_TOP(h) + (unsigned char *)tdb->map_ptr)) { - break; - } - } - } else { - uint32_t off=0; - for (;h < tdb->header.hash_size;h++) { - if (tdb_ofs_read(tdb, TDB_HASH_TOP(h), &off) != 0 || off != 0) { - break; - } - } - } - (*chain) = h; -} - - -int tdb_munmap(struct tdb_context *tdb) -{ - if (tdb->flags & TDB_INTERNAL) - return 0; - -#ifdef HAVE_MMAP - if (tdb->map_ptr) { - int ret; - - ret = munmap(tdb->map_ptr, tdb->map_size); - if (ret != 0) - return ret; - } -#endif - tdb->map_ptr = NULL; - return 0; -} - -/* If mmap isn't coherent, *everyone* must always mmap. */ -static bool should_mmap(const struct tdb_context *tdb) -{ -#ifdef HAVE_INCOHERENT_MMAP - return true; -#else - return !(tdb->flags & TDB_NOMMAP); -#endif -} - -int tdb_mmap(struct tdb_context *tdb) -{ - if (tdb->flags & TDB_INTERNAL) - return 0; - -#ifdef HAVE_MMAP - if (should_mmap(tdb)) { - tdb->map_ptr = mmap(NULL, tdb->map_size, - PROT_READ|(tdb->read_only? 0:PROT_WRITE), - MAP_SHARED|MAP_FILE, tdb->fd, 0); - - /* - * NB. When mmap fails it returns MAP_FAILED *NOT* NULL !!!! - */ - - if (tdb->map_ptr == MAP_FAILED) { - tdb->map_ptr = NULL; - TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_mmap failed for size %d (%s)\n", - tdb->map_size, strerror(errno))); -#ifdef HAVE_INCOHERENT_MMAP - tdb->ecode = TDB_ERR_IO; - return -1; -#endif - } - } else { - tdb->map_ptr = NULL; - } -#else - tdb->map_ptr = NULL; -#endif - return 0; -} - -/* expand a file. we prefer to use ftruncate, as that is what posix - says to use for mmap expansion */ -static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t addition) -{ - char buf[8192]; - - if (tdb->read_only || tdb->traverse_read) { - tdb->ecode = TDB_ERR_RDONLY; - return -1; - } - - if (ftruncate(tdb->fd, size+addition) == -1) { - char b = 0; - ssize_t written = pwrite(tdb->fd, &b, 1, (size+addition) - 1); - if (written == 0) { - /* try once more, potentially revealing errno */ - written = pwrite(tdb->fd, &b, 1, (size+addition) - 1); - } - if (written == 0) { - /* again - give up, guessing errno */ - errno = ENOSPC; - } - if (written != 1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %d failed (%s)\n", - size+addition, strerror(errno))); - return -1; - } - } - - /* now fill the file with something. This ensures that the - file isn't sparse, which would be very bad if we ran out of - disk. This must be done with write, not via mmap */ - memset(buf, TDB_PAD_BYTE, sizeof(buf)); - while (addition) { - size_t n = addition>sizeof(buf)?sizeof(buf):addition; - ssize_t written = pwrite(tdb->fd, buf, n, size); - if (written == 0) { - /* prevent infinite loops: try _once_ more */ - written = pwrite(tdb->fd, buf, n, size); - } - if (written == 0) { - /* give up, trying to provide a useful errno */ - TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write " - "returned 0 twice: giving up!\n")); - errno = ENOSPC; - return -1; - } else if (written == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of " - "%d bytes failed (%s)\n", (int)n, - strerror(errno))); - return -1; - } else if (written != n) { - TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: wrote " - "only %d of %d bytes - retrying\n", (int)written, - (int)n)); - } - addition -= written; - size += written; - } - return 0; -} - - -/* You need 'size', this tells you how much you should expand by. */ -tdb_off_t tdb_expand_adjust(tdb_off_t map_size, tdb_off_t size, int page_size) -{ - tdb_off_t new_size, top_size; - - /* limit size in order to avoid using up huge amounts of memory for - * in memory tdbs if an oddball huge record creeps in */ - if (size > 100 * 1024) { - top_size = map_size + size * 2; - } else { - top_size = map_size + size * 100; - } - - /* always make room for at least top_size more records, and at - least 25% more space. if the DB is smaller than 100MiB, - otherwise grow it by 10% only. */ - if (map_size > 100 * 1024 * 1024) { - new_size = map_size * 1.10; - } else { - new_size = map_size * 1.25; - } - - /* Round the database up to a multiple of the page size */ - new_size = MAX(top_size, new_size); - return TDB_ALIGN(new_size, page_size) - map_size; -} - -/* expand the database at least size bytes by expanding the underlying - file and doing the mmap again if necessary */ -int tdb_expand(struct tdb_context *tdb, tdb_off_t size) -{ - struct tdb_record rec; - tdb_off_t offset; - - if (tdb_lock(tdb, -1, F_WRLCK) == -1) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "lock failed in tdb_expand\n")); - return -1; - } - - /* must know about any previous expansions by another process */ - tdb->methods->tdb_oob(tdb, tdb->map_size, 1, 1); - - size = tdb_expand_adjust(tdb->map_size, size, tdb->page_size); - - /* expand the file itself */ - if (!(tdb->flags & TDB_INTERNAL)) { - if (tdb->methods->tdb_expand_file(tdb, tdb->map_size, size) != 0) - goto fail; - } - - /* form a new freelist record */ - offset = tdb->map_size; - memset(&rec,'\0',sizeof(rec)); - rec.rec_len = size - sizeof(rec); - - if (tdb->flags & TDB_INTERNAL) { - char *new_map_ptr = (char *)realloc(tdb->map_ptr, - tdb->map_size + size); - if (!new_map_ptr) { - goto fail; - } - tdb->map_ptr = new_map_ptr; - tdb->map_size += size; - } else { - /* Explicitly remap: if we're in a transaction, this won't - * happen automatically! */ - tdb_munmap(tdb); - tdb->map_size += size; - if (tdb_mmap(tdb) != 0) { - goto fail; - } - } - - /* link it into the free list */ - if (tdb_free(tdb, offset, &rec) == -1) - goto fail; - - tdb_unlock(tdb, -1, F_WRLCK); - return 0; - fail: - tdb_unlock(tdb, -1, F_WRLCK); - return -1; -} - -/* read/write a tdb_off_t */ -int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d) -{ - return tdb->methods->tdb_read(tdb, offset, (char*)d, sizeof(*d), DOCONV()); -} - -int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d) -{ - tdb_off_t off = *d; - return tdb->methods->tdb_write(tdb, offset, CONVERT(off), sizeof(*d)); -} - - -/* read a lump of data, allocating the space for it */ -unsigned char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len) -{ - unsigned char *buf; - - /* some systems don't like zero length malloc */ - - if (!(buf = (unsigned char *)malloc(len ? len : 1))) { - /* Ensure ecode is set for log fn. */ - tdb->ecode = TDB_ERR_OOM; - TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_alloc_read malloc failed len=%d (%s)\n", - len, strerror(errno))); - return NULL; - } - if (tdb->methods->tdb_read(tdb, offset, buf, len, 0) == -1) { - SAFE_FREE(buf); - return NULL; - } - return buf; -} - -/* Give a piece of tdb data to a parser */ - -int tdb_parse_data(struct tdb_context *tdb, TDB_DATA key, - tdb_off_t offset, tdb_len_t len, - int (*parser)(TDB_DATA key, TDB_DATA data, - void *private_data), - void *private_data) -{ - TDB_DATA data; - int result; - - data.dsize = len; - - if ((tdb->transaction == NULL) && (tdb->map_ptr != NULL)) { - /* - * Optimize by avoiding the malloc/memcpy/free, point the - * parser directly at the mmap area. - */ - if (tdb->methods->tdb_oob(tdb, offset, len, 0) != 0) { - return -1; - } - data.dptr = offset + (unsigned char *)tdb->map_ptr; - return parser(key, data, private_data); - } - - if (!(data.dptr = tdb_alloc_read(tdb, offset, len))) { - return -1; - } - - result = parser(key, data, private_data); - free(data.dptr); - return result; -} - -/* read/write a record */ -int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec) -{ - if (tdb->methods->tdb_read(tdb, offset, rec, sizeof(*rec),DOCONV()) == -1) - return -1; - if (TDB_BAD_MAGIC(rec)) { - /* Ensure ecode is set for log fn. */ - tdb->ecode = TDB_ERR_CORRUPT; - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_rec_read bad magic 0x%x at offset=%d\n", rec->magic, offset)); - return -1; - } - return tdb->methods->tdb_oob(tdb, rec->next, sizeof(*rec), 0); -} - -int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec) -{ - struct tdb_record r = *rec; - return tdb->methods->tdb_write(tdb, offset, CONVERT(r), sizeof(r)); -} - -static const struct tdb_methods io_methods = { - tdb_read, - tdb_write, - tdb_next_hash_chain, - tdb_oob, - tdb_expand_file, -}; - -/* - initialise the default methods table -*/ -void tdb_io_init(struct tdb_context *tdb) -{ - tdb->methods = &io_methods; -} diff --git a/ctdb/lib/tdb/common/lock.c b/ctdb/lib/tdb/common/lock.c deleted file mode 100644 index 260fab668190..000000000000 --- a/ctdb/lib/tdb/common/lock.c +++ /dev/null @@ -1,875 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 1999-2005 - Copyright (C) Paul `Rusty' Russell 2000 - Copyright (C) Jeremy Allison 2000-2003 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ - -#include "tdb_private.h" - -_PUBLIC_ void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *ptr) -{ - tdb->interrupt_sig_ptr = ptr; -} - -static int fcntl_lock(struct tdb_context *tdb, - int rw, off_t off, off_t len, bool waitflag) -{ - struct flock fl; - - fl.l_type = rw; - fl.l_whence = SEEK_SET; - fl.l_start = off; - fl.l_len = len; - fl.l_pid = 0; - - if (waitflag) - return fcntl(tdb->fd, F_SETLKW, &fl); - else - return fcntl(tdb->fd, F_SETLK, &fl); -} - -static int fcntl_unlock(struct tdb_context *tdb, int rw, off_t off, off_t len) -{ - struct flock fl; -#if 0 /* Check they matched up locks and unlocks correctly. */ - char line[80]; - FILE *locks; - bool found = false; - - locks = fopen("/proc/locks", "r"); - - while (fgets(line, 80, locks)) { - char *p; - int type, start, l; - - /* eg. 1: FLOCK ADVISORY WRITE 2440 08:01:2180826 0 EOF */ - p = strchr(line, ':') + 1; - if (strncmp(p, " POSIX ADVISORY ", strlen(" POSIX ADVISORY "))) - continue; - p += strlen(" FLOCK ADVISORY "); - if (strncmp(p, "READ ", strlen("READ ")) == 0) - type = F_RDLCK; - else if (strncmp(p, "WRITE ", strlen("WRITE ")) == 0) - type = F_WRLCK; - else - abort(); - p += 6; - if (atoi(p) != getpid()) - continue; - p = strchr(strchr(p, ' ') + 1, ' ') + 1; - start = atoi(p); - p = strchr(p, ' ') + 1; - if (strncmp(p, "EOF", 3) == 0) - l = 0; - else - l = atoi(p) - start + 1; - - if (off == start) { - if (len != l) { - fprintf(stderr, "Len %u should be %u: %s", - (int)len, l, line); - abort(); - } - if (type != rw) { - fprintf(stderr, "Type %s wrong: %s", - rw == F_RDLCK ? "READ" : "WRITE", line); - abort(); - } - found = true; - break; - } - } - - if (!found) { - fprintf(stderr, "Unlock on %u@%u not found!\n", - (int)off, (int)len); - abort(); - } - - fclose(locks); -#endif - - fl.l_type = F_UNLCK; - fl.l_whence = SEEK_SET; - fl.l_start = off; - fl.l_len = len; - fl.l_pid = 0; - - return fcntl(tdb->fd, F_SETLKW, &fl); -} - -/* list -1 is the alloc list, otherwise a hash chain. */ -static tdb_off_t lock_offset(int list) -{ - return FREELIST_TOP + 4*list; -} - -/* a byte range locking function - return 0 on success - this functions locks/unlocks 1 byte at the specified offset. - - On error, errno is also set so that errors are passed back properly - through tdb_open(). - - note that a len of zero means lock to end of file -*/ -int tdb_brlock(struct tdb_context *tdb, - int rw_type, tdb_off_t offset, size_t len, - enum tdb_lock_flags flags) -{ - int ret; - - if (tdb->flags & TDB_NOLOCK) { - return 0; - } - - if (flags & TDB_LOCK_MARK_ONLY) { - return 0; - } - - if ((rw_type == F_WRLCK) && (tdb->read_only || tdb->traverse_read)) { - tdb->ecode = TDB_ERR_RDONLY; - return -1; - } - - do { - ret = fcntl_lock(tdb, rw_type, offset, len, - flags & TDB_LOCK_WAIT); - /* Check for a sigalarm break. */ - if (ret == -1 && errno == EINTR && - tdb->interrupt_sig_ptr && - *tdb->interrupt_sig_ptr) { - break; - } - } while (ret == -1 && errno == EINTR); - - if (ret == -1) { - tdb->ecode = TDB_ERR_LOCK; - /* Generic lock error. errno set by fcntl. - * EAGAIN is an expected return from non-blocking - * locks. */ - if (!(flags & TDB_LOCK_PROBE) && errno != EAGAIN) { - TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d flags=%d len=%d\n", - tdb->fd, offset, rw_type, flags, (int)len)); - } - return -1; - } - return 0; -} - -int tdb_brunlock(struct tdb_context *tdb, - int rw_type, tdb_off_t offset, size_t len) -{ - int ret; - - if (tdb->flags & TDB_NOLOCK) { - return 0; - } - - do { - ret = fcntl_unlock(tdb, rw_type, offset, len); - } while (ret == -1 && errno == EINTR); - - if (ret == -1) { - TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brunlock failed (fd=%d) at offset %d rw_type=%d len=%d\n", - tdb->fd, offset, rw_type, (int)len)); - } - return ret; -} - -/* - upgrade a read lock to a write lock. This needs to be handled in a - special way as some OSes (such as solaris) have too conservative - deadlock detection and claim a deadlock when progress can be - made. For those OSes we may loop for a while. -*/ -int tdb_allrecord_upgrade(struct tdb_context *tdb) -{ - int count = 1000; - - if (tdb->allrecord_lock.count != 1) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "tdb_allrecord_upgrade failed: count %u too high\n", - tdb->allrecord_lock.count)); - return -1; - } - - if (tdb->allrecord_lock.off != 1) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "tdb_allrecord_upgrade failed: already upgraded?\n")); - return -1; - } - - while (count--) { - struct timeval tv; - if (tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0, - TDB_LOCK_WAIT|TDB_LOCK_PROBE) == 0) { - tdb->allrecord_lock.ltype = F_WRLCK; - tdb->allrecord_lock.off = 0; - return 0; - } - if (errno != EDEADLK) { - break; - } - /* sleep for as short a time as we can - more portable than usleep() */ - tv.tv_sec = 0; - tv.tv_usec = 1; - select(0, NULL, NULL, NULL, &tv); - } - TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_allrecord_upgrade failed\n")); - return -1; -} - -static struct tdb_lock_type *find_nestlock(struct tdb_context *tdb, - tdb_off_t offset) -{ - unsigned int i; - - for (i=0; inum_lockrecs; i++) { - if (tdb->lockrecs[i].off == offset) { - return &tdb->lockrecs[i]; - } - } - return NULL; -} - -/* lock an offset in the database. */ -int tdb_nest_lock(struct tdb_context *tdb, uint32_t offset, int ltype, - enum tdb_lock_flags flags) -{ - struct tdb_lock_type *new_lck; - - if (offset >= lock_offset(tdb->header.hash_size)) { - tdb->ecode = TDB_ERR_LOCK; - TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid offset %u for ltype=%d\n", - offset, ltype)); - return -1; - } - if (tdb->flags & TDB_NOLOCK) - return 0; - - new_lck = find_nestlock(tdb, offset); - if (new_lck) { - /* - * Just increment the in-memory struct, posix locks - * don't stack. - */ - new_lck->count++; - return 0; - } - - new_lck = (struct tdb_lock_type *)realloc( - tdb->lockrecs, - sizeof(*tdb->lockrecs) * (tdb->num_lockrecs+1)); - if (new_lck == NULL) { - errno = ENOMEM; - return -1; - } - tdb->lockrecs = new_lck; - - /* Since fcntl locks don't nest, we do a lock for the first one, - and simply bump the count for future ones */ - if (tdb_brlock(tdb, ltype, offset, 1, flags)) { - return -1; - } - - tdb->lockrecs[tdb->num_lockrecs].off = offset; - tdb->lockrecs[tdb->num_lockrecs].count = 1; - tdb->lockrecs[tdb->num_lockrecs].ltype = ltype; - tdb->num_lockrecs++; - - return 0; -} - -static int tdb_lock_and_recover(struct tdb_context *tdb) -{ - int ret; - - /* We need to match locking order in transaction commit. */ - if (tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0, TDB_LOCK_WAIT)) { - return -1; - } - - if (tdb_brlock(tdb, F_WRLCK, OPEN_LOCK, 1, TDB_LOCK_WAIT)) { - tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0); - return -1; - } - - ret = tdb_transaction_recover(tdb); - - tdb_brunlock(tdb, F_WRLCK, OPEN_LOCK, 1); - tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0); - - return ret; -} - -static bool have_data_locks(const struct tdb_context *tdb) -{ - unsigned int i; - - for (i = 0; i < tdb->num_lockrecs; i++) { - if (tdb->lockrecs[i].off >= lock_offset(-1)) - return true; - } - return false; -} - -static int tdb_lock_list(struct tdb_context *tdb, int list, int ltype, - enum tdb_lock_flags waitflag) -{ - int ret; - bool check = false; - - /* a allrecord lock allows us to avoid per chain locks */ - if (tdb->allrecord_lock.count && - (ltype == tdb->allrecord_lock.ltype || ltype == F_RDLCK)) { - return 0; - } - - if (tdb->allrecord_lock.count) { - tdb->ecode = TDB_ERR_LOCK; - ret = -1; - } else { - /* Only check when we grab first data lock. */ - check = !have_data_locks(tdb); - ret = tdb_nest_lock(tdb, lock_offset(list), ltype, waitflag); - - if (ret == 0 && check && tdb_needs_recovery(tdb)) { - tdb_nest_unlock(tdb, lock_offset(list), ltype, false); - - if (tdb_lock_and_recover(tdb) == -1) { - return -1; - } - return tdb_lock_list(tdb, list, ltype, waitflag); - } - } - return ret; -} - -/* lock a list in the database. list -1 is the alloc list */ -int tdb_lock(struct tdb_context *tdb, int list, int ltype) -{ - int ret; - - ret = tdb_lock_list(tdb, list, ltype, TDB_LOCK_WAIT); - if (ret) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_lock failed on list %d " - "ltype=%d (%s)\n", list, ltype, strerror(errno))); - } - return ret; -} - -/* lock a list in the database. list -1 is the alloc list. non-blocking lock */ -_PUBLIC_ int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype) -{ - return tdb_lock_list(tdb, list, ltype, TDB_LOCK_NOWAIT); -} - - -int tdb_nest_unlock(struct tdb_context *tdb, uint32_t offset, int ltype, - bool mark_lock) -{ - int ret = -1; - struct tdb_lock_type *lck; - - if (tdb->flags & TDB_NOLOCK) - return 0; - - /* Sanity checks */ - if (offset >= lock_offset(tdb->header.hash_size)) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: offset %u invalid (%d)\n", offset, tdb->header.hash_size)); - return ret; - } - - lck = find_nestlock(tdb, offset); - if ((lck == NULL) || (lck->count == 0)) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: count is 0\n")); - return -1; - } - - if (lck->count > 1) { - lck->count--; - return 0; - } - - /* - * This lock has count==1 left, so we need to unlock it in the - * kernel. We don't bother with decrementing the in-memory array - * element, we're about to overwrite it with the last array element - * anyway. - */ - - if (mark_lock) { - ret = 0; - } else { - ret = tdb_brunlock(tdb, ltype, offset, 1); - } - - /* - * Shrink the array by overwriting the element just unlocked with the - * last array element. - */ - *lck = tdb->lockrecs[--tdb->num_lockrecs]; - - /* - * We don't bother with realloc when the array shrinks, but if we have - * a completely idle tdb we should get rid of the locked array. - */ - - if (tdb->num_lockrecs == 0) { - SAFE_FREE(tdb->lockrecs); - } - - if (ret) - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: An error occurred unlocking!\n")); - return ret; -} - -_PUBLIC_ int tdb_unlock(struct tdb_context *tdb, int list, int ltype) -{ - /* a global lock allows us to avoid per chain locks */ - if (tdb->allrecord_lock.count && - (ltype == tdb->allrecord_lock.ltype || ltype == F_RDLCK)) { - return 0; - } - - if (tdb->allrecord_lock.count) { - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - - return tdb_nest_unlock(tdb, lock_offset(list), ltype, false); -} - -/* - get the transaction lock - */ -int tdb_transaction_lock(struct tdb_context *tdb, int ltype, - enum tdb_lock_flags lockflags) -{ - return tdb_nest_lock(tdb, TRANSACTION_LOCK, ltype, lockflags); -} - -/* - release the transaction lock - */ -int tdb_transaction_unlock(struct tdb_context *tdb, int ltype) -{ - return tdb_nest_unlock(tdb, TRANSACTION_LOCK, ltype, false); -} - -/* Returns 0 if all done, -1 if error, 1 if ok. */ -static int tdb_allrecord_check(struct tdb_context *tdb, int ltype, - enum tdb_lock_flags flags, bool upgradable) -{ - /* There are no locks on read-only dbs */ - if (tdb->read_only || tdb->traverse_read) { - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - - if (tdb->allrecord_lock.count && tdb->allrecord_lock.ltype == ltype) { - tdb->allrecord_lock.count++; - return 0; - } - - if (tdb->allrecord_lock.count) { - /* a global lock of a different type exists */ - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - - if (tdb_have_extra_locks(tdb)) { - /* can't combine global and chain locks */ - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - - if (upgradable && ltype != F_RDLCK) { - /* tdb error: you can't upgrade a write lock! */ - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - return 1; -} - -/* We only need to lock individual bytes, but Linux merges consecutive locks - * so we lock in contiguous ranges. */ -static int tdb_chainlock_gradual(struct tdb_context *tdb, - int ltype, enum tdb_lock_flags flags, - size_t off, size_t len) -{ - int ret; - enum tdb_lock_flags nb_flags = (flags & ~TDB_LOCK_WAIT); - - if (len <= 4) { - /* Single record. Just do blocking lock. */ - return tdb_brlock(tdb, ltype, off, len, flags); - } - - /* First we try non-blocking. */ - ret = tdb_brlock(tdb, ltype, off, len, nb_flags); - if (ret == 0) { - return 0; - } - - /* Try locking first half, then second. */ - ret = tdb_chainlock_gradual(tdb, ltype, flags, off, len / 2); - if (ret == -1) - return -1; - - ret = tdb_chainlock_gradual(tdb, ltype, flags, - off + len / 2, len - len / 2); - if (ret == -1) { - tdb_brunlock(tdb, ltype, off, len / 2); - return -1; - } - return 0; -} - -/* lock/unlock entire database. It can only be upgradable if you have some - * other way of guaranteeing exclusivity (ie. transaction write lock). - * We do the locking gradually to avoid being starved by smaller locks. */ -int tdb_allrecord_lock(struct tdb_context *tdb, int ltype, - enum tdb_lock_flags flags, bool upgradable) -{ - switch (tdb_allrecord_check(tdb, ltype, flags, upgradable)) { - case -1: - return -1; - case 0: - return 0; - } - - /* We cover two kinds of locks: - * 1) Normal chain locks. Taken for almost all operations. - * 2) Individual records locks. Taken after normal or free - * chain locks. - * - * It is (1) which cause the starvation problem, so we're only - * gradual for that. */ - if (tdb_chainlock_gradual(tdb, ltype, flags, FREELIST_TOP, - tdb->header.hash_size * 4) == -1) { - return -1; - } - - /* Grab individual record locks. */ - if (tdb_brlock(tdb, ltype, lock_offset(tdb->header.hash_size), 0, - flags) == -1) { - tdb_brunlock(tdb, ltype, FREELIST_TOP, - tdb->header.hash_size * 4); - return -1; - } - - tdb->allrecord_lock.count = 1; - /* If it's upgradable, it's actually exclusive so we can treat - * it as a write lock. */ - tdb->allrecord_lock.ltype = upgradable ? F_WRLCK : ltype; - tdb->allrecord_lock.off = upgradable; - - if (tdb_needs_recovery(tdb)) { - bool mark = flags & TDB_LOCK_MARK_ONLY; - tdb_allrecord_unlock(tdb, ltype, mark); - if (mark) { - tdb->ecode = TDB_ERR_LOCK; - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "tdb_lockall_mark cannot do recovery\n")); - return -1; - } - if (tdb_lock_and_recover(tdb) == -1) { - return -1; - } - return tdb_allrecord_lock(tdb, ltype, flags, upgradable); - } - - return 0; -} - - - -/* unlock entire db */ -int tdb_allrecord_unlock(struct tdb_context *tdb, int ltype, bool mark_lock) -{ - /* There are no locks on read-only dbs */ - if (tdb->read_only || tdb->traverse_read) { - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - - if (tdb->allrecord_lock.count == 0) { - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - - /* Upgradable locks are marked as write locks. */ - if (tdb->allrecord_lock.ltype != ltype - && (!tdb->allrecord_lock.off || ltype != F_RDLCK)) { - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - - if (tdb->allrecord_lock.count > 1) { - tdb->allrecord_lock.count--; - return 0; - } - - if (!mark_lock && tdb_brunlock(tdb, ltype, FREELIST_TOP, 0)) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlockall failed (%s)\n", strerror(errno))); - return -1; - } - - tdb->allrecord_lock.count = 0; - tdb->allrecord_lock.ltype = 0; - - return 0; -} - -/* lock entire database with write lock */ -_PUBLIC_ int tdb_lockall(struct tdb_context *tdb) -{ - tdb_trace(tdb, "tdb_lockall"); - return tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_WAIT, false); -} - -/* lock entire database with write lock - mark only */ -_PUBLIC_ int tdb_lockall_mark(struct tdb_context *tdb) -{ - tdb_trace(tdb, "tdb_lockall_mark"); - return tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_MARK_ONLY, false); -} - -/* unlock entire database with write lock - unmark only */ -_PUBLIC_ int tdb_lockall_unmark(struct tdb_context *tdb) -{ - tdb_trace(tdb, "tdb_lockall_unmark"); - return tdb_allrecord_unlock(tdb, F_WRLCK, true); -} - -/* lock entire database with write lock - nonblocking varient */ -_PUBLIC_ int tdb_lockall_nonblock(struct tdb_context *tdb) -{ - int ret = tdb_allrecord_lock(tdb, F_WRLCK, TDB_LOCK_NOWAIT, false); - tdb_trace_ret(tdb, "tdb_lockall_nonblock", ret); - return ret; -} - -/* unlock entire database with write lock */ -_PUBLIC_ int tdb_unlockall(struct tdb_context *tdb) -{ - tdb_trace(tdb, "tdb_unlockall"); - return tdb_allrecord_unlock(tdb, F_WRLCK, false); -} - -/* lock entire database with read lock */ -_PUBLIC_ int tdb_lockall_read(struct tdb_context *tdb) -{ - tdb_trace(tdb, "tdb_lockall_read"); - return tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, false); -} - -/* lock entire database with read lock - nonblock varient */ -_PUBLIC_ int tdb_lockall_read_nonblock(struct tdb_context *tdb) -{ - int ret = tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_NOWAIT, false); - tdb_trace_ret(tdb, "tdb_lockall_read_nonblock", ret); - return ret; -} - -/* unlock entire database with read lock */ -_PUBLIC_ int tdb_unlockall_read(struct tdb_context *tdb) -{ - tdb_trace(tdb, "tdb_unlockall_read"); - return tdb_allrecord_unlock(tdb, F_RDLCK, false); -} - -/* lock/unlock one hash chain. This is meant to be used to reduce - contention - it cannot guarantee how many records will be locked */ -_PUBLIC_ int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key) -{ - int ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); - tdb_trace_1rec(tdb, "tdb_chainlock", key); - return ret; -} - -/* lock/unlock one hash chain, non-blocking. This is meant to be used - to reduce contention - it cannot guarantee how many records will be - locked */ -_PUBLIC_ int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key) -{ - int ret = tdb_lock_nonblock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); - tdb_trace_1rec_ret(tdb, "tdb_chainlock_nonblock", key, ret); - return ret; -} - -/* mark a chain as locked without actually locking it. Warning! use with great caution! */ -_PUBLIC_ int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key) -{ - int ret = tdb_nest_lock(tdb, lock_offset(BUCKET(tdb->hash_fn(&key))), - F_WRLCK, TDB_LOCK_MARK_ONLY); - tdb_trace_1rec(tdb, "tdb_chainlock_mark", key); - return ret; -} - -/* unmark a chain as locked without actually locking it. Warning! use with great caution! */ -_PUBLIC_ int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key) -{ - tdb_trace_1rec(tdb, "tdb_chainlock_unmark", key); - return tdb_nest_unlock(tdb, lock_offset(BUCKET(tdb->hash_fn(&key))), - F_WRLCK, true); -} - -_PUBLIC_ int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key) -{ - tdb_trace_1rec(tdb, "tdb_chainunlock", key); - return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_WRLCK); -} - -_PUBLIC_ int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key) -{ - int ret; - ret = tdb_lock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK); - tdb_trace_1rec(tdb, "tdb_chainlock_read", key); - return ret; -} - -_PUBLIC_ int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key) -{ - tdb_trace_1rec(tdb, "tdb_chainunlock_read", key); - return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK); -} - -/* record lock stops delete underneath */ -int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off) -{ - if (tdb->allrecord_lock.count) { - return 0; - } - return off ? tdb_brlock(tdb, F_RDLCK, off, 1, TDB_LOCK_WAIT) : 0; -} - -/* - Write locks override our own fcntl readlocks, so check it here. - Note this is meant to be F_SETLK, *not* F_SETLKW, as it's not - an error to fail to get the lock here. -*/ -int tdb_write_lock_record(struct tdb_context *tdb, tdb_off_t off) -{ - struct tdb_traverse_lock *i; - for (i = &tdb->travlocks; i; i = i->next) - if (i->off == off) - return -1; - if (tdb->allrecord_lock.count) { - if (tdb->allrecord_lock.ltype == F_WRLCK) { - return 0; - } - return -1; - } - return tdb_brlock(tdb, F_WRLCK, off, 1, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE); -} - -int tdb_write_unlock_record(struct tdb_context *tdb, tdb_off_t off) -{ - if (tdb->allrecord_lock.count) { - return 0; - } - return tdb_brunlock(tdb, F_WRLCK, off, 1); -} - -/* fcntl locks don't stack: avoid unlocking someone else's */ -int tdb_unlock_record(struct tdb_context *tdb, tdb_off_t off) -{ - struct tdb_traverse_lock *i; - uint32_t count = 0; - - if (tdb->allrecord_lock.count) { - return 0; - } - - if (off == 0) - return 0; - for (i = &tdb->travlocks; i; i = i->next) - if (i->off == off) - count++; - return (count == 1 ? tdb_brunlock(tdb, F_RDLCK, off, 1) : 0); -} - -bool tdb_have_extra_locks(struct tdb_context *tdb) -{ - unsigned int extra = tdb->num_lockrecs; - - /* A transaction holds the lock for all records. */ - if (!tdb->transaction && tdb->allrecord_lock.count) { - return true; - } - - /* We always hold the active lock if CLEAR_IF_FIRST. */ - if (find_nestlock(tdb, ACTIVE_LOCK)) { - extra--; - } - - /* In a transaction, we expect to hold the transaction lock */ - if (tdb->transaction && find_nestlock(tdb, TRANSACTION_LOCK)) { - extra--; - } - - return extra; -} - -/* The transaction code uses this to remove all locks. */ -void tdb_release_transaction_locks(struct tdb_context *tdb) -{ - unsigned int i, active = 0; - - if (tdb->allrecord_lock.count != 0) { - tdb_brunlock(tdb, tdb->allrecord_lock.ltype, FREELIST_TOP, 0); - tdb->allrecord_lock.count = 0; - } - - for (i=0;inum_lockrecs;i++) { - struct tdb_lock_type *lck = &tdb->lockrecs[i]; - - /* Don't release the active lock! Copy it to first entry. */ - if (lck->off == ACTIVE_LOCK) { - tdb->lockrecs[active++] = *lck; - } else { - tdb_brunlock(tdb, lck->ltype, lck->off, 1); - } - } - tdb->num_lockrecs = active; - if (tdb->num_lockrecs == 0) { - SAFE_FREE(tdb->lockrecs); - } -} - -/* Following functions are added specifically to support CTDB. */ - -/* Don't do actual fcntl locking, just mark tdb locked */ -_PUBLIC_ int tdb_transaction_write_lock_mark(struct tdb_context *tdb) -{ - return tdb_transaction_lock(tdb, F_WRLCK, TDB_LOCK_MARK_ONLY); -} - -/* Don't do actual fcntl unlocking, just mark tdb unlocked */ -_PUBLIC_ int tdb_transaction_write_lock_unmark(struct tdb_context *tdb) -{ - return tdb_nest_unlock(tdb, TRANSACTION_LOCK, F_WRLCK, true); -} diff --git a/ctdb/lib/tdb/common/open.c b/ctdb/lib/tdb/common/open.c deleted file mode 100644 index d9f76f083503..000000000000 --- a/ctdb/lib/tdb/common/open.c +++ /dev/null @@ -1,671 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 1999-2005 - Copyright (C) Paul `Rusty' Russell 2000 - Copyright (C) Jeremy Allison 2000-2003 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ - -#include "tdb_private.h" - -/* all contexts, to ensure no double-opens (fcntl locks don't nest!) */ -static struct tdb_context *tdbs = NULL; - -/* We use two hashes to double-check they're using the right hash function. */ -void tdb_header_hash(struct tdb_context *tdb, - uint32_t *magic1_hash, uint32_t *magic2_hash) -{ - TDB_DATA hash_key; - uint32_t tdb_magic = TDB_MAGIC; - - hash_key.dptr = discard_const_p(unsigned char, TDB_MAGIC_FOOD); - hash_key.dsize = sizeof(TDB_MAGIC_FOOD); - *magic1_hash = tdb->hash_fn(&hash_key); - - hash_key.dptr = (unsigned char *)CONVERT(tdb_magic); - hash_key.dsize = sizeof(tdb_magic); - *magic2_hash = tdb->hash_fn(&hash_key); - - /* Make sure at least one hash is non-zero! */ - if (*magic1_hash == 0 && *magic2_hash == 0) - *magic1_hash = 1; -} - -/* initialise a new database with a specified hash size */ -static int tdb_new_database(struct tdb_context *tdb, int hash_size) -{ - struct tdb_header *newdb; - size_t size; - int ret = -1; - - /* We make it up in memory, then write it out if not internal */ - size = sizeof(struct tdb_header) + (hash_size+1)*sizeof(tdb_off_t); - if (!(newdb = (struct tdb_header *)calloc(size, 1))) { - tdb->ecode = TDB_ERR_OOM; - return -1; - } - - /* Fill in the header */ - newdb->version = TDB_VERSION; - newdb->hash_size = hash_size; - - tdb_header_hash(tdb, &newdb->magic1_hash, &newdb->magic2_hash); - - /* Make sure older tdbs (which don't check the magic hash fields) - * will refuse to open this TDB. */ - if (tdb->flags & TDB_INCOMPATIBLE_HASH) - newdb->rwlocks = TDB_HASH_RWLOCK_MAGIC; - - if (tdb->flags & TDB_INTERNAL) { - tdb->map_size = size; - tdb->map_ptr = (char *)newdb; - memcpy(&tdb->header, newdb, sizeof(tdb->header)); - /* Convert the `ondisk' version if asked. */ - CONVERT(*newdb); - return 0; - } - if (lseek(tdb->fd, 0, SEEK_SET) == -1) - goto fail; - - if (ftruncate(tdb->fd, 0) == -1) - goto fail; - - /* This creates an endian-converted header, as if read from disk */ - CONVERT(*newdb); - memcpy(&tdb->header, newdb, sizeof(tdb->header)); - /* Don't endian-convert the magic food! */ - memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1); - /* we still have "ret == -1" here */ - if (tdb_write_all(tdb->fd, newdb, size)) - ret = 0; - - fail: - SAFE_FREE(newdb); - return ret; -} - - - -static int tdb_already_open(dev_t device, - ino_t ino) -{ - struct tdb_context *i; - - for (i = tdbs; i; i = i->next) { - if (i->device == device && i->inode == ino) { - return 1; - } - } - - return 0; -} - -/* open the database, creating it if necessary - - The open_flags and mode are passed straight to the open call on the - database file. A flags value of O_WRONLY is invalid. The hash size - is advisory, use zero for a default value. - - Return is NULL on error, in which case errno is also set. Don't - try to call tdb_error or tdb_errname, just do strerror(errno). - - @param name may be NULL for internal databases. */ -_PUBLIC_ struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags, - int open_flags, mode_t mode) -{ - return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, NULL, NULL); -} - -/* a default logging function */ -static void null_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4); -static void null_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) -{ -} - -static bool check_header_hash(struct tdb_context *tdb, - bool default_hash, uint32_t *m1, uint32_t *m2) -{ - tdb_header_hash(tdb, m1, m2); - if (tdb->header.magic1_hash == *m1 && - tdb->header.magic2_hash == *m2) { - return true; - } - - /* If they explicitly set a hash, always respect it. */ - if (!default_hash) - return false; - - /* Otherwise, try the other inbuilt hash. */ - if (tdb->hash_fn == tdb_old_hash) - tdb->hash_fn = tdb_jenkins_hash; - else - tdb->hash_fn = tdb_old_hash; - return check_header_hash(tdb, false, m1, m2); -} - -_PUBLIC_ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags, - int open_flags, mode_t mode, - const struct tdb_logging_context *log_ctx, - tdb_hash_func hash_fn) -{ - struct tdb_context *tdb; - struct stat st; - int rev = 0, locked = 0; - unsigned char *vp; - uint32_t vertest; - unsigned v; - const char *hash_alg; - uint32_t magic1, magic2; - - if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) { - /* Can't log this */ - errno = ENOMEM; - goto fail; - } - tdb_io_init(tdb); - tdb->fd = -1; -#ifdef TDB_TRACE - tdb->tracefd = -1; -#endif - tdb->name = NULL; - tdb->map_ptr = NULL; - tdb->flags = tdb_flags; - tdb->open_flags = open_flags; - if (log_ctx) { - tdb->log = *log_ctx; - } else { - tdb->log.log_fn = null_log_fn; - tdb->log.log_private = NULL; - } - - if (name == NULL && (tdb_flags & TDB_INTERNAL)) { - name = "__TDB_INTERNAL__"; - } - - if (name == NULL) { - tdb->name = discard_const_p(char, "__NULL__"); - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: called with name == NULL\n")); - tdb->name = NULL; - errno = EINVAL; - goto fail; - } - - /* now make a copy of the name, as the caller memory might went away */ - if (!(tdb->name = (char *)strdup(name))) { - /* - * set the name as the given string, so that tdb_name() will - * work in case of an error. - */ - tdb->name = discard_const_p(char, name); - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: can't strdup(%s)\n", - name)); - tdb->name = NULL; - errno = ENOMEM; - goto fail; - } - - if (hash_fn) { - tdb->hash_fn = hash_fn; - hash_alg = "the user defined"; - } else { - /* This controls what we use when creating a tdb. */ - if (tdb->flags & TDB_INCOMPATIBLE_HASH) { - tdb->hash_fn = tdb_jenkins_hash; - } else { - tdb->hash_fn = tdb_old_hash; - } - hash_alg = "either default"; - } - - /* cache the page size */ - tdb->page_size = getpagesize(); - if (tdb->page_size <= 0) { - tdb->page_size = 0x2000; - } - - tdb->max_dead_records = (tdb_flags & TDB_VOLATILE) ? 5 : 0; - - if ((open_flags & O_ACCMODE) == O_WRONLY) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: can't open tdb %s write-only\n", - name)); - errno = EINVAL; - goto fail; - } - - if (hash_size == 0) - hash_size = DEFAULT_HASH_SIZE; - if ((open_flags & O_ACCMODE) == O_RDONLY) { - tdb->read_only = 1; - /* read only databases don't do locking or clear if first */ - tdb->flags |= TDB_NOLOCK; - tdb->flags &= ~TDB_CLEAR_IF_FIRST; - } - - if ((tdb->flags & TDB_ALLOW_NESTING) && - (tdb->flags & TDB_DISALLOW_NESTING)) { - tdb->ecode = TDB_ERR_NESTING; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: " - "allow_nesting and disallow_nesting are not allowed together!")); - errno = EINVAL; - goto fail; - } - - if (getenv("TDB_NO_FSYNC")) { - tdb->flags |= TDB_NOSYNC; - } - - /* - * TDB_ALLOW_NESTING is the default behavior. - * Note: this may change in future versions! - */ - if (!(tdb->flags & TDB_DISALLOW_NESTING)) { - tdb->flags |= TDB_ALLOW_NESTING; - } - - /* internal databases don't mmap or lock, and start off cleared */ - if (tdb->flags & TDB_INTERNAL) { - tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP); - tdb->flags &= ~TDB_CLEAR_IF_FIRST; - if (tdb_new_database(tdb, hash_size) != 0) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: tdb_new_database failed!")); - goto fail; - } - goto internal; - } - - if ((tdb->fd = open(name, open_flags, mode)) == -1) { - TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_open_ex: could not open file %s: %s\n", - name, strerror(errno))); - goto fail; /* errno set by open(2) */ - } - - /* on exec, don't inherit the fd */ - v = fcntl(tdb->fd, F_GETFD, 0); - fcntl(tdb->fd, F_SETFD, v | FD_CLOEXEC); - - /* ensure there is only one process initialising at once */ - if (tdb_nest_lock(tdb, OPEN_LOCK, F_WRLCK, TDB_LOCK_WAIT) == -1) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get open lock on %s: %s\n", - name, strerror(errno))); - goto fail; /* errno set by tdb_brlock */ - } - - /* we need to zero database if we are the only one with it open */ - if ((tdb_flags & TDB_CLEAR_IF_FIRST) && - (!tdb->read_only) && - (locked = (tdb_nest_lock(tdb, ACTIVE_LOCK, F_WRLCK, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE) == 0))) { - int ret; - ret = tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0, - TDB_LOCK_WAIT); - if (ret == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: " - "tdb_brlock failed for %s: %s\n", - name, strerror(errno))); - goto fail; - } - ret = tdb_new_database(tdb, hash_size); - if (ret == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: " - "tdb_new_database failed for %s: %s\n", - name, strerror(errno))); - tdb_unlockall(tdb); - goto fail; - } - ret = tdb_brunlock(tdb, F_WRLCK, FREELIST_TOP, 0); - if (ret == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: " - "tdb_unlockall failed for %s: %s\n", - name, strerror(errno))); - goto fail; - } - ret = lseek(tdb->fd, 0, SEEK_SET); - if (ret == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: " - "lseek failed for %s: %s\n", - name, strerror(errno))); - goto fail; - } - } - - errno = 0; - if (read(tdb->fd, &tdb->header, sizeof(tdb->header)) != sizeof(tdb->header) - || strcmp(tdb->header.magic_food, TDB_MAGIC_FOOD) != 0) { - if (!(open_flags & O_CREAT) || tdb_new_database(tdb, hash_size) == -1) { - if (errno == 0) { - errno = EIO; /* ie bad format or something */ - } - goto fail; - } - rev = (tdb->flags & TDB_CONVERT); - } else if (tdb->header.version != TDB_VERSION - && !(rev = (tdb->header.version==TDB_BYTEREV(TDB_VERSION)))) { - /* wrong version */ - errno = EIO; - goto fail; - } - vp = (unsigned char *)&tdb->header.version; - vertest = (((uint32_t)vp[0]) << 24) | (((uint32_t)vp[1]) << 16) | - (((uint32_t)vp[2]) << 8) | (uint32_t)vp[3]; - tdb->flags |= (vertest==TDB_VERSION) ? TDB_BIGENDIAN : 0; - if (!rev) - tdb->flags &= ~TDB_CONVERT; - else { - tdb->flags |= TDB_CONVERT; - tdb_convert(&tdb->header, sizeof(tdb->header)); - } - if (fstat(tdb->fd, &st) == -1) - goto fail; - - if (tdb->header.rwlocks != 0 && - tdb->header.rwlocks != TDB_HASH_RWLOCK_MAGIC) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: spinlocks no longer supported\n")); - goto fail; - } - - if ((tdb->header.magic1_hash == 0) && (tdb->header.magic2_hash == 0)) { - /* older TDB without magic hash references */ - tdb->hash_fn = tdb_old_hash; - } else if (!check_header_hash(tdb, !hash_fn, &magic1, &magic2)) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: " - "%s was not created with %s hash function we are using\n" - "magic1_hash[0x%08X %s 0x%08X] " - "magic2_hash[0x%08X %s 0x%08X]\n", - name, hash_alg, - tdb->header.magic1_hash, - (tdb->header.magic1_hash == magic1) ? "==" : "!=", - magic1, - tdb->header.magic2_hash, - (tdb->header.magic2_hash == magic2) ? "==" : "!=", - magic2)); - errno = EINVAL; - goto fail; - } - - /* Is it already in the open list? If so, fail. */ - if (tdb_already_open(st.st_dev, st.st_ino)) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: " - "%s (%d,%d) is already open in this process\n", - name, (int)st.st_dev, (int)st.st_ino)); - errno = EBUSY; - goto fail; - } - - /* Beware truncation! */ - tdb->map_size = st.st_size; - if (tdb->map_size != st.st_size) { - /* Ensure ecode is set for log fn. */ - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: " - "len %llu too large!\n", (long long)st.st_size)); - errno = EIO; - goto fail; - } - - tdb->device = st.st_dev; - tdb->inode = st.st_ino; - tdb_mmap(tdb); - if (locked) { - if (tdb_nest_unlock(tdb, ACTIVE_LOCK, F_WRLCK, false) == -1) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: " - "failed to release ACTIVE_LOCK on %s: %s\n", - name, strerror(errno))); - goto fail; - } - - } - - /* We always need to do this if the CLEAR_IF_FIRST flag is set, even if - we didn't get the initial exclusive lock as we need to let all other - users know we're using it. */ - - if (tdb_flags & TDB_CLEAR_IF_FIRST) { - /* leave this lock in place to indicate it's in use */ - if (tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) { - goto fail; - } - } - - /* if needed, run recovery */ - if (tdb_transaction_recover(tdb) == -1) { - goto fail; - } - -#ifdef TDB_TRACE - { - char tracefile[strlen(name) + 32]; - - snprintf(tracefile, sizeof(tracefile), - "%s.trace.%li", name, (long)getpid()); - tdb->tracefd = open(tracefile, O_WRONLY|O_CREAT|O_EXCL, 0600); - if (tdb->tracefd >= 0) { - tdb_enable_seqnum(tdb); - tdb_trace_open(tdb, "tdb_open", hash_size, tdb_flags, - open_flags); - } else - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to open trace file %s!\n", tracefile)); - } -#endif - - internal: - /* Internal (memory-only) databases skip all the code above to - * do with disk files, and resume here by releasing their - * open lock and hooking into the active list. */ - if (tdb_nest_unlock(tdb, OPEN_LOCK, F_WRLCK, false) == -1) { - goto fail; - } - tdb->next = tdbs; - tdbs = tdb; - return tdb; - - fail: - { int save_errno = errno; - - if (!tdb) - return NULL; - -#ifdef TDB_TRACE - close(tdb->tracefd); -#endif - if (tdb->map_ptr) { - if (tdb->flags & TDB_INTERNAL) - SAFE_FREE(tdb->map_ptr); - else - tdb_munmap(tdb); - } - if (tdb->fd != -1) - if (close(tdb->fd) != 0) - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n")); - SAFE_FREE(tdb->lockrecs); - SAFE_FREE(tdb->name); - SAFE_FREE(tdb); - errno = save_errno; - return NULL; - } -} - -/* - * Set the maximum number of dead records per hash chain - */ - -_PUBLIC_ void tdb_set_max_dead(struct tdb_context *tdb, int max_dead) -{ - tdb->max_dead_records = max_dead; -} - -/** - * Close a database. - * - * @returns -1 for error; 0 for success. - **/ -_PUBLIC_ int tdb_close(struct tdb_context *tdb) -{ - struct tdb_context **i; - int ret = 0; - - if (tdb->transaction) { - tdb_transaction_cancel(tdb); - } - tdb_trace(tdb, "tdb_close"); - - if (tdb->map_ptr) { - if (tdb->flags & TDB_INTERNAL) - SAFE_FREE(tdb->map_ptr); - else - tdb_munmap(tdb); - } - SAFE_FREE(tdb->name); - if (tdb->fd != -1) { - ret = close(tdb->fd); - tdb->fd = -1; - } - SAFE_FREE(tdb->lockrecs); - - /* Remove from contexts list */ - for (i = &tdbs; *i; i = &(*i)->next) { - if (*i == tdb) { - *i = tdb->next; - break; - } - } - -#ifdef TDB_TRACE - close(tdb->tracefd); -#endif - memset(tdb, 0, sizeof(*tdb)); - SAFE_FREE(tdb); - - return ret; -} - -/* register a loging function */ -_PUBLIC_ void tdb_set_logging_function(struct tdb_context *tdb, - const struct tdb_logging_context *log_ctx) -{ - tdb->log = *log_ctx; -} - -_PUBLIC_ void *tdb_get_logging_private(struct tdb_context *tdb) -{ - return tdb->log.log_private; -} - -static int tdb_reopen_internal(struct tdb_context *tdb, bool active_lock) -{ -#if !defined(LIBREPLACE_PREAD_NOT_REPLACED) || \ - !defined(LIBREPLACE_PWRITE_NOT_REPLACED) - struct stat st; -#endif - - if (tdb->flags & TDB_INTERNAL) { - return 0; /* Nothing to do. */ - } - - if (tdb_have_extra_locks(tdb)) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed with locks held\n")); - goto fail; - } - - if (tdb->transaction != 0) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed inside a transaction\n")); - goto fail; - } - -/* If we have real pread & pwrite, we can skip reopen. */ -#if !defined(LIBREPLACE_PREAD_NOT_REPLACED) || \ - !defined(LIBREPLACE_PWRITE_NOT_REPLACED) - if (tdb_munmap(tdb) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: munmap failed (%s)\n", strerror(errno))); - goto fail; - } - if (close(tdb->fd) != 0) - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: WARNING closing tdb->fd failed!\n")); - tdb->fd = open(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0); - if (tdb->fd == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: open failed (%s)\n", strerror(errno))); - goto fail; - } - if (fstat(tdb->fd, &st) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: fstat failed (%s)\n", strerror(errno))); - goto fail; - } - if (st.st_ino != tdb->inode || st.st_dev != tdb->device) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: file dev/inode has changed!\n")); - goto fail; - } - if (tdb_mmap(tdb) != 0) { - goto fail; - } -#endif /* fake pread or pwrite */ - - /* We may still think we hold the active lock. */ - tdb->num_lockrecs = 0; - SAFE_FREE(tdb->lockrecs); - - if (active_lock && tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: failed to obtain active lock\n")); - goto fail; - } - - return 0; - -fail: - tdb_close(tdb); - return -1; -} - -/* reopen a tdb - this can be used after a fork to ensure that we have an independent - seek pointer from our parent and to re-establish locks */ -_PUBLIC_ int tdb_reopen(struct tdb_context *tdb) -{ - return tdb_reopen_internal(tdb, tdb->flags & TDB_CLEAR_IF_FIRST); -} - -/* reopen all tdb's */ -_PUBLIC_ int tdb_reopen_all(int parent_longlived) -{ - struct tdb_context *tdb; - - for (tdb=tdbs; tdb; tdb = tdb->next) { - bool active_lock = (tdb->flags & TDB_CLEAR_IF_FIRST); - - /* - * If the parent is longlived (ie. a - * parent daemon architecture), we know - * it will keep it's active lock on a - * tdb opened with CLEAR_IF_FIRST. Thus - * for child processes we don't have to - * add an active lock. This is essential - * to improve performance on systems that - * keep POSIX locks as a non-scalable data - * structure in the kernel. - */ - if (parent_longlived) { - /* Ensure no clear-if-first. */ - active_lock = false; - } - - if (tdb_reopen_internal(tdb, active_lock) != 0) - return -1; - } - - return 0; -} diff --git a/ctdb/lib/tdb/common/rescue.c b/ctdb/lib/tdb/common/rescue.c deleted file mode 100644 index 03ae8d6ae51b..000000000000 --- a/ctdb/lib/tdb/common/rescue.c +++ /dev/null @@ -1,349 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library, rescue attempt code. - - Copyright (C) Rusty Russell 2012 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ -#include "tdb_private.h" -#include - - -struct found { - tdb_off_t head; /* 0 -> invalid. */ - struct tdb_record rec; - TDB_DATA key; - bool in_hash; - bool in_free; -}; - -struct found_table { - /* As an ordered array (by head offset). */ - struct found *arr; - unsigned int num, max; -}; - -static bool looks_like_valid_record(struct tdb_context *tdb, - tdb_off_t off, - const struct tdb_record *rec, - TDB_DATA *key) -{ - unsigned int hval; - - if (rec->magic != TDB_MAGIC) - return false; - - if (rec->key_len + rec->data_len > rec->rec_len) - return false; - - if (rec->rec_len % TDB_ALIGNMENT) - return false; - - /* Next pointer must make some sense. */ - if (rec->next > 0 && rec->next < TDB_DATA_START(tdb->header.hash_size)) - return false; - - if (tdb->methods->tdb_oob(tdb, rec->next, sizeof(*rec), 1)) - return false; - - key->dsize = rec->key_len; - key->dptr = tdb_alloc_read(tdb, off + sizeof(*rec), key->dsize); - if (!key->dptr) - return false; - - hval = tdb->hash_fn(key); - if (hval != rec->full_hash) { - free(key->dptr); - return false; - } - - /* Caller frees up key->dptr */ - return true; -} - -static bool add_to_table(struct found_table *found, - tdb_off_t off, - struct tdb_record *rec, - TDB_DATA key) -{ - if (found->num + 1 > found->max) { - struct found *new; - found->max = (found->max ? found->max * 2 : 128); - new = realloc(found->arr, found->max * sizeof(found->arr[0])); - if (!new) - return false; - found->arr = new; - } - - found->arr[found->num].head = off; - found->arr[found->num].rec = *rec; - found->arr[found->num].key = key; - found->arr[found->num].in_hash = false; - found->arr[found->num].in_free = false; - - found->num++; - return true; -} - -static bool walk_record(struct tdb_context *tdb, - const struct found *f, - void (*walk)(TDB_DATA, TDB_DATA, void *private_data), - void *private_data) -{ - TDB_DATA data; - - data.dsize = f->rec.data_len; - data.dptr = tdb_alloc_read(tdb, - f->head + sizeof(f->rec) + f->rec.key_len, - data.dsize); - if (!data.dptr) { - if (tdb->ecode == TDB_ERR_OOM) - return false; - /* I/O errors are expected. */ - return true; - } - - walk(f->key, data, private_data); - free(data.dptr); - return true; -} - -/* First entry which has offset >= this one. */ -static unsigned int find_entry(struct found_table *found, tdb_off_t off) -{ - unsigned int start = 0, end = found->num; - - while (start < end) { - /* We can't overflow here. */ - unsigned int mid = (start + end) / 2; - - if (off < found->arr[mid].head) { - end = mid; - } else if (off > found->arr[mid].head) { - start = mid + 1; - } else { - return mid; - } - } - - assert(start == end); - return end; -} - -static void found_in_hashchain(struct found_table *found, tdb_off_t head) -{ - unsigned int match; - - match = find_entry(found, head); - if (match < found->num && found->arr[match].head == head) { - found->arr[match].in_hash = true; - } -} - -static void mark_free_area(struct found_table *found, tdb_off_t head, - tdb_len_t len) -{ - unsigned int match; - - match = find_entry(found, head); - /* Mark everything within this free entry. */ - while (match < found->num) { - if (found->arr[match].head >= head + len) { - break; - } - found->arr[match].in_free = true; - match++; - } -} - -static int cmp_key(const void *a, const void *b) -{ - const struct found *fa = a, *fb = b; - - if (fa->key.dsize < fb->key.dsize) { - return -1; - } else if (fa->key.dsize > fb->key.dsize) { - return 1; - } - return memcmp(fa->key.dptr, fb->key.dptr, fa->key.dsize); -} - -static bool key_eq(TDB_DATA a, TDB_DATA b) -{ - return a.dsize == b.dsize - && memcmp(a.dptr, b.dptr, a.dsize) == 0; -} - -static void free_table(struct found_table *found) -{ - unsigned int i; - - for (i = 0; i < found->num; i++) { - free(found->arr[i].key.dptr); - } - free(found->arr); -} - -static void logging_suppressed(struct tdb_context *tdb, - enum tdb_debug_level level, const char *fmt, ...) -{ -} - -_PUBLIC_ int tdb_rescue(struct tdb_context *tdb, - void (*walk)(TDB_DATA, TDB_DATA, void *private_data), - void *private_data) -{ - struct found_table found = { NULL, 0, 0 }; - tdb_off_t h, off, i; - tdb_log_func oldlog = tdb->log.log_fn; - struct tdb_record rec; - TDB_DATA key; - bool locked; - - /* Read-only databases use no locking at all: it's best-effort. - * We may have a write lock already, so skip that case too. */ - if (tdb->read_only || tdb->allrecord_lock.count != 0) { - locked = false; - } else { - if (tdb_lockall_read(tdb) == -1) - return -1; - locked = true; - } - - /* Make sure we know true size of the underlying file. */ - tdb->methods->tdb_oob(tdb, tdb->map_size, 1, 1); - - /* Suppress logging, since we anticipate errors. */ - tdb->log.log_fn = logging_suppressed; - - /* Now walk entire db looking for records. */ - for (off = TDB_DATA_START(tdb->header.hash_size); - off < tdb->map_size; - off += TDB_ALIGNMENT) { - if (tdb->methods->tdb_read(tdb, off, &rec, sizeof(rec), - DOCONV()) == -1) - continue; - - if (looks_like_valid_record(tdb, off, &rec, &key)) { - if (!add_to_table(&found, off, &rec, key)) { - goto oom; - } - } - } - - /* Walk hash chains to positive vet. */ - for (h = 0; h < 1+tdb->header.hash_size; h++) { - bool slow_chase = false; - tdb_off_t slow_off = FREELIST_TOP + h*sizeof(tdb_off_t); - - if (tdb_ofs_read(tdb, FREELIST_TOP + h*sizeof(tdb_off_t), - &off) == -1) - continue; - - while (off && off != slow_off) { - if (tdb->methods->tdb_read(tdb, off, &rec, sizeof(rec), - DOCONV()) != 0) { - break; - } - - /* 0 is the free list, rest are hash chains. */ - if (h == 0) { - /* Don't mark garbage as free. */ - if (rec.magic != TDB_FREE_MAGIC) { - break; - } - mark_free_area(&found, off, - sizeof(rec) + rec.rec_len); - } else { - found_in_hashchain(&found, off); - } - - off = rec.next; - - /* Loop detection using second pointer at half-speed */ - if (slow_chase) { - /* First entry happens to be next ptr */ - tdb_ofs_read(tdb, slow_off, &slow_off); - } - slow_chase = !slow_chase; - } - } - - /* Recovery area: must be marked as free, since it often has old - * records in there! */ - if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &off) == 0 && off != 0) { - if (tdb->methods->tdb_read(tdb, off, &rec, sizeof(rec), - DOCONV()) == 0) { - mark_free_area(&found, off, sizeof(rec) + rec.rec_len); - } - } - - /* Now sort by key! */ - qsort(found.arr, found.num, sizeof(found.arr[0]), cmp_key); - - for (i = 0; i < found.num; ) { - unsigned int num, num_in_hash = 0; - - /* How many are identical? */ - for (num = 0; num < found.num - i; num++) { - if (!key_eq(found.arr[i].key, found.arr[i+num].key)) { - break; - } - if (found.arr[i+num].in_hash) { - if (!walk_record(tdb, &found.arr[i+num], - walk, private_data)) - goto oom; - num_in_hash++; - } - } - assert(num); - - /* If none were in the hash, we print any not in free list. */ - if (num_in_hash == 0) { - unsigned int j; - - for (j = i; j < i + num; j++) { - if (!found.arr[j].in_free) { - if (!walk_record(tdb, &found.arr[j], - walk, private_data)) - goto oom; - } - } - } - - i += num; - } - - tdb->log.log_fn = oldlog; - if (locked) { - tdb_unlockall_read(tdb); - } - return 0; - -oom: - tdb->log.log_fn = oldlog; - tdb->ecode = TDB_ERR_OOM; - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_rescue: failed allocating\n")); - free_table(&found); - if (locked) { - tdb_unlockall_read(tdb); - } - return -1; -} diff --git a/ctdb/lib/tdb/common/summary.c b/ctdb/lib/tdb/common/summary.c deleted file mode 100644 index 171a1a205543..000000000000 --- a/ctdb/lib/tdb/common/summary.c +++ /dev/null @@ -1,201 +0,0 @@ - /* - Trivial Database: human-readable summary code - Copyright (C) Rusty Russell 2010 - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ -#include "tdb_private.h" - -#define SUMMARY_FORMAT \ - "Size of file/data: %u/%zu\n" \ - "Number of records: %zu\n" \ - "Smallest/average/largest keys: %zu/%zu/%zu\n" \ - "Smallest/average/largest data: %zu/%zu/%zu\n" \ - "Smallest/average/largest padding: %zu/%zu/%zu\n" \ - "Number of dead records: %zu\n" \ - "Smallest/average/largest dead records: %zu/%zu/%zu\n" \ - "Number of free records: %zu\n" \ - "Smallest/average/largest free records: %zu/%zu/%zu\n" \ - "Number of hash chains: %zu\n" \ - "Smallest/average/largest hash chains: %zu/%zu/%zu\n" \ - "Number of uncoalesced records: %zu\n" \ - "Smallest/average/largest uncoalesced runs: %zu/%zu/%zu\n" \ - "Percentage keys/data/padding/free/dead/rechdrs&tailers/hashes: %.0f/%.0f/%.0f/%.0f/%.0f/%.0f/%.0f\n" - -/* We don't use tally module, to keep upstream happy. */ -struct tally { - size_t min, max, total; - size_t num; -}; - -static void tally_init(struct tally *tally) -{ - tally->total = 0; - tally->num = 0; - tally->min = tally->max = 0; -} - -static void tally_add(struct tally *tally, size_t len) -{ - if (tally->num == 0) - tally->max = tally->min = len; - else if (len > tally->max) - tally->max = len; - else if (len < tally->min) - tally->min = len; - tally->num++; - tally->total += len; -} - -static size_t tally_mean(const struct tally *tally) -{ - if (!tally->num) - return 0; - return tally->total / tally->num; -} - -static size_t get_hash_length(struct tdb_context *tdb, unsigned int i) -{ - tdb_off_t rec_ptr; - size_t count = 0; - - if (tdb_ofs_read(tdb, TDB_HASH_TOP(i), &rec_ptr) == -1) - return 0; - - /* keep looking until we find the right record */ - while (rec_ptr) { - struct tdb_record r; - ++count; - if (tdb_rec_read(tdb, rec_ptr, &r) == -1) - return 0; - rec_ptr = r.next; - } - return count; -} - -_PUBLIC_ char *tdb_summary(struct tdb_context *tdb) -{ - tdb_off_t off, rec_off; - struct tally freet, keys, data, dead, extra, hash, uncoal; - struct tdb_record rec; - char *ret = NULL; - bool locked; - size_t len, unc = 0; - struct tdb_record recovery; - - /* Read-only databases use no locking at all: it's best-effort. - * We may have a write lock already, so skip that case too. */ - if (tdb->read_only || tdb->allrecord_lock.count != 0) { - locked = false; - } else { - if (tdb_lockall_read(tdb) == -1) - return NULL; - locked = true; - } - - if (tdb_recovery_area(tdb, tdb->methods, &rec_off, &recovery) != 0) { - goto unlock; - } - - tally_init(&freet); - tally_init(&keys); - tally_init(&data); - tally_init(&dead); - tally_init(&extra); - tally_init(&hash); - tally_init(&uncoal); - - for (off = TDB_DATA_START(tdb->header.hash_size); - off < tdb->map_size - 1; - off += sizeof(rec) + rec.rec_len) { - if (tdb->methods->tdb_read(tdb, off, &rec, sizeof(rec), - DOCONV()) == -1) - goto unlock; - switch (rec.magic) { - case TDB_MAGIC: - tally_add(&keys, rec.key_len); - tally_add(&data, rec.data_len); - tally_add(&extra, rec.rec_len - (rec.key_len - + rec.data_len)); - if (unc > 1) - tally_add(&uncoal, unc - 1); - unc = 0; - break; - case TDB_FREE_MAGIC: - tally_add(&freet, rec.rec_len); - unc++; - break; - /* If we crash after ftruncate, we can get zeroes or fill. */ - case TDB_RECOVERY_INVALID_MAGIC: - case 0x42424242: - unc++; - /* If it's a valid recovery, we can trust rec_len. */ - if (off != rec_off) { - rec.rec_len = tdb_dead_space(tdb, off) - - sizeof(rec); - } - /* Fall through */ - case TDB_DEAD_MAGIC: - tally_add(&dead, rec.rec_len); - break; - default: - TDB_LOG((tdb, TDB_DEBUG_ERROR, - "Unexpected record magic 0x%x at offset %d\n", - rec.magic, off)); - goto unlock; - } - } - if (unc > 1) - tally_add(&uncoal, unc - 1); - - for (off = 0; off < tdb->header.hash_size; off++) - tally_add(&hash, get_hash_length(tdb, off)); - - /* 20 is max length of a %zu. */ - len = strlen(SUMMARY_FORMAT) + 35*20 + 1; - ret = (char *)malloc(len); - if (!ret) - goto unlock; - - snprintf(ret, len, SUMMARY_FORMAT, - tdb->map_size, keys.total+data.total, - keys.num, - keys.min, tally_mean(&keys), keys.max, - data.min, tally_mean(&data), data.max, - extra.min, tally_mean(&extra), extra.max, - dead.num, - dead.min, tally_mean(&dead), dead.max, - freet.num, - freet.min, tally_mean(&freet), freet.max, - hash.num, - hash.min, tally_mean(&hash), hash.max, - uncoal.total, - uncoal.min, tally_mean(&uncoal), uncoal.max, - keys.total * 100.0 / tdb->map_size, - data.total * 100.0 / tdb->map_size, - extra.total * 100.0 / tdb->map_size, - freet.total * 100.0 / tdb->map_size, - dead.total * 100.0 / tdb->map_size, - (keys.num + freet.num + dead.num) - * (sizeof(struct tdb_record) + sizeof(uint32_t)) - * 100.0 / tdb->map_size, - tdb->header.hash_size * sizeof(tdb_off_t) - * 100.0 / tdb->map_size); - -unlock: - if (locked) { - tdb_unlockall_read(tdb); - } - return ret; -} diff --git a/ctdb/lib/tdb/common/tdb.c b/ctdb/lib/tdb/common/tdb.c deleted file mode 100644 index fc1f5608fa27..000000000000 --- a/ctdb/lib/tdb/common/tdb.c +++ /dev/null @@ -1,1154 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 1999-2005 - Copyright (C) Paul `Rusty' Russell 2000 - Copyright (C) Jeremy Allison 2000-2003 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ - -#include "tdb_private.h" - -_PUBLIC_ TDB_DATA tdb_null; - -/* - non-blocking increment of the tdb sequence number if the tdb has been opened using - the TDB_SEQNUM flag -*/ -_PUBLIC_ void tdb_increment_seqnum_nonblock(struct tdb_context *tdb) -{ - tdb_off_t seqnum=0; - - if (!(tdb->flags & TDB_SEQNUM)) { - return; - } - - /* we ignore errors from this, as we have no sane way of - dealing with them. - */ - tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum); - seqnum++; - tdb_ofs_write(tdb, TDB_SEQNUM_OFS, &seqnum); -} - -/* - increment the tdb sequence number if the tdb has been opened using - the TDB_SEQNUM flag -*/ -static void tdb_increment_seqnum(struct tdb_context *tdb) -{ - if (!(tdb->flags & TDB_SEQNUM)) { - return; - } - - if (tdb_nest_lock(tdb, TDB_SEQNUM_OFS, F_WRLCK, - TDB_LOCK_WAIT|TDB_LOCK_PROBE) != 0) { - return; - } - - tdb_increment_seqnum_nonblock(tdb); - - tdb_nest_unlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, false); -} - -static int tdb_key_compare(TDB_DATA key, TDB_DATA data, void *private_data) -{ - return memcmp(data.dptr, key.dptr, data.dsize); -} - -/* Returns 0 on fail. On success, return offset of record, and fills - in rec */ -static tdb_off_t tdb_find(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, - struct tdb_record *r) -{ - tdb_off_t rec_ptr; - - /* read in the hash top */ - if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) - return 0; - - /* keep looking until we find the right record */ - while (rec_ptr) { - if (tdb_rec_read(tdb, rec_ptr, r) == -1) - return 0; - - if (!TDB_DEAD(r) && hash==r->full_hash - && key.dsize==r->key_len - && tdb_parse_data(tdb, key, rec_ptr + sizeof(*r), - r->key_len, tdb_key_compare, - NULL) == 0) { - return rec_ptr; - } - /* detect tight infinite loop */ - if (rec_ptr == r->next) { - tdb->ecode = TDB_ERR_CORRUPT; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_find: loop detected.\n")); - return 0; - } - rec_ptr = r->next; - } - tdb->ecode = TDB_ERR_NOEXIST; - return 0; -} - -/* As tdb_find, but if you succeed, keep the lock */ -tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype, - struct tdb_record *rec) -{ - uint32_t rec_ptr; - - if (tdb_lock(tdb, BUCKET(hash), locktype) == -1) - return 0; - if (!(rec_ptr = tdb_find(tdb, key, hash, rec))) - tdb_unlock(tdb, BUCKET(hash), locktype); - return rec_ptr; -} - -static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key); - -static int tdb_update_hash_cmp(TDB_DATA key, TDB_DATA data, void *private_data) -{ - TDB_DATA *dbuf = (TDB_DATA *)private_data; - - if (dbuf->dsize != data.dsize) { - return -1; - } - if (memcmp(dbuf->dptr, data.dptr, data.dsize) != 0) { - return -1; - } - return 0; -} - -/* update an entry in place - this only works if the new data size - is <= the old data size and the key exists. - on failure return -1. -*/ -static int tdb_update_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, TDB_DATA dbuf) -{ - struct tdb_record rec; - tdb_off_t rec_ptr; - - /* find entry */ - if (!(rec_ptr = tdb_find(tdb, key, hash, &rec))) - return -1; - - /* it could be an exact duplicate of what is there - this is - * surprisingly common (eg. with a ldb re-index). */ - if (rec.key_len == key.dsize && - rec.data_len == dbuf.dsize && - rec.full_hash == hash && - tdb_parse_record(tdb, key, tdb_update_hash_cmp, &dbuf) == 0) { - return 0; - } - - /* must be long enough key, data and tailer */ - if (rec.rec_len < key.dsize + dbuf.dsize + sizeof(tdb_off_t)) { - tdb->ecode = TDB_SUCCESS; /* Not really an error */ - return -1; - } - - if (tdb->methods->tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len, - dbuf.dptr, dbuf.dsize) == -1) - return -1; - - if (dbuf.dsize != rec.data_len) { - /* update size */ - rec.data_len = dbuf.dsize; - return tdb_rec_write(tdb, rec_ptr, &rec); - } - - return 0; -} - -/* find an entry in the database given a key */ -/* If an entry doesn't exist tdb_err will be set to - * TDB_ERR_NOEXIST. If a key has no data attached - * then the TDB_DATA will have zero length but - * a non-zero pointer - */ -static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key) -{ - tdb_off_t rec_ptr; - struct tdb_record rec; - TDB_DATA ret; - uint32_t hash; - - /* find which hash bucket it is in */ - hash = tdb->hash_fn(&key); - if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) - return tdb_null; - - ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len, - rec.data_len); - ret.dsize = rec.data_len; - tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK); - return ret; -} - -_PUBLIC_ TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key) -{ - TDB_DATA ret = _tdb_fetch(tdb, key); - - tdb_trace_1rec_retrec(tdb, "tdb_fetch", key, ret); - return ret; -} - -/* - * Find an entry in the database and hand the record's data to a parsing - * function. The parsing function is executed under the chain read lock, so it - * should be fast and should not block on other syscalls. - * - * DON'T CALL OTHER TDB CALLS FROM THE PARSER, THIS MIGHT LEAD TO SEGFAULTS. - * - * For mmapped tdb's that do not have a transaction open it points the parsing - * function directly at the mmap area, it avoids the malloc/memcpy in this - * case. If a transaction is open or no mmap is available, it has to do - * malloc/read/parse/free. - * - * This is interesting for all readers of potentially large data structures in - * the tdb records, ldb indexes being one example. - * - * Return -1 if the record was not found. - */ - -_PUBLIC_ int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key, - int (*parser)(TDB_DATA key, TDB_DATA data, - void *private_data), - void *private_data) -{ - tdb_off_t rec_ptr; - struct tdb_record rec; - int ret; - uint32_t hash; - - /* find which hash bucket it is in */ - hash = tdb->hash_fn(&key); - - if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) { - /* record not found */ - tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, -1); - tdb->ecode = TDB_ERR_NOEXIST; - return -1; - } - tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, 0); - - ret = tdb_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len, - rec.data_len, parser, private_data); - - tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK); - - return ret; -} - -/* check if an entry in the database exists - - note that 1 is returned if the key is found and 0 is returned if not found - this doesn't match the conventions in the rest of this module, but is - compatible with gdbm -*/ -static int tdb_exists_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash) -{ - struct tdb_record rec; - - if (tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0) - return 0; - tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK); - return 1; -} - -_PUBLIC_ int tdb_exists(struct tdb_context *tdb, TDB_DATA key) -{ - uint32_t hash = tdb->hash_fn(&key); - int ret; - - ret = tdb_exists_hash(tdb, key, hash); - tdb_trace_1rec_ret(tdb, "tdb_exists", key, ret); - return ret; -} - -/* actually delete an entry in the database given the offset */ -int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct tdb_record *rec) -{ - tdb_off_t last_ptr, i; - struct tdb_record lastrec; - - if (tdb->read_only || tdb->traverse_read) return -1; - - if (((tdb->traverse_write != 0) && (!TDB_DEAD(rec))) || - tdb_write_lock_record(tdb, rec_ptr) == -1) { - /* Someone traversing here: mark it as dead */ - rec->magic = TDB_DEAD_MAGIC; - return tdb_rec_write(tdb, rec_ptr, rec); - } - if (tdb_write_unlock_record(tdb, rec_ptr) != 0) - return -1; - - /* find previous record in hash chain */ - if (tdb_ofs_read(tdb, TDB_HASH_TOP(rec->full_hash), &i) == -1) - return -1; - for (last_ptr = 0; i != rec_ptr; last_ptr = i, i = lastrec.next) - if (tdb_rec_read(tdb, i, &lastrec) == -1) - return -1; - - /* unlink it: next ptr is at start of record. */ - if (last_ptr == 0) - last_ptr = TDB_HASH_TOP(rec->full_hash); - if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1) - return -1; - - /* recover the space */ - if (tdb_free(tdb, rec_ptr, rec) == -1) - return -1; - return 0; -} - -static int tdb_count_dead(struct tdb_context *tdb, uint32_t hash) -{ - int res = 0; - tdb_off_t rec_ptr; - struct tdb_record rec; - - /* read in the hash top */ - if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) - return 0; - - while (rec_ptr) { - if (tdb_rec_read(tdb, rec_ptr, &rec) == -1) - return 0; - - if (rec.magic == TDB_DEAD_MAGIC) { - res += 1; - } - rec_ptr = rec.next; - } - return res; -} - -/* - * Purge all DEAD records from a hash chain - */ -static int tdb_purge_dead(struct tdb_context *tdb, uint32_t hash) -{ - int res = -1; - struct tdb_record rec; - tdb_off_t rec_ptr; - - if (tdb_lock(tdb, -1, F_WRLCK) == -1) { - return -1; - } - - /* read in the hash top */ - if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) - goto fail; - - while (rec_ptr) { - tdb_off_t next; - - if (tdb_rec_read(tdb, rec_ptr, &rec) == -1) { - goto fail; - } - - next = rec.next; - - if (rec.magic == TDB_DEAD_MAGIC - && tdb_do_delete(tdb, rec_ptr, &rec) == -1) { - goto fail; - } - rec_ptr = next; - } - res = 0; - fail: - tdb_unlock(tdb, -1, F_WRLCK); - return res; -} - -/* delete an entry in the database given a key */ -static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash) -{ - tdb_off_t rec_ptr; - struct tdb_record rec; - int ret; - - if (tdb->max_dead_records != 0) { - - /* - * Allow for some dead records per hash chain, mainly for - * tdb's with a very high create/delete rate like locking.tdb. - */ - - if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1) - return -1; - - if (tdb_count_dead(tdb, hash) >= tdb->max_dead_records) { - /* - * Don't let the per-chain freelist grow too large, - * delete all existing dead records - */ - tdb_purge_dead(tdb, hash); - } - - if (!(rec_ptr = tdb_find(tdb, key, hash, &rec))) { - tdb_unlock(tdb, BUCKET(hash), F_WRLCK); - return -1; - } - - /* - * Just mark the record as dead. - */ - rec.magic = TDB_DEAD_MAGIC; - ret = tdb_rec_write(tdb, rec_ptr, &rec); - } - else { - if (!(rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK, - &rec))) - return -1; - - ret = tdb_do_delete(tdb, rec_ptr, &rec); - } - - if (ret == 0) { - tdb_increment_seqnum(tdb); - } - - if (tdb_unlock(tdb, BUCKET(rec.full_hash), F_WRLCK) != 0) - TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_delete: WARNING tdb_unlock failed!\n")); - return ret; -} - -_PUBLIC_ int tdb_delete(struct tdb_context *tdb, TDB_DATA key) -{ - uint32_t hash = tdb->hash_fn(&key); - int ret; - - ret = tdb_delete_hash(tdb, key, hash); - tdb_trace_1rec_ret(tdb, "tdb_delete", key, ret); - return ret; -} - -/* - * See if we have a dead record around with enough space - */ -static tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash, - struct tdb_record *r, tdb_len_t length) -{ - tdb_off_t rec_ptr; - - /* read in the hash top */ - if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) - return 0; - - /* keep looking until we find the right record */ - while (rec_ptr) { - if (tdb_rec_read(tdb, rec_ptr, r) == -1) - return 0; - - if (TDB_DEAD(r) && r->rec_len >= length) { - /* - * First fit for simple coding, TODO: change to best - * fit - */ - return rec_ptr; - } - rec_ptr = r->next; - } - return 0; -} - -static int _tdb_store(struct tdb_context *tdb, TDB_DATA key, - TDB_DATA dbuf, int flag, uint32_t hash) -{ - struct tdb_record rec; - tdb_off_t rec_ptr; - int ret = -1; - - /* check for it existing, on insert. */ - if (flag == TDB_INSERT) { - if (tdb_exists_hash(tdb, key, hash)) { - tdb->ecode = TDB_ERR_EXISTS; - goto fail; - } - } else { - /* first try in-place update, on modify or replace. */ - if (tdb_update_hash(tdb, key, hash, dbuf) == 0) { - goto done; - } - if (tdb->ecode == TDB_ERR_NOEXIST && - flag == TDB_MODIFY) { - /* if the record doesn't exist and we are in TDB_MODIFY mode then - we should fail the store */ - goto fail; - } - } - /* reset the error code potentially set by the tdb_update() */ - tdb->ecode = TDB_SUCCESS; - - /* delete any existing record - if it doesn't exist we don't - care. Doing this first reduces fragmentation, and avoids - coalescing with `allocated' block before it's updated. */ - if (flag != TDB_INSERT) - tdb_delete_hash(tdb, key, hash); - - if (tdb->max_dead_records != 0) { - /* - * Allow for some dead records per hash chain, look if we can - * find one that can hold the new record. We need enough space - * for key, data and tailer. If we find one, we don't have to - * consult the central freelist. - */ - rec_ptr = tdb_find_dead( - tdb, hash, &rec, - key.dsize + dbuf.dsize + sizeof(tdb_off_t)); - - if (rec_ptr != 0) { - rec.key_len = key.dsize; - rec.data_len = dbuf.dsize; - rec.full_hash = hash; - rec.magic = TDB_MAGIC; - if (tdb_rec_write(tdb, rec_ptr, &rec) == -1 - || tdb->methods->tdb_write( - tdb, rec_ptr + sizeof(rec), - key.dptr, key.dsize) == -1 - || tdb->methods->tdb_write( - tdb, rec_ptr + sizeof(rec) + key.dsize, - dbuf.dptr, dbuf.dsize) == -1) { - goto fail; - } - goto done; - } - } - - /* - * We have to allocate some space from the freelist, so this means we - * have to lock it. Use the chance to purge all the DEAD records from - * the hash chain under the freelist lock. - */ - - if (tdb_lock(tdb, -1, F_WRLCK) == -1) { - goto fail; - } - - if ((tdb->max_dead_records != 0) - && (tdb_purge_dead(tdb, hash) == -1)) { - tdb_unlock(tdb, -1, F_WRLCK); - goto fail; - } - - /* we have to allocate some space */ - rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize, &rec); - - tdb_unlock(tdb, -1, F_WRLCK); - - if (rec_ptr == 0) { - goto fail; - } - - /* Read hash top into next ptr */ - if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1) - goto fail; - - rec.key_len = key.dsize; - rec.data_len = dbuf.dsize; - rec.full_hash = hash; - rec.magic = TDB_MAGIC; - - /* write out and point the top of the hash chain at it */ - if (tdb_rec_write(tdb, rec_ptr, &rec) == -1 - || tdb->methods->tdb_write(tdb, rec_ptr+sizeof(rec), - key.dptr, key.dsize) == -1 - || tdb->methods->tdb_write(tdb, rec_ptr+sizeof(rec)+key.dsize, - dbuf.dptr, dbuf.dsize) == -1 - || tdb_ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) { - /* Need to tdb_unallocate() here */ - goto fail; - } - - done: - ret = 0; - fail: - if (ret == 0) { - tdb_increment_seqnum(tdb); - } - return ret; -} - -/* store an element in the database, replacing any existing element - with the same key - - return 0 on success, -1 on failure -*/ -_PUBLIC_ int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag) -{ - uint32_t hash; - int ret; - - if (tdb->read_only || tdb->traverse_read) { - tdb->ecode = TDB_ERR_RDONLY; - tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, -1); - return -1; - } - - /* find which hash bucket it is in */ - hash = tdb->hash_fn(&key); - if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1) - return -1; - - ret = _tdb_store(tdb, key, dbuf, flag, hash); - tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, ret); - tdb_unlock(tdb, BUCKET(hash), F_WRLCK); - return ret; -} - -/* Append to an entry. Create if not exist. */ -_PUBLIC_ int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf) -{ - uint32_t hash; - TDB_DATA dbuf; - int ret = -1; - - /* find which hash bucket it is in */ - hash = tdb->hash_fn(&key); - if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1) - return -1; - - dbuf = _tdb_fetch(tdb, key); - - if (dbuf.dptr == NULL) { - dbuf.dptr = (unsigned char *)malloc(new_dbuf.dsize); - } else { - unsigned int new_len = dbuf.dsize + new_dbuf.dsize; - unsigned char *new_dptr; - - /* realloc '0' is special: don't do that. */ - if (new_len == 0) - new_len = 1; - new_dptr = (unsigned char *)realloc(dbuf.dptr, new_len); - if (new_dptr == NULL) { - free(dbuf.dptr); - } - dbuf.dptr = new_dptr; - } - - if (dbuf.dptr == NULL) { - tdb->ecode = TDB_ERR_OOM; - goto failed; - } - - memcpy(dbuf.dptr + dbuf.dsize, new_dbuf.dptr, new_dbuf.dsize); - dbuf.dsize += new_dbuf.dsize; - - ret = _tdb_store(tdb, key, dbuf, 0, hash); - tdb_trace_2rec_retrec(tdb, "tdb_append", key, new_dbuf, dbuf); - -failed: - tdb_unlock(tdb, BUCKET(hash), F_WRLCK); - SAFE_FREE(dbuf.dptr); - return ret; -} - - -/* - return the name of the current tdb file - useful for external logging functions -*/ -_PUBLIC_ const char *tdb_name(struct tdb_context *tdb) -{ - return tdb->name; -} - -/* - return the underlying file descriptor being used by tdb, or -1 - useful for external routines that want to check the device/inode - of the fd -*/ -_PUBLIC_ int tdb_fd(struct tdb_context *tdb) -{ - return tdb->fd; -} - -/* - return the current logging function - useful for external tdb routines that wish to log tdb errors -*/ -_PUBLIC_ tdb_log_func tdb_log_fn(struct tdb_context *tdb) -{ - return tdb->log.log_fn; -} - - -/* - get the tdb sequence number. Only makes sense if the writers opened - with TDB_SEQNUM set. Note that this sequence number will wrap quite - quickly, so it should only be used for a 'has something changed' - test, not for code that relies on the count of the number of changes - made. If you want a counter then use a tdb record. - - The aim of this sequence number is to allow for a very lightweight - test of a possible tdb change. -*/ -_PUBLIC_ int tdb_get_seqnum(struct tdb_context *tdb) -{ - tdb_off_t seqnum=0; - - tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum); - return seqnum; -} - -_PUBLIC_ int tdb_hash_size(struct tdb_context *tdb) -{ - return tdb->header.hash_size; -} - -_PUBLIC_ size_t tdb_map_size(struct tdb_context *tdb) -{ - return tdb->map_size; -} - -_PUBLIC_ int tdb_get_flags(struct tdb_context *tdb) -{ - return tdb->flags; -} - -_PUBLIC_ void tdb_add_flags(struct tdb_context *tdb, unsigned flags) -{ - if ((flags & TDB_ALLOW_NESTING) && - (flags & TDB_DISALLOW_NESTING)) { - tdb->ecode = TDB_ERR_NESTING; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_add_flags: " - "allow_nesting and disallow_nesting are not allowed together!")); - return; - } - - if (flags & TDB_ALLOW_NESTING) { - tdb->flags &= ~TDB_DISALLOW_NESTING; - } - if (flags & TDB_DISALLOW_NESTING) { - tdb->flags &= ~TDB_ALLOW_NESTING; - } - - tdb->flags |= flags; -} - -_PUBLIC_ void tdb_remove_flags(struct tdb_context *tdb, unsigned flags) -{ - if ((flags & TDB_ALLOW_NESTING) && - (flags & TDB_DISALLOW_NESTING)) { - tdb->ecode = TDB_ERR_NESTING; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_remove_flags: " - "allow_nesting and disallow_nesting are not allowed together!")); - return; - } - - if (flags & TDB_ALLOW_NESTING) { - tdb->flags |= TDB_DISALLOW_NESTING; - } - if (flags & TDB_DISALLOW_NESTING) { - tdb->flags |= TDB_ALLOW_NESTING; - } - - tdb->flags &= ~flags; -} - - -/* - enable sequence number handling on an open tdb -*/ -_PUBLIC_ void tdb_enable_seqnum(struct tdb_context *tdb) -{ - tdb->flags |= TDB_SEQNUM; -} - - -/* - add a region of the file to the freelist. Length is the size of the region in bytes, - which includes the free list header that needs to be added - */ -static int tdb_free_region(struct tdb_context *tdb, tdb_off_t offset, ssize_t length) -{ - struct tdb_record rec; - if (length <= sizeof(rec)) { - /* the region is not worth adding */ - return 0; - } - if (length + offset > tdb->map_size) { - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: adding region beyond end of file\n")); - return -1; - } - memset(&rec,'\0',sizeof(rec)); - rec.rec_len = length - sizeof(rec); - if (tdb_free(tdb, offset, &rec) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: failed to add free record\n")); - return -1; - } - return 0; -} - -/* - wipe the entire database, deleting all records. This can be done - very fast by using a allrecord lock. The entire data portion of the - file becomes a single entry in the freelist. - - This code carefully steps around the recovery area, leaving it alone - */ -_PUBLIC_ int tdb_wipe_all(struct tdb_context *tdb) -{ - int i; - tdb_off_t offset = 0; - ssize_t data_len; - tdb_off_t recovery_head; - tdb_len_t recovery_size = 0; - - if (tdb_lockall(tdb) != 0) { - return -1; - } - - tdb_trace(tdb, "tdb_wipe_all"); - - /* see if the tdb has a recovery area, and remember its size - if so. We don't want to lose this as otherwise each - tdb_wipe_all() in a transaction will increase the size of - the tdb by the size of the recovery area */ - if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery head\n")); - goto failed; - } - - if (recovery_head != 0) { - struct tdb_record rec; - if (tdb->methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery record\n")); - return -1; - } - recovery_size = rec.rec_len + sizeof(rec); - } - - /* wipe the hashes */ - for (i=0;iheader.hash_size;i++) { - if (tdb_ofs_write(tdb, TDB_HASH_TOP(i), &offset) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write hash %d\n", i)); - goto failed; - } - } - - /* wipe the freelist */ - if (tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write freelist\n")); - goto failed; - } - - /* add all the rest of the file to the freelist, possibly leaving a gap - for the recovery area */ - if (recovery_size == 0) { - /* the simple case - the whole file can be used as a freelist */ - data_len = (tdb->map_size - TDB_DATA_START(tdb->header.hash_size)); - if (tdb_free_region(tdb, TDB_DATA_START(tdb->header.hash_size), data_len) != 0) { - goto failed; - } - } else { - /* we need to add two freelist entries - one on either - side of the recovery area - - Note that we cannot shift the recovery area during - this operation. Only the transaction.c code may - move the recovery area or we risk subtle data - corruption - */ - data_len = (recovery_head - TDB_DATA_START(tdb->header.hash_size)); - if (tdb_free_region(tdb, TDB_DATA_START(tdb->header.hash_size), data_len) != 0) { - goto failed; - } - /* and the 2nd free list entry after the recovery area - if any */ - data_len = tdb->map_size - (recovery_head+recovery_size); - if (tdb_free_region(tdb, recovery_head+recovery_size, data_len) != 0) { - goto failed; - } - } - - tdb_increment_seqnum_nonblock(tdb); - - if (tdb_unlockall(tdb) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to unlock\n")); - goto failed; - } - - return 0; - -failed: - tdb_unlockall(tdb); - return -1; -} - -struct traverse_state { - bool error; - struct tdb_context *dest_db; -}; - -/* - traverse function for repacking - */ -static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private_data) -{ - struct traverse_state *state = (struct traverse_state *)private_data; - if (tdb_store(state->dest_db, key, data, TDB_INSERT) != 0) { - state->error = true; - return -1; - } - return 0; -} - -/* - repack a tdb - */ -_PUBLIC_ int tdb_repack(struct tdb_context *tdb) -{ - struct tdb_context *tmp_db; - struct traverse_state state; - - tdb_trace(tdb, "tdb_repack"); - - if (tdb_transaction_start(tdb) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to start transaction\n")); - return -1; - } - - tmp_db = tdb_open("tmpdb", tdb_hash_size(tdb), TDB_INTERNAL, O_RDWR|O_CREAT, 0); - if (tmp_db == NULL) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to create tmp_db\n")); - tdb_transaction_cancel(tdb); - return -1; - } - - state.error = false; - state.dest_db = tmp_db; - - if (tdb_traverse_read(tdb, repack_traverse, &state) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to traverse copying out\n")); - tdb_transaction_cancel(tdb); - tdb_close(tmp_db); - return -1; - } - - if (state.error) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Error during traversal\n")); - tdb_transaction_cancel(tdb); - tdb_close(tmp_db); - return -1; - } - - if (tdb_wipe_all(tdb) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to wipe database\n")); - tdb_transaction_cancel(tdb); - tdb_close(tmp_db); - return -1; - } - - state.error = false; - state.dest_db = tdb; - - if (tdb_traverse_read(tmp_db, repack_traverse, &state) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to traverse copying back\n")); - tdb_transaction_cancel(tdb); - tdb_close(tmp_db); - return -1; - } - - if (state.error) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Error during second traversal\n")); - tdb_transaction_cancel(tdb); - tdb_close(tmp_db); - return -1; - } - - tdb_close(tmp_db); - - if (tdb_transaction_commit(tdb) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to commit\n")); - return -1; - } - - return 0; -} - -/* Even on files, we can get partial writes due to signals. */ -bool tdb_write_all(int fd, const void *buf, size_t count) -{ - while (count) { - ssize_t ret; - ret = write(fd, buf, count); - if (ret < 0) - return false; - buf = (const char *)buf + ret; - count -= ret; - } - return true; -} - -#ifdef TDB_TRACE -static void tdb_trace_write(struct tdb_context *tdb, const char *str) -{ - if (!tdb_write_all(tdb->tracefd, str, strlen(str))) { - close(tdb->tracefd); - tdb->tracefd = -1; - } -} - -static void tdb_trace_start(struct tdb_context *tdb) -{ - tdb_off_t seqnum=0; - char msg[sizeof(tdb_off_t) * 4 + 1]; - - tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum); - snprintf(msg, sizeof(msg), "%u ", seqnum); - tdb_trace_write(tdb, msg); -} - -static void tdb_trace_end(struct tdb_context *tdb) -{ - tdb_trace_write(tdb, "\n"); -} - -static void tdb_trace_end_ret(struct tdb_context *tdb, int ret) -{ - char msg[sizeof(ret) * 4 + 4]; - snprintf(msg, sizeof(msg), " = %i\n", ret); - tdb_trace_write(tdb, msg); -} - -static void tdb_trace_record(struct tdb_context *tdb, TDB_DATA rec) -{ - char msg[20 + rec.dsize*2], *p; - unsigned int i; - - /* We differentiate zero-length records from non-existent ones. */ - if (rec.dptr == NULL) { - tdb_trace_write(tdb, " NULL"); - return; - } - - /* snprintf here is purely cargo-cult programming. */ - p = msg; - p += snprintf(p, sizeof(msg), " %zu:", rec.dsize); - for (i = 0; i < rec.dsize; i++) - p += snprintf(p, 2, "%02x", rec.dptr[i]); - - tdb_trace_write(tdb, msg); -} - -void tdb_trace(struct tdb_context *tdb, const char *op) -{ - tdb_trace_start(tdb); - tdb_trace_write(tdb, op); - tdb_trace_end(tdb); -} - -void tdb_trace_seqnum(struct tdb_context *tdb, uint32_t seqnum, const char *op) -{ - char msg[sizeof(tdb_off_t) * 4 + 1]; - - snprintf(msg, sizeof(msg), "%u ", seqnum); - tdb_trace_write(tdb, msg); - tdb_trace_write(tdb, op); - tdb_trace_end(tdb); -} - -void tdb_trace_open(struct tdb_context *tdb, const char *op, - unsigned hash_size, unsigned tdb_flags, unsigned open_flags) -{ - char msg[128]; - - snprintf(msg, sizeof(msg), - "%s %u 0x%x 0x%x", op, hash_size, tdb_flags, open_flags); - tdb_trace_start(tdb); - tdb_trace_write(tdb, msg); - tdb_trace_end(tdb); -} - -void tdb_trace_ret(struct tdb_context *tdb, const char *op, int ret) -{ - tdb_trace_start(tdb); - tdb_trace_write(tdb, op); - tdb_trace_end_ret(tdb, ret); -} - -void tdb_trace_retrec(struct tdb_context *tdb, const char *op, TDB_DATA ret) -{ - tdb_trace_start(tdb); - tdb_trace_write(tdb, op); - tdb_trace_write(tdb, " ="); - tdb_trace_record(tdb, ret); - tdb_trace_end(tdb); -} - -void tdb_trace_1rec(struct tdb_context *tdb, const char *op, - TDB_DATA rec) -{ - tdb_trace_start(tdb); - tdb_trace_write(tdb, op); - tdb_trace_record(tdb, rec); - tdb_trace_end(tdb); -} - -void tdb_trace_1rec_ret(struct tdb_context *tdb, const char *op, - TDB_DATA rec, int ret) -{ - tdb_trace_start(tdb); - tdb_trace_write(tdb, op); - tdb_trace_record(tdb, rec); - tdb_trace_end_ret(tdb, ret); -} - -void tdb_trace_1rec_retrec(struct tdb_context *tdb, const char *op, - TDB_DATA rec, TDB_DATA ret) -{ - tdb_trace_start(tdb); - tdb_trace_write(tdb, op); - tdb_trace_record(tdb, rec); - tdb_trace_write(tdb, " ="); - tdb_trace_record(tdb, ret); - tdb_trace_end(tdb); -} - -void tdb_trace_2rec_flag_ret(struct tdb_context *tdb, const char *op, - TDB_DATA rec1, TDB_DATA rec2, unsigned flag, - int ret) -{ - char msg[1 + sizeof(ret) * 4]; - - snprintf(msg, sizeof(msg), " %#x", flag); - tdb_trace_start(tdb); - tdb_trace_write(tdb, op); - tdb_trace_record(tdb, rec1); - tdb_trace_record(tdb, rec2); - tdb_trace_write(tdb, msg); - tdb_trace_end_ret(tdb, ret); -} - -void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op, - TDB_DATA rec1, TDB_DATA rec2, TDB_DATA ret) -{ - tdb_trace_start(tdb); - tdb_trace_write(tdb, op); - tdb_trace_record(tdb, rec1); - tdb_trace_record(tdb, rec2); - tdb_trace_write(tdb, " ="); - tdb_trace_record(tdb, ret); - tdb_trace_end(tdb); -} -#endif diff --git a/ctdb/lib/tdb/common/tdb_private.h b/ctdb/lib/tdb/common/tdb_private.h deleted file mode 100644 index 0441fb287fdf..000000000000 --- a/ctdb/lib/tdb/common/tdb_private.h +++ /dev/null @@ -1,285 +0,0 @@ -#ifndef TDB_PRIVATE_H -#define TDB_PRIVATE_H - /* - Unix SMB/CIFS implementation. - - trivial database library - private includes - - Copyright (C) Andrew Tridgell 2005 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ - -#include "replace.h" -#include "system/filesys.h" -#include "system/time.h" -#include "system/shmem.h" -#include "system/select.h" -#include "system/wait.h" -#include "tdb.h" - -/* #define TDB_TRACE 1 */ -#ifndef HAVE_GETPAGESIZE -#define getpagesize() 0x2000 -#endif - -typedef uint32_t tdb_len_t; -typedef uint32_t tdb_off_t; - -#ifndef offsetof -#define offsetof(t,f) ((unsigned int)&((t *)0)->f) -#endif - -#define TDB_MAGIC_FOOD "TDB file\n" -#define TDB_VERSION (0x26011967 + 6) -#define TDB_MAGIC (0x26011999U) -#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)) -#define TDB_ALIGN(x,a) (((x) + (a)-1) & ~((a)-1)) -#define TDB_BYTEREV(x) (((((x)&0xff)<<24)|((x)&0xFF00)<<8)|(((x)>>8)&0xFF00)|((x)>>24)) -#define TDB_DEAD(r) ((r)->magic == TDB_DEAD_MAGIC) -#define TDB_BAD_MAGIC(r) ((r)->magic != TDB_MAGIC && !TDB_DEAD(r)) -#define TDB_HASH_TOP(hash) (FREELIST_TOP + (BUCKET(hash)+1)*sizeof(tdb_off_t)) -#define TDB_HASHTABLE_SIZE(tdb) ((tdb->header.hash_size+1)*sizeof(tdb_off_t)) -#define TDB_DATA_START(hash_size) (TDB_HASH_TOP(hash_size-1) + sizeof(tdb_off_t)) -#define TDB_RECOVERY_HEAD offsetof(struct tdb_header, recovery_start) -#define TDB_SEQNUM_OFS offsetof(struct tdb_header, sequence_number) -#define TDB_PAD_BYTE 0x42 -#define TDB_PAD_U32 0x42424242 - -/* NB assumes there is a local variable called "tdb" that is the - * current context, also takes doubly-parenthesized print-style - * argument. */ -#define TDB_LOG(x) tdb->log.log_fn x - -#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); -void tdb_trace_retrec(struct tdb_context *tdb, const char *op, TDB_DATA ret); -void tdb_trace_1rec(struct tdb_context *tdb, const char *op, - TDB_DATA rec); -void tdb_trace_1rec_ret(struct tdb_context *tdb, const char *op, - TDB_DATA rec, int ret); -void tdb_trace_1rec_retrec(struct tdb_context *tdb, const char *op, - TDB_DATA rec, TDB_DATA ret); -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_2rec_retrec(struct tdb_context *tdb, const char *op, - 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) -#define tdb_trace_1rec(tdb, op, rec) -#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_2rec_retrec(tdb, op, rec1, rec2, ret) -#endif /* !TDB_TRACE */ - -/* lock offsets */ -#define OPEN_LOCK 0 -#define ACTIVE_LOCK 4 -#define TRANSACTION_LOCK 8 - -/* free memory if the pointer is valid and zero the pointer */ -#ifndef SAFE_FREE -#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0) -#endif - -#define BUCKET(hash) ((hash) % tdb->header.hash_size) - -#define DOCONV() (tdb->flags & TDB_CONVERT) -#define CONVERT(x) (DOCONV() ? tdb_convert(&x, sizeof(x)) : &x) - - -/* 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 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_len_t data_len; /* byte length of data */ - uint32_t full_hash; /* the full 32 bit hash of the key */ - uint32_t magic; /* try to catch errors */ - /* the following union is implied: - union { - char record[rec_len]; - struct { - char key[key_len]; - char data[data_len]; - } - uint32_t totalsize; (tailer) - } - */ -}; - - -/* this is stored at the front of every database */ -struct tdb_header { - char magic_food[32]; /* for /etc/magic */ - uint32_t version; /* version of the code */ - uint32_t hash_size; /* number of hash entries */ - 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 */ - 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 { - uint32_t off; - uint32_t count; - uint32_t ltype; -}; - -struct tdb_traverse_lock { - struct tdb_traverse_lock *next; - uint32_t off; - uint32_t hash; - 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 ); - int (*tdb_write)(struct tdb_context *, tdb_off_t, const void *, tdb_len_t); - void (*next_hash_chain)(struct tdb_context *, uint32_t *); - int (*tdb_oob)(struct tdb_context *, tdb_off_t , tdb_len_t, int ); - int (*tdb_expand_file)(struct tdb_context *, tdb_off_t , tdb_off_t ); -}; - -struct tdb_context { - char *name; /* the name of the database */ - void *map_ptr; /* where it is currently mapped */ - int fd; /* open file descriptor for the database */ - tdb_len_t map_size; /* how much space has been mapped */ - int read_only; /* opened read-only */ - int traverse_read; /* read-only traversal */ - int traverse_write; /* read-write traversal */ - 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_header header; /* a cached copy of the header */ - uint32_t flags; /* the flags passed to tdb_open */ - struct tdb_traverse_lock travlocks; /* current traversal locks */ - struct tdb_context *next; /* all tdbs to avoid multiple opens */ - dev_t device; /* uniquely identifies this tdb */ - ino_t inode; /* uniquely identifies this tdb */ - struct tdb_logging_context log; - unsigned int (*hash_fn)(TDB_DATA *key); - int open_flags; /* flags used in the open - needed by reopen */ - const struct tdb_methods *methods; - struct tdb_transaction *transaction; - int page_size; - int max_dead_records; -#ifdef TDB_TRACE - int tracefd; -#endif - volatile sig_atomic_t *interrupt_sig_ptr; -}; - - -/* - internal prototypes -*/ -int tdb_munmap(struct tdb_context *tdb); -int 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); -int tdb_unlock(struct tdb_context *tdb, int list, int ltype); -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_transaction_locks(struct tdb_context *tdb); -int tdb_transaction_lock(struct tdb_context *tdb, int ltype, - enum tdb_lock_flags lockflags); -int tdb_transaction_unlock(struct tdb_context *tdb, int ltype); -int tdb_recovery_area(struct tdb_context *tdb, - const struct tdb_methods *methods, - tdb_off_t *recovery_offset, - struct tdb_record *rec); -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 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); -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, - int (*parser)(TDB_DATA key, TDB_DATA data, - 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 tdb_record *rec); -void tdb_io_init(struct tdb_context *tdb); -int tdb_expand(struct tdb_context *tdb, tdb_off_t size); -tdb_off_t tdb_expand_adjust(tdb_off_t map_size, tdb_off_t size, int page_size); -int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off, - struct tdb_record *rec); -bool tdb_write_all(int fd, const void *buf, size_t count); -int tdb_transaction_recover(struct tdb_context *tdb); -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 /* TDB_PRIVATE_H */ diff --git a/ctdb/lib/tdb/common/transaction.c b/ctdb/lib/tdb/common/transaction.c deleted file mode 100644 index f18b4c229eb8..000000000000 --- a/ctdb/lib/tdb/common/transaction.c +++ /dev/null @@ -1,1294 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 2005 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ - -#include "tdb_private.h" - -/* - transaction design: - - - only allow a single transaction at a time per database. This makes - using the transaction API simpler, as otherwise the caller would - have to cope with temporary failures in transactions that conflict - with other current transactions - - - keep the transaction recovery information in the same file as the - database, using a special 'transaction recovery' record pointed at - by the header. This removes the need for extra journal files as - used by some other databases - - - dynamically allocated the transaction recover record, re-using it - for subsequent transactions. If a larger record is needed then - tdb_free() the old record to place it on the normal tdb freelist - before allocating the new record - - - during transactions, keep a linked list of writes all that have - been performed by intercepting all tdb_write() calls. The hooked - transaction versions of tdb_read() and tdb_write() check this - linked list and try to use the elements of the list in preference - to the real database. - - - don't allow any locks to be held when a transaction starts, - otherwise we can end up with deadlock (plus lack of lock nesting - in posix locks would mean the lock is lost) - - - if the caller gains a lock during the transaction but doesn't - release it then fail the commit - - - allow for nested calls to tdb_transaction_start(), re-using the - existing transaction record. If the inner transaction is cancelled - then a subsequent commit will fail - - - keep a mirrored copy of the tdb hash chain heads to allow for the - fast hash heads scan on traverse, updating the mirrored copy in - the transaction version of tdb_write - - - allow callers to mix transaction and non-transaction use of tdb, - although once a transaction is started then an exclusive lock is - gained until the transaction is committed or cancelled - - - the commit stategy involves first saving away all modified data - into a linearised buffer in the transaction recovery area, then - marking the transaction recovery area with a magic value to - indicate a valid recovery record. In total 4 fsync/msync calls are - needed per commit to prevent race conditions. It might be possible - to reduce this to 3 or even 2 with some more work. - - - check for a valid recovery record on open of the tdb, while the - open lock is held. Automatically recover from the transaction - recovery area if needed, then continue with the open as - usual. This allows for smooth crash recovery with no administrator - intervention. - - - if TDB_NOSYNC is passed to flags in tdb_open then transactions are - still available, but no fsync/msync calls are made. This means we - are still proof against a process dying during transaction commit, - but not against machine reboot. - - - if TDB_ALLOW_NESTING is passed to flags in tdb open, or added using - tdb_add_flags() transaction nesting is enabled. - It resets the TDB_DISALLOW_NESTING flag, as both cannot be used together. - The default is that transaction nesting is allowed. - Note: this default may change in future versions of tdb. - - Beware. when transactions are nested a transaction successfully - completed with tdb_transaction_commit() can be silently unrolled later. - - - if TDB_DISALLOW_NESTING is passed to flags in tdb open, or added using - tdb_add_flags() transaction nesting is disabled. - It resets the TDB_ALLOW_NESTING flag, as both cannot be used together. - An attempt create a nested transaction will fail with TDB_ERR_NESTING. - The default is that transaction nesting is allowed. - Note: this default may change in future versions of tdb. -*/ - - -/* - hold the context of any current transaction -*/ -struct tdb_transaction { - /* we keep a mirrored copy of the tdb hash heads here so - tdb_next_hash_chain() can operate efficiently */ - uint32_t *hash_heads; - - /* the original io methods - used to do IOs to the real db */ - const struct tdb_methods *io_methods; - - /* the list of transaction blocks. When a block is first - written to, it gets created in this list */ - uint8_t **blocks; - uint32_t num_blocks; - uint32_t block_size; /* bytes in each block */ - uint32_t last_block_size; /* number of valid bytes in the last block */ - - /* non-zero when an internal transaction error has - occurred. All write operations will then fail until the - transaction is ended */ - int transaction_error; - - /* when inside a transaction we need to keep track of any - nested tdb_transaction_start() calls, as these are allowed, - but don't create a new transaction */ - int nesting; - - /* set when a prepare has already occurred */ - bool prepared; - tdb_off_t magic_offset; - - /* old file size before transaction */ - tdb_len_t old_map_size; - - /* did we expand in this transaction */ - bool expanded; -}; - - -/* - read while in a transaction. We need to check first if the data is in our list - of transaction elements, then if not do a real read -*/ -static int transaction_read(struct tdb_context *tdb, tdb_off_t off, void *buf, - tdb_len_t len, int cv) -{ - uint32_t blk; - - /* break it down into block sized ops */ - while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) { - tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size); - if (transaction_read(tdb, off, buf, len2, cv) != 0) { - return -1; - } - len -= len2; - off += len2; - buf = (void *)(len2 + (char *)buf); - } - - if (len == 0) { - return 0; - } - - blk = off / tdb->transaction->block_size; - - /* see if we have it in the block list */ - if (tdb->transaction->num_blocks <= blk || - tdb->transaction->blocks[blk] == NULL) { - /* nope, do a real read */ - if (tdb->transaction->io_methods->tdb_read(tdb, off, buf, len, cv) != 0) { - goto fail; - } - return 0; - } - - /* it is in the block list. Now check for the last block */ - if (blk == tdb->transaction->num_blocks-1) { - if (len > tdb->transaction->last_block_size) { - goto fail; - } - } - - /* now copy it out of this block */ - memcpy(buf, tdb->transaction->blocks[blk] + (off % tdb->transaction->block_size), len); - if (cv) { - tdb_convert(buf, len); - } - return 0; - -fail: - TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_read: failed at off=%d len=%d\n", off, len)); - tdb->ecode = TDB_ERR_IO; - tdb->transaction->transaction_error = 1; - return -1; -} - - -/* - write while in a transaction -*/ -static int transaction_write(struct tdb_context *tdb, tdb_off_t off, - const void *buf, tdb_len_t len) -{ - uint32_t blk; - - /* Only a commit is allowed on a prepared transaction */ - if (tdb->transaction->prepared) { - tdb->ecode = TDB_ERR_EINVAL; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: transaction already prepared, write not allowed\n")); - tdb->transaction->transaction_error = 1; - return -1; - } - - /* if the write is to a hash head, then update the transaction - hash heads */ - if (len == sizeof(tdb_off_t) && off >= FREELIST_TOP && - off < FREELIST_TOP+TDB_HASHTABLE_SIZE(tdb)) { - uint32_t chain = (off-FREELIST_TOP) / sizeof(tdb_off_t); - memcpy(&tdb->transaction->hash_heads[chain], buf, len); - } - - /* break it up into block sized chunks */ - while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) { - tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size); - if (transaction_write(tdb, off, buf, len2) != 0) { - return -1; - } - len -= len2; - off += len2; - if (buf != NULL) { - buf = (const void *)(len2 + (const char *)buf); - } - } - - if (len == 0) { - return 0; - } - - blk = off / tdb->transaction->block_size; - off = off % tdb->transaction->block_size; - - if (tdb->transaction->num_blocks <= blk) { - uint8_t **new_blocks; - /* expand the blocks array */ - if (tdb->transaction->blocks == NULL) { - new_blocks = (uint8_t **)malloc( - (blk+1)*sizeof(uint8_t *)); - } else { - new_blocks = (uint8_t **)realloc( - tdb->transaction->blocks, - (blk+1)*sizeof(uint8_t *)); - } - if (new_blocks == NULL) { - tdb->ecode = TDB_ERR_OOM; - goto fail; - } - memset(&new_blocks[tdb->transaction->num_blocks], 0, - (1+(blk - tdb->transaction->num_blocks))*sizeof(uint8_t *)); - tdb->transaction->blocks = new_blocks; - tdb->transaction->num_blocks = blk+1; - tdb->transaction->last_block_size = 0; - } - - /* allocate and fill a block? */ - if (tdb->transaction->blocks[blk] == NULL) { - tdb->transaction->blocks[blk] = (uint8_t *)calloc(tdb->transaction->block_size, 1); - if (tdb->transaction->blocks[blk] == NULL) { - tdb->ecode = TDB_ERR_OOM; - tdb->transaction->transaction_error = 1; - return -1; - } - if (tdb->transaction->old_map_size > blk * tdb->transaction->block_size) { - tdb_len_t len2 = tdb->transaction->block_size; - if (len2 + (blk * tdb->transaction->block_size) > tdb->transaction->old_map_size) { - len2 = tdb->transaction->old_map_size - (blk * tdb->transaction->block_size); - } - if (tdb->transaction->io_methods->tdb_read(tdb, blk * tdb->transaction->block_size, - tdb->transaction->blocks[blk], - len2, 0) != 0) { - SAFE_FREE(tdb->transaction->blocks[blk]); - tdb->ecode = TDB_ERR_IO; - goto fail; - } - if (blk == tdb->transaction->num_blocks-1) { - tdb->transaction->last_block_size = len2; - } - } - } - - /* overwrite part of an existing block */ - if (buf == NULL) { - memset(tdb->transaction->blocks[blk] + off, 0, len); - } else { - memcpy(tdb->transaction->blocks[blk] + off, buf, len); - } - if (blk == tdb->transaction->num_blocks-1) { - if (len + off > tdb->transaction->last_block_size) { - tdb->transaction->last_block_size = len + off; - } - } - - return 0; - -fail: - TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: failed at off=%d len=%d\n", - (blk*tdb->transaction->block_size) + off, len)); - tdb->transaction->transaction_error = 1; - return -1; -} - - -/* - write while in a transaction - this varient never expands the transaction blocks, it only - updates existing blocks. This means it cannot change the recovery size -*/ -static int transaction_write_existing(struct tdb_context *tdb, tdb_off_t off, - const void *buf, tdb_len_t len) -{ - uint32_t blk; - - /* break it up into block sized chunks */ - while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) { - tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size); - if (transaction_write_existing(tdb, off, buf, len2) != 0) { - return -1; - } - len -= len2; - off += len2; - if (buf != NULL) { - buf = (const void *)(len2 + (const char *)buf); - } - } - - if (len == 0) { - return 0; - } - - blk = off / tdb->transaction->block_size; - off = off % tdb->transaction->block_size; - - if (tdb->transaction->num_blocks <= blk || - tdb->transaction->blocks[blk] == NULL) { - return 0; - } - - if (blk == tdb->transaction->num_blocks-1 && - off + len > tdb->transaction->last_block_size) { - if (off >= tdb->transaction->last_block_size) { - return 0; - } - len = tdb->transaction->last_block_size - off; - } - - /* overwrite part of an existing block */ - memcpy(tdb->transaction->blocks[blk] + off, buf, len); - - return 0; -} - - -/* - accelerated hash chain head search, using the cached hash heads -*/ -static void transaction_next_hash_chain(struct tdb_context *tdb, uint32_t *chain) -{ - uint32_t h = *chain; - for (;h < tdb->header.hash_size;h++) { - /* the +1 takes account of the freelist */ - if (0 != tdb->transaction->hash_heads[h+1]) { - break; - } - } - (*chain) = h; -} - -/* - out of bounds check during a transaction -*/ -static int transaction_oob(struct tdb_context *tdb, tdb_off_t off, - tdb_len_t len, int probe) -{ - if (off + len >= off && off + len <= tdb->map_size) { - return 0; - } - tdb->ecode = TDB_ERR_IO; - return -1; -} - -/* - transaction version of tdb_expand(). -*/ -static int transaction_expand_file(struct tdb_context *tdb, tdb_off_t size, - tdb_off_t addition) -{ - /* add a write to the transaction elements, so subsequent - reads see the zero data */ - if (transaction_write(tdb, size, NULL, addition) != 0) { - return -1; - } - - tdb->transaction->expanded = true; - - return 0; -} - -static const struct tdb_methods transaction_methods = { - transaction_read, - transaction_write, - transaction_next_hash_chain, - transaction_oob, - transaction_expand_file, -}; - - -/* - start a tdb transaction. No token is returned, as only a single - transaction is allowed to be pending per tdb_context -*/ -static int _tdb_transaction_start(struct tdb_context *tdb, - enum tdb_lock_flags lockflags) -{ - /* some sanity checks */ - if (tdb->read_only || (tdb->flags & TDB_INTERNAL) || tdb->traverse_read) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction on a read-only or internal db\n")); - tdb->ecode = TDB_ERR_EINVAL; - return -1; - } - - /* cope with nested tdb_transaction_start() calls */ - if (tdb->transaction != NULL) { - if (!(tdb->flags & TDB_ALLOW_NESTING)) { - tdb->ecode = TDB_ERR_NESTING; - return -1; - } - tdb->transaction->nesting++; - TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_start: nesting %d\n", - tdb->transaction->nesting)); - return 0; - } - - if (tdb_have_extra_locks(tdb)) { - /* the caller must not have any locks when starting a - transaction as otherwise we'll be screwed by lack - of nested locks in posix */ - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction with locks held\n")); - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - - if (tdb->travlocks.next != NULL) { - /* you cannot use transactions inside a traverse (although you can use - traverse inside a transaction) as otherwise you can end up with - deadlock */ - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction within a traverse\n")); - tdb->ecode = TDB_ERR_LOCK; - return -1; - } - - tdb->transaction = (struct tdb_transaction *) - calloc(sizeof(struct tdb_transaction), 1); - if (tdb->transaction == NULL) { - tdb->ecode = TDB_ERR_OOM; - return -1; - } - - /* a page at a time seems like a reasonable compromise between compactness and efficiency */ - tdb->transaction->block_size = tdb->page_size; - - /* get the transaction write lock. This is a blocking lock. As - discussed with Volker, there are a number of ways we could - make this async, which we will probably do in the future */ - if (tdb_transaction_lock(tdb, F_WRLCK, lockflags) == -1) { - SAFE_FREE(tdb->transaction->blocks); - SAFE_FREE(tdb->transaction); - if ((lockflags & TDB_LOCK_WAIT) == 0) { - tdb->ecode = TDB_ERR_NOLOCK; - } - return -1; - } - - /* get a read lock from the freelist to the end of file. This - is upgraded to a write lock during the commit */ - if (tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, true) == -1) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to get hash locks\n")); - goto fail_allrecord_lock; - } - - /* setup a copy of the hash table heads so the hash scan in - traverse can be fast */ - tdb->transaction->hash_heads = (uint32_t *) - calloc(tdb->header.hash_size+1, sizeof(uint32_t)); - if (tdb->transaction->hash_heads == NULL) { - tdb->ecode = TDB_ERR_OOM; - goto fail; - } - if (tdb->methods->tdb_read(tdb, FREELIST_TOP, tdb->transaction->hash_heads, - TDB_HASHTABLE_SIZE(tdb), 0) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_start: failed to read hash heads\n")); - tdb->ecode = TDB_ERR_IO; - goto fail; - } - - /* make sure we know about any file expansions already done by - anyone else */ - tdb->methods->tdb_oob(tdb, tdb->map_size, 1, 1); - tdb->transaction->old_map_size = tdb->map_size; - - /* finally hook the io methods, replacing them with - transaction specific methods */ - tdb->transaction->io_methods = tdb->methods; - tdb->methods = &transaction_methods; - - /* Trace at the end, so we get sequence number correct. */ - tdb_trace(tdb, "tdb_transaction_start"); - return 0; - -fail: - tdb_allrecord_unlock(tdb, F_RDLCK, false); -fail_allrecord_lock: - tdb_transaction_unlock(tdb, F_WRLCK); - SAFE_FREE(tdb->transaction->blocks); - SAFE_FREE(tdb->transaction->hash_heads); - SAFE_FREE(tdb->transaction); - return -1; -} - -_PUBLIC_ int tdb_transaction_start(struct tdb_context *tdb) -{ - return _tdb_transaction_start(tdb, TDB_LOCK_WAIT); -} - -_PUBLIC_ int tdb_transaction_start_nonblock(struct tdb_context *tdb) -{ - return _tdb_transaction_start(tdb, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE); -} - -/* - sync to disk -*/ -static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t length) -{ - if (tdb->flags & TDB_NOSYNC) { - return 0; - } - -#ifdef HAVE_FDATASYNC - if (fdatasync(tdb->fd) != 0) { -#else - if (fsync(tdb->fd) != 0) { -#endif - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n")); - return -1; - } -#ifdef HAVE_MMAP - if (tdb->map_ptr) { - tdb_off_t moffset = offset & ~(tdb->page_size-1); - if (msync(moffset + (char *)tdb->map_ptr, - length + (offset - moffset), MS_SYNC) != 0) { - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: msync failed - %s\n", - strerror(errno))); - return -1; - } - } -#endif - return 0; -} - - -static int _tdb_transaction_cancel(struct tdb_context *tdb) -{ - int i, ret = 0; - - if (tdb->transaction == NULL) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_cancel: no transaction\n")); - return -1; - } - - if (tdb->transaction->nesting != 0) { - tdb->transaction->transaction_error = 1; - tdb->transaction->nesting--; - return 0; - } - - tdb->map_size = tdb->transaction->old_map_size; - - /* free all the transaction blocks */ - for (i=0;itransaction->num_blocks;i++) { - if (tdb->transaction->blocks[i] != NULL) { - free(tdb->transaction->blocks[i]); - } - } - SAFE_FREE(tdb->transaction->blocks); - - if (tdb->transaction->magic_offset) { - const struct tdb_methods *methods = tdb->transaction->io_methods; - const uint32_t invalid = TDB_RECOVERY_INVALID_MAGIC; - - /* remove the recovery marker */ - if (methods->tdb_write(tdb, tdb->transaction->magic_offset, &invalid, 4) == -1 || - transaction_sync(tdb, tdb->transaction->magic_offset, 4) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_cancel: failed to remove recovery magic\n")); - ret = -1; - } - } - - /* This also removes the OPEN_LOCK, if we have it. */ - tdb_release_transaction_locks(tdb); - - /* restore the normal io methods */ - tdb->methods = tdb->transaction->io_methods; - - SAFE_FREE(tdb->transaction->hash_heads); - SAFE_FREE(tdb->transaction); - - return ret; -} - -/* - cancel the current transaction -*/ -_PUBLIC_ int tdb_transaction_cancel(struct tdb_context *tdb) -{ - tdb_trace(tdb, "tdb_transaction_cancel"); - return _tdb_transaction_cancel(tdb); -} - -/* - work out how much space the linearised recovery data will consume -*/ -static tdb_len_t tdb_recovery_size(struct tdb_context *tdb) -{ - tdb_len_t recovery_size = 0; - int i; - - recovery_size = sizeof(uint32_t); - for (i=0;itransaction->num_blocks;i++) { - if (i * tdb->transaction->block_size >= tdb->transaction->old_map_size) { - break; - } - if (tdb->transaction->blocks[i] == NULL) { - continue; - } - recovery_size += 2*sizeof(tdb_off_t); - if (i == tdb->transaction->num_blocks-1) { - recovery_size += tdb->transaction->last_block_size; - } else { - recovery_size += tdb->transaction->block_size; - } - } - - return recovery_size; -} - -int tdb_recovery_area(struct tdb_context *tdb, - const struct tdb_methods *methods, - tdb_off_t *recovery_offset, - struct tdb_record *rec) -{ - if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, recovery_offset) == -1) { - return -1; - } - - if (*recovery_offset == 0) { - rec->rec_len = 0; - return 0; - } - - if (methods->tdb_read(tdb, *recovery_offset, rec, sizeof(*rec), - DOCONV()) == -1) { - return -1; - } - - /* ignore invalid recovery regions: can happen in crash */ - if (rec->magic != TDB_RECOVERY_MAGIC && - rec->magic != TDB_RECOVERY_INVALID_MAGIC) { - *recovery_offset = 0; - rec->rec_len = 0; - } - return 0; -} - -/* - allocate the recovery area, or use an existing recovery area if it is - large enough -*/ -static int tdb_recovery_allocate(struct tdb_context *tdb, - tdb_len_t *recovery_size, - tdb_off_t *recovery_offset, - tdb_len_t *recovery_max_size) -{ - struct tdb_record rec; - const struct tdb_methods *methods = tdb->transaction->io_methods; - tdb_off_t recovery_head, new_end; - - if (tdb_recovery_area(tdb, methods, &recovery_head, &rec) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery head\n")); - return -1; - } - - *recovery_size = tdb_recovery_size(tdb); - - /* Existing recovery area? */ - if (recovery_head != 0 && *recovery_size <= rec.rec_len) { - /* it fits in the existing area */ - *recovery_max_size = rec.rec_len; - *recovery_offset = recovery_head; - return 0; - } - - /* If recovery area in middle of file, we need a new one. */ - if (recovery_head == 0 - || recovery_head + sizeof(rec) + rec.rec_len != tdb->map_size) { - /* we need to free up the old recovery area, then allocate a - new one at the end of the file. Note that we cannot use - tdb_allocate() to allocate the new one as that might return - us an area that is being currently used (as of the start of - the transaction) */ - if (recovery_head) { - if (tdb_free(tdb, recovery_head, &rec) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, - "tdb_recovery_allocate: failed to" - " free previous recovery area\n")); - return -1; - } - - /* the tdb_free() call might have increased - * the recovery size */ - *recovery_size = tdb_recovery_size(tdb); - } - - /* New head will be at end of file. */ - recovery_head = tdb->map_size; - } - - /* Now we know where it will be. */ - *recovery_offset = recovery_head; - - /* Expand by more than we need, so we don't do it often. */ - *recovery_max_size = tdb_expand_adjust(tdb->map_size, - *recovery_size, - tdb->page_size) - - sizeof(rec); - - new_end = recovery_head + sizeof(rec) + *recovery_max_size; - - if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size, - new_end - tdb->transaction->old_map_size) - == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to create recovery area\n")); - return -1; - } - - /* remap the file (if using mmap) */ - methods->tdb_oob(tdb, tdb->map_size, 1, 1); - - /* we have to reset the old map size so that we don't try to expand the file - again in the transaction commit, which would destroy the recovery area */ - tdb->transaction->old_map_size = tdb->map_size; - - /* write the recovery header offset and sync - we can sync without a race here - as the magic ptr in the recovery record has not been set */ - CONVERT(recovery_head); - if (methods->tdb_write(tdb, TDB_RECOVERY_HEAD, - &recovery_head, sizeof(tdb_off_t)) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n")); - return -1; - } - if (transaction_write_existing(tdb, TDB_RECOVERY_HEAD, &recovery_head, sizeof(tdb_off_t)) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n")); - return -1; - } - - return 0; -} - - -/* - setup the recovery data that will be used on a crash during commit -*/ -static int transaction_setup_recovery(struct tdb_context *tdb, - tdb_off_t *magic_offset) -{ - tdb_len_t recovery_size; - unsigned char *data, *p; - const struct tdb_methods *methods = tdb->transaction->io_methods; - struct tdb_record *rec; - tdb_off_t recovery_offset, recovery_max_size; - tdb_off_t old_map_size = tdb->transaction->old_map_size; - uint32_t magic, tailer; - int i; - - /* - check that the recovery area has enough space - */ - if (tdb_recovery_allocate(tdb, &recovery_size, - &recovery_offset, &recovery_max_size) == -1) { - return -1; - } - - data = (unsigned char *)malloc(recovery_size + sizeof(*rec)); - if (data == NULL) { - tdb->ecode = TDB_ERR_OOM; - return -1; - } - - rec = (struct tdb_record *)data; - memset(rec, 0, sizeof(*rec)); - - rec->magic = TDB_RECOVERY_INVALID_MAGIC; - rec->data_len = recovery_size; - rec->rec_len = recovery_max_size; - rec->key_len = old_map_size; - CONVERT(*rec); - - /* build the recovery data into a single blob to allow us to do a single - large write, which should be more efficient */ - p = data + sizeof(*rec); - for (i=0;itransaction->num_blocks;i++) { - tdb_off_t offset; - tdb_len_t length; - - if (tdb->transaction->blocks[i] == NULL) { - continue; - } - - offset = i * tdb->transaction->block_size; - length = tdb->transaction->block_size; - if (i == tdb->transaction->num_blocks-1) { - length = tdb->transaction->last_block_size; - } - - if (offset >= old_map_size) { - continue; - } - if (offset + length > tdb->transaction->old_map_size) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: transaction data over new region boundary\n")); - free(data); - tdb->ecode = TDB_ERR_CORRUPT; - return -1; - } - memcpy(p, &offset, 4); - memcpy(p+4, &length, 4); - if (DOCONV()) { - tdb_convert(p, 8); - } - /* the recovery area contains the old data, not the - new data, so we have to call the original tdb_read - method to get it */ - if (methods->tdb_read(tdb, offset, p + 8, length, 0) != 0) { - free(data); - tdb->ecode = TDB_ERR_IO; - return -1; - } - p += 8 + length; - } - - /* and the tailer */ - tailer = sizeof(*rec) + recovery_max_size; - memcpy(p, &tailer, 4); - if (DOCONV()) { - tdb_convert(p, 4); - } - - /* write the recovery data to the recovery area */ - if (methods->tdb_write(tdb, recovery_offset, data, sizeof(*rec) + recovery_size) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write recovery data\n")); - free(data); - tdb->ecode = TDB_ERR_IO; - return -1; - } - if (transaction_write_existing(tdb, recovery_offset, data, sizeof(*rec) + recovery_size) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write secondary recovery data\n")); - free(data); - tdb->ecode = TDB_ERR_IO; - return -1; - } - - /* as we don't have ordered writes, we have to sync the recovery - data before we update the magic to indicate that the recovery - data is present */ - if (transaction_sync(tdb, recovery_offset, sizeof(*rec) + recovery_size) == -1) { - free(data); - return -1; - } - - free(data); - - magic = TDB_RECOVERY_MAGIC; - CONVERT(magic); - - *magic_offset = recovery_offset + offsetof(struct tdb_record, magic); - - if (methods->tdb_write(tdb, *magic_offset, &magic, sizeof(magic)) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write recovery magic\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - if (transaction_write_existing(tdb, *magic_offset, &magic, sizeof(magic)) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write secondary recovery magic\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - - /* ensure the recovery magic marker is on disk */ - if (transaction_sync(tdb, *magic_offset, sizeof(magic)) == -1) { - return -1; - } - - return 0; -} - -static int _tdb_transaction_prepare_commit(struct tdb_context *tdb) -{ - const struct tdb_methods *methods; - - if (tdb->transaction == NULL) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: no transaction\n")); - return -1; - } - - if (tdb->transaction->prepared) { - tdb->ecode = TDB_ERR_EINVAL; - _tdb_transaction_cancel(tdb); - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: transaction already prepared\n")); - return -1; - } - - if (tdb->transaction->transaction_error) { - tdb->ecode = TDB_ERR_IO; - _tdb_transaction_cancel(tdb); - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: transaction error pending\n")); - return -1; - } - - - if (tdb->transaction->nesting != 0) { - return 0; - } - - /* check for a null transaction */ - if (tdb->transaction->blocks == NULL) { - return 0; - } - - methods = tdb->transaction->io_methods; - - /* if there are any locks pending then the caller has not - nested their locks properly, so fail the transaction */ - if (tdb_have_extra_locks(tdb)) { - tdb->ecode = TDB_ERR_LOCK; - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: locks pending on commit\n")); - _tdb_transaction_cancel(tdb); - return -1; - } - - /* upgrade the main transaction lock region to a write lock */ - if (tdb_allrecord_upgrade(tdb) == -1) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to upgrade hash locks\n")); - _tdb_transaction_cancel(tdb); - return -1; - } - - /* get the open lock - this prevents new users attaching to the database - during the commit */ - if (tdb_nest_lock(tdb, OPEN_LOCK, F_WRLCK, TDB_LOCK_WAIT) == -1) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to get open lock\n")); - _tdb_transaction_cancel(tdb); - return -1; - } - - /* write the recovery data to the end of the file */ - if (transaction_setup_recovery(tdb, &tdb->transaction->magic_offset) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: failed to setup recovery data\n")); - _tdb_transaction_cancel(tdb); - return -1; - } - - tdb->transaction->prepared = true; - - /* expand the file to the new size if needed */ - if (tdb->map_size != tdb->transaction->old_map_size) { - if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size, - tdb->map_size - - tdb->transaction->old_map_size) == -1) { - tdb->ecode = TDB_ERR_IO; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: expansion failed\n")); - _tdb_transaction_cancel(tdb); - return -1; - } - tdb->map_size = tdb->transaction->old_map_size; - methods->tdb_oob(tdb, tdb->map_size, 1, 1); - } - - /* Keep the open lock until the actual commit */ - - return 0; -} - -/* - prepare to commit the current transaction -*/ -_PUBLIC_ int tdb_transaction_prepare_commit(struct tdb_context *tdb) -{ - tdb_trace(tdb, "tdb_transaction_prepare_commit"); - return _tdb_transaction_prepare_commit(tdb); -} - -/* A repack is worthwhile if the largest is less than half total free. */ -static bool repack_worthwhile(struct tdb_context *tdb) -{ - tdb_off_t ptr; - struct tdb_record rec; - tdb_len_t total = 0, largest = 0; - - if (tdb_ofs_read(tdb, FREELIST_TOP, &ptr) == -1) { - return false; - } - - while (ptr != 0 && tdb_rec_free_read(tdb, ptr, &rec) == 0) { - total += rec.rec_len; - if (rec.rec_len > largest) { - largest = rec.rec_len; - } - ptr = rec.next; - } - - return total > largest * 2; -} - -/* - commit the current transaction -*/ -_PUBLIC_ int tdb_transaction_commit(struct tdb_context *tdb) -{ - const struct tdb_methods *methods; - int i; - bool need_repack = false; - - if (tdb->transaction == NULL) { - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: no transaction\n")); - return -1; - } - - tdb_trace(tdb, "tdb_transaction_commit"); - - if (tdb->transaction->transaction_error) { - tdb->ecode = TDB_ERR_IO; - _tdb_transaction_cancel(tdb); - TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: transaction error pending\n")); - return -1; - } - - - if (tdb->transaction->nesting != 0) { - tdb->transaction->nesting--; - return 0; - } - - /* check for a null transaction */ - if (tdb->transaction->blocks == NULL) { - _tdb_transaction_cancel(tdb); - return 0; - } - - if (!tdb->transaction->prepared) { - int ret = _tdb_transaction_prepare_commit(tdb); - if (ret) - return ret; - } - - methods = tdb->transaction->io_methods; - - /* perform all the writes */ - for (i=0;itransaction->num_blocks;i++) { - tdb_off_t offset; - tdb_len_t length; - - if (tdb->transaction->blocks[i] == NULL) { - continue; - } - - offset = i * tdb->transaction->block_size; - length = tdb->transaction->block_size; - if (i == tdb->transaction->num_blocks-1) { - length = tdb->transaction->last_block_size; - } - - if (methods->tdb_write(tdb, offset, tdb->transaction->blocks[i], length) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed during commit\n")); - - /* we've overwritten part of the data and - possibly expanded the file, so we need to - run the crash recovery code */ - tdb->methods = methods; - tdb_transaction_recover(tdb); - - _tdb_transaction_cancel(tdb); - - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: write failed\n")); - return -1; - } - SAFE_FREE(tdb->transaction->blocks[i]); - } - - /* Do this before we drop lock or blocks. */ - if (tdb->transaction->expanded) { - need_repack = repack_worthwhile(tdb); - } - - SAFE_FREE(tdb->transaction->blocks); - tdb->transaction->num_blocks = 0; - - /* ensure the new data is on disk */ - if (transaction_sync(tdb, 0, tdb->map_size) == -1) { - return -1; - } - - /* - TODO: maybe write to some dummy hdr field, or write to magic - offset without mmap, before the last sync, instead of the - utime() call - */ - - /* on some systems (like Linux 2.6.x) changes via mmap/msync - don't change the mtime of the file, this means the file may - not be backed up (as tdb rounding to block sizes means that - file size changes are quite rare too). The following forces - mtime changes when a transaction completes */ -#ifdef HAVE_UTIME - utime(tdb->name, NULL); -#endif - - /* use a transaction cancel to free memory and remove the - transaction locks */ - _tdb_transaction_cancel(tdb); - - if (need_repack) { - return tdb_repack(tdb); - } - - return 0; -} - - -/* - recover from an aborted transaction. Must be called with exclusive - database write access already established (including the open - lock to prevent new processes attaching) -*/ -int tdb_transaction_recover(struct tdb_context *tdb) -{ - tdb_off_t recovery_head, recovery_eof; - unsigned char *data, *p; - uint32_t zero = 0; - struct tdb_record rec; - - /* find the recovery area */ - if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery head\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - - if (recovery_head == 0) { - /* we have never allocated a recovery record */ - return 0; - } - - /* read the recovery record */ - if (tdb->methods->tdb_read(tdb, recovery_head, &rec, - sizeof(rec), DOCONV()) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery record\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - - if (rec.magic != TDB_RECOVERY_MAGIC) { - /* there is no valid recovery data */ - return 0; - } - - if (tdb->read_only) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: attempt to recover read only database\n")); - tdb->ecode = TDB_ERR_CORRUPT; - return -1; - } - - recovery_eof = rec.key_len; - - data = (unsigned char *)malloc(rec.data_len); - if (data == NULL) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to allocate recovery data\n")); - tdb->ecode = TDB_ERR_OOM; - return -1; - } - - /* read the full recovery data */ - if (tdb->methods->tdb_read(tdb, recovery_head + sizeof(rec), data, - rec.data_len, 0) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery data\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - - /* recover the file data */ - p = data; - while (p+8 < data + rec.data_len) { - uint32_t ofs, len; - if (DOCONV()) { - tdb_convert(p, 8); - } - memcpy(&ofs, p, 4); - memcpy(&len, p+4, 4); - - if (tdb->methods->tdb_write(tdb, ofs, p+8, len) == -1) { - free(data); - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to recover %d bytes at offset %d\n", len, ofs)); - tdb->ecode = TDB_ERR_IO; - return -1; - } - p += 8 + len; - } - - free(data); - - if (transaction_sync(tdb, 0, tdb->map_size) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to sync recovery\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - - /* if the recovery area is after the recovered eof then remove it */ - if (recovery_eof <= recovery_head) { - if (tdb_ofs_write(tdb, TDB_RECOVERY_HEAD, &zero) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery head\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - } - - /* remove the recovery magic */ - if (tdb_ofs_write(tdb, recovery_head + offsetof(struct tdb_record, magic), - &zero) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery magic\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - - if (transaction_sync(tdb, 0, recovery_eof) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to sync2 recovery\n")); - tdb->ecode = TDB_ERR_IO; - return -1; - } - - TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_recover: recovered %d byte database\n", - recovery_eof)); - - /* all done */ - return 0; -} - -/* Any I/O failures we say "needs recovery". */ -bool tdb_needs_recovery(struct tdb_context *tdb) -{ - tdb_off_t recovery_head; - struct tdb_record rec; - - /* find the recovery area */ - if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) { - return true; - } - - if (recovery_head == 0) { - /* we have never allocated a recovery record */ - return false; - } - - /* read the recovery record */ - if (tdb->methods->tdb_read(tdb, recovery_head, &rec, - sizeof(rec), DOCONV()) == -1) { - return true; - } - - return (rec.magic == TDB_RECOVERY_MAGIC); -} diff --git a/ctdb/lib/tdb/common/traverse.c b/ctdb/lib/tdb/common/traverse.c deleted file mode 100644 index 517fecb4fc8d..000000000000 --- a/ctdb/lib/tdb/common/traverse.c +++ /dev/null @@ -1,366 +0,0 @@ - /* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 1999-2005 - Copyright (C) Paul `Rusty' Russell 2000 - Copyright (C) Jeremy Allison 2000-2003 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ - -#include "tdb_private.h" - -#define TDB_NEXT_LOCK_ERR ((tdb_off_t)-1) - -/* Uses traverse lock: 0 = finish, TDB_NEXT_LOCK_ERR = error, - other = record offset */ -static tdb_off_t tdb_next_lock(struct tdb_context *tdb, struct tdb_traverse_lock *tlock, - struct tdb_record *rec) -{ - int want_next = (tlock->off != 0); - - /* Lock each chain from the start one. */ - for (; tlock->hash < tdb->header.hash_size; tlock->hash++) { - if (!tlock->off && tlock->hash != 0) { - /* 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). - */ - tdb->methods->next_hash_chain(tdb, &tlock->hash); - if (tlock->hash == tdb->header.hash_size) { - continue; - } - } - - if (tdb_lock(tdb, tlock->hash, tlock->lock_rw) == -1) - return TDB_NEXT_LOCK_ERR; - - /* No previous record? Start at top of chain. */ - if (!tlock->off) { - if (tdb_ofs_read(tdb, TDB_HASH_TOP(tlock->hash), - &tlock->off) == -1) - goto fail; - } else { - /* Otherwise unlock the previous record. */ - if (tdb_unlock_record(tdb, tlock->off) != 0) - goto fail; - } - - if (want_next) { - /* We have offset of old record: grab next */ - if (tdb_rec_read(tdb, tlock->off, rec) == -1) - goto fail; - tlock->off = rec->next; - } - - /* Iterate through chain */ - while( tlock->off) { - tdb_off_t current; - if (tdb_rec_read(tdb, tlock->off, rec) == -1) - goto fail; - - /* Detect infinite loops. From "Shlomi Yaakobovich" . */ - if (tlock->off == rec->next) { - tdb->ecode = TDB_ERR_CORRUPT; - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_next_lock: loop detected.\n")); - goto fail; - } - - if (!TDB_DEAD(rec)) { - /* Woohoo: we found one! */ - if (tdb_lock_record(tdb, tlock->off) != 0) - goto fail; - return tlock->off; - } - - /* Try to clean dead ones from old traverses */ - current = tlock->off; - tlock->off = rec->next; - if (!(tdb->read_only || tdb->traverse_read) && - tdb_do_delete(tdb, current, rec) != 0) - goto fail; - } - tdb_unlock(tdb, tlock->hash, tlock->lock_rw); - want_next = 0; - } - /* We finished iteration without finding anything */ - tdb->ecode = TDB_SUCCESS; - return 0; - - fail: - tlock->off = 0; - if (tdb_unlock(tdb, tlock->hash, tlock->lock_rw) != 0) - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_next_lock: On error unlock failed!\n")); - return TDB_NEXT_LOCK_ERR; -} - -/* traverse the entire database - calling fn(tdb, key, data) on each element. - return -1 on error or the record count traversed - if fn is NULL then it is not called - a non-zero return value from fn() indicates that the traversal should stop - */ -static int tdb_traverse_internal(struct tdb_context *tdb, - tdb_traverse_func fn, void *private_data, - struct tdb_traverse_lock *tl) -{ - TDB_DATA key, dbuf; - struct tdb_record rec; - int ret = 0, count = 0; - tdb_off_t off; - - /* This was in the initializaton, above, but the IRIX compiler - * did not like it. crh - */ - tl->next = tdb->travlocks.next; - - /* fcntl locks don't stack: beware traverse inside traverse */ - tdb->travlocks.next = tl; - - /* tdb_next_lock places locks on the record returned, and its chain */ - while ((off = tdb_next_lock(tdb, tl, &rec)) != 0) { - if (off == TDB_NEXT_LOCK_ERR) { - ret = -1; - goto out; - } - count++; - /* now read the full record */ - key.dptr = tdb_alloc_read(tdb, tl->off + sizeof(rec), - rec.key_len + rec.data_len); - if (!key.dptr) { - ret = -1; - if (tdb_unlock(tdb, tl->hash, tl->lock_rw) != 0) - goto out; - if (tdb_unlock_record(tdb, tl->off) != 0) - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_traverse: key.dptr == NULL and unlock_record failed!\n")); - goto out; - } - key.dsize = rec.key_len; - dbuf.dptr = key.dptr + rec.key_len; - dbuf.dsize = rec.data_len; - - tdb_trace_1rec_retrec(tdb, "traverse", key, dbuf); - - /* Drop chain lock, call out */ - if (tdb_unlock(tdb, tl->hash, tl->lock_rw) != 0) { - ret = -1; - SAFE_FREE(key.dptr); - goto out; - } - if (fn && fn(tdb, key, dbuf, private_data)) { - /* They want us to terminate traversal */ - tdb_trace_ret(tdb, "tdb_traverse_end", count); - if (tdb_unlock_record(tdb, tl->off) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_traverse: unlock_record failed!\n"));; - ret = -1; - } - SAFE_FREE(key.dptr); - goto out; - } - SAFE_FREE(key.dptr); - } - tdb_trace(tdb, "tdb_traverse_end"); -out: - tdb->travlocks.next = tl->next; - if (ret < 0) - return -1; - else - return count; -} - - -/* - a write style traverse - temporarily marks the db read only -*/ -_PUBLIC_ int tdb_traverse_read(struct tdb_context *tdb, - tdb_traverse_func fn, void *private_data) -{ - struct tdb_traverse_lock tl = { NULL, 0, 0, F_RDLCK }; - int ret; - - /* we need to get a read lock on the transaction lock here to - cope with the lock ordering semantics of solaris10 */ - if (tdb_transaction_lock(tdb, F_RDLCK, TDB_LOCK_WAIT)) { - return -1; - } - - tdb->traverse_read++; - tdb_trace(tdb, "tdb_traverse_read_start"); - ret = tdb_traverse_internal(tdb, fn, private_data, &tl); - tdb->traverse_read--; - - tdb_transaction_unlock(tdb, F_RDLCK); - - return ret; -} - -/* - a write style traverse - needs to get the transaction lock to - prevent deadlocks - - WARNING: The data buffer given to the callback fn does NOT meet the - alignment restrictions malloc gives you. -*/ -_PUBLIC_ int tdb_traverse(struct tdb_context *tdb, - tdb_traverse_func fn, void *private_data) -{ - struct tdb_traverse_lock tl = { NULL, 0, 0, F_WRLCK }; - int ret; - - if (tdb->read_only || tdb->traverse_read) { - return tdb_traverse_read(tdb, fn, private_data); - } - - if (tdb_transaction_lock(tdb, F_WRLCK, TDB_LOCK_WAIT)) { - return -1; - } - - tdb->traverse_write++; - tdb_trace(tdb, "tdb_traverse_start"); - ret = tdb_traverse_internal(tdb, fn, private_data, &tl); - tdb->traverse_write--; - - tdb_transaction_unlock(tdb, F_WRLCK); - - return ret; -} - - -/* find the first entry in the database and return its key */ -_PUBLIC_ TDB_DATA tdb_firstkey(struct tdb_context *tdb) -{ - TDB_DATA key; - struct tdb_record rec; - tdb_off_t off; - - /* release any old lock */ - if (tdb_unlock_record(tdb, tdb->travlocks.off) != 0) - return tdb_null; - tdb->travlocks.off = tdb->travlocks.hash = 0; - tdb->travlocks.lock_rw = F_RDLCK; - - /* Grab first record: locks chain and returned record. */ - off = tdb_next_lock(tdb, &tdb->travlocks, &rec); - if (off == 0 || off == TDB_NEXT_LOCK_ERR) { - tdb_trace_retrec(tdb, "tdb_firstkey", tdb_null); - return tdb_null; - } - /* now read the key */ - key.dsize = rec.key_len; - key.dptr =tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec),key.dsize); - - tdb_trace_retrec(tdb, "tdb_firstkey", key); - - /* Unlock the hash chain of the record we just read. */ - if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0) - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_firstkey: error occurred while tdb_unlocking!\n")); - return key; -} - -/* find the next entry in the database, returning its key */ -_PUBLIC_ TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA oldkey) -{ - uint32_t oldhash; - TDB_DATA key = tdb_null; - struct tdb_record rec; - unsigned char *k = NULL; - tdb_off_t off; - - /* Is locked key the old key? If so, traverse will be reliable. */ - if (tdb->travlocks.off) { - if (tdb_lock(tdb,tdb->travlocks.hash,tdb->travlocks.lock_rw)) - return tdb_null; - if (tdb_rec_read(tdb, tdb->travlocks.off, &rec) == -1 - || !(k = tdb_alloc_read(tdb,tdb->travlocks.off+sizeof(rec), - rec.key_len)) - || memcmp(k, oldkey.dptr, oldkey.dsize) != 0) { - /* No, it wasn't: unlock it and start from scratch */ - if (tdb_unlock_record(tdb, tdb->travlocks.off) != 0) { - tdb_trace_1rec_retrec(tdb, "tdb_nextkey", - oldkey, tdb_null); - SAFE_FREE(k); - return tdb_null; - } - if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0) { - SAFE_FREE(k); - return tdb_null; - } - tdb->travlocks.off = 0; - } - - SAFE_FREE(k); - } - - if (!tdb->travlocks.off) { - /* No previous element: do normal find, and lock record */ - tdb->travlocks.off = tdb_find_lock_hash(tdb, oldkey, tdb->hash_fn(&oldkey), tdb->travlocks.lock_rw, &rec); - if (!tdb->travlocks.off) { - tdb_trace_1rec_retrec(tdb, "tdb_nextkey", oldkey, tdb_null); - return tdb_null; - } - tdb->travlocks.hash = BUCKET(rec.full_hash); - if (tdb_lock_record(tdb, tdb->travlocks.off) != 0) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: lock_record failed (%s)!\n", strerror(errno))); - return tdb_null; - } - } - oldhash = tdb->travlocks.hash; - - /* Grab next record: locks chain and returned record, - unlocks old record */ - off = tdb_next_lock(tdb, &tdb->travlocks, &rec); - if (off != TDB_NEXT_LOCK_ERR && off != 0) { - key.dsize = rec.key_len; - key.dptr = tdb_alloc_read(tdb, tdb->travlocks.off+sizeof(rec), - key.dsize); - /* Unlock the chain of this new record */ - if (tdb_unlock(tdb, tdb->travlocks.hash, tdb->travlocks.lock_rw) != 0) - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n")); - } - /* Unlock the chain of old record */ - if (tdb_unlock(tdb, BUCKET(oldhash), tdb->travlocks.lock_rw) != 0) - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_nextkey: WARNING tdb_unlock failed!\n")); - tdb_trace_1rec_retrec(tdb, "tdb_nextkey", oldkey, key); - return key; -} - diff --git a/ctdb/lib/tdb/docs/README b/ctdb/lib/tdb/docs/README deleted file mode 100644 index fe0e2581838a..000000000000 --- a/ctdb/lib/tdb/docs/README +++ /dev/null @@ -1,273 +0,0 @@ -tdb - a trivial database system -tridge@linuxcare.com December 1999 -================================== - -This is a simple database API. It was inspired by the realisation that -in Samba we have several ad-hoc bits of code that essentially -implement small databases for sharing structures between parts of -Samba. As I was about to add another I realised that a generic -database module was called for to replace all the ad-hoc bits. - -I based the interface on gdbm. I couldn't use gdbm as we need to be -able to have multiple writers to the databases at one time. - -Compilation ------------ - -add HAVE_MMAP=1 to use mmap instead of read/write -add NOLOCK=1 to disable locking code - -Testing -------- - -Compile tdbtest.c and link with gdbm for testing. tdbtest will perform -identical operations via tdb and gdbm then make sure the result is the -same - -Also included is tdbtool, which allows simple database manipulation -on the commandline. - -tdbtest and tdbtool are not built as part of Samba, but are included -for completeness. - -Interface ---------- - -The interface is very similar to gdbm except for the following: - -- different open interface. The tdb_open call is more similar to a - traditional open() -- no tdbm_reorganise() function -- no tdbm_sync() function. No operations are cached in the library anyway -- added a tdb_traverse() function for traversing the whole database -- added transactions support - -A general rule for using tdb is that the caller frees any returned -TDB_DATA structures. Just call free(p.dptr) to free a TDB_DATA -return value called p. This is the same as gdbm. - -here is a full list of tdb functions with brief descriptions. - - ----------------------------------------------------------------------- -TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags, - int open_flags, mode_t mode) - - open the database, creating it if necessary - - The open_flags and mode are passed straight to the open call on the database - file. A flags value of O_WRONLY is invalid - - The hash size is advisory, use zero for a default value. - - return is NULL on error - - possible tdb_flags are: - TDB_CLEAR_IF_FIRST - clear database if we are the only one with it open - TDB_INTERNAL - don't use a file, instaed store the data in - memory. The filename is ignored in this case. - TDB_NOLOCK - don't do any locking - TDB_NOMMAP - don't use mmap - TDB_NOSYNC - don't synchronise transactions to disk - TDB_SEQNUM - maintain a sequence number - TDB_VOLATILE - activate the per-hashchain freelist, default 5 - TDB_ALLOW_NESTING - allow transactions to nest - TDB_DISALLOW_NESTING - disallow transactions to nest - ----------------------------------------------------------------------- -TDB_CONTEXT *tdb_open_ex(char *name, int hash_size, int tdb_flags, - int open_flags, mode_t mode, - const struct tdb_logging_context *log_ctx, - tdb_hash_func hash_fn) - -This is like tdb_open(), but allows you to pass an initial logging and -hash function. Be careful when passing a hash function - all users of -the database must use the same hash function or you will get data -corruption. - - ----------------------------------------------------------------------- -char *tdb_error(TDB_CONTEXT *tdb); - - return a error string for the last tdb error - ----------------------------------------------------------------------- -int tdb_close(TDB_CONTEXT *tdb); - - close a database - ----------------------------------------------------------------------- -TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key); - - fetch an entry in the database given a key - if the return value has a null dptr then a error occurred - - caller must free the resulting data - ----------------------------------------------------------------------- -int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key, - int (*parser)(TDB_DATA key, TDB_DATA data, - void *private_data), - void *private_data); - - Hand a record to a parser function without allocating it. - - This function is meant as a fast tdb_fetch alternative for large records - that are frequently read. The "key" and "data" arguments point directly - into the tdb shared memory, they are not aligned at any boundary. - - WARNING: The parser is called while tdb holds a lock on the record. DO NOT - call other tdb routines from within the parser. Also, for good performance - you should make the parser fast to allow parallel operations. - - tdb_parse_record returns -1 if the record was not found. If the record was - found, the return value of "parser" is passed up to the caller. - ----------------------------------------------------------------------- -int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key); - - check if an entry in the database exists - - note that 1 is returned if the key is found and 0 is returned if not found - this doesn't match the conventions in the rest of this module, but is - compatible with gdbm - ----------------------------------------------------------------------- -int tdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb, - TDB_DATA key, TDB_DATA dbuf, void *state), void *state); - - traverse the entire database - calling fn(tdb, key, data, state) on each - element. - - return -1 on error or the record count traversed - - if fn is NULL then it is not called - - a non-zero return value from fn() indicates that the traversal - should stop. Traversal callbacks may not start transactions. - - WARNING: The data buffer given to the callback fn does NOT meet the - alignment restrictions malloc gives you. - ----------------------------------------------------------------------- -int tdb_traverse_read(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb, - TDB_DATA key, TDB_DATA dbuf, void *state), void *state); - - traverse the entire database - calling fn(tdb, key, data, state) on - each element, but marking the database read only during the - traversal, so any write operations will fail. This allows tdb to - use read locks, which increases the parallelism possible during the - traversal. - - return -1 on error or the record count traversed - - if fn is NULL then it is not called - - a non-zero return value from fn() indicates that the traversal - should stop. Traversal callbacks may not start transactions. - ----------------------------------------------------------------------- -TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb); - - find the first entry in the database and return its key - - the caller must free the returned data - ----------------------------------------------------------------------- -TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key); - - find the next entry in the database, returning its key - - the caller must free the returned data - ----------------------------------------------------------------------- -int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key); - - delete an entry in the database given a key - ----------------------------------------------------------------------- -int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag); - - store an element in the database, replacing any existing element - with the same key - - If flag==TDB_INSERT then don't overwrite an existing entry - If flag==TDB_MODIFY then don't create a new entry - - return 0 on success, -1 on failure - ----------------------------------------------------------------------- -int tdb_writelock(TDB_CONTEXT *tdb); - - lock the database. If we already have it locked then don't do anything - ----------------------------------------------------------------------- -int tdb_writeunlock(TDB_CONTEXT *tdb); - unlock the database - ----------------------------------------------------------------------- -int tdb_lockchain(TDB_CONTEXT *tdb, TDB_DATA key); - - lock one hash chain. This is meant to be used to reduce locking - contention - it cannot guarantee how many records will be locked - ----------------------------------------------------------------------- -int tdb_unlockchain(TDB_CONTEXT *tdb, TDB_DATA key); - - unlock one hash chain - ----------------------------------------------------------------------- -int tdb_transaction_start(TDB_CONTEXT *tdb) - - start a transaction. All operations after the transaction start can - either be committed with tdb_transaction_commit() or cancelled with - tdb_transaction_cancel(). - - If you call tdb_transaction_start() again on the same tdb context - while a transaction is in progress, then the same transaction - buffer is re-used. The number of tdb_transaction_{commit,cancel} - operations must match the number of successful - tdb_transaction_start() calls. - - Note that transactions are by default disk synchronous, and use a - recover area in the database to automatically recover the database - on the next open if the system crashes during a transaction. You - can disable the synchronous transaction recovery setup using the - TDB_NOSYNC flag, which will greatly speed up operations at the risk - of corrupting your database if the system crashes. - - Operations made within a transaction are not visible to other users - of the database until a successful commit. - ----------------------------------------------------------------------- -int tdb_transaction_cancel(TDB_CONTEXT *tdb) - - cancel a current transaction, discarding all write and lock - operations that have been made since the transaction started. - - ----------------------------------------------------------------------- -int tdb_transaction_commit(TDB_CONTEXT *tdb) - - commit a current transaction, updating the database and releasing - the transaction locks. - ----------------------------------------------------------------------- -int tdb_transaction_prepare_commit(TDB_CONTEXT *tdb) - - prepare to commit a current transaction, for two-phase commits. - Once prepared for commit, the only allowed calls are - tdb_transaction_commit() or tdb_transaction_cancel(). Preparing - allocates disk space for the pending updates, so a subsequent - commit should succeed (barring any hardware failures). - ----------------------------------------------------------------------- -int tdb_check(TDB_CONTEXT *tdb, - int (*check)(TDB_DATA key, TDB_DATA data, void *private_data), - void *private_data);) - - check the consistency of the database, calling back the check function - (if non-NULL) with each record. If some consistency check fails, or - the supplied check function returns -1, tdb_check returns -1, otherwise - 0. Note that logging function (if set) will be called with additional - information on the corruption found. diff --git a/ctdb/lib/tdb/docs/mainpage.dox b/ctdb/lib/tdb/docs/mainpage.dox deleted file mode 100644 index d1307693566f..000000000000 --- a/ctdb/lib/tdb/docs/mainpage.dox +++ /dev/null @@ -1,61 +0,0 @@ -/** - -@mainpage - -This is a simple database API. It was inspired by the realisation that in Samba -we have several ad-hoc bits of code that essentially implement small databases -for sharing structures between parts of Samba. - -The interface is based on gdbm. gdbm couldn't be use as we needed to be able to -have multiple writers to the databases at one time. - -@section tdb_download Download - -You can download the latest releases of tdb from the -tdb directory on the samba public source -archive. - -You can download the latest code either via git or rsync. - -To fetch via git see the following guide: - -Using Git for Samba Development -Once you have cloned the tree switch to the master branch and cd into the source/lib/tdb directory. - -To fetch via rsync use these commands: - -
-  rsync -Pavz samba.org::ftp/unpacked/standalone_projects/lib/tdb .
-  rsync -Pavz samba.org::ftp/unpacked/standalone_projects/lib/replace .
-
- -and build in tdb. It will find the replace library in the directory above -automatically. - -@section tdb_bugs Discussion and bug reports - -tdb does not currently have its own mailing list or bug tracking system. For now, -please use the -samba-technical -mailing list, and the Samba bugzilla bug -tracking system. - - -@section tdb_compilation Compilation - -add HAVE_MMAP=1 to use mmap instead of read/write -add NOLOCK=1 to disable locking code - -@section tdb_testing Testing - -Compile tdbtest.c and link with gdbm for testing. tdbtest will perform -identical operations via tdb and gdbm then make sure the result is the -same - -Also included is tdbtool, which allows simple database manipulation -on the commandline. - -tdbtest and tdbtool are not built as part of Samba, but are included -for completeness. - -*/ diff --git a/ctdb/lib/tdb/docs/tdb.magic b/ctdb/lib/tdb/docs/tdb.magic deleted file mode 100644 index f5619e7327e2..000000000000 --- a/ctdb/lib/tdb/docs/tdb.magic +++ /dev/null @@ -1,10 +0,0 @@ -# Magic file(1) information about tdb files. -# -# Install this into /etc/magic or the corresponding location for your -# system, or pass as a -m argument to file(1). - -# You may use and redistribute this file without restriction. - -0 string TDB\ file TDB database ->32 lelong =0x2601196D version 6, little-endian ->>36 lelong x hash size %d bytes diff --git a/ctdb/lib/tdb/docs/tracing.txt b/ctdb/lib/tdb/docs/tracing.txt deleted file mode 100644 index 98c5db9a51b4..000000000000 --- a/ctdb/lib/tdb/docs/tracing.txt +++ /dev/null @@ -1,46 +0,0 @@ -How And Why To Use TDB Tracing -============================== - -You can trace all TDB operations, using TDB_TRACE. It is not complete -(error conditions which expect to the logged will not always be traced -correctly, so you should set up a logging function too), but is designed -to collect benchmark-style traces to allow us to optimize TDB. - -Note: tracing is not efficient, and the trace files are huge: a -traverse of the database is particularly large! But they compress very -well with rzip (http://rzip.samba.org) - -How to gather trace files: --------------------------- -1) Uncomment /* #define TDB_TRACE 1 */ in tdb_private.h. -2) Rebuild TDB, and everything that uses it. -3) Run something. - -Your trace files will be called .trace.. These files -will not be overwritten: if the same process reopens the same TDB, an -error will be logged and tracing will be disabled. - -How to replay trace files: --------------------------- -1) For benchmarking, remember to rebuild tdb with #define TDB_TRACE commented - out again! -2) Grab the latest "replace_trace.c" from CCAN's tdb module (tools/ dir): - http://ccan.ozlabs.org/tarballs/tdb.tar.bz2 -3) Compile up replay_trace, munging as necessary. -4) Run replay_trace ... - -If given more than one trace file (presumably from the same tdb) -replay_trace will try to figure out the dependencies between the operations -and fire off a child to run each trace. Occasionally it gets stuck, in -which case it will add another dependency and retry. Eventually it will -give a speed value. - -replay_trace can intuit the existence of previous data in the tdb (ie. -activity prior to the trace(s) supplied) and will prepopulate as -neccessary. - -You can run --quiet for straight benchmark results, and -n to run multiple -times (this saves time, since it need only calculate dependencies once). - -Good luck! -Rusty Russell diff --git a/ctdb/lib/tdb/doxy.config b/ctdb/lib/tdb/doxy.config deleted file mode 100644 index f55e9c3c274f..000000000000 --- a/ctdb/lib/tdb/doxy.config +++ /dev/null @@ -1,1697 +0,0 @@ -# Doxyfile 1.7.3 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project. -# -# All text after a hash (#) is considered a comment and will be ignored. -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" "). - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = tdb - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = 1.2.9 - -# Using the PROJECT_BRIEF tag one can provide an optional one line description for a project that appears at the top of each page and should give viewer a quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = - -# With the PROJECT_LOGO tag one can specify an logo or icon that is -# included in the documentation. The maximum height of the logo should not -# exceed 55 pixels and the maximum width should not exceed 200 pixels. -# Doxygen will copy the logo to the output directory. - -PROJECT_LOGO = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = docs - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, -# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English -# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, -# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, -# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = "The $name class" \ - "The $name widget" \ - "The $name file" \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = YES - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful if your file system -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = YES - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 8 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = YES - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given extension. -# Doxygen has a built-in mapping, but you can override or extend it using this -# tag. The format is ext=language, where ext is a file extension, and language -# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, -# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions -# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. - -EXTENSION_MAPPING = - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also makes the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = NO - -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penalty. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will roughly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols - -SYMBOL_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = NO - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = NO - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespaces are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = YES - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = YES - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen -# will list include files with double quotes in the documentation -# rather than with sharp brackets. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen -# will sort the (brief and detailed) documentation of class members so that -# constructors and destructors are listed first. If set to NO (the default) -# the constructors will appear in the respective orders defined by -# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. -# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO -# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper type resolution of all parameters of a function it will reject a -# match between the prototype and the implementation of a member function even if there is only one candidate or it is obvious which candidate to choose by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen -# will still accept a match between prototype and implementation in such cases. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or macro consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and macros in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = NO - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. -# This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. The create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. -# You can optionally specify a file name after the option, if omitted -# DoxygenLayout.xml will be used as the name of the layout file. - -LAYOUT_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# The WARN_NO_PARAMDOC option can be enabled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = include \ - docs - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh -# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py -# *.f90 *.f *.for *.vhd *.vhdl - -FILE_PATTERNS = *.cpp \ - *.cc \ - *.c \ - *.h \ - *.hh \ - *.hpp \ - *.dox - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = NO - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = */.git/* - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. -# If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. -# Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. -# The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty or if -# non of the patterns match the file name, INPUT_FILTER is applied. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) -# and it is also possible to disable source filtering for a specific pattern -# using *.ext= (so without naming a filter). This option only has effect when -# FILTER_SOURCE_FILES is enabled. - -FILTER_SOURCE_PATTERNS = - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. -# Otherwise they will link to the documentation. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = NO - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. -# Doxygen will adjust the colors in the stylesheet and background images -# according to this color. Hue is specified as an angle on a colorwheel, -# see http://en.wikipedia.org/wiki/Hue for more information. -# For instance the value 0 represents red, 60 is yellow, 120 is green, -# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. -# The allowed range is 0 to 359. - -HTML_COLORSTYLE_HUE = 220 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of -# the colors in the HTML output. For a value of 0 the output will use -# grayscales only. A value of 255 will produce the most vivid colors. - -HTML_COLORSTYLE_SAT = 100 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to -# the luminance component of the colors in the HTML output. Values below -# 100 gradually make the output lighter, whereas values above 100 make -# the output darker. The value divided by 100 is the actual gamma applied, -# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, -# and 100 does not change the gamma. - -HTML_COLORSTYLE_GAMMA = 80 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting -# this to NO can help when comparing the output of multiple runs. - -HTML_TIMESTAMP = NO - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). - -HTML_DYNAMIC_SECTIONS = NO - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. - -CHM_INDEX_ENCODING = - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated -# that can be used as input for Qt's qhelpgenerator to generate a -# Qt Compressed Help (.qch) of the generated HTML documentation. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace - -QHP_NAMESPACE = - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders - -QHP_VIRTUAL_FOLDER = doc - -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to -# add. For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see -# -# Qt Help Project / Custom Filters. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's -# filter section matches. -# -# Qt Help Project / Filter Attributes. - -QHP_SECT_FILTER_ATTRS = - -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files -# will be generated, which together with the HTML files, form an Eclipse help -# plugin. To install this plugin and make it available under the help contents -# menu in Eclipse, the contents of the directory containing the HTML and XML -# files needs to be copied into the plugins directory of eclipse. The name of -# the directory within the plugins directory should be the same as -# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before -# the help appears. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have -# this name. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [0,1..20]) -# that doxygen will group on one line in the generated HTML documentation. -# Note that a value of 0 will completely suppress the enum values from appearing in the overview section. - -ENUM_VALUES_PER_LINE = 4 - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to YES, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). -# Windows users are probably better off using the HTML help feature. - -GENERATE_TREEVIEW = NONE - -# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, -# and Class Hierarchy pages using a tree view instead of an ordered list. - -USE_INLINE_TREES = NO - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open -# links to external symbols imported via tag files in a separate window. - -EXT_LINKS_IN_WINDOW = NO - -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are -# not supported properly for IE 6.0, but are supported on all modern browsers. -# Note that when changing this option you need to delete any form_*.png files -# in the HTML output before the changes have effect. - -FORMULA_TRANSPARENT = YES - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax -# (see http://www.mathjax.org) which uses client side Javascript for the -# rendering instead of using prerendered bitmaps. Use this if you do not -# have LaTeX installed or if you want to formulas look prettier in the HTML -# output. When enabled you also need to install MathJax separately and -# configure the path to it using the MATHJAX_RELPATH option. - -USE_MATHJAX = NO - -# When MathJax is enabled you need to specify the location relative to the -# HTML output directory using the MATHJAX_RELPATH option. The destination -# directory should contain the MathJax.js script. For instance, if the mathjax -# directory is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to the mathjax.org site, so you can quickly see the result without installing -# MathJax, but it is strongly recommended to install a local copy of MathJax -# before deployment. - -MATHJAX_RELPATH = http://www.mathjax.org/mathjax - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box -# for the HTML output. The underlying search engine uses javascript -# and DHTML and should work on any modern browser. Note that when using -# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets -# (GENERATE_DOCSET) there is already a search function so this one should -# typically be disabled. For large projects the javascript based search engine -# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. - -SEARCHENGINE = NO - -# When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a PHP enabled web server instead of at the web client -# using Javascript. Doxygen will generate the search PHP script and index -# file to put on the web server. The advantage of the server -# based approach is that it scales better to large projects and allows -# full text search. The disadvantages are that it is more difficult to setup -# and does not have live searching capabilities. - -SERVER_BASED_SEARCH = NO - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = YES - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. -# Note that when enabling USE_PDFLATEX this option is only used for -# generating bitmaps for formulas in the HTML output, but not in the -# Makefile that is written to the output directory. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -# If LATEX_SOURCE_CODE is set to YES then doxygen will include -# source code with syntax highlighting in the LaTeX output. -# Note that which sources are shown also depends on other settings -# such as SOURCE_BROWSER. - -LATEX_SOURCE_CODE = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = YES - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. -# This is useful -# if you want to understand what is going on. -# On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = YES - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = YES - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = DOXYGEN \ - PRINTF_ATTRIBUTE(x,y)= - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition that overrules the definition found in the source code. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all references to function-like macros -# that are alone on a line, have an all uppercase name, and do not end with a -# semicolon, because these will confuse the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option also works with HAVE_DOT disabled, but it is recommended to -# install and use dot, since it yields more powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is -# allowed to run in parallel. When set to 0 (the default) doxygen will -# base this on the number of processors available in the system. You can set it -# explicitly to a value larger than 0 to get control over the balance -# between CPU load and processing speed. - -DOT_NUM_THREADS = 0 - -# By default doxygen will write a font called Helvetica to the output -# directory and reference it in all dot files that doxygen generates. -# When you want a differently looking font you can specify the font name -# using DOT_FONTNAME. You need to make sure dot is able to find the font, -# which can be done by putting it in a standard location or by setting the -# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory -# containing the font. - -DOT_FONTNAME = FreeSans - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the output directory to look for the -# FreeSans.ttf font (which doxygen will put there itself). If you specify a -# different font using DOT_FONTNAME you can set the path where dot -# can find it using this tag. - -DOT_FONTPATH = - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will generate a graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, svg, gif or svg. -# If left blank png will be used. - -DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the -# \mscfile command). - -MSCFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = YES - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES diff --git a/ctdb/lib/tdb/include/tdb.h b/ctdb/lib/tdb/include/tdb.h deleted file mode 100644 index d19439e76022..000000000000 --- a/ctdb/lib/tdb/include/tdb.h +++ /dev/null @@ -1,869 +0,0 @@ -#ifndef __TDB_H__ -#define __TDB_H__ - -/* - Unix SMB/CIFS implementation. - - trivial database library - - Copyright (C) Andrew Tridgell 1999-2004 - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/** - * @defgroup tdb The tdb API - * - * tdb is a Trivial database. In concept, it is very much like GDBM, and BSD's - * DB except that it allows multiple simultaneous writers and uses locking - * internally to keep writers from trampling on each other. tdb is also - * extremely small. - * - * @section tdb_interface Interface - * - * The interface is very similar to gdbm except for the following: - * - *
    - *
  • different open interface. The tdb_open call is more similar to a - * traditional open()
  • - *
  • no tdbm_reorganise() function
  • - *
  • no tdbm_sync() function. No operations are cached in the library - * anyway
  • - *
  • added a tdb_traverse() function for traversing the whole database
  • - *
  • added transactions support
  • - *
- * - * A general rule for using tdb is that the caller frees any returned TDB_DATA - * structures. Just call free(p.dptr) to free a TDB_DATA return value called p. - * This is the same as gdbm. - * - * @{ - */ - -/** Flags to tdb_store() */ -#define TDB_REPLACE 1 /** Unused */ -#define TDB_INSERT 2 /** Don't overwrite an existing entry */ -#define TDB_MODIFY 3 /** Don't create an existing entry */ - -/** Flags for tdb_open() */ -#define TDB_DEFAULT 0 /** just a readability place holder */ -#define TDB_CLEAR_IF_FIRST 1 /** If this is the first open, wipe the db */ -#define TDB_INTERNAL 2 /** Don't store on disk */ -#define TDB_NOLOCK 4 /** Don't do any locking */ -#define TDB_NOMMAP 8 /** Don't use mmap */ -#define TDB_CONVERT 16 /** Convert endian (internal use) */ -#define TDB_BIGENDIAN 32 /** Header is big-endian (internal use) */ -#define TDB_NOSYNC 64 /** Don't use synchronous transactions */ -#define TDB_SEQNUM 128 /** Maintain a sequence number */ -#define TDB_VOLATILE 256 /** Activate the per-hashchain freelist, default 5 */ -#define TDB_ALLOW_NESTING 512 /** Allow transactions to nest */ -#define TDB_DISALLOW_NESTING 1024 /** Disallow transactions to nest */ -#define TDB_INCOMPATIBLE_HASH 2048 /** Better hashing: can't be opened by tdb < 1.2.6. */ - -/** The tdb error codes */ -enum TDB_ERROR {TDB_SUCCESS=0, TDB_ERR_CORRUPT, TDB_ERR_IO, TDB_ERR_LOCK, - TDB_ERR_OOM, TDB_ERR_EXISTS, TDB_ERR_NOLOCK, TDB_ERR_LOCK_TIMEOUT, - TDB_ERR_NOEXIST, TDB_ERR_EINVAL, TDB_ERR_RDONLY, - TDB_ERR_NESTING}; - -/** Debugging uses one of the following levels */ -enum tdb_debug_level {TDB_DEBUG_FATAL = 0, TDB_DEBUG_ERROR, - TDB_DEBUG_WARNING, TDB_DEBUG_TRACE}; - -/** The tdb data structure */ -typedef struct TDB_DATA { - unsigned char *dptr; - size_t dsize; -} TDB_DATA; - -#ifndef PRINTF_ATTRIBUTE -#if (__GNUC__ >= 3) -/** Use gcc attribute to check printf fns. a1 is the 1-based index of - * the parameter containing the format, and a2 the index of the first - * argument. Note that some gcc 2.x versions don't handle this - * properly **/ -#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2))) -#else -#define PRINTF_ATTRIBUTE(a1, a2) -#endif -#endif - -/** This is the context structure that is returned from a db open. */ -typedef struct tdb_context TDB_CONTEXT; - -typedef int (*tdb_traverse_func)(struct tdb_context *, TDB_DATA, TDB_DATA, void *); -typedef void (*tdb_log_func)(struct tdb_context *, enum tdb_debug_level, const char *, ...) PRINTF_ATTRIBUTE(3, 4); -typedef unsigned int (*tdb_hash_func)(TDB_DATA *key); - -struct tdb_logging_context { - tdb_log_func log_fn; - void *log_private; -}; - -/** - * @brief Open the database and creating it if necessary. - * - * @param[in] name The name of the db to open. - * - * @param[in] hash_size The hash size is advisory, use zero for a default - * value. - * - * @param[in] tdb_flags The flags to use to open the db:\n\n - * TDB_CLEAR_IF_FIRST - Clear database if we are the - * only one with it open\n - * TDB_INTERNAL - Don't use a file, instaed store the - * data in memory. The filename is - * ignored in this case.\n - * TDB_NOLOCK - Don't do any locking\n - * TDB_NOMMAP - Don't use mmap\n - * TDB_NOSYNC - Don't synchronise transactions to disk\n - * TDB_SEQNUM - Maintain a sequence number\n - * TDB_VOLATILE - activate the per-hashchain freelist, - * default 5.\n - * TDB_ALLOW_NESTING - Allow transactions to nest.\n - * TDB_DISALLOW_NESTING - Disallow transactions to nest.\n - * - * @param[in] open_flags Flags for the open(2) function. - * - * @param[in] mode The mode for the open(2) function. - * - * @return A tdb context structure, NULL on error. - */ -struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags, - int open_flags, mode_t mode); - -/** - * @brief Open the database and creating it if necessary. - * - * This is like tdb_open(), but allows you to pass an initial logging and - * hash function. Be careful when passing a hash function - all users of the - * database must use the same hash function or you will get data corruption. - * - * @param[in] name The name of the db to open. - * - * @param[in] hash_size The hash size is advisory, use zero for a default - * value. - * - * @param[in] tdb_flags The flags to use to open the db:\n\n - * TDB_CLEAR_IF_FIRST - Clear database if we are the - * only one with it open\n - * TDB_INTERNAL - Don't use a file, instaed store the - * data in memory. The filename is - * ignored in this case.\n - * TDB_NOLOCK - Don't do any locking\n - * TDB_NOMMAP - Don't use mmap\n - * TDB_NOSYNC - Don't synchronise transactions to disk\n - * TDB_SEQNUM - Maintain a sequence number\n - * TDB_VOLATILE - activate the per-hashchain freelist, - * default 5.\n - * TDB_ALLOW_NESTING - Allow transactions to nest.\n - * TDB_DISALLOW_NESTING - Disallow transactions to nest.\n - * - * @param[in] open_flags Flags for the open(2) function. - * - * @param[in] mode The mode for the open(2) function. - * - * @param[in] log_ctx The logging function to use. - * - * @param[in] hash_fn The hash function you want to use. - * - * @return A tdb context structure, NULL on error. - * - * @see tdb_open() - */ -struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags, - int open_flags, mode_t mode, - const struct tdb_logging_context *log_ctx, - tdb_hash_func hash_fn); - -/** - * @brief Set the maximum number of dead records per hash chain. - * - * @param[in] tdb The database handle to set the maximum. - * - * @param[in] max_dead The maximum number of dead records per hash chain. - */ -void tdb_set_max_dead(struct tdb_context *tdb, int max_dead); - -/** - * @brief Reopen a tdb. - * - * This can be used after a fork to ensure that we have an independent seek - * pointer from our parent and to re-establish locks. - * - * @param[in] tdb The database to reopen. - * - * @return 0 on success, -1 on error. - */ -int tdb_reopen(struct tdb_context *tdb); - -/** - * @brief Reopen all tdb's - * - * If the parent is longlived (ie. a parent daemon architecture), we know it - * will keep it's active lock on a tdb opened with CLEAR_IF_FIRST. Thus for - * child processes we don't have to add an active lock. This is essential to - * improve performance on systems that keep POSIX locks as a non-scalable data - * structure in the kernel. - * - * @param[in] parent_longlived Wether the parent is longlived or not. - * - * @return 0 on success, -1 on error. - */ -int tdb_reopen_all(int parent_longlived); - -/** - * @brief Set a different tdb logging function. - * - * @param[in] tdb The tdb to set the logging function. - * - * @param[in] log_ctx The logging function to set. - */ -void tdb_set_logging_function(struct tdb_context *tdb, const struct tdb_logging_context *log_ctx); - -/** - * @brief Get the tdb last error code. - * - * @param[in] tdb The tdb to get the error code from. - * - * @return A TDB_ERROR code. - * - * @see TDB_ERROR - */ -enum TDB_ERROR tdb_error(struct tdb_context *tdb); - -/** - * @brief Get a error string for the last tdb error - * - * @param[in] tdb The tdb to get the error code from. - * - * @return An error string. - */ -const char *tdb_errorstr(struct tdb_context *tdb); - -/** - * @brief Fetch an entry in the database given a key. - * - * The caller must free the resulting data. - * - * @param[in] tdb The tdb to fetch the key. - * - * @param[in] key The key to fetch. - * - * @return The key entry found in the database, NULL on error with - * TDB_ERROR set. - * - * @see tdb_error() - * @see tdb_errorstr() - */ -TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key); - -/** - * @brief Hand a record to a parser function without allocating it. - * - * This function is meant as a fast tdb_fetch alternative for large records - * that are frequently read. The "key" and "data" arguments point directly - * into the tdb shared memory, they are not aligned at any boundary. - * - * @warning The parser is called while tdb holds a lock on the record. DO NOT - * call other tdb routines from within the parser. Also, for good performance - * you should make the parser fast to allow parallel operations. - * - * @param[in] tdb The tdb to parse the record. - * - * @param[in] key The key to parse. - * - * @param[in] parser The parser to use to parse the data. - * - * @param[in] private_data A private data pointer which is passed to the parser - * function. - * - * @return -1 if the record was not found. If the record was found, - * the return value of "parser" is passed up to the caller. - */ -int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key, - int (*parser)(TDB_DATA key, TDB_DATA data, - void *private_data), - void *private_data); - -/** - * @brief Delete an entry in the database given a key. - * - * @param[in] tdb The tdb to delete the key. - * - * @param[in] key The key to delete. - * - * @return 0 on success, -1 if the key doesn't exist. - */ -int tdb_delete(struct tdb_context *tdb, TDB_DATA key); - -/** - * @brief Store an element in the database. - * - * This replaces any existing element with the same key. - * - * @param[in] tdb The tdb to store the entry. - * - * @param[in] key The key to use to store the entry. - * - * @param[in] dbuf The data to store under the key. - * - * @param[in] flag The flags to store the key:\n\n - * TDB_INSERT: Don't overwrite an existing entry.\n - * TDB_MODIFY: Don't create a new entry\n - * - * @return 0 on success, -1 on error with error code set. - * - * @see tdb_error() - * @see tdb_errorstr() - */ -int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag); - -/** - * @brief Append data to an entry. - * - * If the entry doesn't exist, it will create a new one. - * - * @param[in] tdb The database to use. - * - * @param[in] key The key to append the data. - * - * @param[in] new_dbuf The data to append to the key. - * - * @return 0 on success, -1 on error with error code set. - * - * @see tdb_error() - * @see tdb_errorstr() - */ -int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf); - -/** - * @brief Close a database. - * - * @param[in] tdb The database to close. - * - * @return 0 for success, -1 on error. - */ -int tdb_close(struct tdb_context *tdb); - -/** - * @brief Find the first entry in the database and return its key. - * - * The caller must free the returned data. - * - * @param[in] tdb The database to use. - * - * @return The first entry of the database, an empty TDB_DATA entry - * if the database is empty. - */ -TDB_DATA tdb_firstkey(struct tdb_context *tdb); - -/** - * @brief Find the next entry in the database, returning its key. - * - * The caller must free the returned data. - * - * @param[in] tdb The database to use. - * - * @param[in] key The key from which you want the next key. - * - * @return The next entry of the current key, an empty TDB_DATA - * entry if there is no entry. - */ -TDB_DATA tdb_nextkey(struct tdb_context *tdb, TDB_DATA key); - -/** - * @brief Traverse the entire database. - * - * While travering the function fn(tdb, key, data, state) is called on each - * element. If fn is NULL then it is not called. A non-zero return value from - * fn() indicates that the traversal should stop. Traversal callbacks may not - * start transactions. - * - * @warning The data buffer given to the callback fn does NOT meet the alignment - * restrictions malloc gives you. - * - * @param[in] tdb The database to traverse. - * - * @param[in] fn The function to call on each entry. - * - * @param[in] private_data The private data which should be passed to the - * traversing function. - * - * @return The record count traversed, -1 on error. - */ -int tdb_traverse(struct tdb_context *tdb, tdb_traverse_func fn, void *private_data); - -/** - * @brief Traverse the entire database. - * - * While traversing the database the function fn(tdb, key, data, state) is - * called on each element, but marking the database read only during the - * traversal, so any write operations will fail. This allows tdb to use read - * locks, which increases the parallelism possible during the traversal. - * - * @param[in] tdb The database to traverse. - * - * @param[in] fn The function to call on each entry. - * - * @param[in] private_data The private data which should be passed to the - * traversing function. - * - * @return The record count traversed, -1 on error. - */ -int tdb_traverse_read(struct tdb_context *tdb, tdb_traverse_func fn, void *private_data); - -/** - * @brief Check if an entry in the database exists. - * - * @note 1 is returned if the key is found and 0 is returned if not found this - * doesn't match the conventions in the rest of this module, but is compatible - * with gdbm. - * - * @param[in] tdb The database to check if the entry exists. - * - * @param[in] key The key to check if the entry exists. - * - * @return 1 if the key is found, 0 if not. - */ -int tdb_exists(struct tdb_context *tdb, TDB_DATA key); - -/** - * @brief Lock entire database with a write lock. - * - * @param[in] tdb The database to lock. - * - * @return 0 on success, -1 on error with error code set. - * - * @see tdb_error() - * @see tdb_errorstr() - */ -int tdb_lockall(struct tdb_context *tdb); - -/** - * @brief Lock entire database with a write lock. - * - * This is the non-blocking call. - * - * @param[in] tdb The database to lock. - * - * @return 0 on success, -1 on error with error code set. - * - * @see tdb_lockall() - * @see tdb_error() - * @see tdb_errorstr() - */ -int tdb_lockall_nonblock(struct tdb_context *tdb); - -/** - * @brief Unlock entire database with write lock. - * - * @param[in] tdb The database to unlock. - * - * @return 0 on success, -1 on error with error code set. - * - * @see tdb_lockall() - * @see tdb_error() - * @see tdb_errorstr() - */ -int tdb_unlockall(struct tdb_context *tdb); - -/** - * @brief Lock entire database with a read lock. - * - * @param[in] tdb The database to lock. - * - * @return 0 on success, -1 on error with error code set. - * - * @see tdb_error() - * @see tdb_errorstr() - */ -int tdb_lockall_read(struct tdb_context *tdb); - -/** - * @brief Lock entire database with a read lock. - * - * This is the non-blocking call. - * - * @param[in] tdb The database to lock. - * - * @return 0 on success, -1 on error with error code set. - * - * @see tdb_lockall_read() - * @see tdb_error() - * @see tdb_errorstr() - */ -int tdb_lockall_read_nonblock(struct tdb_context *tdb); - -/** - * @brief Unlock entire database with read lock. - * - * @param[in] tdb The database to unlock. - * - * @return 0 on success, -1 on error with error code set. - * - * @see tdb_lockall_read() - * @see tdb_error() - * @see tdb_errorstr() - */ -int tdb_unlockall_read(struct tdb_context *tdb); - -/** - * @brief Lock entire database with write lock - mark only. - * - * @todo Add more details. - * - * @param[in] tdb The database to mark. - * - * @return 0 on success, -1 on error with error code set. - * - * @see tdb_error() - * @see tdb_errorstr() - */ -int tdb_lockall_mark(struct tdb_context *tdb); - -/** - * @brief Lock entire database with write lock - unmark only. - * - * @todo Add more details. - * - * @param[in] tdb The database to mark. - * - * @return 0 on success, -1 on error with error code set. - * - * @see tdb_error() - * @see tdb_errorstr() - */ -int tdb_lockall_unmark(struct tdb_context *tdb); - -/** - * @brief Get the name of the current tdb file. - * - * This is useful for external logging functions. - * - * @param[in] tdb The database to get the name from. - * - * @return The name of the database. - */ -const char *tdb_name(struct tdb_context *tdb); - -/** - * @brief Get the underlying file descriptor being used by tdb. - * - * This is useful for external routines that want to check the device/inode - * of the fd. - * - * @param[in] tdb The database to get the fd from. - * - * @return The file descriptor or -1. - */ -int tdb_fd(struct tdb_context *tdb); - -/** - * @brief Get the current logging function. - * - * This is useful for external tdb routines that wish to log tdb errors. - * - * @param[in] tdb The database to get the logging function from. - * - * @return The logging function of the database. - * - * @see tdb_get_logging_private() - */ -tdb_log_func tdb_log_fn(struct tdb_context *tdb); - -/** - * @brief Get the private data of the logging function. - * - * @param[in] tdb The database to get the data from. - * - * @return The private data pointer of the logging function. - * - * @see tdb_log_fn() - */ -void *tdb_get_logging_private(struct tdb_context *tdb); - -/** - * @brief Start a transaction. - * - * All operations after the transaction start can either be committed with - * tdb_transaction_commit() or cancelled with tdb_transaction_cancel(). - * - * If you call tdb_transaction_start() again on the same tdb context while a - * transaction is in progress, then the same transaction buffer is re-used. The - * number of tdb_transaction_{commit,cancel} operations must match the number - * of successful tdb_transaction_start() calls. - * - * Note that transactions are by default disk synchronous, and use a recover - * area in the database to automatically recover the database on the next open - * if the system crashes during a transaction. You can disable the synchronous - * transaction recovery setup using the TDB_NOSYNC flag, which will greatly - * speed up operations at the risk of corrupting your database if the system - * crashes. - * - * Operations made within a transaction are not visible to other users of the - * database until a successful commit. - * - * @param[in] tdb The database to start the transaction. - * - * @return 0 on success, -1 on error with error code set. - * - * @see tdb_error() - * @see tdb_errorstr() - */ -int tdb_transaction_start(struct tdb_context *tdb); - -/** - * @brief Start a transaction, non-blocking. - * - * @param[in] tdb The database to start the transaction. - * - * @return 0 on success, -1 on error with error code set. - * - * @see tdb_error() - * @see tdb_errorstr() - * @see tdb_transaction_start() - */ -int tdb_transaction_start_nonblock(struct tdb_context *tdb); - -/** - * @brief Prepare to commit a current transaction, for two-phase commits. - * - * Once prepared for commit, the only allowed calls are tdb_transaction_commit() - * or tdb_transaction_cancel(). Preparing allocates disk space for the pending - * updates, so a subsequent commit should succeed (barring any hardware - * failures). - * - * @param[in] tdb The database to prepare the commit. - * - * @return 0 on success, -1 on error with error code set. - * - * @see tdb_error() - * @see tdb_errorstr() - */ -int tdb_transaction_prepare_commit(struct tdb_context *tdb); - -/** - * @brief Commit a current transaction. - * - * This updates the database and releases the current transaction locks. - * - * @param[in] tdb The database to commit the transaction. - * - * @return 0 on success, -1 on error with error code set. - * - * @see tdb_error() - * @see tdb_errorstr() - */ -int tdb_transaction_commit(struct tdb_context *tdb); - -/** - * @brief Cancel a current transaction. - * - * This discards all write and lock operations that have been made since the - * transaction started. - * - * @param[in] tdb The tdb to cancel the transaction on. - * - * @return 0 on success, -1 on error with error code set. - * - * @see tdb_error() - * @see tdb_errorstr() - */ -int tdb_transaction_cancel(struct tdb_context *tdb); - -/** - * @brief Get the tdb sequence number. - * - * Only makes sense if the writers opened with TDB_SEQNUM set. Note that this - * sequence number will wrap quite quickly, so it should only be used for a - * 'has something changed' test, not for code that relies on the count of the - * number of changes made. If you want a counter then use a tdb record. - * - * The aim of this sequence number is to allow for a very lightweight test of a - * possible tdb change. - * - * @param[in] tdb The database to get the sequence number from. - * - * @return The sequence number or 0. - * - * @see tdb_open() - * @see tdb_enable_seqnum() - */ -int tdb_get_seqnum(struct tdb_context *tdb); - -/** - * @brief Get the hash size. - * - * @param[in] tdb The database to get the hash size from. - * - * @return The hash size. - */ -int tdb_hash_size(struct tdb_context *tdb); - -/** - * @brief Get the map size. - * - * @param[in] tdb The database to get the map size from. - * - * @return The map size. - */ -size_t tdb_map_size(struct tdb_context *tdb); - -/** - * @brief Get the tdb flags set during open. - * - * @param[in] tdb The database to get the flags form. - * - * @return The flags set to on the database. - */ -int tdb_get_flags(struct tdb_context *tdb); - -/** - * @brief Add flags to the database. - * - * @param[in] tdb The database to add the flags. - * - * @param[in] flag The tdb flags to add. - */ -void tdb_add_flags(struct tdb_context *tdb, unsigned flag); - -/** - * @brief Remove flags from the database. - * - * @param[in] tdb The database to remove the flags. - * - * @param[in] flag The tdb flags to remove. - */ -void tdb_remove_flags(struct tdb_context *tdb, unsigned flag); - -/** - * @brief Enable sequence number handling on an open tdb. - * - * @param[in] tdb The database to enable sequence number handling. - * - * @see tdb_get_seqnum() - */ -void tdb_enable_seqnum(struct tdb_context *tdb); - -/** - * @brief Increment the tdb sequence number. - * - * This only works if the tdb has been opened using the TDB_SEQNUM flag or - * enabled useing tdb_enable_seqnum(). - * - * @param[in] tdb The database to increment the sequence number. - * - * @see tdb_enable_seqnum() - * @see tdb_get_seqnum() - */ -void tdb_increment_seqnum_nonblock(struct tdb_context *tdb); - -/** - * @brief Create a hash of the key. - * - * @param[in] key The key to hash - * - * @return The hash. - */ -unsigned int tdb_jenkins_hash(TDB_DATA *key); - -/** - * @brief Check the consistency of the database. - * - * This check the consistency of the database calling back the check function - * (if non-NULL) on each record. If some consistency check fails, or the - * supplied check function returns -1, tdb_check returns -1, otherwise 0. - * - * @note The logging function (if set) will be called with additional - * information on the corruption found. - * - * @param[in] tdb The database to check. - * - * @param[in] check The check function to use. - * - * @param[in] private_data the private data to pass to the check function. - * - * @return 0 on success, -1 on error with error code set. - * - * @see tdb_error() - * @see tdb_errorstr() - */ -int tdb_check(struct tdb_context *tdb, - int (*check) (TDB_DATA key, TDB_DATA data, void *private_data), - void *private_data); - -/** - * @brief Dump all possible records in a corrupt database. - * - * This is the only way to get data out of a database where tdb_check() fails. - * It will call walk() with anything which looks like a database record; this - * may well include invalid, incomplete or duplicate records. - * - * @param[in] tdb The database to check. - * - * @param[in] walk The walk function to use. - * - * @param[in] private_data the private data to pass to the walk function. - * - * @return 0 on success, -1 on error with error code set. - * - * @see tdb_error() - * @see tdb_errorstr() - */ -int tdb_rescue(struct tdb_context *tdb, - void (*walk) (TDB_DATA key, TDB_DATA data, void *private_data), - void *private_data); - -/* @} ******************************************************************/ - -/* Low level locking functions: use with care */ -int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key); -int tdb_chainlock_nonblock(struct tdb_context *tdb, TDB_DATA key); -int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key); -int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key); -int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key); -int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key); -int tdb_chainlock_unmark(struct tdb_context *tdb, TDB_DATA key); - -void tdb_setalarm_sigptr(struct tdb_context *tdb, volatile sig_atomic_t *sigptr); - -/* wipe and repack */ -int tdb_wipe_all(struct tdb_context *tdb); -int tdb_repack(struct tdb_context *tdb); - -/* Debug functions. Not used in production. */ -void tdb_dump_all(struct tdb_context *tdb); -int tdb_printfreelist(struct tdb_context *tdb); -int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries); -int tdb_freelist_size(struct tdb_context *tdb); -char *tdb_summary(struct tdb_context *tdb); - -extern TDB_DATA tdb_null; - -#ifdef __cplusplus -} -#endif - -#endif /* tdb.h */ diff --git a/ctdb/lib/tdb/libtdb.m4 b/ctdb/lib/tdb/libtdb.m4 deleted file mode 100644 index 86efc7d32c8c..000000000000 --- a/ctdb/lib/tdb/libtdb.m4 +++ /dev/null @@ -1,59 +0,0 @@ -dnl Check to see if we should use the included tdb - -INCLUDED_TDB=auto -AC_ARG_WITH(included-tdb, - [AC_HELP_STRING([--with-included-tdb], [use bundled tdb library, not from system])], - [ INCLUDED_TDB=$withval ]) - -AC_SUBST(TDB_LIBS) -AC_SUBST(TDB_CFLAGS) - -if test x"$INCLUDED_TDB" != x"yes" ; then - AC_CHECK_HEADERS(tdb.h) - AC_CHECK_LIB(tdb, tdb_transaction_write_lock_mark, - [ TDB_LIBS="-ltdb" - TDB_CFLAGS="" - INCLUDED_TDB=no ], - [ TDB_LIBS="" - TDB_CFLAGS="" - INCLUDED_TDB=yes]) -fi - -AC_MSG_CHECKING(whether to use included tdb) -AC_MSG_RESULT($INCLUDED_TDB) -if test x"$INCLUDED_TDB" != x"no" ; then - dnl find the tdb sources. This is meant to work both for - dnl tdb standalone builds, and builds of packages using tdb - tdbdir="" - tdbpaths=". lib/tdb tdb ../tdb ../lib/tdb" - for d in $tdbpaths; do - if test -f "$srcdir/$d/common/tdb.c"; then - tdbdir="$d" - AC_SUBST(tdbdir) - break; - fi - done - if test x"$tdbdir" = "x"; then - AC_MSG_ERROR([cannot find tdb source in $tdbpaths]) - fi - TDB_OBJ="common/tdb.o common/dump.o common/transaction.o common/error.o common/traverse.o" - TDB_OBJ="$TDB_OBJ common/freelist.o common/freelistcheck.o common/io.o common/lock.o common/open.o common/check.o common/hash.o common/summary.o common/rescue.o" - AC_SUBST(TDB_OBJ) - - TDB_LIBS="" - AC_SUBST(TDB_LIBS) - - TDB_CFLAGS="-I$tdbdir/include" - AC_SUBST(TDB_CFLAGS) -fi - -AC_CHECK_FUNCS(mmap pread pwrite getpagesize utime) -AC_CHECK_HEADERS(getopt.h sys/select.h sys/time.h) - -AC_HAVE_DECL(pread, [#include ]) -AC_HAVE_DECL(pwrite, [#include ]) - -if test x"$VERSIONSCRIPT" != "x"; then - EXPORTSFILE=tdb.exports - AC_SUBST(EXPORTSFILE) -fi diff --git a/ctdb/lib/tdb/manpages/tdbbackup.8.xml b/ctdb/lib/tdb/manpages/tdbbackup.8.xml deleted file mode 100644 index 78fe32eb8ec1..000000000000 --- a/ctdb/lib/tdb/manpages/tdbbackup.8.xml +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - tdbbackup - 8 - Samba - System Administration tools - 3.6 - - - - - tdbbackup - tool for backing up and for validating the integrity of samba .tdb files - - - - - tdbbackup - -s suffix - -v - -h - - - - - DESCRIPTION - - This tool is part of the samba - 1 suite. - - tdbbackup is a tool that may be used to backup samba .tdb - files. This tool may also be used to verify the integrity of the .tdb files prior - to samba startup or during normal operation. If it finds file damage and it finds - a prior backup the backup file will be restored. - - - - - - OPTIONS - - - - - -h - - Get help information. - - - - - -s suffix - - The -s option allows the adminisistrator to specify a file - backup extension. This way it is possible to keep a history of tdb backup - files by using a new suffix for each backup. - - - - - -v - - The -v will check the database for damages (currupt data) - which if detected causes the backup to be restored. - - - - - - - - - COMMANDS - - GENERAL INFORMATION - - - The tdbbackup utility can safely be run at any time. It was designed so - that it can be used at any time to validate the integrity of tdb files, even during Samba - operation. Typical usage for the command will be: - - - tdbbackup [-s suffix] *.tdb - - - Before restarting samba the following command may be run to validate .tdb files: - - - tdbbackup -v [-s suffix] *.tdb - - - Samba .tdb files are stored in various locations, be sure to run backup all - .tdb file on the system. Important files includes: - - - - - secrets.tdb - usual location is in the /usr/local/samba/private - directory, or on some systems in /etc/samba. - - - - passdb.tdb - usual location is in the /usr/local/samba/private - directory, or on some systems in /etc/samba. - - - - *.tdb located in the /usr/local/samba/var directory or on some - systems in the /var/cache or /var/lib/samba directories. - - - - - - - VERSION - - This man page is correct for version 3 of the Samba suite. - - - - AUTHOR - - - The original Samba software and related utilities were created by Andrew Tridgell. - Samba is now developed by the Samba Team as an Open Source project similar to the way - the Linux kernel is developed. - - - The tdbbackup man page was written by John H Terpstra. - - - diff --git a/ctdb/lib/tdb/manpages/tdbdump.8.xml b/ctdb/lib/tdb/manpages/tdbdump.8.xml deleted file mode 100644 index 34201932434c..000000000000 --- a/ctdb/lib/tdb/manpages/tdbdump.8.xml +++ /dev/null @@ -1,92 +0,0 @@ - - - - - - tdbdump - 8 - Samba - System Administration tools - 3.6 - - - - - tdbdump - tool for printing the contents of a TDB file - - - - - tdbdump - -k keyname - -e - -h - filename - - - - - DESCRIPTION - - This tool is part of the samba - 1 suite. - - tdbdump is a very simple utility that 'dumps' the - contents of a TDB (Trivial DataBase) file to standard output in a - human-readable format. - - - This tool can be used when debugging problems with TDB files. It is - intended for those who are somewhat familiar with Samba internals. - - - - - OPTIONS - - - - - -h - - Get help information. - - - - - -k keyname - - The -k option restricts dumping to a single key, if found. - - - - - -e - - The -e tries to dump out from a corrupt database. Naturally, such a dump is unreliable, at best. - - - - - - - - VERSION - - This man page is correct for version 3 of the Samba suite. - - - - AUTHOR - - - The original Samba software and related utilities were created by Andrew Tridgell. - Samba is now developed by the Samba Team as an Open Source project similar to the way - the Linux kernel is developed. - - - The tdbdump man page was written by Jelmer Vernooij. - - - diff --git a/ctdb/lib/tdb/manpages/tdbrestore.8.xml b/ctdb/lib/tdb/manpages/tdbrestore.8.xml deleted file mode 100644 index 64c0ba2dac18..000000000000 --- a/ctdb/lib/tdb/manpages/tdbrestore.8.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - tdbrestore - 8 - Samba - System Administration tools - 3.6 - - - - - tdbrestore - tool for creating a TDB file out of a tdbdump output - - - - - tdbrestore - tdbfilename - - - - - DESCRIPTION - - This tool is part of the samba - 1 suite. - - tdbrestore is a very simple utility that 'restores' the - contents of dump file into TDB (Trivial DataBase) file. The dump file is obtained from the tdbdump - command. - - - This tool wait on the standard input for the content of the dump and will write the tdb in the tdbfilename - parameter. - - This tool can be used for unpacking the content of tdb as backup mean. - - - - - - VERSION - - This man page is correct for version 3 of the Samba suite. - - - - AUTHOR - - - The original Samba software and related utilities were created by Andrew Tridgell. - Samba is now developed by the Samba Team as an Open Source project similar to the way - the Linux kernel is developed. - - This tool was initially written by Volker Lendecke based on an - idea by Simon McVittie. - - - The tdbrestore man page was written by Matthieu Patou. - - - diff --git a/ctdb/lib/tdb/manpages/tdbtool.8.xml b/ctdb/lib/tdb/manpages/tdbtool.8.xml deleted file mode 100644 index 9f96db277dbb..000000000000 --- a/ctdb/lib/tdb/manpages/tdbtool.8.xml +++ /dev/null @@ -1,235 +0,0 @@ - - - - - - tdbtool - 8 - Samba - System Administration tools - 3.6 - - - - - tdbtool - manipulate the contents TDB files - - - - - - tdbtool - - - - tdbtool - - TDBFILE - - - COMMANDS - - - - - - - DESCRIPTION - - This tool is part of the - samba - 1 suite. - - tdbtool a tool for displaying and - altering the contents of Samba TDB (Trivial DataBase) files. Each - of the commands listed below can be entered interactively or - provided on the command line. - - - - - - COMMANDS - - - - - - TDBFILE - Create a new database named - TDBFILE. - - - - - - TDBFILE - Open an existing database named - TDBFILE. - - - - - - Erase the current database. - - - - - - Dump the current database as strings. - - - - - - Dump the current database as connection records. - - - - - - Dump the current database keys as strings. - - - - - - Dump the current database keys as hex values. - - - - - - Print summary information about the - current database. - - - - - - KEY - DATA - - Insert a record into the - current database. - - - - - - KEY - TDBFILE - - Move a record from the - current database into TDBFILE. - - - - - - KEY - DATA - - Store (replace) a record in the - current database. - - - - - - KEY - - Show a record by key. - - - - - - KEY - - Delete a record by key. - - - - - - - Print the current database hash table and free list. - - - - - - - Print the current database and free list. - - - - - - COMMAND - - Execute the given system command. - - - - - - - - Print the first record in the current database. - - - - - - - - Print the next record in the current database. - - - - - - - - Check the integrity of the current database. - - - - - - - - Exit tdbtool. - - - - - - - - CAVEATS - The contents of the Samba TDB files are private - to the implementation and should not be altered with - tdbtool. - - - - - VERSION - This man page is correct for version 3.0.25 of the Samba suite. - - - - AUTHOR - - The original Samba software and related utilities were - created by Andrew Tridgell. Samba is now developed by the - Samba Team as an Open Source project similar to the way the - Linux kernel is developed. - - - diff --git a/ctdb/lib/tdb/pytdb.c b/ctdb/lib/tdb/pytdb.c deleted file mode 100644 index 98a624687ebd..000000000000 --- a/ctdb/lib/tdb/pytdb.c +++ /dev/null @@ -1,685 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Python interface to tdb. - - Copyright (C) 2004-2006 Tim Potter - Copyright (C) 2007-2008 Jelmer Vernooij - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ - -#include -#include "replace.h" -#include "system/filesys.h" - -/* Include tdb headers */ -#include - -typedef struct { - PyObject_HEAD - TDB_CONTEXT *ctx; - bool closed; -} PyTdbObject; - -staticforward PyTypeObject PyTdb; - -static void PyErr_SetTDBError(TDB_CONTEXT *tdb) -{ - PyErr_SetObject(PyExc_RuntimeError, - Py_BuildValue("(i,s)", tdb_error(tdb), tdb_errorstr(tdb))); -} - -static TDB_DATA PyString_AsTDB_DATA(PyObject *data) -{ - TDB_DATA ret; - ret.dptr = (unsigned char *)PyString_AsString(data); - ret.dsize = PyString_Size(data); - return ret; -} - -static PyObject *PyString_FromTDB_DATA(TDB_DATA data) -{ - if (data.dptr == NULL && data.dsize == 0) { - Py_RETURN_NONE; - } else { - PyObject *ret = PyString_FromStringAndSize((const char *)data.dptr, - data.dsize); - free(data.dptr); - return ret; - } -} - -#define PyErr_TDB_ERROR_IS_ERR_RAISE(ret, tdb) \ - if (ret != 0) { \ - PyErr_SetTDBError(tdb); \ - return NULL; \ - } - -#define PyErr_TDB_RAISE_IF_CLOSED(self) \ - if (self->closed) { \ - PyErr_SetObject(PyExc_RuntimeError, \ - Py_BuildValue("(i,s)", TDB_ERR_IO, "Database is already closed")); \ - return NULL; \ - } - -#define PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self) \ - if (self->closed) { \ - PyErr_SetObject(PyExc_RuntimeError, \ - Py_BuildValue("(i,s)", TDB_ERR_IO, "Database is already closed")); \ - return -1; \ - } - -static PyObject *py_tdb_open(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - char *name = NULL; - int hash_size = 0, tdb_flags = TDB_DEFAULT, flags = O_RDWR, mode = 0600; - TDB_CONTEXT *ctx; - PyTdbObject *ret; - const char *kwnames[] = { "name", "hash_size", "tdb_flags", "flags", "mode", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|siiii", (char **)kwnames, &name, &hash_size, &tdb_flags, &flags, &mode)) - return NULL; - - if (name == NULL) { - tdb_flags |= TDB_INTERNAL; - } - - ctx = tdb_open(name, hash_size, tdb_flags, flags, mode); - if (ctx == NULL) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - - ret = PyObject_New(PyTdbObject, &PyTdb); - if (!ret) { - tdb_close(ctx); - return NULL; - } - - ret->ctx = ctx; - ret->closed = false; - return (PyObject *)ret; -} - -static PyObject *obj_transaction_cancel(PyTdbObject *self) -{ - int ret; - - PyErr_TDB_RAISE_IF_CLOSED(self); - - ret = tdb_transaction_cancel(self->ctx); - PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); - Py_RETURN_NONE; -} - -static PyObject *obj_transaction_commit(PyTdbObject *self) -{ - int ret; - PyErr_TDB_RAISE_IF_CLOSED(self); - ret = tdb_transaction_commit(self->ctx); - PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); - Py_RETURN_NONE; -} - -static PyObject *obj_transaction_prepare_commit(PyTdbObject *self) -{ - int ret; - PyErr_TDB_RAISE_IF_CLOSED(self); - ret = tdb_transaction_prepare_commit(self->ctx); - PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); - Py_RETURN_NONE; -} - -static PyObject *obj_transaction_start(PyTdbObject *self) -{ - int ret; - PyErr_TDB_RAISE_IF_CLOSED(self); - ret = tdb_transaction_start(self->ctx); - PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); - Py_RETURN_NONE; -} - -static PyObject *obj_reopen(PyTdbObject *self) -{ - int ret; - PyErr_TDB_RAISE_IF_CLOSED(self); - ret = tdb_reopen(self->ctx); - PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); - Py_RETURN_NONE; -} - -static PyObject *obj_lockall(PyTdbObject *self) -{ - int ret; - PyErr_TDB_RAISE_IF_CLOSED(self); - ret = tdb_lockall(self->ctx); - PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); - Py_RETURN_NONE; -} - -static PyObject *obj_unlockall(PyTdbObject *self) -{ - int ret; - PyErr_TDB_RAISE_IF_CLOSED(self); - ret = tdb_unlockall(self->ctx); - PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); - Py_RETURN_NONE; -} - -static PyObject *obj_lockall_read(PyTdbObject *self) -{ - int ret; - PyErr_TDB_RAISE_IF_CLOSED(self); - ret = tdb_lockall_read(self->ctx); - PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); - Py_RETURN_NONE; -} - -static PyObject *obj_unlockall_read(PyTdbObject *self) -{ - int ret = tdb_unlockall_read(self->ctx); - PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); - Py_RETURN_NONE; -} - -static PyObject *obj_close(PyTdbObject *self) -{ - int ret; - if (self->closed) - Py_RETURN_NONE; - ret = tdb_close(self->ctx); - self->closed = true; - PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); - Py_RETURN_NONE; -} - -static PyObject *obj_get(PyTdbObject *self, PyObject *args) -{ - TDB_DATA key; - PyObject *py_key; - - PyErr_TDB_RAISE_IF_CLOSED(self); - - if (!PyArg_ParseTuple(args, "O", &py_key)) - return NULL; - - key = PyString_AsTDB_DATA(py_key); - if (!key.dptr) - return NULL; - - return PyString_FromTDB_DATA(tdb_fetch(self->ctx, key)); -} - -static PyObject *obj_append(PyTdbObject *self, PyObject *args) -{ - TDB_DATA key, data; - PyObject *py_key, *py_data; - int ret; - - PyErr_TDB_RAISE_IF_CLOSED(self); - - if (!PyArg_ParseTuple(args, "OO", &py_key, &py_data)) - return NULL; - - key = PyString_AsTDB_DATA(py_key); - if (!key.dptr) - return NULL; - data = PyString_AsTDB_DATA(py_data); - if (!data.dptr) - return NULL; - - ret = tdb_append(self->ctx, key, data); - PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); - Py_RETURN_NONE; -} - -static PyObject *obj_firstkey(PyTdbObject *self) -{ - PyErr_TDB_RAISE_IF_CLOSED(self); - - return PyString_FromTDB_DATA(tdb_firstkey(self->ctx)); -} - -static PyObject *obj_nextkey(PyTdbObject *self, PyObject *args) -{ - TDB_DATA key; - PyObject *py_key; - PyErr_TDB_RAISE_IF_CLOSED(self); - - if (!PyArg_ParseTuple(args, "O", &py_key)) - return NULL; - - key = PyString_AsTDB_DATA(py_key); - if (!key.dptr) - return NULL; - - return PyString_FromTDB_DATA(tdb_nextkey(self->ctx, key)); -} - -static PyObject *obj_delete(PyTdbObject *self, PyObject *args) -{ - TDB_DATA key; - PyObject *py_key; - int ret; - PyErr_TDB_RAISE_IF_CLOSED(self); - - if (!PyArg_ParseTuple(args, "O", &py_key)) - return NULL; - - key = PyString_AsTDB_DATA(py_key); - if (!key.dptr) - return NULL; - ret = tdb_delete(self->ctx, key); - PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); - Py_RETURN_NONE; -} - -static PyObject *obj_has_key(PyTdbObject *self, PyObject *args) -{ - TDB_DATA key; - int ret; - PyObject *py_key; - PyErr_TDB_RAISE_IF_CLOSED(self); - - if (!PyArg_ParseTuple(args, "O", &py_key)) - return NULL; - - key = PyString_AsTDB_DATA(py_key); - if (!key.dptr) - return NULL; - ret = tdb_exists(self->ctx, key); - if (ret != TDB_ERR_NOEXIST) { - PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); - } - - return (ret == TDB_ERR_NOEXIST)?Py_False:Py_True; -} - -static PyObject *obj_store(PyTdbObject *self, PyObject *args) -{ - TDB_DATA key, value; - int ret; - int flag = TDB_REPLACE; - PyObject *py_key, *py_value; - - PyErr_TDB_RAISE_IF_CLOSED(self); - - if (!PyArg_ParseTuple(args, "OO|i", &py_key, &py_value, &flag)) - return NULL; - - key = PyString_AsTDB_DATA(py_key); - if (!key.dptr) - return NULL; - value = PyString_AsTDB_DATA(py_value); - if (!value.dptr) - return NULL; - - ret = tdb_store(self->ctx, key, value, flag); - PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); - Py_RETURN_NONE; -} - -static PyObject *obj_add_flags(PyTdbObject *self, PyObject *args) -{ - unsigned flags; - - PyErr_TDB_RAISE_IF_CLOSED(self); - - if (!PyArg_ParseTuple(args, "I", &flags)) - return NULL; - - tdb_add_flags(self->ctx, flags); - Py_RETURN_NONE; -} - -static PyObject *obj_remove_flags(PyTdbObject *self, PyObject *args) -{ - unsigned flags; - - PyErr_TDB_RAISE_IF_CLOSED(self); - - if (!PyArg_ParseTuple(args, "I", &flags)) - return NULL; - - tdb_remove_flags(self->ctx, flags); - Py_RETURN_NONE; -} - -typedef struct { - PyObject_HEAD - TDB_DATA current; - PyTdbObject *iteratee; -} PyTdbIteratorObject; - -static PyObject *tdb_iter_next(PyTdbIteratorObject *self) -{ - TDB_DATA current; - PyObject *ret; - if (self->current.dptr == NULL && self->current.dsize == 0) - return NULL; - current = self->current; - self->current = tdb_nextkey(self->iteratee->ctx, self->current); - ret = PyString_FromTDB_DATA(current); - return ret; -} - -static void tdb_iter_dealloc(PyTdbIteratorObject *self) -{ - Py_DECREF(self->iteratee); - PyObject_Del(self); -} - -PyTypeObject PyTdbIterator = { - .tp_name = "Iterator", - .tp_basicsize = sizeof(PyTdbIteratorObject), - .tp_iternext = (iternextfunc)tdb_iter_next, - .tp_dealloc = (destructor)tdb_iter_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_iter = PyObject_SelfIter, -}; - -static PyObject *tdb_object_iter(PyTdbObject *self) -{ - PyTdbIteratorObject *ret; - - PyErr_TDB_RAISE_IF_CLOSED(self); - - ret = PyObject_New(PyTdbIteratorObject, &PyTdbIterator); - if (!ret) - return NULL; - ret->current = tdb_firstkey(self->ctx); - ret->iteratee = self; - Py_INCREF(self); - return (PyObject *)ret; -} - -static PyObject *obj_clear(PyTdbObject *self) -{ - int ret; - PyErr_TDB_RAISE_IF_CLOSED(self); - ret = tdb_wipe_all(self->ctx); - PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); - Py_RETURN_NONE; -} - -static PyObject *obj_repack(PyTdbObject *self) -{ - int ret; - PyErr_TDB_RAISE_IF_CLOSED(self); - ret = tdb_repack(self->ctx); - PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); - Py_RETURN_NONE; -} - -static PyObject *obj_enable_seqnum(PyTdbObject *self) -{ - PyErr_TDB_RAISE_IF_CLOSED(self); - tdb_enable_seqnum(self->ctx); - Py_RETURN_NONE; -} - -static PyObject *obj_increment_seqnum_nonblock(PyTdbObject *self) -{ - PyErr_TDB_RAISE_IF_CLOSED(self); - tdb_increment_seqnum_nonblock(self->ctx); - Py_RETURN_NONE; -} - -static PyMethodDef tdb_object_methods[] = { - { "transaction_cancel", (PyCFunction)obj_transaction_cancel, METH_NOARGS, - "S.transaction_cancel() -> None\n" - "Cancel the currently active transaction." }, - { "transaction_commit", (PyCFunction)obj_transaction_commit, METH_NOARGS, - "S.transaction_commit() -> None\n" - "Commit the currently active transaction." }, - { "transaction_prepare_commit", (PyCFunction)obj_transaction_prepare_commit, METH_NOARGS, - "S.transaction_prepare_commit() -> None\n" - "Prepare to commit the currently active transaction" }, - { "transaction_start", (PyCFunction)obj_transaction_start, METH_NOARGS, - "S.transaction_start() -> None\n" - "Start a new transaction." }, - { "reopen", (PyCFunction)obj_reopen, METH_NOARGS, "Reopen this file." }, - { "lock_all", (PyCFunction)obj_lockall, METH_NOARGS, NULL }, - { "unlock_all", (PyCFunction)obj_unlockall, METH_NOARGS, NULL }, - { "read_lock_all", (PyCFunction)obj_lockall_read, METH_NOARGS, NULL }, - { "read_unlock_all", (PyCFunction)obj_unlockall_read, METH_NOARGS, NULL }, - { "close", (PyCFunction)obj_close, METH_NOARGS, NULL }, - { "get", (PyCFunction)obj_get, METH_VARARGS, "S.get(key) -> value\n" - "Fetch a value." }, - { "append", (PyCFunction)obj_append, METH_VARARGS, "S.append(key, value) -> None\n" - "Append data to an existing key." }, - { "firstkey", (PyCFunction)obj_firstkey, METH_NOARGS, "S.firstkey() -> data\n" - "Return the first key in this database." }, - { "nextkey", (PyCFunction)obj_nextkey, METH_NOARGS, "S.nextkey(key) -> data\n" - "Return the next key in this database." }, - { "delete", (PyCFunction)obj_delete, METH_VARARGS, "S.delete(key) -> None\n" - "Delete an entry." }, - { "has_key", (PyCFunction)obj_has_key, METH_VARARGS, "S.has_key(key) -> None\n" - "Check whether key exists in this database." }, - { "store", (PyCFunction)obj_store, METH_VARARGS, "S.store(key, data, flag=REPLACE) -> None" - "Store data." }, - { "add_flags", (PyCFunction)obj_add_flags, METH_VARARGS, "S.add_flags(flags) -> None" }, - { "remove_flags", (PyCFunction)obj_remove_flags, METH_VARARGS, "S.remove_flags(flags) -> None" }, - { "iterkeys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.iterkeys() -> iterator" }, - { "clear", (PyCFunction)obj_clear, METH_NOARGS, "S.clear() -> None\n" - "Wipe the entire database." }, - { "repack", (PyCFunction)obj_repack, METH_NOARGS, "S.repack() -> None\n" - "Repack the entire database." }, - { "enable_seqnum", (PyCFunction)obj_enable_seqnum, METH_NOARGS, - "S.enable_seqnum() -> None" }, - { "increment_seqnum_nonblock", (PyCFunction)obj_increment_seqnum_nonblock, METH_NOARGS, - "S.increment_seqnum_nonblock() -> None" }, - { NULL } -}; - -static PyObject *obj_get_hash_size(PyTdbObject *self, void *closure) -{ - PyErr_TDB_RAISE_IF_CLOSED(self); - return PyInt_FromLong(tdb_hash_size(self->ctx)); -} - -static int obj_set_max_dead(PyTdbObject *self, PyObject *max_dead, void *closure) -{ - PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self); - if (!PyInt_Check(max_dead)) - return -1; - tdb_set_max_dead(self->ctx, PyInt_AsLong(max_dead)); - return 0; -} - -static PyObject *obj_get_map_size(PyTdbObject *self, void *closure) -{ - PyErr_TDB_RAISE_IF_CLOSED(self); - return PyInt_FromLong(tdb_map_size(self->ctx)); -} - -static PyObject *obj_get_freelist_size(PyTdbObject *self, void *closure) -{ - PyErr_TDB_RAISE_IF_CLOSED(self); - return PyInt_FromLong(tdb_freelist_size(self->ctx)); -} - -static PyObject *obj_get_flags(PyTdbObject *self, void *closure) -{ - PyErr_TDB_RAISE_IF_CLOSED(self); - return PyInt_FromLong(tdb_get_flags(self->ctx)); -} - -static PyObject *obj_get_filename(PyTdbObject *self, void *closure) -{ - PyErr_TDB_RAISE_IF_CLOSED(self); - return PyString_FromString(tdb_name(self->ctx)); -} - -static PyObject *obj_get_seqnum(PyTdbObject *self, void *closure) -{ - PyErr_TDB_RAISE_IF_CLOSED(self); - return PyInt_FromLong(tdb_get_seqnum(self->ctx)); -} - - -static PyGetSetDef tdb_object_getsetters[] = { - { (char *)"hash_size", (getter)obj_get_hash_size, NULL, NULL }, - { (char *)"map_size", (getter)obj_get_map_size, NULL, NULL }, - { (char *)"freelist_size", (getter)obj_get_freelist_size, NULL, NULL }, - { (char *)"flags", (getter)obj_get_flags, NULL, NULL }, - { (char *)"max_dead", NULL, (setter)obj_set_max_dead, NULL }, - { (char *)"filename", (getter)obj_get_filename, NULL, (char *)"The filename of this TDB file."}, - { (char *)"seqnum", (getter)obj_get_seqnum, NULL, NULL }, - { NULL } -}; - -static PyObject *tdb_object_repr(PyTdbObject *self) -{ - PyErr_TDB_RAISE_IF_CLOSED(self); - if (tdb_get_flags(self->ctx) & TDB_INTERNAL) { - return PyString_FromString("Tdb()"); - } else { - return PyString_FromFormat("Tdb('%s')", tdb_name(self->ctx)); - } -} - -static void tdb_object_dealloc(PyTdbObject *self) -{ - if (!self->closed) - tdb_close(self->ctx); - self->ob_type->tp_free(self); -} - -static PyObject *obj_getitem(PyTdbObject *self, PyObject *key) -{ - TDB_DATA tkey, val; - PyErr_TDB_RAISE_IF_CLOSED(self); - if (!PyString_Check(key)) { - PyErr_SetString(PyExc_TypeError, "Expected string as key"); - return NULL; - } - - tkey.dptr = (unsigned char *)PyString_AsString(key); - tkey.dsize = PyString_Size(key); - - val = tdb_fetch(self->ctx, tkey); - if (val.dptr == NULL) { - PyErr_SetString(PyExc_KeyError, "No such TDB entry"); - return NULL; - } else { - return PyString_FromTDB_DATA(val); - } -} - -static int obj_setitem(PyTdbObject *self, PyObject *key, PyObject *value) -{ - TDB_DATA tkey, tval; - int ret; - PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self); - if (!PyString_Check(key)) { - PyErr_SetString(PyExc_TypeError, "Expected string as key"); - return -1; - } - - tkey = PyString_AsTDB_DATA(key); - - if (value == NULL) { - ret = tdb_delete(self->ctx, tkey); - } else { - if (!PyString_Check(value)) { - PyErr_SetString(PyExc_TypeError, "Expected string as value"); - return -1; - } - - tval = PyString_AsTDB_DATA(value); - - ret = tdb_store(self->ctx, tkey, tval, TDB_REPLACE); - } - - if (ret != 0) { - PyErr_SetTDBError(self->ctx); - return -1; - } - - return ret; -} - -static PyMappingMethods tdb_object_mapping = { - .mp_subscript = (binaryfunc)obj_getitem, - .mp_ass_subscript = (objobjargproc)obj_setitem, -}; -static PyTypeObject PyTdb = { - .tp_name = "tdb.Tdb", - .tp_basicsize = sizeof(PyTdbObject), - .tp_methods = tdb_object_methods, - .tp_getset = tdb_object_getsetters, - .tp_new = py_tdb_open, - .tp_doc = "A TDB file", - .tp_repr = (reprfunc)tdb_object_repr, - .tp_dealloc = (destructor)tdb_object_dealloc, - .tp_as_mapping = &tdb_object_mapping, - .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_ITER, - .tp_iter = (getiterfunc)tdb_object_iter, -}; - -static PyMethodDef tdb_methods[] = { - { "open", (PyCFunction)py_tdb_open, METH_VARARGS|METH_KEYWORDS, "open(name, hash_size=0, tdb_flags=TDB_DEFAULT, flags=O_RDWR, mode=0600)\n" - "Open a TDB file." }, - { NULL } -}; - -void inittdb(void); -void inittdb(void) -{ - PyObject *m; - - if (PyType_Ready(&PyTdb) < 0) - return; - - if (PyType_Ready(&PyTdbIterator) < 0) - return; - - m = Py_InitModule3("tdb", tdb_methods, - "simple key-value database that supports multiple writers."); - if (m == NULL) - return; - - PyModule_AddObject(m, "REPLACE", PyInt_FromLong(TDB_REPLACE)); - PyModule_AddObject(m, "INSERT", PyInt_FromLong(TDB_INSERT)); - PyModule_AddObject(m, "MODIFY", PyInt_FromLong(TDB_MODIFY)); - - PyModule_AddObject(m, "DEFAULT", PyInt_FromLong(TDB_DEFAULT)); - PyModule_AddObject(m, "CLEAR_IF_FIRST", PyInt_FromLong(TDB_CLEAR_IF_FIRST)); - PyModule_AddObject(m, "INTERNAL", PyInt_FromLong(TDB_INTERNAL)); - PyModule_AddObject(m, "NOLOCK", PyInt_FromLong(TDB_NOLOCK)); - PyModule_AddObject(m, "NOMMAP", PyInt_FromLong(TDB_NOMMAP)); - PyModule_AddObject(m, "CONVERT", PyInt_FromLong(TDB_CONVERT)); - PyModule_AddObject(m, "BIGENDIAN", PyInt_FromLong(TDB_BIGENDIAN)); - PyModule_AddObject(m, "NOSYNC", PyInt_FromLong(TDB_NOSYNC)); - PyModule_AddObject(m, "SEQNUM", PyInt_FromLong(TDB_SEQNUM)); - PyModule_AddObject(m, "VOLATILE", PyInt_FromLong(TDB_VOLATILE)); - PyModule_AddObject(m, "ALLOW_NESTING", PyInt_FromLong(TDB_ALLOW_NESTING)); - PyModule_AddObject(m, "DISALLOW_NESTING", PyInt_FromLong(TDB_DISALLOW_NESTING)); - PyModule_AddObject(m, "INCOMPATIBLE_HASH", PyInt_FromLong(TDB_INCOMPATIBLE_HASH)); - - PyModule_AddObject(m, "__docformat__", PyString_FromString("restructuredText")); - - PyModule_AddObject(m, "__version__", PyString_FromString(PACKAGE_VERSION)); - - Py_INCREF(&PyTdb); - PyModule_AddObject(m, "Tdb", (PyObject *)&PyTdb); - - Py_INCREF(&PyTdbIterator); -} diff --git a/ctdb/lib/tdb/python/tdbdump.py b/ctdb/lib/tdb/python/tdbdump.py deleted file mode 100644 index 01859ebce267..000000000000 --- a/ctdb/lib/tdb/python/tdbdump.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -# Trivial reimplementation of tdbdump in Python - -import tdb, sys - -if len(sys.argv) < 2: - print "Usage: tdbdump.py " - sys.exit(1) - -db = tdb.Tdb(sys.argv[1]) -for (k, v) in db.iteritems(): - print "{\nkey(%d) = %r\ndata(%d) = %r\n}" % (len(k), k, len(v), v) diff --git a/ctdb/lib/tdb/python/tests/simple.py b/ctdb/lib/tdb/python/tests/simple.py deleted file mode 100644 index 7e295a8c9529..000000000000 --- a/ctdb/lib/tdb/python/tests/simple.py +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/env python -# Some simple tests for the Python bindings for TDB -# Note that this tests the interface of the Python bindings -# It does not test tdb itself. -# -# Copyright (C) 2007-2008 Jelmer Vernooij -# Published under the GNU LGPLv3 or later - -import tdb -from unittest import TestCase -import os, tempfile - - -class OpenTdbTests(TestCase): - - def test_nonexistent_read(self): - self.assertRaises(IOError, tdb.Tdb, "/some/nonexistent/file", 0, - tdb.DEFAULT, os.O_RDWR) - -class CloseTdbTests(TestCase): - - def test_double_close(self): - # No hash size in tdb2. - if tdb.__version__.startswith("2"): - self.tdb = tdb.Tdb(tempfile.mkstemp()[1], tdb.DEFAULT, - os.O_CREAT|os.O_RDWR) - else: - self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT, - os.O_CREAT|os.O_RDWR) - self.assertNotEqual(None, self.tdb) - - # ensure that double close does not crash python - self.tdb.close() - self.tdb.close() - - # Check that further operations do not crash python - self.assertRaises(RuntimeError, lambda: self.tdb.transaction_start()) - - self.assertRaises(RuntimeError, lambda: self.tdb["bar"]) - - -class InternalTdbTests(TestCase): - - def test_repr(self): - self.tdb = tdb.Tdb() - - # repr used to crash on internal db - self.assertEquals(repr(self.tdb), "Tdb()") - - -class SimpleTdbTests(TestCase): - - def setUp(self): - super(SimpleTdbTests, self).setUp() - if tdb.__version__.startswith("2"): - self.tdb = tdb.Tdb(tempfile.mkstemp()[1], tdb.DEFAULT, - os.O_CREAT|os.O_RDWR) - else: - self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT, - os.O_CREAT|os.O_RDWR) - self.assertNotEqual(None, self.tdb) - - def tearDown(self): - del self.tdb - - def test_repr(self): - self.assertTrue(repr(self.tdb).startswith("Tdb('")) - - def test_lockall(self): - self.tdb.lock_all() - - def test_max_dead(self): - if not tdb.__version__.startswith("2"): - self.tdb.max_dead = 20 - - def test_unlockall(self): - self.tdb.lock_all() - self.tdb.unlock_all() - - def test_lockall_read(self): - self.tdb.read_lock_all() - self.tdb.read_unlock_all() - - def test_reopen(self): - if not tdb.__version__.startswith("2"): - self.tdb.reopen() - - def test_store(self): - self.tdb.store("bar", "bla") - self.assertEquals("bla", self.tdb.get("bar")) - - def test_getitem(self): - self.tdb["bar"] = "foo" - if not tdb.__version__.startswith("2"): - self.tdb.reopen() - self.assertEquals("foo", self.tdb["bar"]) - - def test_delete(self): - self.tdb["bar"] = "foo" - del self.tdb["bar"] - self.assertRaises(KeyError, lambda: self.tdb["bar"]) - - def test_contains(self): - self.tdb["bla"] = "bloe" - self.assertTrue("bla" in self.tdb) - - def test_keyerror(self): - self.assertRaises(KeyError, lambda: self.tdb["bla"]) - - def test_hash_size(self): - if not tdb.__version__.startswith("2"): - self.tdb.hash_size - - def test_map_size(self): - if not tdb.__version__.startswith("2"): - self.tdb.map_size - - def test_freelist_size(self): - if not tdb.__version__.startswith("2"): - self.tdb.freelist_size - - def test_name(self): - self.tdb.filename - - def test_iterator(self): - self.tdb["bla"] = "1" - self.tdb["brainslug"] = "2" - l = list(self.tdb) - l.sort() - self.assertEquals(["bla", "brainslug"], l) - - def test_transaction_cancel(self): - self.tdb["bloe"] = "2" - self.tdb.transaction_start() - self.tdb["bloe"] = "1" - self.tdb.transaction_cancel() - self.assertEquals("2", self.tdb["bloe"]) - - def test_transaction_commit(self): - self.tdb["bloe"] = "2" - self.tdb.transaction_start() - self.tdb["bloe"] = "1" - self.tdb.transaction_commit() - self.assertEquals("1", self.tdb["bloe"]) - - def test_transaction_prepare_commit(self): - self.tdb["bloe"] = "2" - self.tdb.transaction_start() - self.tdb["bloe"] = "1" - self.tdb.transaction_prepare_commit() - self.tdb.transaction_commit() - self.assertEquals("1", self.tdb["bloe"]) - - def test_iterkeys(self): - self.tdb["bloe"] = "2" - self.tdb["bla"] = "25" - i = self.tdb.iterkeys() - self.assertEquals(set(["bloe", "bla"]), set([i.next(), i.next()])) - - def test_clear(self): - self.tdb["bloe"] = "2" - self.tdb["bla"] = "25" - self.assertEquals(2, len(list(self.tdb))) - self.tdb.clear() - self.assertEquals(0, len(list(self.tdb))) - - def test_repack(self): - if not tdb.__version__.startswith("2"): - self.tdb["foo"] = "abc" - self.tdb["bar"] = "def" - del self.tdb["foo"] - self.tdb.repack() - - def test_seqnum(self): - if not tdb.__version__.startswith("2"): - self.tdb.enable_seqnum() - seq1 = self.tdb.seqnum - self.tdb.increment_seqnum_nonblock() - seq2 = self.tdb.seqnum - self.assertEquals(seq2-seq1, 1) - - def test_len(self): - self.assertEquals(0, len(list(self.tdb))) - self.tdb["entry"] = "value" - self.assertEquals(1, len(list(self.tdb))) - - def test_add_flags(self): - if tdb.__version__.startswith("2"): - self.tdb.add_flag(tdb.NOMMAP) - self.tdb.remove_flag(tdb.NOMMAP) - else: - self.tdb.add_flags(tdb.NOMMAP) - self.tdb.remove_flags(tdb.NOMMAP) - - -class VersionTests(TestCase): - - def test_present(self): - self.assertTrue(isinstance(tdb.__version__, str)) - - -if __name__ == '__main__': - import unittest - unittest.TestProgram() diff --git a/ctdb/lib/tdb/tdb.pc.in b/ctdb/lib/tdb/tdb.pc.in deleted file mode 100644 index b78419ea7845..000000000000 --- a/ctdb/lib/tdb/tdb.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: tdb -Description: A trivial database -Version: @PACKAGE_VERSION@ -Libs: @LIB_RPATH@ -L${libdir} -ltdb -Cflags: -I${includedir} -URL: http://tdb.samba.org/ diff --git a/ctdb/lib/tdb/test/external-agent.c b/ctdb/lib/tdb/test/external-agent.c deleted file mode 100644 index 8140e70ead05..000000000000 --- a/ctdb/lib/tdb/test/external-agent.c +++ /dev/null @@ -1,198 +0,0 @@ -#include "external-agent.h" -#include "lock-tracking.h" -#include "logging.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "../common/tdb_private.h" -#include "tap-interface.h" -#include -#include - -static struct tdb_context *tdb; - -static enum agent_return do_operation(enum operation op, const char *name) -{ - TDB_DATA k; - enum agent_return ret; - TDB_DATA data; - - if (op != OPEN && op != OPEN_WITH_CLEAR_IF_FIRST && !tdb) { - diag("external: No tdb open!"); - return OTHER_FAILURE; - } - - k.dptr = (void *)name; - k.dsize = strlen(name); - - locking_would_block = 0; - switch (op) { - case OPEN: - if (tdb) { - diag("Already have tdb %s open", tdb_name(tdb)); - return OTHER_FAILURE; - } - tdb = tdb_open_ex(name, 0, TDB_DEFAULT, O_RDWR, 0, - &taplogctx, NULL); - if (!tdb) { - if (!locking_would_block) - diag("Opening tdb gave %s", strerror(errno)); - ret = OTHER_FAILURE; - } else - ret = SUCCESS; - break; - case OPEN_WITH_CLEAR_IF_FIRST: - if (tdb) - return OTHER_FAILURE; - tdb = tdb_open_ex(name, 0, TDB_CLEAR_IF_FIRST, O_RDWR, 0, - &taplogctx, NULL); - ret = tdb ? SUCCESS : OTHER_FAILURE; - break; - case TRANSACTION_START: - ret = tdb_transaction_start(tdb) == 0 ? SUCCESS : OTHER_FAILURE; - break; - case FETCH: - data = tdb_fetch(tdb, k); - if (data.dptr == NULL) { - if (tdb_error(tdb) == TDB_ERR_NOEXIST) - ret = FAILED; - else - ret = OTHER_FAILURE; - } else if (data.dsize != k.dsize - || memcmp(data.dptr, k.dptr, k.dsize) != 0) { - ret = OTHER_FAILURE; - } else { - ret = SUCCESS; - } - free(data.dptr); - break; - case STORE: - ret = tdb_store(tdb, k, k, 0) == 0 ? SUCCESS : OTHER_FAILURE; - break; - case TRANSACTION_COMMIT: - ret = tdb_transaction_commit(tdb)==0 ? SUCCESS : OTHER_FAILURE; - break; - case CHECK: - ret = tdb_check(tdb, NULL, NULL) == 0 ? SUCCESS : OTHER_FAILURE; - break; - case NEEDS_RECOVERY: - ret = tdb_needs_recovery(tdb) ? SUCCESS : FAILED; - break; - case CLOSE: - ret = tdb_close(tdb) == 0 ? SUCCESS : OTHER_FAILURE; - tdb = NULL; - break; - default: - ret = OTHER_FAILURE; - } - - if (locking_would_block) - ret = WOULD_HAVE_BLOCKED; - - return ret; -} - -struct agent { - int cmdfd, responsefd; -}; - -/* Do this before doing any tdb stuff. Return handle, or NULL. */ -struct agent *prepare_external_agent(void) -{ - int pid, ret; - int command[2], response[2]; - char name[1+PATH_MAX]; - - if (pipe(command) != 0 || pipe(response) != 0) { - fprintf(stderr, "pipe failed: %s\n", strerror(errno)); - exit(1); - } - - pid = fork(); - if (pid < 0) { - fprintf(stderr, "fork failed: %s\n", strerror(errno)); - exit(1); - } - - if (pid != 0) { - struct agent *agent = malloc(sizeof(*agent)); - - close(command[0]); - close(response[1]); - agent->cmdfd = command[1]; - agent->responsefd = response[0]; - return agent; - } - - close(command[1]); - close(response[0]); - - /* We want to fail, not block. */ - nonblocking_locks = true; - log_prefix = "external: "; - while ((ret = read(command[0], name, sizeof(name))) > 0) { - enum agent_return result; - - result = do_operation(name[0], name+1); - if (write(response[1], &result, sizeof(result)) - != sizeof(result)) - abort(); - } - exit(0); -} - -/* Ask the external agent to try to do an operation. */ -enum agent_return external_agent_operation(struct agent *agent, - enum operation op, - const char *name) -{ - enum agent_return res; - unsigned int len; - char *string; - - if (!name) - name = ""; - len = 1 + strlen(name) + 1; - string = malloc(len); - - string[0] = op; - strcpy(string+1, name); - - if (write(agent->cmdfd, string, len) != len - || read(agent->responsefd, &res, sizeof(res)) != sizeof(res)) - res = AGENT_DIED; - - free(string); - return res; -} - -const char *agent_return_name(enum agent_return ret) -{ - return ret == SUCCESS ? "SUCCESS" - : ret == WOULD_HAVE_BLOCKED ? "WOULD_HAVE_BLOCKED" - : ret == AGENT_DIED ? "AGENT_DIED" - : ret == FAILED ? "FAILED" - : ret == OTHER_FAILURE ? "OTHER_FAILURE" - : "**INVALID**"; -} - -const char *operation_name(enum operation op) -{ - switch (op) { - case OPEN: return "OPEN"; - case OPEN_WITH_CLEAR_IF_FIRST: return "OPEN_WITH_CLEAR_IF_FIRST"; - case TRANSACTION_START: return "TRANSACTION_START"; - case FETCH: return "FETCH"; - case STORE: return "STORE"; - case TRANSACTION_COMMIT: return "TRANSACTION_COMMIT"; - case CHECK: return "CHECK"; - case NEEDS_RECOVERY: return "NEEDS_RECOVERY"; - case CLOSE: return "CLOSE"; - } - return "**INVALID**"; -} diff --git a/ctdb/lib/tdb/test/external-agent.h b/ctdb/lib/tdb/test/external-agent.h deleted file mode 100644 index dffdca962f6f..000000000000 --- a/ctdb/lib/tdb/test/external-agent.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef TDB_TEST_EXTERNAL_AGENT_H -#define TDB_TEST_EXTERNAL_AGENT_H - -/* For locking tests, we need a different process to try things at - * various times. */ -enum operation { - OPEN, - OPEN_WITH_CLEAR_IF_FIRST, - TRANSACTION_START, - FETCH, - STORE, - TRANSACTION_COMMIT, - CHECK, - NEEDS_RECOVERY, - CLOSE, -}; - -/* Do this before doing any tdb stuff. Return handle, or -1. */ -struct agent *prepare_external_agent(void); - -enum agent_return { - SUCCESS, - WOULD_HAVE_BLOCKED, - AGENT_DIED, - FAILED, /* For fetch, or NEEDS_RECOVERY */ - OTHER_FAILURE, -}; - -/* Ask the external agent to try to do an operation. - * name == tdb name for OPEN/OPEN_WITH_CLEAR_IF_FIRST, - * record name for FETCH/STORE (store stores name as data too) - */ -enum agent_return external_agent_operation(struct agent *handle, - enum operation op, - const char *name); - -/* Mapping enum -> string. */ -const char *agent_return_name(enum agent_return ret); -const char *operation_name(enum operation op); - -#endif /* TDB_TEST_EXTERNAL_AGENT_H */ diff --git a/ctdb/lib/tdb/test/jenkins-be-hash.tdb b/ctdb/lib/tdb/test/jenkins-be-hash.tdb deleted file mode 100644 index b65284041485..000000000000 Binary files a/ctdb/lib/tdb/test/jenkins-be-hash.tdb and /dev/null differ diff --git a/ctdb/lib/tdb/test/jenkins-le-hash.tdb b/ctdb/lib/tdb/test/jenkins-le-hash.tdb deleted file mode 100644 index 007e0a336843..000000000000 Binary files a/ctdb/lib/tdb/test/jenkins-le-hash.tdb and /dev/null differ diff --git a/ctdb/lib/tdb/test/lock-tracking.c b/ctdb/lib/tdb/test/lock-tracking.c deleted file mode 100644 index 90a07f8ef164..000000000000 --- a/ctdb/lib/tdb/test/lock-tracking.c +++ /dev/null @@ -1,146 +0,0 @@ -/* We save the locks so we can reaquire them. */ -#include "../common/tdb_private.h" -#include -#include -#include -#include -#include "tap-interface.h" -#include "lock-tracking.h" - -struct testlock { - struct testlock *next; - unsigned int off; - unsigned int len; - int type; -}; -static struct testlock *testlocks; -int locking_errors = 0; -bool suppress_lockcheck = false; -bool nonblocking_locks; -int locking_would_block = 0; -void (*unlock_callback)(int fd); - -int fcntl_with_lockcheck(int fd, int cmd, ... /* arg */ ) -{ - va_list ap; - int ret, arg3; - struct flock *fl; - bool may_block = false; - - if (cmd != F_SETLK && cmd != F_SETLKW) { - /* This may be totally bogus, but we don't know in general. */ - va_start(ap, cmd); - arg3 = va_arg(ap, int); - va_end(ap); - - return fcntl(fd, cmd, arg3); - } - - va_start(ap, cmd); - fl = va_arg(ap, struct flock *); - va_end(ap); - - if (cmd == F_SETLKW && nonblocking_locks) { - cmd = F_SETLK; - may_block = true; - } - ret = fcntl(fd, cmd, fl); - - /* Detect when we failed, but might have been OK if we waited. */ - if (may_block && ret == -1 && (errno == EAGAIN || errno == EACCES)) { - locking_would_block++; - } - - if (fl->l_type == F_UNLCK) { - struct testlock **l; - struct testlock *old = NULL; - - for (l = &testlocks; *l; l = &(*l)->next) { - if ((*l)->off == fl->l_start - && (*l)->len == fl->l_len) { - if (ret == 0) { - old = *l; - *l = (*l)->next; - free(old); - } - break; - } - } - if (!old && !suppress_lockcheck) { - diag("Unknown unlock %u@%u - %i", - (int)fl->l_len, (int)fl->l_start, ret); - locking_errors++; - } - } else { - struct testlock *new, *i; - unsigned int fl_end = fl->l_start + fl->l_len; - if (fl->l_len == 0) - fl_end = (unsigned int)-1; - - /* Check for overlaps: we shouldn't do this. */ - for (i = testlocks; i; i = i->next) { - unsigned int i_end = i->off + i->len; - if (i->len == 0) - i_end = (unsigned int)-1; - - if (fl->l_start >= i->off && fl->l_start < i_end) - break; - if (fl_end >= i->off && fl_end < i_end) - break; - - /* tdb_allrecord_lock does this, handle adjacent: */ - if (fl->l_start == i_end && fl->l_type == i->type) { - if (ret == 0) { - i->len = fl->l_len - ? i->len + fl->l_len - : 0; - } - goto done; - } - } - if (i) { - /* Special case: upgrade of allrecord lock. */ - if (i->type == F_RDLCK && fl->l_type == F_WRLCK - && i->off == FREELIST_TOP - && fl->l_start == FREELIST_TOP - && i->len == 0 - && fl->l_len == 0) { - if (ret == 0) - i->type = F_WRLCK; - goto done; - } - if (!suppress_lockcheck) { - diag("%s testlock %u@%u overlaps %u@%u", - fl->l_type == F_WRLCK ? "write" : "read", - (int)fl->l_len, (int)fl->l_start, - i->len, (int)i->off); - locking_errors++; - } - } - - if (ret == 0) { - new = malloc(sizeof *new); - new->off = fl->l_start; - new->len = fl->l_len; - new->type = fl->l_type; - new->next = testlocks; - testlocks = new; - } - } -done: - if (ret == 0 && fl->l_type == F_UNLCK && unlock_callback) - unlock_callback(fd); - return ret; -} - -unsigned int forget_locking(void) -{ - unsigned int num = 0; - while (testlocks) { - struct testlock *next = testlocks->next; - free(testlocks); - testlocks = next; - num++; - } - return num; -} diff --git a/ctdb/lib/tdb/test/lock-tracking.h b/ctdb/lib/tdb/test/lock-tracking.h deleted file mode 100644 index f2c9c44653ba..000000000000 --- a/ctdb/lib/tdb/test/lock-tracking.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef LOCK_TRACKING_H -#define LOCK_TRACKING_H -#include - -/* Set this if you want a callback after fnctl unlock. */ -extern void (*unlock_callback)(int fd); - -/* Replacement fcntl. */ -int fcntl_with_lockcheck(int fd, int cmd, ... /* arg */ ); - -/* Discard locking info: returns number of locks outstanding. */ -unsigned int forget_locking(void); - -/* Number of errors in locking. */ -extern int locking_errors; - -/* Suppress lock checking. */ -extern bool suppress_lockcheck; - -/* Make all locks non-blocking. */ -extern bool nonblocking_locks; - -/* Number of times we failed a lock because we made it non-blocking. */ -extern int locking_would_block; -#endif /* LOCK_TRACKING_H */ diff --git a/ctdb/lib/tdb/test/logging.c b/ctdb/lib/tdb/test/logging.c deleted file mode 100644 index dfab4868d256..000000000000 --- a/ctdb/lib/tdb/test/logging.c +++ /dev/null @@ -1,33 +0,0 @@ -#include "logging.h" -#include "tap-interface.h" -#include -#include -#include -#include - -bool suppress_logging = false; -const char *log_prefix = ""; - -/* Turn log messages into tap diag messages. */ -static void taplog(struct tdb_context *tdb, - enum tdb_debug_level level, - const char *fmt, ...) -{ - va_list ap; - char line[200]; - - if (suppress_logging) - return; - - va_start(ap, fmt); - vsprintf(line, fmt, ap); - va_end(ap); - - /* Strip trailing \n: diag adds it. */ - if (line[0] && line[strlen(line)-1] == '\n') - diag("%s%.*s", log_prefix, (unsigned)strlen(line)-1, line); - else - diag("%s%s", log_prefix, line); -} - -struct tdb_logging_context taplogctx = { taplog, NULL }; diff --git a/ctdb/lib/tdb/test/logging.h b/ctdb/lib/tdb/test/logging.h deleted file mode 100644 index 89e77b21080e..000000000000 --- a/ctdb/lib/tdb/test/logging.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef TDB_TEST_LOGGING_H -#define TDB_TEST_LOGGING_H -#include "replace.h" -#include "../include/tdb.h" -#include - -extern bool suppress_logging; -extern const char *log_prefix; -extern struct tdb_logging_context taplogctx; - -#endif /* TDB_TEST_LOGGING_H */ diff --git a/ctdb/lib/tdb/test/old-nohash-be.tdb b/ctdb/lib/tdb/test/old-nohash-be.tdb deleted file mode 100644 index 1c49116c1d94..000000000000 Binary files a/ctdb/lib/tdb/test/old-nohash-be.tdb and /dev/null differ diff --git a/ctdb/lib/tdb/test/old-nohash-le.tdb b/ctdb/lib/tdb/test/old-nohash-le.tdb deleted file mode 100644 index 0655072d8822..000000000000 Binary files a/ctdb/lib/tdb/test/old-nohash-le.tdb and /dev/null differ diff --git a/ctdb/lib/tdb/test/run-3G-file.c b/ctdb/lib/tdb/test/run-3G-file.c deleted file mode 100644 index 3ee9de15ed74..000000000000 --- a/ctdb/lib/tdb/test/run-3G-file.c +++ /dev/null @@ -1,144 +0,0 @@ -#include "../common/tdb_private.h" -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#include -#include "logging.h" - -static int tdb_expand_file_sparse(struct tdb_context *tdb, - tdb_off_t size, - tdb_off_t addition) -{ - if (tdb->read_only || tdb->traverse_read) { - tdb->ecode = TDB_ERR_RDONLY; - return -1; - } - - if (ftruncate(tdb->fd, size+addition) == -1) { - char b = 0; - ssize_t written = pwrite(tdb->fd, &b, 1, (size+addition) - 1); - if (written == 0) { - /* try once more, potentially revealing errno */ - written = pwrite(tdb->fd, &b, 1, (size+addition) - 1); - } - if (written == 0) { - /* again - give up, guessing errno */ - errno = ENOSPC; - } - if (written != 1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %d failed (%s)\n", - size+addition, strerror(errno))); - return -1; - } - } - - return 0; -} - -static const struct tdb_methods large_io_methods = { - tdb_read, - tdb_write, - tdb_next_hash_chain, - tdb_oob, - tdb_expand_file_sparse -}; - -static int test_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, - void *_data) -{ - TDB_DATA *expect = _data; - ok1(key.dsize == strlen("hi")); - ok1(memcmp(key.dptr, "hi", strlen("hi")) == 0); - ok1(data.dsize == expect->dsize); - ok1(memcmp(data.dptr, expect->dptr, data.dsize) == 0); - return 0; -} - -int main(int argc, char *argv[]) -{ - struct tdb_context *tdb; - TDB_DATA key, orig_data, data; - uint32_t hash; - tdb_off_t rec_ptr; - struct tdb_record rec; - int ret; - - plan_tests(24); - tdb = tdb_open_ex("run-36-file.tdb", 1024, TDB_CLEAR_IF_FIRST, - O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL); - - ok1(tdb); - tdb->methods = &large_io_methods; - - key.dsize = strlen("hi"); - key.dptr = (void *)"hi"; - orig_data.dsize = strlen("world"); - orig_data.dptr = (void *)"world"; - - /* Enlarge the file (internally multiplies by 2). */ - ret = tdb_expand(tdb, 1500000000); -#ifdef HAVE_INCOHERENT_MMAP - /* This can fail due to mmap failure on 32 bit systems. */ - if (ret == -1) { - /* These should now fail. */ - ok1(tdb_store(tdb, key, orig_data, TDB_INSERT) == -1); - data = tdb_fetch(tdb, key); - ok1(data.dptr == NULL); - ok1(tdb_traverse(tdb, test_traverse, &orig_data) == -1); - ok1(tdb_delete(tdb, key) == -1); - ok1(tdb_traverse(tdb, test_traverse, NULL) == -1); - /* Skip the rest... */ - for (ret = 0; ret < 24 - 6; ret++) - ok1(1); - tdb_close(tdb); - return exit_status(); - } -#endif - ok1(ret == 0); - - /* Put an entry in, and check it. */ - ok1(tdb_store(tdb, key, orig_data, TDB_INSERT) == 0); - - data = tdb_fetch(tdb, key); - ok1(data.dsize == strlen("world")); - ok1(memcmp(data.dptr, "world", strlen("world")) == 0); - free(data.dptr); - - /* That currently fills at the end, make sure that's true. */ - hash = tdb->hash_fn(&key); - rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec); - ok1(rec_ptr); - ok1(rec_ptr > 2U*1024*1024*1024); - tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK); - - /* Traverse must work. */ - ok1(tdb_traverse(tdb, test_traverse, &orig_data) == 1); - - /* Delete should work. */ - ok1(tdb_delete(tdb, key) == 0); - - ok1(tdb_traverse(tdb, test_traverse, NULL) == 0); - - /* Transactions should work. */ - ok1(tdb_transaction_start(tdb) == 0); - ok1(tdb_store(tdb, key, orig_data, TDB_INSERT) == 0); - - data = tdb_fetch(tdb, key); - ok1(data.dsize == strlen("world")); - ok1(memcmp(data.dptr, "world", strlen("world")) == 0); - free(data.dptr); - ok1(tdb_transaction_commit(tdb) == 0); - - ok1(tdb_traverse(tdb, test_traverse, &orig_data) == 1); - tdb_close(tdb); - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-bad-tdb-header.c b/ctdb/lib/tdb/test/run-bad-tdb-header.c deleted file mode 100644 index b00fb8934a45..000000000000 --- a/ctdb/lib/tdb/test/run-bad-tdb-header.c +++ /dev/null @@ -1,58 +0,0 @@ -#include "../common/tdb_private.h" -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#include -#include "logging.h" - -int main(int argc, char *argv[]) -{ - struct tdb_context *tdb; - struct tdb_header hdr; - int fd; - - plan_tests(11); - /* Can open fine if complete crap, as long as O_CREAT. */ - fd = open("run-bad-tdb-header.tdb", O_RDWR|O_CREAT|O_TRUNC, 0600); - ok1(fd >= 0); - ok1(write(fd, "hello world", 11) == 11); - close(fd); - tdb = tdb_open_ex("run-bad-tdb-header.tdb", 1024, 0, O_RDWR, 0, - &taplogctx, NULL); - ok1(!tdb); - tdb = tdb_open_ex("run-bad-tdb-header.tdb", 1024, 0, O_CREAT|O_RDWR, - 0600, &taplogctx, NULL); - ok1(tdb); - tdb_close(tdb); - - /* Now, with wrong version it should *not* overwrite. */ - fd = open("run-bad-tdb-header.tdb", O_RDWR); - ok1(fd >= 0); - ok1(read(fd, &hdr, sizeof(hdr)) == sizeof(hdr)); - ok1(hdr.version == TDB_VERSION); - hdr.version++; - lseek(fd, 0, SEEK_SET); - ok1(write(fd, &hdr, sizeof(hdr)) == sizeof(hdr)); - close(fd); - - tdb = tdb_open_ex("run-bad-tdb-header.tdb", 1024, 0, O_RDWR|O_CREAT, - 0600, &taplogctx, NULL); - ok1(errno == EIO); - ok1(!tdb); - - /* With truncate, will be fine. */ - tdb = tdb_open_ex("run-bad-tdb-header.tdb", 1024, 0, - O_RDWR|O_CREAT|O_TRUNC, 0600, &taplogctx, NULL); - ok1(tdb); - tdb_close(tdb); - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-check.c b/ctdb/lib/tdb/test/run-check.c deleted file mode 100644 index 05f7aecd0839..000000000000 --- a/ctdb/lib/tdb/test/run-check.c +++ /dev/null @@ -1,64 +0,0 @@ -#include "../common/tdb_private.h" -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#include -#include "logging.h" - -int main(int argc, char *argv[]) -{ - struct tdb_context *tdb; - TDB_DATA key, data; - - plan_tests(13); - tdb = tdb_open_ex("run-check.tdb", 1, TDB_CLEAR_IF_FIRST, - O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL); - - ok1(tdb); - ok1(tdb_check(tdb, NULL, NULL) == 0); - - key.dsize = strlen("hi"); - key.dptr = (void *)"hi"; - data.dsize = strlen("world"); - data.dptr = (void *)"world"; - - ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - - tdb = tdb_open_ex("run-check.tdb", 1024, 0, O_RDWR, 0, - &taplogctx, NULL); - ok1(tdb); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - - tdb = tdb_open_ex("test/tdb.corrupt", 1024, 0, O_RDWR, 0, - &taplogctx, NULL); - ok1(tdb); - ok1(tdb_check(tdb, NULL, NULL) == -1); - ok1(tdb_error(tdb) == TDB_ERR_CORRUPT); - tdb_close(tdb); - - /* Big and little endian should work! */ - tdb = tdb_open_ex("test/old-nohash-le.tdb", 1024, 0, O_RDWR, 0, - &taplogctx, NULL); - ok1(tdb); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - - tdb = tdb_open_ex("test/old-nohash-be.tdb", 1024, 0, O_RDWR, 0, - &taplogctx, NULL); - ok1(tdb); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-corrupt.c b/ctdb/lib/tdb/test/run-corrupt.c deleted file mode 100644 index 1a3c76918324..000000000000 --- a/ctdb/lib/tdb/test/run-corrupt.c +++ /dev/null @@ -1,131 +0,0 @@ -#include "../common/tdb_private.h" -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#include -#include "logging.h" - -static int check(TDB_DATA key, TDB_DATA data, void *private) -{ - unsigned int *sizes = private; - - if (key.dsize > strlen("hello")) - return -1; - if (memcmp(key.dptr, "hello", key.dsize) != 0) - return -1; - - if (data.dsize != strlen("world")) - return -1; - if (memcmp(data.dptr, "world", data.dsize) != 0) - return -1; - - sizes[0] += key.dsize; - sizes[1] += data.dsize; - return 0; -} - -static void tdb_flip_bit(struct tdb_context *tdb, unsigned int bit) -{ - unsigned int off = bit / CHAR_BIT; - unsigned char mask = (1 << (bit % CHAR_BIT)); - - if (tdb->map_ptr) - ((unsigned char *)tdb->map_ptr)[off] ^= mask; - else { - unsigned char c; - if (pread(tdb->fd, &c, 1, off) != 1) { - fprintf(stderr, "pread: %s\n", strerror(errno)); - exit(1); - } - c ^= mask; - if (pwrite(tdb->fd, &c, 1, off) != 1) { - fprintf(stderr, "pwrite: %s\n", strerror(errno)); - exit(1); - } - } -} - -static void check_test(struct tdb_context *tdb) -{ - TDB_DATA key, data; - unsigned int i, verifiable, corrupt, sizes[2], dsize, ksize; - - ok1(tdb_check(tdb, NULL, NULL) == 0); - - key.dptr = (void *)"hello"; - data.dsize = strlen("world"); - data.dptr = (void *)"world"; - - /* Key and data size respectively. */ - dsize = ksize = 0; - - /* 5 keys in hash size 2 means we'll have multichains. */ - for (key.dsize = 1; key.dsize <= 5; key.dsize++) { - ksize += key.dsize; - dsize += data.dsize; - if (tdb_store(tdb, key, data, TDB_INSERT) != 0) - abort(); - } - - /* This is how many bytes we expect to be verifiable. */ - /* From the file header. */ - verifiable = strlen(TDB_MAGIC_FOOD) + 1 - + 2 * sizeof(uint32_t) + 2 * sizeof(tdb_off_t) - + 2 * sizeof(uint32_t); - /* From the free list chain and hash chains. */ - verifiable += 3 * sizeof(tdb_off_t); - /* From the record headers & tailer */ - verifiable += 5 * (sizeof(struct tdb_record) + sizeof(uint32_t)); - /* The free block: we ignore datalen, keylen, full_hash. */ - verifiable += sizeof(struct tdb_record) - 3*sizeof(uint32_t) + - sizeof(uint32_t); - /* Our check function verifies the key and data. */ - verifiable += ksize + dsize; - - /* Flip one bit at a time, make sure it detects verifiable bytes. */ - for (i = 0, corrupt = 0; i < tdb->map_size * CHAR_BIT; i++) { - tdb_flip_bit(tdb, i); - memset(sizes, 0, sizeof(sizes)); - if (tdb_check(tdb, check, sizes) != 0) - corrupt++; - else if (sizes[0] != ksize || sizes[1] != dsize) - corrupt++; - tdb_flip_bit(tdb, i); - } - ok(corrupt == verifiable * CHAR_BIT, "corrupt %u should be %u", - corrupt, verifiable * CHAR_BIT); -} - -int main(int argc, char *argv[]) -{ - struct tdb_context *tdb; - - plan_tests(4); - /* This should use mmap. */ - tdb = tdb_open_ex("run-corrupt.tdb", 2, TDB_CLEAR_IF_FIRST, - O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL); - - if (!tdb) - abort(); - check_test(tdb); - tdb_close(tdb); - - /* This should not. */ - tdb = tdb_open_ex("run-corrupt.tdb", 2, TDB_CLEAR_IF_FIRST|TDB_NOMMAP, - O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL); - - if (!tdb) - abort(); - check_test(tdb); - tdb_close(tdb); - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-die-during-transaction.c b/ctdb/lib/tdb/test/run-die-during-transaction.c deleted file mode 100644 index 6e3a70d4ae67..000000000000 --- a/ctdb/lib/tdb/test/run-die-during-transaction.c +++ /dev/null @@ -1,231 +0,0 @@ -#include "../common/tdb_private.h" -#include "lock-tracking.h" -static ssize_t pwrite_check(int fd, const void *buf, size_t count, off_t offset); -static ssize_t write_check(int fd, const void *buf, size_t count); -static int ftruncate_check(int fd, off_t length); - -#define pwrite pwrite_check -#define write write_check -#define fcntl fcntl_with_lockcheck -#define ftruncate ftruncate_check - -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#include -#include -#include -#include -#include "external-agent.h" -#include "logging.h" - -#undef write -#undef pwrite -#undef fcntl -#undef ftruncate - -static bool in_transaction; -static int target, current; -static jmp_buf jmpbuf; -#define TEST_DBNAME "run-die-during-transaction.tdb" -#define KEY_STRING "helloworld" - -static void maybe_die(int fd) -{ - if (in_transaction && current++ == target) { - longjmp(jmpbuf, 1); - } -} - -static ssize_t pwrite_check(int fd, - const void *buf, size_t count, off_t offset) -{ - ssize_t ret; - - maybe_die(fd); - - ret = pwrite(fd, buf, count, offset); - if (ret != count) - return ret; - - maybe_die(fd); - return ret; -} - -static ssize_t write_check(int fd, const void *buf, size_t count) -{ - ssize_t ret; - - maybe_die(fd); - - ret = write(fd, buf, count); - if (ret != count) - return ret; - - maybe_die(fd); - return ret; -} - -static int ftruncate_check(int fd, off_t length) -{ - int ret; - - maybe_die(fd); - - ret = ftruncate(fd, length); - - maybe_die(fd); - return ret; -} - -static bool test_death(enum operation op, struct agent *agent) -{ - struct tdb_context *tdb = NULL; - TDB_DATA key; - enum agent_return ret; - int needed_recovery = 0; - - current = target = 0; -reset: - unlink(TEST_DBNAME); - tdb = tdb_open_ex(TEST_DBNAME, 1024, TDB_NOMMAP, - O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL); - - if (setjmp(jmpbuf) != 0) { - /* We're partway through. Simulate our death. */ - close(tdb->fd); - forget_locking(); - in_transaction = false; - - ret = external_agent_operation(agent, NEEDS_RECOVERY, ""); - if (ret == SUCCESS) - needed_recovery++; - else if (ret != FAILED) { - diag("Step %u agent NEEDS_RECOVERY = %s", current, - agent_return_name(ret)); - return false; - } - - ret = external_agent_operation(agent, op, KEY_STRING); - if (ret != SUCCESS) { - diag("Step %u op %s failed = %s", current, - operation_name(op), - agent_return_name(ret)); - return false; - } - - ret = external_agent_operation(agent, NEEDS_RECOVERY, ""); - if (ret != FAILED) { - diag("Still needs recovery after step %u = %s", - current, agent_return_name(ret)); - return false; - } - - ret = external_agent_operation(agent, CHECK, ""); - if (ret != SUCCESS) { - diag("Step %u check failed = %s", current, - agent_return_name(ret)); - return false; - } - - ret = external_agent_operation(agent, CLOSE, ""); - if (ret != SUCCESS) { - diag("Step %u close failed = %s", current, - agent_return_name(ret)); - return false; - } - - /* Suppress logging as this tries to use closed fd. */ - suppress_logging = true; - suppress_lockcheck = true; - tdb_close(tdb); - suppress_logging = false; - suppress_lockcheck = false; - target++; - current = 0; - goto reset; - } - - /* Put key for agent to fetch. */ - key.dsize = strlen(KEY_STRING); - key.dptr = (void *)KEY_STRING; - if (tdb_store(tdb, key, key, TDB_INSERT) != 0) - return false; - - /* This is the key we insert in transaction. */ - key.dsize--; - - ret = external_agent_operation(agent, OPEN, TEST_DBNAME); - if (ret != SUCCESS) { - fprintf(stderr, "Agent failed to open: %s\n", - agent_return_name(ret)); - exit(1); - } - - ret = external_agent_operation(agent, FETCH, KEY_STRING); - if (ret != SUCCESS) { - fprintf(stderr, "Agent failed find key: %s\n", - agent_return_name(ret)); - exit(1); - } - - in_transaction = true; - if (tdb_transaction_start(tdb) != 0) - return false; - - if (tdb_store(tdb, key, key, TDB_INSERT) != 0) - return false; - - if (tdb_transaction_commit(tdb) != 0) - return false; - - in_transaction = false; - - /* We made it! */ - diag("Completed %u runs", current); - tdb_close(tdb); - ret = external_agent_operation(agent, CLOSE, ""); - if (ret != SUCCESS) { - diag("Step %u close failed = %s", current, - agent_return_name(ret)); - return false; - } - -#ifdef HAVE_INCOHERENT_MMAP - /* This means we always mmap, which makes this test a noop. */ - ok1(1); -#else - ok1(needed_recovery); -#endif - ok1(locking_errors == 0); - ok1(forget_locking() == 0); - locking_errors = 0; - return true; -} - -int main(int argc, char *argv[]) -{ - enum operation ops[] = { FETCH, STORE, TRANSACTION_START }; - struct agent *agent; - int i; - - plan_tests(12); - unlock_callback = maybe_die; - - agent = prepare_external_agent(); - - for (i = 0; i < sizeof(ops)/sizeof(ops[0]); i++) { - diag("Testing %s after death", operation_name(ops[i])); - ok1(test_death(ops[i], agent)); - } - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-endian.c b/ctdb/lib/tdb/test/run-endian.c deleted file mode 100644 index b19ffd373f1f..000000000000 --- a/ctdb/lib/tdb/test/run-endian.c +++ /dev/null @@ -1,63 +0,0 @@ -#include "../common/tdb_private.h" -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#include -#include "logging.h" - -int main(int argc, char *argv[]) -{ - struct tdb_context *tdb; - TDB_DATA key, data; - - plan_tests(13); - tdb = tdb_open_ex("run-endian.tdb", 1024, - TDB_CLEAR_IF_FIRST|TDB_CONVERT, - O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL); - - ok1(tdb); - key.dsize = strlen("hi"); - key.dptr = (void *)"hi"; - data.dsize = strlen("world"); - data.dptr = (void *)"world"; - - ok1(tdb_store(tdb, key, data, TDB_MODIFY) < 0); - ok1(tdb_error(tdb) == TDB_ERR_NOEXIST); - ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0); - ok1(tdb_store(tdb, key, data, TDB_INSERT) < 0); - ok1(tdb_error(tdb) == TDB_ERR_EXISTS); - ok1(tdb_store(tdb, key, data, TDB_MODIFY) == 0); - - data = tdb_fetch(tdb, key); - ok1(data.dsize == strlen("world")); - ok1(memcmp(data.dptr, "world", strlen("world")) == 0); - free(data.dptr); - - key.dsize++; - data = tdb_fetch(tdb, key); - ok1(data.dptr == NULL); - tdb_close(tdb); - - /* Reopen: should read it */ - tdb = tdb_open_ex("run-endian.tdb", 1024, 0, O_RDWR, 0, - &taplogctx, NULL); - ok1(tdb); - - key.dsize = strlen("hi"); - key.dptr = (void *)"hi"; - data = tdb_fetch(tdb, key); - ok1(data.dsize == strlen("world")); - ok1(memcmp(data.dptr, "world", strlen("world")) == 0); - free(data.dptr); - tdb_close(tdb); - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-incompatible.c b/ctdb/lib/tdb/test/run-incompatible.c deleted file mode 100644 index 628927c88687..000000000000 --- a/ctdb/lib/tdb/test/run-incompatible.c +++ /dev/null @@ -1,185 +0,0 @@ -#include "../common/tdb_private.h" -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#include - -static unsigned int tdb_dumb_hash(TDB_DATA *key) -{ - return key->dsize; -} - -static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) -{ - unsigned int *count = tdb_get_logging_private(tdb); - if (strstr(fmt, "hash")) - (*count)++; -} - -static unsigned int hdr_rwlocks(const char *fname) -{ - struct tdb_header hdr; - - int fd = open(fname, O_RDONLY); - if (fd == -1) - return -1; - - if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) - return -1; - - close(fd); - return hdr.rwlocks; -} - -int main(int argc, char *argv[]) -{ - struct tdb_context *tdb; - unsigned int log_count, flags; - TDB_DATA d, r; - struct tdb_logging_context log_ctx = { log_fn, &log_count }; - - plan_tests(38 * 2); - - for (flags = 0; flags <= TDB_CONVERT; flags += TDB_CONVERT) { - unsigned int rwmagic = TDB_HASH_RWLOCK_MAGIC; - - if (flags & TDB_CONVERT) - tdb_convert(&rwmagic, sizeof(rwmagic)); - - /* Create an old-style hash. */ - log_count = 0; - tdb = tdb_open_ex("run-incompatible.tdb", 0, flags, - O_CREAT|O_RDWR|O_TRUNC, 0600, &log_ctx, - NULL); - ok1(tdb); - ok1(log_count == 0); - d.dptr = (void *)"Hello"; - d.dsize = 5; - ok1(tdb_store(tdb, d, d, TDB_INSERT) == 0); - tdb_close(tdb); - - /* Should not have marked rwlocks field. */ - ok1(hdr_rwlocks("run-incompatible.tdb") == 0); - - /* We can still open any old-style with incompat flag. */ - log_count = 0; - tdb = tdb_open_ex("run-incompatible.tdb", 0, - TDB_INCOMPATIBLE_HASH, - O_RDWR, 0600, &log_ctx, NULL); - ok1(tdb); - ok1(log_count == 0); - r = tdb_fetch(tdb, d); - ok1(r.dsize == 5); - free(r.dptr); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - - log_count = 0; - tdb = tdb_open_ex("test/jenkins-le-hash.tdb", 0, 0, O_RDONLY, - 0, &log_ctx, tdb_jenkins_hash); - ok1(tdb); - ok1(log_count == 0); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - - log_count = 0; - tdb = tdb_open_ex("test/jenkins-be-hash.tdb", 0, 0, O_RDONLY, - 0, &log_ctx, tdb_jenkins_hash); - ok1(tdb); - ok1(log_count == 0); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - - /* OK, now create with incompatible flag, default hash. */ - log_count = 0; - tdb = tdb_open_ex("run-incompatible.tdb", 0, - flags|TDB_INCOMPATIBLE_HASH, - O_CREAT|O_RDWR|O_TRUNC, 0600, &log_ctx, - NULL); - ok1(tdb); - ok1(log_count == 0); - d.dptr = (void *)"Hello"; - d.dsize = 5; - ok1(tdb_store(tdb, d, d, TDB_INSERT) == 0); - tdb_close(tdb); - - /* Should have marked rwlocks field. */ - ok1(hdr_rwlocks("run-incompatible.tdb") == rwmagic); - - /* Cannot open with old hash. */ - log_count = 0; - tdb = tdb_open_ex("run-incompatible.tdb", 0, 0, - O_RDWR, 0600, &log_ctx, tdb_old_hash); - ok1(!tdb); - ok1(log_count == 1); - - /* Can open with jenkins hash. */ - log_count = 0; - tdb = tdb_open_ex("run-incompatible.tdb", 0, 0, - O_RDWR, 0600, &log_ctx, tdb_jenkins_hash); - ok1(tdb); - ok1(log_count == 0); - r = tdb_fetch(tdb, d); - ok1(r.dsize == 5); - free(r.dptr); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - - /* Can open by letting it figure it out itself. */ - log_count = 0; - tdb = tdb_open_ex("run-incompatible.tdb", 0, 0, - O_RDWR, 0600, &log_ctx, NULL); - ok1(tdb); - ok1(log_count == 0); - r = tdb_fetch(tdb, d); - ok1(r.dsize == 5); - free(r.dptr); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - - /* We can also use incompatible hash with other hashes. */ - log_count = 0; - tdb = tdb_open_ex("run-incompatible.tdb", 0, - flags|TDB_INCOMPATIBLE_HASH, - O_CREAT|O_RDWR|O_TRUNC, 0600, &log_ctx, - tdb_dumb_hash); - ok1(tdb); - ok1(log_count == 0); - d.dptr = (void *)"Hello"; - d.dsize = 5; - ok1(tdb_store(tdb, d, d, TDB_INSERT) == 0); - tdb_close(tdb); - - /* Should have marked rwlocks field. */ - ok1(hdr_rwlocks("run-incompatible.tdb") == rwmagic); - - /* It should not open if we don't specify. */ - log_count = 0; - tdb = tdb_open_ex("run-incompatible.tdb", 0, 0, O_RDWR, 0, - &log_ctx, NULL); - ok1(!tdb); - ok1(log_count == 1); - - /* Should reopen with correct hash. */ - log_count = 0; - tdb = tdb_open_ex("run-incompatible.tdb", 0, 0, O_RDWR, 0, - &log_ctx, tdb_dumb_hash); - ok1(tdb); - ok1(log_count == 0); - r = tdb_fetch(tdb, d); - ok1(r.dsize == 5); - free(r.dptr); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - } - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-nested-transactions.c b/ctdb/lib/tdb/test/run-nested-transactions.c deleted file mode 100644 index 8c84bcac836a..000000000000 --- a/ctdb/lib/tdb/test/run-nested-transactions.c +++ /dev/null @@ -1,78 +0,0 @@ -#include "../common/tdb_private.h" -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#include -#include -#include "logging.h" - -int main(int argc, char *argv[]) -{ - struct tdb_context *tdb; - TDB_DATA key, data; - - plan_tests(27); - key.dsize = strlen("hi"); - key.dptr = (void *)"hi"; - - tdb = tdb_open_ex("run-nested-transactions.tdb", - 1024, TDB_CLEAR_IF_FIRST|TDB_DISALLOW_NESTING, - O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL); - ok1(tdb); - - /* Nesting disallowed. */ - ok1(tdb_transaction_start(tdb) == 0); - data.dptr = (void *)"world"; - data.dsize = strlen("world"); - ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0); - data = tdb_fetch(tdb, key); - ok1(data.dsize == strlen("world")); - ok1(memcmp(data.dptr, "world", strlen("world")) == 0); - free(data.dptr); - ok1(tdb_transaction_start(tdb) != 0); - ok1(tdb_error(tdb) == TDB_ERR_NESTING); - - data = tdb_fetch(tdb, key); - ok1(data.dsize == strlen("world")); - ok1(memcmp(data.dptr, "world", strlen("world")) == 0); - free(data.dptr); - ok1(tdb_transaction_commit(tdb) == 0); - data = tdb_fetch(tdb, key); - ok1(data.dsize == strlen("world")); - ok1(memcmp(data.dptr, "world", strlen("world")) == 0); - free(data.dptr); - tdb_close(tdb); - - /* Nesting allowed by default */ - tdb = tdb_open_ex("run-nested-transactions.tdb", - 1024, TDB_DEFAULT, O_RDWR, 0, &taplogctx, NULL); - ok1(tdb); - - ok1(tdb_transaction_start(tdb) == 0); - ok1(tdb_transaction_start(tdb) == 0); - ok1(tdb_delete(tdb, key) == 0); - ok1(tdb_transaction_commit(tdb) == 0); - ok1(!tdb_exists(tdb, key)); - ok1(tdb_transaction_cancel(tdb) == 0); - /* Surprise! Kills inner "committed" transaction. */ - ok1(tdb_exists(tdb, key)); - - ok1(tdb_transaction_start(tdb) == 0); - ok1(tdb_transaction_start(tdb) == 0); - ok1(tdb_delete(tdb, key) == 0); - ok1(tdb_transaction_commit(tdb) == 0); - ok1(!tdb_exists(tdb, key)); - ok1(tdb_transaction_commit(tdb) == 0); - ok1(!tdb_exists(tdb, key)); - tdb_close(tdb); - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-nested-traverse.c b/ctdb/lib/tdb/test/run-nested-traverse.c deleted file mode 100644 index 37d57c012581..000000000000 --- a/ctdb/lib/tdb/test/run-nested-traverse.c +++ /dev/null @@ -1,87 +0,0 @@ -#include "../common/tdb_private.h" -#include "lock-tracking.h" -#define fcntl fcntl_with_lockcheck -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#undef fcntl -#include -#include -#include "external-agent.h" -#include "logging.h" - -static struct agent *agent; - -static bool correct_key(TDB_DATA key) -{ - return key.dsize == strlen("hi") - && memcmp(key.dptr, "hi", key.dsize) == 0; -} - -static bool correct_data(TDB_DATA data) -{ - return data.dsize == strlen("world") - && memcmp(data.dptr, "world", data.dsize) == 0; -} - -static int traverse2(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, - void *p) -{ - ok1(correct_key(key)); - ok1(correct_data(data)); - return 0; -} - -static int traverse1(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, - void *p) -{ - ok1(correct_key(key)); - ok1(correct_data(data)); - ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb)) - == WOULD_HAVE_BLOCKED); - tdb_traverse(tdb, traverse2, NULL); - - /* That should *not* release the transaction lock! */ - ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb)) - == WOULD_HAVE_BLOCKED); - return 0; -} - -int main(int argc, char *argv[]) -{ - struct tdb_context *tdb; - TDB_DATA key, data; - - plan_tests(17); - agent = prepare_external_agent(); - - tdb = tdb_open_ex("run-nested-traverse.tdb", 1024, TDB_CLEAR_IF_FIRST, - O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL); - ok1(tdb); - - ok1(external_agent_operation(agent, OPEN, tdb_name(tdb)) == SUCCESS); - ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb)) - == SUCCESS); - ok1(external_agent_operation(agent, TRANSACTION_COMMIT, tdb_name(tdb)) - == SUCCESS); - - key.dsize = strlen("hi"); - key.dptr = (void *)"hi"; - data.dptr = (void *)"world"; - data.dsize = strlen("world"); - - ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0); - tdb_traverse(tdb, traverse1, NULL); - tdb_traverse_read(tdb, traverse1, NULL); - tdb_close(tdb); - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-no-lock-during-traverse.c b/ctdb/lib/tdb/test/run-no-lock-during-traverse.c deleted file mode 100644 index 0a72282eb6d8..000000000000 --- a/ctdb/lib/tdb/test/run-no-lock-during-traverse.c +++ /dev/null @@ -1,113 +0,0 @@ -#include "../common/tdb_private.h" -#include "lock-tracking.h" - -#define fcntl fcntl_with_lockcheck - -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#include -#include "logging.h" - -#undef fcntl - -#define NUM_ENTRIES 10 - -static bool prepare_entries(struct tdb_context *tdb) -{ - unsigned int i; - TDB_DATA key, data; - - for (i = 0; i < NUM_ENTRIES; i++) { - key.dsize = sizeof(i); - key.dptr = (void *)&i; - data.dsize = strlen("world"); - data.dptr = (void *)"world"; - - if (tdb_store(tdb, key, data, 0) != 0) - return false; - } - return true; -} - -static void delete_entries(struct tdb_context *tdb) -{ - unsigned int i; - TDB_DATA key; - - for (i = 0; i < NUM_ENTRIES; i++) { - key.dsize = sizeof(i); - key.dptr = (void *)&i; - - ok1(tdb_delete(tdb, key) == 0); - } -} - -/* We don't know how many times this will run. */ -static int delete_other(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, - void *private_data) -{ - unsigned int i; - memcpy(&i, key.dptr, 4); - i = (i + 1) % NUM_ENTRIES; - key.dptr = (void *)&i; - if (tdb_delete(tdb, key) != 0) - (*(int *)private_data)++; - return 0; -} - -static int delete_self(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, - void *private_data) -{ - ok1(tdb_delete(tdb, key) == 0); - return 0; -} - -int main(int argc, char *argv[]) -{ - struct tdb_context *tdb; - int errors = 0; - - plan_tests(41); - tdb = tdb_open_ex("run-no-lock-during-traverse.tdb", - 1024, TDB_CLEAR_IF_FIRST, O_CREAT|O_TRUNC|O_RDWR, - 0600, &taplogctx, NULL); - - ok1(tdb); - ok1(prepare_entries(tdb)); - ok1(locking_errors == 0); - ok1(tdb_lockall(tdb) == 0); - ok1(locking_errors == 0); - tdb_traverse(tdb, delete_other, &errors); - ok1(errors == 0); - ok1(locking_errors == 0); - ok1(tdb_unlockall(tdb) == 0); - - ok1(prepare_entries(tdb)); - ok1(locking_errors == 0); - ok1(tdb_lockall(tdb) == 0); - ok1(locking_errors == 0); - tdb_traverse(tdb, delete_self, NULL); - ok1(locking_errors == 0); - ok1(tdb_unlockall(tdb) == 0); - - ok1(prepare_entries(tdb)); - ok1(locking_errors == 0); - ok1(tdb_lockall(tdb) == 0); - ok1(locking_errors == 0); - delete_entries(tdb); - ok1(locking_errors == 0); - ok1(tdb_unlockall(tdb) == 0); - - ok1(tdb_close(tdb) == 0); - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-oldhash.c b/ctdb/lib/tdb/test/run-oldhash.c deleted file mode 100644 index 535336cb473c..000000000000 --- a/ctdb/lib/tdb/test/run-oldhash.c +++ /dev/null @@ -1,49 +0,0 @@ -#include "../common/tdb_private.h" -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#include -#include "logging.h" - -int main(int argc, char *argv[]) -{ - struct tdb_context *tdb; - - plan_tests(8); - - /* Old format (with zeroes in the hash magic fields) should - * open with any hash (since we don't know what hash they used). */ - tdb = tdb_open_ex("test/old-nohash-le.tdb", 0, 0, O_RDWR, 0, - &taplogctx, NULL); - ok1(tdb); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - - tdb = tdb_open_ex("test/old-nohash-be.tdb", 0, 0, O_RDWR, 0, - &taplogctx, NULL); - ok1(tdb); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - - tdb = tdb_open_ex("test/old-nohash-le.tdb", 0, 0, O_RDWR, 0, - &taplogctx, tdb_jenkins_hash); - ok1(tdb); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - - tdb = tdb_open_ex("test/old-nohash-be.tdb", 0, 0, O_RDWR, 0, - &taplogctx, tdb_jenkins_hash); - ok1(tdb); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-open-during-transaction.c b/ctdb/lib/tdb/test/run-open-during-transaction.c deleted file mode 100644 index a825e6269d75..000000000000 --- a/ctdb/lib/tdb/test/run-open-during-transaction.c +++ /dev/null @@ -1,181 +0,0 @@ -#include "../common/tdb_private.h" -#include "lock-tracking.h" - -static ssize_t pwrite_check(int fd, const void *buf, size_t count, off_t offset); -static ssize_t write_check(int fd, const void *buf, size_t count); -static int ftruncate_check(int fd, off_t length); - -#define pwrite pwrite_check -#define write write_check -#define fcntl fcntl_with_lockcheck -#define ftruncate ftruncate_check - -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#include -#include -#include -#include "external-agent.h" -#include "logging.h" - -static struct agent *agent; -static bool opened; -static int errors = 0; -static bool clear_if_first; -#define TEST_DBNAME "run-open-during-transaction.tdb" - -#undef write -#undef pwrite -#undef fcntl -#undef ftruncate - -static bool is_same(const char *snapshot, const char *latest, off_t len) -{ - unsigned i; - - for (i = 0; i < len; i++) { - if (snapshot[i] != latest[i]) - return false; - } - return true; -} - -static bool compare_file(int fd, const char *snapshot, off_t snapshot_len) -{ - char *contents; - bool same; - - /* over-length read serves as length check. */ - contents = malloc(snapshot_len+1); - same = pread(fd, contents, snapshot_len+1, 0) == snapshot_len - && is_same(snapshot, contents, snapshot_len); - free(contents); - return same; -} - -static void check_file_intact(int fd) -{ - enum agent_return ret; - struct stat st; - char *contents; - - fstat(fd, &st); - contents = malloc(st.st_size); - if (pread(fd, contents, st.st_size, 0) != st.st_size) { - diag("Read fail"); - errors++; - return; - } - - /* Ask agent to open file. */ - ret = external_agent_operation(agent, clear_if_first ? - OPEN_WITH_CLEAR_IF_FIRST : - OPEN, - TEST_DBNAME); - - /* It's OK to open it, but it must not have changed! */ - if (!compare_file(fd, contents, st.st_size)) { - diag("Agent changed file after opening %s", - agent_return_name(ret)); - errors++; - } - - if (ret == SUCCESS) { - ret = external_agent_operation(agent, CLOSE, NULL); - if (ret != SUCCESS) { - diag("Agent failed to close tdb: %s", - agent_return_name(ret)); - errors++; - } - } else if (ret != WOULD_HAVE_BLOCKED) { - diag("Agent opening file gave %s", - agent_return_name(ret)); - errors++; - } - - free(contents); -} - -static void after_unlock(int fd) -{ - if (opened) - check_file_intact(fd); -} - -static ssize_t pwrite_check(int fd, - const void *buf, size_t count, off_t offset) -{ - if (opened) - check_file_intact(fd); - - return pwrite(fd, buf, count, offset); -} - -static ssize_t write_check(int fd, const void *buf, size_t count) -{ - if (opened) - check_file_intact(fd); - - return write(fd, buf, count); -} - -static int ftruncate_check(int fd, off_t length) -{ - if (opened) - check_file_intact(fd); - - return ftruncate(fd, length); - -} - -int main(int argc, char *argv[]) -{ - const int flags[] = { TDB_DEFAULT, - TDB_CLEAR_IF_FIRST, - TDB_NOMMAP, - TDB_CLEAR_IF_FIRST | TDB_NOMMAP }; - int i; - struct tdb_context *tdb; - TDB_DATA key, data; - - plan_tests(20); - agent = prepare_external_agent(); - - unlock_callback = after_unlock; - for (i = 0; i < sizeof(flags)/sizeof(flags[0]); i++) { - clear_if_first = (flags[i] & TDB_CLEAR_IF_FIRST); - diag("Test with %s and %s\n", - clear_if_first ? "CLEAR" : "DEFAULT", - (flags[i] & TDB_NOMMAP) ? "no mmap" : "mmap"); - unlink(TEST_DBNAME); - tdb = tdb_open_ex(TEST_DBNAME, 1024, flags[i], - O_CREAT|O_TRUNC|O_RDWR, 0600, - &taplogctx, NULL); - ok1(tdb); - - opened = true; - ok1(tdb_transaction_start(tdb) == 0); - key.dsize = strlen("hi"); - key.dptr = (void *)"hi"; - data.dptr = (void *)"world"; - data.dsize = strlen("world"); - - ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0); - ok1(tdb_transaction_commit(tdb) == 0); - ok(!errors, "We had %u open errors", errors); - - opened = false; - tdb_close(tdb); - } - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-readonly-check.c b/ctdb/lib/tdb/test/run-readonly-check.c deleted file mode 100644 index fdd9507cdad2..000000000000 --- a/ctdb/lib/tdb/test/run-readonly-check.c +++ /dev/null @@ -1,52 +0,0 @@ -/* We should be able to tdb_check a O_RDONLY tdb, and we were previously allowed - * to tdb_check() inside a transaction (though that's paranoia!). */ -#include "../common/tdb_private.h" -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#include -#include "logging.h" - -int main(int argc, char *argv[]) -{ - struct tdb_context *tdb; - TDB_DATA key, data; - - plan_tests(11); - tdb = tdb_open_ex("run-readonly-check.tdb", 1024, - TDB_DEFAULT, - O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL); - - ok1(tdb); - key.dsize = strlen("hi"); - key.dptr = (void *)"hi"; - data.dsize = strlen("world"); - data.dptr = (void *)"world"; - - ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0); - ok1(tdb_check(tdb, NULL, NULL) == 0); - - /* We are also allowed to do a check inside a transaction. */ - ok1(tdb_transaction_start(tdb) == 0); - ok1(tdb_check(tdb, NULL, NULL) == 0); - ok1(tdb_close(tdb) == 0); - - tdb = tdb_open_ex("run-readonly-check.tdb", 1024, - TDB_DEFAULT, O_RDONLY, 0, &taplogctx, NULL); - - ok1(tdb); - ok1(tdb_store(tdb, key, data, TDB_MODIFY) == -1); - ok1(tdb_error(tdb) == TDB_ERR_RDONLY); - ok1(tdb_check(tdb, NULL, NULL) == 0); - ok1(tdb_close(tdb) == 0); - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-rescue-find_entry.c b/ctdb/lib/tdb/test/run-rescue-find_entry.c deleted file mode 100644 index 25f4f1c05f46..000000000000 --- a/ctdb/lib/tdb/test/run-rescue-find_entry.c +++ /dev/null @@ -1,50 +0,0 @@ -#include "../common/tdb_private.h" -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "../common/rescue.c" -#include "tap-interface.h" -#include -#include "logging.h" - -#define NUM 20 - -/* Binary searches are deceptively simple: easy to screw up! */ -int main(int argc, char *argv[]) -{ - unsigned int i, j, n; - struct found f[NUM+1]; - struct found_table table; - - /* Set up array for searching. */ - for (i = 0; i < NUM+1; i++) { - f[i].head = i * 3; - } - table.arr = f; - - for (i = 0; i < NUM; i++) { - table.num = i; - for (j = 0; j < (i + 2) * 3; j++) { - n = find_entry(&table, j); - ok1(n <= i); - - /* If we were searching for something too large... */ - if (j > i*3) - ok1(n == i); - else { - /* It must give us something after j */ - ok1(f[n].head >= j); - ok1(n == 0 || f[n-1].head < j); - } - } - } - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-rescue.c b/ctdb/lib/tdb/test/run-rescue.c deleted file mode 100644 index a26c493972ab..000000000000 --- a/ctdb/lib/tdb/test/run-rescue.c +++ /dev/null @@ -1,126 +0,0 @@ -#include "../common/tdb_private.h" -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "../common/rescue.c" -#include "tap-interface.h" -#include -#include "logging.h" - -struct walk_data { - TDB_DATA key; - TDB_DATA data; - bool fail; - unsigned count; -}; - -static inline bool tdb_deq(TDB_DATA a, TDB_DATA b) -{ - return a.dsize == b.dsize && memcmp(a.dptr, b.dptr, a.dsize) == 0; -} - -static inline TDB_DATA tdb_mkdata(const void *p, size_t len) -{ - TDB_DATA d; - d.dptr = (void *)p; - d.dsize = len; - return d; -} - -static void walk(TDB_DATA key, TDB_DATA data, void *_wd) -{ - struct walk_data *wd = _wd; - - if (!tdb_deq(key, wd->key)) { - wd->fail = true; - } - - if (!tdb_deq(data, wd->data)) { - wd->fail = true; - } - wd->count++; -} - -static void count_records(TDB_DATA key, TDB_DATA data, void *_wd) -{ - struct walk_data *wd = _wd; - - if (!tdb_deq(key, wd->key) || !tdb_deq(data, wd->data)) - diag("%.*s::%.*s\n", - (int)key.dsize, key.dptr, (int)data.dsize, data.dptr); - wd->count++; -} - -static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) -{ - unsigned int *count = tdb_get_logging_private(tdb); - (*count)++; -} - -int main(int argc, char *argv[]) -{ - struct tdb_context *tdb; - struct walk_data wd; - unsigned int i, size, log_count = 0; - struct tdb_logging_context log_ctx = { log_fn, &log_count }; - - plan_tests(8); - tdb = tdb_open_ex("run-rescue.tdb", 1, TDB_CLEAR_IF_FIRST, - O_CREAT|O_TRUNC|O_RDWR, 0600, &log_ctx, NULL); - - wd.key.dsize = strlen("hi"); - wd.key.dptr = (void *)"hi"; - wd.data.dsize = strlen("world"); - wd.data.dptr = (void *)"world"; - wd.count = 0; - wd.fail = false; - - ok1(tdb_store(tdb, wd.key, wd.data, TDB_INSERT) == 0); - - ok1(tdb_rescue(tdb, walk, &wd) == 0); - ok1(!wd.fail); - ok1(wd.count == 1); - - /* Corrupt the database, walk should either get it or not. */ - size = tdb->map_size; - for (i = sizeof(struct tdb_header); i < size; i++) { - char c; - if (tdb->methods->tdb_read(tdb, i, &c, 1, false) != 0) - fail("Reading offset %i", i); - if (tdb->methods->tdb_write(tdb, i, "X", 1) != 0) - fail("Writing X at offset %i", i); - - wd.count = 0; - if (tdb_rescue(tdb, count_records, &wd) != 0) { - wd.fail = true; - break; - } - /* Could be 0 or 1. */ - if (wd.count > 1) { - wd.fail = true; - break; - } - if (tdb->methods->tdb_write(tdb, i, &c, 1) != 0) - fail("Restoring offset %i", i); - } - ok1(log_count == 0); - ok1(!wd.fail); - tdb_close(tdb); - - /* Now try our known-corrupt db. */ - tdb = tdb_open_ex("test/tdb.corrupt", 1024, 0, O_RDWR, 0, - &taplogctx, NULL); - wd.count = 0; - ok1(tdb_rescue(tdb, count_records, &wd) == 0); - ok1(wd.count == 1627); - tdb_close(tdb); - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-rwlock-check.c b/ctdb/lib/tdb/test/run-rwlock-check.c deleted file mode 100644 index 8b8072db1e67..000000000000 --- a/ctdb/lib/tdb/test/run-rwlock-check.c +++ /dev/null @@ -1,45 +0,0 @@ -#include "../common/tdb_private.h" -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#include - -static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) -{ - unsigned int *count = tdb_get_logging_private(tdb); - if (strstr(fmt, "spinlocks")) - (*count)++; -} - -/* The code should barf on TDBs created with rwlocks. */ -int main(int argc, char *argv[]) -{ - struct tdb_context *tdb; - unsigned int log_count; - struct tdb_logging_context log_ctx = { log_fn, &log_count }; - - plan_tests(4); - - /* We should fail to open rwlock-using tdbs of either endian. */ - log_count = 0; - tdb = tdb_open_ex("test/rwlock-le.tdb", 0, 0, O_RDWR, 0, - &log_ctx, NULL); - ok1(!tdb); - ok1(log_count == 1); - - log_count = 0; - tdb = tdb_open_ex("test/rwlock-be.tdb", 0, 0, O_RDWR, 0, - &log_ctx, NULL); - ok1(!tdb); - ok1(log_count == 1); - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-summary.c b/ctdb/lib/tdb/test/run-summary.c deleted file mode 100644 index 22312843e79e..000000000000 --- a/ctdb/lib/tdb/test/run-summary.c +++ /dev/null @@ -1,64 +0,0 @@ -#include "../common/tdb_private.h" -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "../common/summary.c" -#include "tap-interface.h" -#include - -int main(int argc, char *argv[]) -{ - unsigned int i, j; - struct tdb_context *tdb; - int flags[] = { TDB_INTERNAL, TDB_DEFAULT, TDB_NOMMAP, - TDB_INTERNAL|TDB_CONVERT, TDB_CONVERT, - TDB_NOMMAP|TDB_CONVERT }; - TDB_DATA key = { (unsigned char *)&j, sizeof(j) }; - TDB_DATA data = { (unsigned char *)&j, sizeof(j) }; - char *summary; - - plan_tests(sizeof(flags) / sizeof(flags[0]) * 14); - for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) { - tdb = tdb_open("run-summary.tdb", 131, flags[i], - O_RDWR|O_CREAT|O_TRUNC, 0600); - ok1(tdb); - if (!tdb) - continue; - - /* Put some stuff in there. */ - for (j = 0; j < 500; j++) { - /* Make sure padding varies to we get some graphs! */ - data.dsize = j % (sizeof(j) + 1); - if (tdb_store(tdb, key, data, TDB_REPLACE) != 0) - fail("Storing in tdb"); - } - - summary = tdb_summary(tdb); - diag("%s", summary); - ok1(strstr(summary, "Size of file/data: ")); - ok1(strstr(summary, "Number of records: 500\n")); - ok1(strstr(summary, "Smallest/average/largest keys: 4/4/4\n")); - ok1(strstr(summary, "Smallest/average/largest data: 0/2/4\n")); - ok1(strstr(summary, "Smallest/average/largest padding: ")); - ok1(strstr(summary, "Number of dead records: 0\n")); - ok1(strstr(summary, "Number of free records: 1\n")); - ok1(strstr(summary, "Smallest/average/largest free records: ")); - ok1(strstr(summary, "Number of hash chains: 131\n")); - ok1(strstr(summary, "Smallest/average/largest hash chains: ")); - ok1(strstr(summary, "Number of uncoalesced records: 0\n")); - ok1(strstr(summary, "Smallest/average/largest uncoalesced runs: 0/0/0\n")); - ok1(strstr(summary, "Percentage keys/data/padding/free/dead/rechdrs&tailers/hashes: ")); - - free(summary); - tdb_close(tdb); - } - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-transaction-expand.c b/ctdb/lib/tdb/test/run-transaction-expand.c deleted file mode 100644 index 1271d92b3313..000000000000 --- a/ctdb/lib/tdb/test/run-transaction-expand.c +++ /dev/null @@ -1,119 +0,0 @@ -#include "../common/tdb_private.h" - -/* Speed up the tests, but do the actual sync tests. */ -static unsigned int sync_counts = 0; -static inline int fake_fsync(int fd) -{ - sync_counts++; - return 0; -} -#define fsync fake_fsync - -#ifdef MS_SYNC -static inline int fake_msync(void *addr, size_t length, int flags) -{ - sync_counts++; - return 0; -} -#define msync fake_msync -#endif - -#ifdef HAVE_FDATASYNC -static inline int fake_fdatasync(int fd) -{ - sync_counts++; - return 0; -} -#define fdatasync fake_fdatasync -#endif - -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#include -#include "logging.h" - -static void write_record(struct tdb_context *tdb, size_t extra_len, - TDB_DATA *data) -{ - TDB_DATA key; - key.dsize = strlen("hi"); - key.dptr = (void *)"hi"; - - data->dsize += extra_len; - tdb_transaction_start(tdb); - tdb_store(tdb, key, *data, TDB_REPLACE); - tdb_transaction_commit(tdb); -} - -int main(int argc, char *argv[]) -{ - struct tdb_context *tdb; - size_t i; - TDB_DATA data; - struct tdb_record rec; - tdb_off_t off; - - /* Do *not* suppress sync for this test; we do it ourselves. */ - unsetenv("TDB_NO_FSYNC"); - - plan_tests(5); - tdb = tdb_open_ex("run-transaction-expand.tdb", - 1024, TDB_CLEAR_IF_FIRST, - O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL); - ok1(tdb); - - data.dsize = 0; - data.dptr = calloc(1000, getpagesize()); - - /* Simulate a slowly growing record. */ - for (i = 0; i < 1000; i++) - write_record(tdb, getpagesize(), &data); - - tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &off); - tdb_read(tdb, off, &rec, sizeof(rec), DOCONV()); - diag("TDB size = %zu, recovery = %llu-%llu", - (size_t)tdb->map_size, (unsigned long long)off, (unsigned long long)(off + sizeof(rec) + rec.rec_len)); - - /* We should only be about 5 times larger than largest record. */ - ok1(tdb->map_size < 6 * i * getpagesize()); - tdb_close(tdb); - - tdb = tdb_open_ex("run-transaction-expand.tdb", - 1024, TDB_CLEAR_IF_FIRST, - O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL); - ok1(tdb); - - data.dsize = 0; - - /* Simulate a slowly growing record, repacking to keep - * recovery area at end. */ - for (i = 0; i < 1000; i++) { - write_record(tdb, getpagesize(), &data); - if (i % 10 == 0) - tdb_repack(tdb); - } - - tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &off); - tdb_read(tdb, off, &rec, sizeof(rec), DOCONV()); - diag("TDB size = %zu, recovery = %llu-%llu", - (size_t)tdb->map_size, (unsigned long long)off, (unsigned long long)(off + sizeof(rec) + rec.rec_len)); - - /* We should only be about 4 times larger than largest record. */ - ok1(tdb->map_size < 5 * i * getpagesize()); - - /* We should have synchronized multiple times. */ - ok1(sync_counts); - tdb_close(tdb); - free(data.dptr); - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-traverse-in-transaction.c b/ctdb/lib/tdb/test/run-traverse-in-transaction.c deleted file mode 100644 index bcdc3545cd5b..000000000000 --- a/ctdb/lib/tdb/test/run-traverse-in-transaction.c +++ /dev/null @@ -1,86 +0,0 @@ -#include "lock-tracking.h" -#include "../common/tdb_private.h" -#define fcntl fcntl_with_lockcheck -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#undef fcntl_with_lockcheck -#include -#include -#include "external-agent.h" -#include "logging.h" - -static struct agent *agent; - -static bool correct_key(TDB_DATA key) -{ - return key.dsize == strlen("hi") - && memcmp(key.dptr, "hi", key.dsize) == 0; -} - -static bool correct_data(TDB_DATA data) -{ - return data.dsize == strlen("world") - && memcmp(data.dptr, "world", data.dsize) == 0; -} - -static int traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, - void *p) -{ - ok1(correct_key(key)); - ok1(correct_data(data)); - return 0; -} - -int main(int argc, char *argv[]) -{ - struct tdb_context *tdb; - TDB_DATA key, data; - - plan_tests(13); - agent = prepare_external_agent(); - - tdb = tdb_open_ex("run-traverse-in-transaction.tdb", - 1024, TDB_CLEAR_IF_FIRST, O_CREAT|O_TRUNC|O_RDWR, - 0600, &taplogctx, NULL); - ok1(tdb); - - key.dsize = strlen("hi"); - key.dptr = (void *)"hi"; - data.dptr = (void *)"world"; - data.dsize = strlen("world"); - - ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0); - - ok1(external_agent_operation(agent, OPEN, tdb_name(tdb)) == SUCCESS); - - ok1(tdb_transaction_start(tdb) == 0); - ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb)) - == WOULD_HAVE_BLOCKED); - tdb_traverse(tdb, traverse, NULL); - - /* That should *not* release the transaction lock! */ - ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb)) - == WOULD_HAVE_BLOCKED); - tdb_traverse_read(tdb, traverse, NULL); - - /* That should *not* release the transaction lock! */ - ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb)) - == WOULD_HAVE_BLOCKED); - ok1(tdb_transaction_commit(tdb) == 0); - /* Now we should be fine. */ - ok1(external_agent_operation(agent, TRANSACTION_START, tdb_name(tdb)) - == SUCCESS); - - tdb_close(tdb); - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-wronghash-fail.c b/ctdb/lib/tdb/test/run-wronghash-fail.c deleted file mode 100644 index 74bbc30ba6fb..000000000000 --- a/ctdb/lib/tdb/test/run-wronghash-fail.c +++ /dev/null @@ -1,120 +0,0 @@ -#include "../common/tdb_private.h" -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#include - -static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) -{ - unsigned int *count = tdb_get_logging_private(tdb); - if (strstr(fmt, "hash")) - (*count)++; -} - -int main(int argc, char *argv[]) -{ - struct tdb_context *tdb; - unsigned int log_count; - TDB_DATA d; - struct tdb_logging_context log_ctx = { log_fn, &log_count }; - - plan_tests(28); - - /* Create with default hash. */ - log_count = 0; - tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0, - O_CREAT|O_RDWR|O_TRUNC, 0600, &log_ctx, NULL); - ok1(tdb); - ok1(log_count == 0); - d.dptr = (void *)"Hello"; - d.dsize = 5; - ok1(tdb_store(tdb, d, d, TDB_INSERT) == 0); - tdb_close(tdb); - - /* Fail to open with different hash. */ - tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0, O_RDWR, 0, - &log_ctx, tdb_jenkins_hash); - ok1(!tdb); - ok1(log_count == 1); - - /* Create with different hash. */ - log_count = 0; - tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0, - O_CREAT|O_RDWR|O_TRUNC, - 0600, &log_ctx, tdb_jenkins_hash); - ok1(tdb); - ok1(log_count == 0); - tdb_close(tdb); - - /* Endian should be no problem. */ - log_count = 0; - tdb = tdb_open_ex("test/jenkins-le-hash.tdb", 0, 0, O_RDWR, 0, - &log_ctx, tdb_old_hash); - ok1(!tdb); - ok1(log_count == 1); - - log_count = 0; - tdb = tdb_open_ex("test/jenkins-be-hash.tdb", 0, 0, O_RDWR, 0, - &log_ctx, tdb_old_hash); - ok1(!tdb); - ok1(log_count == 1); - - log_count = 0; - /* Fail to open with old default hash. */ - tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0, O_RDWR, 0, - &log_ctx, tdb_old_hash); - ok1(!tdb); - ok1(log_count == 1); - - log_count = 0; - tdb = tdb_open_ex("test/jenkins-le-hash.tdb", 0, 0, O_RDONLY, - 0, &log_ctx, tdb_jenkins_hash); - ok1(tdb); - ok1(log_count == 0); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - - log_count = 0; - tdb = tdb_open_ex("test/jenkins-be-hash.tdb", 0, 0, O_RDONLY, - 0, &log_ctx, tdb_jenkins_hash); - ok1(tdb); - ok1(log_count == 0); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - - /* It should open with jenkins hash if we don't specify. */ - log_count = 0; - tdb = tdb_open_ex("test/jenkins-le-hash.tdb", 0, 0, O_RDWR, 0, - &log_ctx, NULL); - ok1(tdb); - ok1(log_count == 0); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - - log_count = 0; - tdb = tdb_open_ex("test/jenkins-be-hash.tdb", 0, 0, O_RDWR, 0, - &log_ctx, NULL); - ok1(tdb); - ok1(log_count == 0); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - - log_count = 0; - tdb = tdb_open_ex("run-wronghash-fail.tdb", 0, 0, O_RDONLY, - 0, &log_ctx, NULL); - ok1(tdb); - ok1(log_count == 0); - ok1(tdb_check(tdb, NULL, NULL) == 0); - tdb_close(tdb); - - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run-zero-append.c b/ctdb/lib/tdb/test/run-zero-append.c deleted file mode 100644 index 36bf6990f53e..000000000000 --- a/ctdb/lib/tdb/test/run-zero-append.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "../common/tdb_private.h" -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#include -#include "logging.h" - -int main(int argc, char *argv[]) -{ - struct tdb_context *tdb; - TDB_DATA key, data; - - plan_tests(4); - tdb = tdb_open_ex(NULL, 1024, TDB_INTERNAL, O_CREAT|O_TRUNC|O_RDWR, - 0600, &taplogctx, NULL); - ok1(tdb); - - /* Tickle bug on appending zero length buffer to zero length buffer. */ - key.dsize = strlen("hi"); - key.dptr = (void *)"hi"; - data.dptr = (void *)"world"; - data.dsize = 0; - - ok1(tdb_append(tdb, key, data) == 0); - ok1(tdb_append(tdb, key, data) == 0); - data = tdb_fetch(tdb, key); - ok1(data.dsize == 0); - tdb_close(tdb); - free(data.dptr); - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/run.c b/ctdb/lib/tdb/test/run.c deleted file mode 100644 index f49e85055e56..000000000000 --- a/ctdb/lib/tdb/test/run.c +++ /dev/null @@ -1,49 +0,0 @@ -#include "../common/tdb_private.h" -#include "../common/io.c" -#include "../common/tdb.c" -#include "../common/lock.c" -#include "../common/freelist.c" -#include "../common/traverse.c" -#include "../common/transaction.c" -#include "../common/error.c" -#include "../common/open.c" -#include "../common/check.c" -#include "../common/hash.c" -#include "tap-interface.h" -#include -#include "logging.h" - -int main(int argc, char *argv[]) -{ - struct tdb_context *tdb; - TDB_DATA key, data; - - plan_tests(10); - tdb = tdb_open_ex("run.tdb", 1024, TDB_CLEAR_IF_FIRST, - O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL); - - ok1(tdb); - key.dsize = strlen("hi"); - key.dptr = (void *)"hi"; - data.dsize = strlen("world"); - data.dptr = (void *)"world"; - - ok1(tdb_store(tdb, key, data, TDB_MODIFY) < 0); - ok1(tdb_error(tdb) == TDB_ERR_NOEXIST); - ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0); - ok1(tdb_store(tdb, key, data, TDB_INSERT) < 0); - ok1(tdb_error(tdb) == TDB_ERR_EXISTS); - ok1(tdb_store(tdb, key, data, TDB_MODIFY) == 0); - - data = tdb_fetch(tdb, key); - ok1(data.dsize == strlen("world")); - ok1(memcmp(data.dptr, "world", strlen("world")) == 0); - free(data.dptr); - - key.dsize++; - data = tdb_fetch(tdb, key); - ok1(data.dptr == NULL); - tdb_close(tdb); - - return exit_status(); -} diff --git a/ctdb/lib/tdb/test/rwlock-be.tdb b/ctdb/lib/tdb/test/rwlock-be.tdb deleted file mode 100644 index 45b5f09a1b61..000000000000 Binary files a/ctdb/lib/tdb/test/rwlock-be.tdb and /dev/null differ diff --git a/ctdb/lib/tdb/test/rwlock-le.tdb b/ctdb/lib/tdb/test/rwlock-le.tdb deleted file mode 100644 index 45b5f09a1b61..000000000000 Binary files a/ctdb/lib/tdb/test/rwlock-le.tdb and /dev/null differ diff --git a/ctdb/lib/tdb/test/tap-interface.h b/ctdb/lib/tdb/test/tap-interface.h deleted file mode 100644 index d9ed6e84ea5e..000000000000 --- a/ctdb/lib/tdb/test/tap-interface.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Simplistic implementation of tap interface. - - Copyright (C) Rusty Russell 2012 - - ** NOTE! The following LGPL license applies to the talloc - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ -#include - -#ifndef __location__ -#define __TAP_STRING_LINE1__(s) #s -#define __TAP_STRING_LINE2__(s) __TAP_STRING_LINE1__(s) -#define __TAP_STRING_LINE3__ __TAP_STRING_LINE2__(__LINE__) -#define __location__ __FILE__ ":" __TAP_STRING_LINE3__ -#endif - -#define plan_tests(num) -#define ok(e, ...) do { if (e) { (void)printf("."); } else { fprintf(stderr, __VA_ARGS__); exit(1); } } while(0) -#define ok1(e) ok((e), "%s:%s", __location__, #e) -#define pass(...) printf(".") -#define fail(...) do { fprintf(stderr, __VA_ARGS__); exit(1); } while(0) -#define diag printf -#define exit_status() 0 diff --git a/ctdb/lib/tdb/test/tap-to-subunit.h b/ctdb/lib/tdb/test/tap-to-subunit.h deleted file mode 100644 index a5cf74fb0467..000000000000 --- a/ctdb/lib/tdb/test/tap-to-subunit.h +++ /dev/null @@ -1,155 +0,0 @@ -#ifndef TAP_TO_SUBUNIT_H -#define TAP_TO_SUBUNIT_H -/* - * tap-style wrapper for subunit. - * - * Copyright (c) 2011 Rusty Russell - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include "replace.h" - -/** - * plan_tests - announce the number of tests you plan to run - * @tests: the number of tests - * - * This should be the first call in your test program: it allows tracing - * of failures which mean that not all tests are run. - * - * If you don't know how many tests will actually be run, assume all of them - * and use skip() if you don't actually run some tests. - * - * Example: - * plan_tests(13); - */ -void plan_tests(unsigned int tests); - -/** - * ok1 - Simple conditional test - * @e: the expression which we expect to be true. - * - * This is the simplest kind of test: if the expression is true, the - * test passes. The name of the test which is printed will simply be - * file name, line number, and the expression itself. - * - * Example: - * ok1(somefunc() == 1); - */ -# define ok1(e) ((e) ? \ - _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : \ - _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e)) - -/** - * ok - Conditional test with a name - * @e: the expression which we expect to be true. - * @...: the printf-style name of the test. - * - * If the expression is true, the test passes. The name of the test will be - * the filename, line number, and the printf-style string. This can be clearer - * than simply the expression itself. - * - * Example: - * ok1(somefunc() == 1); - * ok(somefunc() == 0, "Second somefunc() should fail"); - */ -# define ok(e, ...) ((e) ? \ - _gen_result(1, __func__, __FILE__, __LINE__, \ - __VA_ARGS__) : \ - _gen_result(0, __func__, __FILE__, __LINE__, \ - __VA_ARGS__)) - -/** - * pass - Note that a test passed - * @...: the printf-style name of the test. - * - * For complicated code paths, it can be easiest to simply call pass() in one - * branch and fail() in another. - * - * Example: - * int x = somefunc(); - * if (x > 0) - * pass("somefunc() returned a valid value"); - * else - * fail("somefunc() returned an invalid value"); - */ -# define pass(...) ok(1, __VA_ARGS__) - -/** - * fail - Note that a test failed - * @...: the printf-style name of the test. - * - * For complicated code paths, it can be easiest to simply call pass() in one - * branch and fail() in another. - */ -# define fail(...) ok(0, __VA_ARGS__) - -unsigned int _gen_result(int, const char *, const char *, unsigned int, - const char *, ...) PRINTF_ATTRIBUTE(5, 6); - -/** - * diag - print a diagnostic message (use instead of printf/fprintf) - * @fmt: the format of the printf-style message - * - * diag ensures that the output will not be considered to be a test - * result by the TAP test harness. It will append '\n' for you. - * - * Example: - * diag("Now running complex tests"); - */ -void diag(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2); - -/** - * skip - print a diagnostic message (use instead of printf/fprintf) - * @n: number of tests you're skipping. - * @fmt: the format of the reason you're skipping the tests. - * - * Sometimes tests cannot be run because the test system lacks some feature: - * you should explicitly document that you're skipping tests using skip(). - * - * From the Test::More documentation: - * If it's something the user might not be able to do, use SKIP. This - * includes optional modules that aren't installed, running under an OS that - * doesn't have some feature (like fork() or symlinks), or maybe you need an - * Internet connection and one isn't available. - * - * Example: - * #ifdef HAVE_SOME_FEATURE - * ok1(somefunc()); - * #else - * skip(1, "Don't have SOME_FEATURE"); - * #endif - */ -void skip(unsigned int n, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3); - -/** - * exit_status - the value that main should return. - * - * For maximum compatibility your test program should return a particular exit - * code (ie. 0 if all tests were run, and every test which was expected to - * succeed succeeded). - * - * Example: - * exit(exit_status()); - */ -int exit_status(void); -#endif /* CCAN_TAP_H */ diff --git a/ctdb/lib/tdb/test/tdb.corrupt b/ctdb/lib/tdb/test/tdb.corrupt deleted file mode 100644 index 83d667745430..000000000000 Binary files a/ctdb/lib/tdb/test/tdb.corrupt and /dev/null differ diff --git a/ctdb/lib/tdb/tools/tdbbackup.c b/ctdb/lib/tdb/tools/tdbbackup.c deleted file mode 100644 index 11ecaa0290ae..000000000000 --- a/ctdb/lib/tdb/tools/tdbbackup.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - Unix SMB/CIFS implementation. - low level tdb backup and restore utility - Copyright (C) Andrew Tridgell 2002 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -/* - - This program is meant for backup/restore of tdb databases. Typical usage would be: - tdbbackup *.tdb - when Samba shuts down cleanly, which will make a backup of all the local databases - to *.bak files. Then on Samba startup you would use: - tdbbackup -v *.tdb - and this will check the databases for corruption and if corruption is detected then - the backup will be restored. - - You may also like to do a backup on a regular basis while Samba is - running, perhaps using cron. - - The reason this program is needed is to cope with power failures - while Samba is running. A power failure could lead to database - corruption and Samba will then not start correctly. - - Note that many of the databases in Samba are transient and thus - don't need to be backed up, so you can optimise the above a little - by only running the backup on the critical databases. - - */ - -#include "replace.h" -#include "system/locale.h" -#include "system/time.h" -#include "system/filesys.h" -#include "system/wait.h" -#include "tdb.h" - -#ifdef HAVE_GETOPT_H -#include -#endif - -static int failed; - -static struct tdb_logging_context log_ctx; - -#ifdef PRINTF_ATTRIBUTE -static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...) PRINTF_ATTRIBUTE(3,4); -#endif -static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - vfprintf(stdout, format, ap); - va_end(ap); - fflush(stdout); -} - -static char *add_suffix(const char *name, const char *suffix) -{ - char *ret; - int len = strlen(name) + strlen(suffix) + 1; - ret = (char *)malloc(len); - if (!ret) { - fprintf(stderr,"Out of memory!\n"); - exit(1); - } - snprintf(ret, len, "%s%s", name, suffix); - return ret; -} - -static int copy_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state) -{ - TDB_CONTEXT *tdb_new = (TDB_CONTEXT *)state; - - if (tdb_store(tdb_new, key, dbuf, TDB_INSERT) != 0) { - fprintf(stderr,"Failed to insert into %s\n", tdb_name(tdb_new)); - failed = 1; - return 1; - } - return 0; -} - - -static int test_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state) -{ - return 0; -} - -/* - carefully backup a tdb, validating the contents and - only doing the backup if its OK - this function is also used for restore -*/ -static int backup_tdb(const char *old_name, const char *new_name, int hash_size) -{ - TDB_CONTEXT *tdb; - TDB_CONTEXT *tdb_new; - char *tmp_name; - struct stat st; - int count1, count2; - - tmp_name = add_suffix(new_name, ".tmp"); - - /* stat the old tdb to find its permissions */ - if (stat(old_name, &st) != 0) { - perror(old_name); - free(tmp_name); - return 1; - } - - /* open the old tdb */ - tdb = tdb_open_ex(old_name, 0, 0, - O_RDWR, 0, &log_ctx, NULL); - if (!tdb) { - printf("Failed to open %s\n", old_name); - free(tmp_name); - return 1; - } - - /* create the new tdb */ - unlink(tmp_name); - tdb_new = tdb_open_ex(tmp_name, - hash_size ? hash_size : tdb_hash_size(tdb), - TDB_DEFAULT, - O_RDWR|O_CREAT|O_EXCL, st.st_mode & 0777, - &log_ctx, NULL); - if (!tdb_new) { - perror(tmp_name); - free(tmp_name); - return 1; - } - - if (tdb_transaction_start(tdb) != 0) { - printf("Failed to start transaction on old tdb\n"); - tdb_close(tdb); - tdb_close(tdb_new); - unlink(tmp_name); - free(tmp_name); - return 1; - } - - /* lock the backup tdb so that nobody else can change it */ - if (tdb_lockall(tdb_new) != 0) { - printf("Failed to lock backup tdb\n"); - tdb_close(tdb); - tdb_close(tdb_new); - unlink(tmp_name); - free(tmp_name); - return 1; - } - - failed = 0; - - /* traverse and copy */ - count1 = tdb_traverse(tdb, copy_fn, (void *)tdb_new); - if (count1 < 0 || failed) { - fprintf(stderr,"failed to copy %s\n", old_name); - tdb_close(tdb); - tdb_close(tdb_new); - unlink(tmp_name); - free(tmp_name); - return 1; - } - - /* close the old tdb */ - tdb_close(tdb); - - /* copy done, unlock the backup tdb */ - tdb_unlockall(tdb_new); - -#ifdef HAVE_FDATASYNC - if (fdatasync(tdb_fd(tdb_new)) != 0) { -#else - if (fsync(tdb_fd(tdb_new)) != 0) { -#endif - /* not fatal */ - fprintf(stderr, "failed to fsync backup file\n"); - } - - /* close the new tdb and re-open read-only */ - tdb_close(tdb_new); - tdb_new = tdb_open_ex(tmp_name, - 0, - TDB_DEFAULT, - O_RDONLY, 0, - &log_ctx, NULL); - if (!tdb_new) { - fprintf(stderr,"failed to reopen %s\n", tmp_name); - unlink(tmp_name); - perror(tmp_name); - free(tmp_name); - return 1; - } - - /* traverse the new tdb to confirm */ - count2 = tdb_traverse(tdb_new, test_fn, NULL); - if (count2 != count1) { - fprintf(stderr,"failed to copy %s\n", old_name); - tdb_close(tdb_new); - unlink(tmp_name); - free(tmp_name); - return 1; - } - - /* close the new tdb and rename it to .bak */ - tdb_close(tdb_new); - if (rename(tmp_name, new_name) != 0) { - perror(new_name); - free(tmp_name); - return 1; - } - - free(tmp_name); - - return 0; -} - -/* - verify a tdb and if it is corrupt then restore from *.bak -*/ -static int verify_tdb(const char *fname, const char *bak_name) -{ - TDB_CONTEXT *tdb; - int count = -1; - - /* open the tdb */ - tdb = tdb_open_ex(fname, 0, 0, - O_RDONLY, 0, &log_ctx, NULL); - - /* traverse the tdb, then close it */ - if (tdb) { - count = tdb_traverse(tdb, test_fn, NULL); - tdb_close(tdb); - } - - /* count is < 0 means an error */ - if (count < 0) { - printf("restoring %s\n", fname); - return backup_tdb(bak_name, fname, 0); - } - - printf("%s : %d records\n", fname, count); - - return 0; -} - -/* - see if one file is newer than another -*/ -static int file_newer(const char *fname1, const char *fname2) -{ - struct stat st1, st2; - if (stat(fname1, &st1) != 0) { - return 0; - } - if (stat(fname2, &st2) != 0) { - return 1; - } - return (st1.st_mtime > st2.st_mtime); -} - -static void usage(void) -{ - printf("Usage: tdbbackup [options] \n\n"); - printf(" -h this help message\n"); - printf(" -s suffix set the backup suffix\n"); - printf(" -v verify mode (restore if corrupt)\n"); - printf(" -n hashsize set the new hash size for the backup\n"); -} - - - int main(int argc, char *argv[]) -{ - int i; - int ret = 0; - int c; - int verify = 0; - int hashsize = 0; - const char *suffix = ".bak"; - - log_ctx.log_fn = tdb_log; - - while ((c = getopt(argc, argv, "vhs:n:")) != -1) { - switch (c) { - case 'h': - usage(); - exit(0); - case 'v': - verify = 1; - break; - case 's': - suffix = optarg; - break; - case 'n': - hashsize = atoi(optarg); - break; - } - } - - argc -= optind; - argv += optind; - - if (argc < 1) { - usage(); - exit(1); - } - - for (i=0; i. -*/ - -#include "replace.h" -#include "system/locale.h" -#include "system/time.h" -#include "system/filesys.h" -#include "system/wait.h" -#include "tdb.h" - -static void print_data(TDB_DATA d) -{ - unsigned char *p = (unsigned char *)d.dptr; - int len = d.dsize; - while (len--) { - if (isprint(*p) && !strchr("\"\\", *p)) { - fputc(*p, stdout); - } else { - printf("\\%02X", *p); - } - p++; - } -} - -static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state) -{ - printf("{\n"); - printf("key(%d) = \"", (int)key.dsize); - print_data(key); - printf("\"\n"); - printf("data(%d) = \"", (int)dbuf.dsize); - print_data(dbuf); - printf("\"\n"); - printf("}\n"); - return 0; -} - -static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level, - const char *fmt, ...) -{ - va_list ap; - char *ptr = NULL; - int debuglevel = 0; - int ret; - const char *name = tdb_name(tdb); - const char *prefix = ""; - - if (!name) - name = "unnamed"; - - switch (level) { - case TDB_DEBUG_ERROR: - prefix = "ERROR: "; - break; - case TDB_DEBUG_WARNING: - prefix = "WARNING: "; - break; - case TDB_DEBUG_TRACE: - return; - - default: - case TDB_DEBUG_FATAL: - prefix = "FATAL: "; - break; - } - - va_start(ap, fmt); - fprintf(stderr, "tdb(%s): %s", name, prefix); - vfprintf(stderr, fmt, ap); - va_end(ap); -} - -static void emergency_walk(TDB_DATA key, TDB_DATA dbuf, void *keyname) -{ - if (keyname) { - if (key.dsize != strlen(keyname)) - return; - if (memcmp(key.dptr, keyname, key.dsize) != 0) - return; - } - traverse_fn(NULL, key, dbuf, NULL); -} - -static int dump_tdb(const char *fname, const char *keyname, bool emergency) -{ - TDB_CONTEXT *tdb; - TDB_DATA key, value; - struct tdb_logging_context logfn = { log_stderr }; - - tdb = tdb_open_ex(fname, 0, 0, O_RDONLY, 0, &logfn, NULL); - if (!tdb) { - printf("Failed to open %s\n", fname); - return 1; - } - - if (emergency) { - return tdb_rescue(tdb, emergency_walk, keyname) == 0; - } - if (!keyname) { - return tdb_traverse(tdb, traverse_fn, NULL) == -1 ? 1 : 0; - } else { - key.dptr = discard_const_p(uint8_t, keyname); - key.dsize = strlen(keyname); - value = tdb_fetch(tdb, key); - if (!value.dptr) { - return 1; - } else { - print_data(value); - free(value.dptr); - } - } - - return 0; -} - -static void usage( void) -{ - printf( "Usage: tdbdump [options] \n\n"); - printf( " -h this help message\n"); - printf( " -k keyname dumps value of keyname\n"); - printf( " -e emergency dump, for corrupt databases\n"); -} - - int main(int argc, char *argv[]) -{ - char *fname, *keyname=NULL; - bool emergency = false; - int c; - - if (argc < 2) { - printf("Usage: tdbdump \n"); - exit(1); - } - - while ((c = getopt( argc, argv, "hk:e")) != -1) { - switch (c) { - case 'h': - usage(); - exit( 0); - case 'k': - keyname = optarg; - break; - case 'e': - emergency = true; - break; - default: - usage(); - exit( 1); - } - } - - fname = argv[optind]; - - return dump_tdb(fname, keyname, emergency); -} diff --git a/ctdb/lib/tdb/tools/tdbrestore.c b/ctdb/lib/tdb/tools/tdbrestore.c deleted file mode 100644 index f65b36fa12e4..000000000000 --- a/ctdb/lib/tdb/tools/tdbrestore.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - tdbrestore -- construct a tdb from tdbdump output. - Copyright (C) Volker Lendecke 2010 - Copyright (C) Simon McVittie 2005 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include -#include "replace.h" -#include "system/locale.h" -#include "system/time.h" -#include "system/filesys.h" -#include "system/wait.h" -#include "tdb.h" - -static int read_linehead(FILE *f) -{ - int i, c; - int num_bytes; - char prefix[128]; - - while (1) { - c = getc(f); - if (c == EOF) { - return -1; - } - if (c == '(') { - break; - } - } - for (i=0; idptr = (unsigned char *)malloc(size); - if (d->dptr == NULL) { - return -1; - } - d->dsize = size; - - for (i=0; idptr[i] = (low|high); - } else { - d->dptr[i] = c; - } - } - return 0; -} - -static int swallow(FILE *f, const char *s, int *eof) -{ - char line[128]; - - if (fgets(line, sizeof(line), f) == NULL) { - if (eof != NULL) { - *eof = 1; - } - return -1; - } - if (strcmp(line, s) != 0) { - return -1; - } - return 0; -} - -static int read_rec(FILE *f, TDB_CONTEXT *tdb, int *eof) -{ - int length; - TDB_DATA key, data; - int ret = -1; - - key.dptr = NULL; - data.dptr = NULL; - - if (swallow(f, "{\n", eof) == -1) { - goto fail; - } - length = read_linehead(f); - if (length == -1) { - goto fail; - } - if (read_data(f, &key, length) == -1) { - goto fail; - } - if (swallow(f, "\"\n", NULL) == -1) { - goto fail; - } - length = read_linehead(f); - if (length == -1) { - goto fail; - } - if (read_data(f, &data, length) == -1) { - goto fail; - } - if ((swallow(f, "\"\n", NULL) == -1) - || (swallow(f, "}\n", NULL) == -1)) { - goto fail; - } - if (tdb_store(tdb, key, data, TDB_INSERT) != 0) { - fprintf(stderr, "TDB error: %s\n", tdb_errorstr(tdb)); - goto fail; - } - - ret = 0; -fail: - free(key.dptr); - free(data.dptr); - return ret; -} - -static int restore_tdb(const char *fname) -{ - TDB_CONTEXT *tdb; - - tdb = tdb_open(fname, 0, 0, O_RDWR|O_CREAT|O_EXCL, 0666); - if (!tdb) { - perror("tdb_open"); - fprintf(stderr, "Failed to open %s\n", fname); - return 1; - } - - while (1) { - int eof = 0; - if (read_rec(stdin, tdb, &eof) == -1) { - if (eof) { - break; - } - return 1; - } - } - if (tdb_close(tdb)) { - fprintf(stderr, "Error closing tdb\n"); - return 1; - } - return 0; -} - -int main(int argc, char *argv[]) -{ - char *fname; - - if (argc < 2) { - printf("Usage: %s dbname < tdbdump_output\n", argv[0]); - exit(1); - } - - fname = argv[1]; - - return restore_tdb(fname); -} diff --git a/ctdb/lib/tdb/tools/tdbtest.c b/ctdb/lib/tdb/tools/tdbtest.c deleted file mode 100644 index 44c78efda5cf..000000000000 --- a/ctdb/lib/tdb/tools/tdbtest.c +++ /dev/null @@ -1,290 +0,0 @@ -/* a test program for tdb - the trivial database */ - -#include "replace.h" -#include "tdb.h" -#include "system/filesys.h" -#include "system/time.h" - -#include - - -#define DELETE_PROB 7 -#define STORE_PROB 5 - -static struct tdb_context *db; -static GDBM_FILE gdbm; - -struct timeval tp1,tp2; - -static void _start_timer(void) -{ - gettimeofday(&tp1,NULL); -} - -static double _end_timer(void) -{ - gettimeofday(&tp2,NULL); - return((tp2.tv_sec - tp1.tv_sec) + - (tp2.tv_usec - tp1.tv_usec)*1.0e-6); -} - -static void fatal(const char *why) -{ - perror(why); - exit(1); -} - -#ifdef PRINTF_ATTRIBUTE -static void tdb_log(struct tdb_context *tdb, int level, const char *format, ...) PRINTF_ATTRIBUTE(3,4); -#endif -static void tdb_log(struct tdb_context *tdb, int level, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - vfprintf(stdout, format, ap); - va_end(ap); - fflush(stdout); -} - -static void compare_db(void) -{ - TDB_DATA d, key, nextkey; - datum gd, gkey, gnextkey; - - key = tdb_firstkey(db); - while (key.dptr) { - d = tdb_fetch(db, key); - gkey.dptr = key.dptr; - gkey.dsize = key.dsize; - - gd = gdbm_fetch(gdbm, gkey); - - if (!gd.dptr) fatal("key not in gdbm"); - if (gd.dsize != d.dsize) fatal("data sizes differ"); - if (memcmp(gd.dptr, d.dptr, d.dsize)) { - fatal("data differs"); - } - - nextkey = tdb_nextkey(db, key); - free(key.dptr); - free(d.dptr); - free(gd.dptr); - key = nextkey; - } - - gkey = gdbm_firstkey(gdbm); - while (gkey.dptr) { - gd = gdbm_fetch(gdbm, gkey); - key.dptr = gkey.dptr; - key.dsize = gkey.dsize; - - d = tdb_fetch(db, key); - - if (!d.dptr) fatal("key not in db"); - if (d.dsize != gd.dsize) fatal("data sizes differ"); - if (memcmp(d.dptr, gd.dptr, gd.dsize)) { - fatal("data differs"); - } - - gnextkey = gdbm_nextkey(gdbm, gkey); - free(gkey.dptr); - free(gd.dptr); - free(d.dptr); - gkey = gnextkey; - } -} - -static char *randbuf(int len) -{ - char *buf; - int i; - buf = (char *)malloc(len+1); - - for (i=0;i. -*/ - -#include "replace.h" -#include "system/locale.h" -#include "system/time.h" -#include "system/filesys.h" -#include "system/wait.h" -#include "tdb.h" - -static int do_command(void); -const char *cmdname; -char *arg1, *arg2; -size_t arg1len, arg2len; -int bIterate = 0; -char *line; -TDB_DATA iterate_kbuf; -char cmdline[1024]; -static int disable_mmap; - -enum commands { - CMD_CREATE_TDB, - CMD_OPEN_TDB, - CMD_TRANSACTION_START, - CMD_TRANSACTION_COMMIT, - CMD_TRANSACTION_CANCEL, - CMD_ERASE, - CMD_DUMP, - CMD_INSERT, - CMD_MOVE, - CMD_STORE, - CMD_SHOW, - CMD_KEYS, - CMD_HEXKEYS, - CMD_DELETE, - CMD_LIST_HASH_FREE, - CMD_LIST_FREE, - CMD_INFO, - CMD_MMAP, - CMD_SPEED, - CMD_FIRST, - CMD_NEXT, - CMD_SYSTEM, - CMD_CHECK, - CMD_REPACK, - CMD_QUIT, - CMD_HELP -}; - -typedef struct { - const char *name; - enum commands cmd; -} COMMAND_TABLE; - -COMMAND_TABLE cmd_table[] = { - {"create", CMD_CREATE_TDB}, - {"open", CMD_OPEN_TDB}, - {"transaction_start", CMD_TRANSACTION_START}, - {"transaction_commit", CMD_TRANSACTION_COMMIT}, - {"transaction_cancel", CMD_TRANSACTION_CANCEL}, - {"erase", CMD_ERASE}, - {"dump", CMD_DUMP}, - {"insert", CMD_INSERT}, - {"move", CMD_MOVE}, - {"store", CMD_STORE}, - {"show", CMD_SHOW}, - {"keys", CMD_KEYS}, - {"hexkeys", CMD_HEXKEYS}, - {"delete", CMD_DELETE}, - {"list", CMD_LIST_HASH_FREE}, - {"free", CMD_LIST_FREE}, - {"info", CMD_INFO}, - {"speed", CMD_SPEED}, - {"mmap", CMD_MMAP}, - {"first", CMD_FIRST}, - {"1", CMD_FIRST}, - {"next", CMD_NEXT}, - {"n", CMD_NEXT}, - {"check", CMD_CHECK}, - {"quit", CMD_QUIT}, - {"q", CMD_QUIT}, - {"!", CMD_SYSTEM}, - {"repack", CMD_REPACK}, - {NULL, CMD_HELP} -}; - -struct timeval tp1,tp2; - -static void _start_timer(void) -{ - gettimeofday(&tp1,NULL); -} - -static double _end_timer(void) -{ - gettimeofday(&tp2,NULL); - return((tp2.tv_sec - tp1.tv_sec) + - (tp2.tv_usec - tp1.tv_usec)*1.0e-6); -} - -#ifdef PRINTF_ATTRIBUTE -static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...) PRINTF_ATTRIBUTE(3,4); -#endif -static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); -} - -/* a tdb tool for manipulating a tdb database */ - -static TDB_CONTEXT *tdb; - -static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state); -static int print_key(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state); -static int print_hexkey(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state); - -static void print_asc(const char *buf,int len) -{ - int i; - - /* We're probably printing ASCII strings so don't try to display - the trailing NULL character. */ - - if (buf[len - 1] == 0) - len--; - - for (i=0;i8) printf(" "); - while (n--) printf(" "); - - n = i%16; - if (n > 8) n = 8; - print_asc(&buf[i-(i%16)],n); printf(" "); - n = (i%16) - n; - if (n>0) print_asc(&buf[i-n],n); - printf("\n"); - } -} - -static void help(void) -{ - printf("\n" -"tdbtool: \n" -" create dbname : create a database\n" -" open dbname : open an existing database\n" -" transaction_start : start a transaction\n" -" transaction_commit : commit a transaction\n" -" transaction_cancel : cancel a transaction\n" -" erase : erase the database\n" -" dump : dump the database as strings\n" -" keys : dump the database keys as strings\n" -" hexkeys : dump the database keys as hex values\n" -" info : print summary info about the database\n" -" insert key data : insert a record\n" -" move key file : move a record to a destination tdb\n" -" store key data : store a record (replace)\n" -" show key : show a record by key\n" -" delete key : delete a record by key\n" -" list : print the database hash table and freelist\n" -" free : print the database freelist\n" -" check : check the integrity of an opened database\n" -" repack : repack the database\n" -" speed : perform speed tests on the database\n" -" ! command : execute system command\n" -" 1 | first : print the first record\n" -" n | next : print the next record\n" -" q | quit : terminate\n" -" \\n : repeat 'next' command\n" -"\n"); -} - -static void terror(const char *why) -{ - printf("%s\n", why); -} - -static void create_tdb(const char *tdbname) -{ - struct tdb_logging_context log_ctx; - log_ctx.log_fn = tdb_log; - - if (tdb) tdb_close(tdb); - tdb = tdb_open_ex(tdbname, 0, TDB_CLEAR_IF_FIRST | (disable_mmap?TDB_NOMMAP:0), - O_RDWR | O_CREAT | O_TRUNC, 0600, &log_ctx, NULL); - if (!tdb) { - printf("Could not create %s: %s\n", tdbname, strerror(errno)); - } -} - -static void open_tdb(const char *tdbname) -{ - struct tdb_logging_context log_ctx; - log_ctx.log_fn = tdb_log; - - if (tdb) tdb_close(tdb); - tdb = tdb_open_ex(tdbname, 0, disable_mmap?TDB_NOMMAP:0, O_RDWR, 0600, - &log_ctx, NULL); - if (!tdb) { - printf("Could not open %s: %s\n", tdbname, strerror(errno)); - } -} - -static void insert_tdb(char *keyname, size_t keylen, char* data, size_t datalen) -{ - TDB_DATA key, dbuf; - - if ((keyname == NULL) || (keylen == 0)) { - terror("need key"); - return; - } - - key.dptr = (unsigned char *)keyname; - key.dsize = keylen; - dbuf.dptr = (unsigned char *)data; - dbuf.dsize = datalen; - - if (tdb_store(tdb, key, dbuf, TDB_INSERT) != 0) { - terror("insert failed"); - } -} - -static void store_tdb(char *keyname, size_t keylen, char* data, size_t datalen) -{ - TDB_DATA key, dbuf; - - if ((keyname == NULL) || (keylen == 0)) { - terror("need key"); - return; - } - - if ((data == NULL) || (datalen == 0)) { - terror("need data"); - return; - } - - key.dptr = (unsigned char *)keyname; - key.dsize = keylen; - dbuf.dptr = (unsigned char *)data; - dbuf.dsize = datalen; - - printf("Storing key:\n"); - print_rec(tdb, key, dbuf, NULL); - - if (tdb_store(tdb, key, dbuf, TDB_REPLACE) != 0) { - terror("store failed"); - } -} - -static void show_tdb(char *keyname, size_t keylen) -{ - TDB_DATA key, dbuf; - - if ((keyname == NULL) || (keylen == 0)) { - terror("need key"); - return; - } - - key.dptr = (unsigned char *)keyname; - key.dsize = keylen; - - dbuf = tdb_fetch(tdb, key); - if (!dbuf.dptr) { - terror("fetch failed"); - return; - } - - print_rec(tdb, key, dbuf, NULL); - - free( dbuf.dptr ); - - return; -} - -static void delete_tdb(char *keyname, size_t keylen) -{ - TDB_DATA key; - - if ((keyname == NULL) || (keylen == 0)) { - terror("need key"); - return; - } - - key.dptr = (unsigned char *)keyname; - key.dsize = keylen; - - if (tdb_delete(tdb, key) != 0) { - terror("delete failed"); - } -} - -static void move_rec(char *keyname, size_t keylen, char* tdbname) -{ - TDB_DATA key, dbuf; - TDB_CONTEXT *dst_tdb; - - if ((keyname == NULL) || (keylen == 0)) { - terror("need key"); - return; - } - - if ( !tdbname ) { - terror("need destination tdb name"); - return; - } - - key.dptr = (unsigned char *)keyname; - key.dsize = keylen; - - dbuf = tdb_fetch(tdb, key); - if (!dbuf.dptr) { - terror("fetch failed"); - return; - } - - print_rec(tdb, key, dbuf, NULL); - - dst_tdb = tdb_open(tdbname, 0, 0, O_RDWR, 0600); - if ( !dst_tdb ) { - terror("unable to open destination tdb"); - return; - } - - if (tdb_store( dst_tdb, key, dbuf, TDB_REPLACE ) != 0) { - terror("failed to move record"); - } - else - printf("record moved\n"); - - tdb_close( dst_tdb ); - - return; -} - -static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state) -{ - printf("\nkey %d bytes\n", (int)key.dsize); - print_asc((const char *)key.dptr, key.dsize); - printf("\ndata %d bytes\n", (int)dbuf.dsize); - print_data((const char *)dbuf.dptr, dbuf.dsize); - return 0; -} - -static int print_key(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state) -{ - printf("key %d bytes: ", (int)key.dsize); - print_asc((const char *)key.dptr, key.dsize); - printf("\n"); - return 0; -} - -static int print_hexkey(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state) -{ - printf("key %d bytes\n", (int)key.dsize); - print_data((const char *)key.dptr, key.dsize); - printf("\n"); - return 0; -} - -static int total_bytes; - -static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state) -{ - total_bytes += dbuf.dsize; - return 0; -} - -static void info_tdb(void) -{ - char *summary = tdb_summary(tdb); - - if (!summary) { - printf("Error = %s\n", tdb_errorstr(tdb)); - } else { - printf("%s", summary); - free(summary); - } -} - -static void speed_tdb(const char *tlimit) -{ - const char *str = "store test", *str2 = "transaction test"; - unsigned timelimit = tlimit?atoi(tlimit):0; - double t; - int ops; - if (timelimit == 0) timelimit = 5; - - ops = 0; - printf("Testing store speed for %u seconds\n", timelimit); - _start_timer(); - do { - long int r = random(); - TDB_DATA key, dbuf; - key.dptr = discard_const_p(uint8_t, str); - key.dsize = strlen((char *)key.dptr); - dbuf.dptr = (uint8_t *) &r; - dbuf.dsize = sizeof(r); - tdb_store(tdb, key, dbuf, TDB_REPLACE); - t = _end_timer(); - ops++; - } while (t < timelimit); - printf("%10.3f ops/sec\n", ops/t); - - ops = 0; - printf("Testing fetch speed for %u seconds\n", timelimit); - _start_timer(); - do { - TDB_DATA key; - key.dptr = discard_const_p(uint8_t, str); - key.dsize = strlen((char *)key.dptr); - tdb_fetch(tdb, key); - t = _end_timer(); - ops++; - } while (t < timelimit); - printf("%10.3f ops/sec\n", ops/t); - - ops = 0; - printf("Testing transaction speed for %u seconds\n", timelimit); - _start_timer(); - do { - long int r = random(); - TDB_DATA key, dbuf; - key.dptr = discard_const_p(uint8_t, str2); - key.dsize = strlen((char *)key.dptr); - dbuf.dptr = (uint8_t *) &r; - dbuf.dsize = sizeof(r); - tdb_transaction_start(tdb); - tdb_store(tdb, key, dbuf, TDB_REPLACE); - tdb_transaction_commit(tdb); - t = _end_timer(); - ops++; - } while (t < timelimit); - printf("%10.3f ops/sec\n", ops/t); - - ops = 0; - printf("Testing traverse speed for %u seconds\n", timelimit); - _start_timer(); - do { - tdb_traverse(tdb, traverse_fn, NULL); - t = _end_timer(); - ops++; - } while (t < timelimit); - printf("%10.3f ops/sec\n", ops/t); -} - -static void toggle_mmap(void) -{ - disable_mmap = !disable_mmap; - if (disable_mmap) { - printf("mmap is disabled\n"); - } else { - printf("mmap is enabled\n"); - } -} - -static char *tdb_getline(const char *prompt) -{ - static char thisline[1024]; - char *p; - fputs(prompt, stdout); - thisline[0] = 0; - p = fgets(thisline, sizeof(thisline)-1, stdin); - if (p) p = strchr(p, '\n'); - if (p) *p = 0; - return p?thisline:NULL; -} - -static int do_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, - void *state) -{ - return tdb_delete(the_tdb, key); -} - -static void first_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey) -{ - TDB_DATA dbuf; - *pkey = tdb_firstkey(the_tdb); - - dbuf = tdb_fetch(the_tdb, *pkey); - if (!dbuf.dptr) terror("fetch failed"); - else { - print_rec(the_tdb, *pkey, dbuf, NULL); - } -} - -static void next_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey) -{ - TDB_DATA dbuf; - *pkey = tdb_nextkey(the_tdb, *pkey); - - dbuf = tdb_fetch(the_tdb, *pkey); - if (!dbuf.dptr) - terror("fetch failed"); - else - print_rec(the_tdb, *pkey, dbuf, NULL); -} - -static int count(TDB_DATA key, TDB_DATA data, void *private_data) -{ - (*(unsigned int *)private_data)++; - return 0; -} - -static void check_db(TDB_CONTEXT *the_tdb) -{ - int tdbcount = 0; - if (!the_tdb) - printf("Error: No database opened!\n"); - else if (tdb_check(the_tdb, count, &tdbcount) == -1) - printf("Integrity check for the opened database failed.\n"); - else - printf("Database integrity is OK and has %d records.\n", - tdbcount); -} - -static int do_command(void) -{ - COMMAND_TABLE *ctp = cmd_table; - enum commands mycmd = CMD_HELP; - int cmd_len; - - if (cmdname && strlen(cmdname) == 0) { - mycmd = CMD_NEXT; - } else { - while (ctp->name) { - cmd_len = strlen(ctp->name); - if (strncmp(ctp->name,cmdname,cmd_len) == 0) { - mycmd = ctp->cmd; - break; - } - ctp++; - } - } - - switch (mycmd) { - case CMD_CREATE_TDB: - bIterate = 0; - create_tdb(arg1); - return 0; - case CMD_OPEN_TDB: - bIterate = 0; - open_tdb(arg1); - return 0; - case CMD_SYSTEM: - /* Shell command */ - if (system(arg1) == -1) { - terror("system() call failed\n"); - } - return 0; - case CMD_QUIT: - return 1; - default: - /* all the rest require a open database */ - if (!tdb) { - bIterate = 0; - terror("database not open"); - help(); - return 0; - } - switch (mycmd) { - case CMD_TRANSACTION_START: - bIterate = 0; - tdb_transaction_start(tdb); - return 0; - case CMD_TRANSACTION_COMMIT: - bIterate = 0; - tdb_transaction_commit(tdb); - return 0; - case CMD_REPACK: - bIterate = 0; - tdb_repack(tdb); - return 0; - case CMD_TRANSACTION_CANCEL: - bIterate = 0; - tdb_transaction_cancel(tdb); - return 0; - case CMD_ERASE: - bIterate = 0; - tdb_traverse(tdb, do_delete_fn, NULL); - return 0; - case CMD_DUMP: - bIterate = 0; - tdb_traverse(tdb, print_rec, NULL); - return 0; - case CMD_INSERT: - bIterate = 0; - insert_tdb(arg1, arg1len,arg2,arg2len); - return 0; - case CMD_MOVE: - bIterate = 0; - move_rec(arg1,arg1len,arg2); - return 0; - case CMD_STORE: - bIterate = 0; - store_tdb(arg1,arg1len,arg2,arg2len); - return 0; - case CMD_SHOW: - bIterate = 0; - show_tdb(arg1, arg1len); - return 0; - case CMD_KEYS: - tdb_traverse(tdb, print_key, NULL); - return 0; - case CMD_HEXKEYS: - tdb_traverse(tdb, print_hexkey, NULL); - return 0; - case CMD_DELETE: - bIterate = 0; - delete_tdb(arg1,arg1len); - return 0; - case CMD_LIST_HASH_FREE: - tdb_dump_all(tdb); - return 0; - case CMD_LIST_FREE: - tdb_printfreelist(tdb); - return 0; - case CMD_INFO: - info_tdb(); - return 0; - case CMD_SPEED: - speed_tdb(arg1); - return 0; - case CMD_MMAP: - toggle_mmap(); - return 0; - case CMD_FIRST: - bIterate = 1; - first_record(tdb, &iterate_kbuf); - return 0; - case CMD_NEXT: - if (bIterate) - next_record(tdb, &iterate_kbuf); - return 0; - case CMD_CHECK: - check_db(tdb); - return 0; - case CMD_HELP: - help(); - return 0; - case CMD_CREATE_TDB: - case CMD_OPEN_TDB: - case CMD_SYSTEM: - case CMD_QUIT: - /* - * unhandled commands. cases included here to avoid compiler - * warnings. - */ - return 0; - } - } - - return 0; -} - -static char *tdb_convert_string(char *instring, size_t *sizep) -{ - size_t length = 0; - char *outp, *inp; - char temp[3]; - - outp = inp = instring; - - while (*inp) { - if (*inp == '\\') { - inp++; - if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) { - temp[0] = *inp++; - temp[1] = '\0'; - if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) { - temp[1] = *inp++; - temp[2] = '\0'; - } - *outp++ = (char)strtol((const char *)temp,NULL,16); - } else { - *outp++ = *inp++; - } - } else { - *outp++ = *inp++; - } - length++; - } - *sizep = length; - return instring; -} - -int main(int argc, char *argv[]) -{ - cmdname = ""; - arg1 = NULL; - arg1len = 0; - arg2 = NULL; - arg2len = 0; - - if (argv[1]) { - cmdname = "open"; - arg1 = argv[1]; - do_command(); - cmdname = ""; - arg1 = NULL; - } - - switch (argc) { - case 1: - case 2: - /* Interactive mode */ - while ((cmdname = tdb_getline("tdb> "))) { - arg2 = arg1 = NULL; - if ((arg1 = strchr((const char *)cmdname,' ')) != NULL) { - arg1++; - arg2 = arg1; - while (*arg2) { - if (*arg2 == ' ') { - *arg2++ = '\0'; - break; - } - if ((*arg2++ == '\\') && (*arg2 == ' ')) { - arg2++; - } - } - } - if (arg1) arg1 = tdb_convert_string(arg1,&arg1len); - if (arg2) arg2 = tdb_convert_string(arg2,&arg2len); - if (do_command()) break; - } - break; - case 5: - arg2 = tdb_convert_string(argv[4],&arg2len); - case 4: - arg1 = tdb_convert_string(argv[3],&arg1len); - case 3: - cmdname = argv[2]; - default: - do_command(); - break; - } - - if (tdb) tdb_close(tdb); - - return 0; -} diff --git a/ctdb/lib/tdb/tools/tdbtorture.c b/ctdb/lib/tdb/tools/tdbtorture.c deleted file mode 100644 index 64c504344120..000000000000 --- a/ctdb/lib/tdb/tools/tdbtorture.c +++ /dev/null @@ -1,453 +0,0 @@ -/* this tests tdb by doing lots of ops from several simultaneous - writers - that stresses the locking code. -*/ - -#include "replace.h" -#include "system/time.h" -#include "system/wait.h" -#include "system/filesys.h" -#include "tdb.h" - -#ifdef HAVE_GETOPT_H -#include -#endif - - -#define REOPEN_PROB 30 -#define DELETE_PROB 8 -#define STORE_PROB 4 -#define APPEND_PROB 6 -#define TRANSACTION_PROB 10 -#define TRANSACTION_PREPARE_PROB 2 -#define LOCKSTORE_PROB 5 -#define TRAVERSE_PROB 20 -#define TRAVERSE_READ_PROB 20 -#define CULL_PROB 100 -#define KEYLEN 3 -#define DATALEN 100 - -static struct tdb_context *db; -static int in_transaction; -static int error_count; -static int always_transaction = 0; -static int hash_size = 2; -static int loopnum; -static int count_pipe; -static struct tdb_logging_context log_ctx; - -#ifdef PRINTF_ATTRIBUTE -static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...) PRINTF_ATTRIBUTE(3,4); -#endif -static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...) -{ - va_list ap; - - /* trace level messages do not indicate an error */ - if (level != TDB_DEBUG_TRACE) { - error_count++; - } - - va_start(ap, format); - vfprintf(stdout, format, ap); - va_end(ap); - fflush(stdout); -#if 0 - if (level != TDB_DEBUG_TRACE) { - char *ptr; - signal(SIGUSR1, SIG_IGN); - asprintf(&ptr,"xterm -e gdb /proc/%d/exe %d", getpid(), getpid()); - system(ptr); - free(ptr); - } -#endif -} - -static void fatal(const char *why) -{ - perror(why); - error_count++; -} - -static char *randbuf(int len) -{ - char *buf; - int i; - buf = (char *)malloc(len+1); - - for (i=0;i - - -ldb - - - -

tdb

- -TDB is a Trivial Database. In concept, it is very much like GDBM, and BSD's DB -except that it allows multiple simultaneous writers and uses locking -internally to keep writers from trampling on each other. TDB is also extremely -small. - -

Download

-You can download the latest releases of tdb from the tdb directory on the samba public -source archive. - - -

Discussion and bug reports

- -tdb does not currently have its own mailing list or bug tracking -system. For now, please use the samba-technical -mailing list, and the Samba -bugzilla bug tracking system. - -

Download

- -You can download the latest code either via git or rsync.
-
-To fetch via git see the following guide:
-Using Git for Samba Development
-Once you have cloned the tree switch to the master branch and cd into the source/lib/tdb directory.
-
-To fetch via rsync use these commands: - -
-  rsync -Pavz samba.org::ftp/unpacked/standalone_projects/lib/tdb .
-  rsync -Pavz samba.org::ftp/unpacked/standalone_projects/lib/replace .
-
- -and build in tdb. It will find the replace library in the directory -above automatically. - - - diff --git a/ctdb/lib/tdb/wscript b/ctdb/lib/tdb/wscript deleted file mode 100644 index 9d309a0325c3..000000000000 --- a/ctdb/lib/tdb/wscript +++ /dev/null @@ -1,224 +0,0 @@ -#!/usr/bin/env python - -APPNAME = 'tdb' -VERSION = '1.2.11' - -blddir = 'bin' - -import sys, os - -# find the buildtools directory -srcdir = '.' -while not os.path.exists(srcdir+'/buildtools') and len(srcdir.split('/')) < 5: - srcdir = '../' + srcdir -sys.path.insert(0, srcdir + '/buildtools/wafsamba') - -import wafsamba, samba_dist, Options, Logs - -samba_dist.DIST_DIRS('lib/tdb:. lib/replace:lib/replace buildtools:buildtools') - -def set_options(opt): - opt.BUILTIN_DEFAULT('replace') - opt.PRIVATE_EXTENSION_DEFAULT('tdb', noextension='tdb') - opt.RECURSE('lib/replace') - if opt.IN_LAUNCH_DIR(): - opt.add_option('--disable-python', - help=("disable the pytdb module"), - action="store_true", dest='disable_python', default=False) - - -def configure(conf): - conf.RECURSE('lib/replace') - - conf.env.standalone_tdb = conf.IN_LAUNCH_DIR() - conf.env.building_tdb = True - - if not conf.env.standalone_tdb: - if conf.CHECK_BUNDLED_SYSTEM_PKG('tdb', minversion=VERSION, - implied_deps='replace'): - conf.define('USING_SYSTEM_TDB', 1) - conf.env.building_tdb = False - if conf.CHECK_BUNDLED_SYSTEM_PYTHON('pytdb', 'tdb', minversion=VERSION): - conf.define('USING_SYSTEM_PYTDB', 1) - - conf.env.disable_python = getattr(Options.options, 'disable_python', False) - - conf.CHECK_XSLTPROC_MANPAGES() - - if not conf.env.disable_python: - # also disable if we don't have the python libs installed - conf.find_program('python', var='PYTHON') - conf.check_tool('python') - conf.check_python_version((2,4,2)) - conf.SAMBA_CHECK_PYTHON_HEADERS(mandatory=False) - if not conf.env.HAVE_PYTHON_H: - Logs.warn('Disabling pytdb as python devel libs not found') - conf.env.disable_python = True - - conf.SAMBA_CONFIG_H() - - conf.SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS() - -def build(bld): - bld.RECURSE('lib/replace') - - COMMON_SRC = bld.SUBDIR('common', - '''check.c error.c tdb.c traverse.c - freelistcheck.c lock.c dump.c freelist.c - io.c open.c transaction.c hash.c summary.c rescue.c''') - - if bld.env.standalone_tdb: - bld.env.PKGCONFIGDIR = '${LIBDIR}/pkgconfig' - private_library = False - else: - private_library = True - - if not bld.CONFIG_SET('USING_SYSTEM_TDB'): - bld.SAMBA_LIBRARY('tdb', - COMMON_SRC, - deps='replace', - includes='include', - abi_directory='ABI', - abi_match='tdb_*', - hide_symbols=True, - vnum=VERSION, - public_headers='include/tdb.h', - public_headers_install=not private_library, - pc_files='tdb.pc', - private_library=private_library) - - bld.SAMBA_BINARY('tdbtorture', - 'tools/tdbtorture.c', - 'tdb', - install=False) - - bld.SAMBA_BINARY('tdbrestore', - 'tools/tdbrestore.c', - 'tdb', manpages='manpages/tdbrestore.8') - - bld.SAMBA_BINARY('tdbdump', - 'tools/tdbdump.c', - 'tdb', manpages='manpages/tdbdump.8') - - bld.SAMBA_BINARY('tdbbackup', - 'tools/tdbbackup.c', - 'tdb', - manpages='manpages/tdbbackup.8') - - bld.SAMBA_BINARY('tdbtool', - 'tools/tdbtool.c', - 'tdb', manpages='manpages/tdbtool.8') - - # FIXME: This hardcoded list is stupid, stupid, stupid. - bld.SAMBA_SUBSYSTEM('tdb-test-helpers', - 'test/external-agent.c test/lock-tracking.c test/logging.c', - 'replace', - includes='include') - - bld.SAMBA_BINARY('tdb1-run-3G-file', 'test/run-3G-file.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-bad-tdb-header', 'test/run-bad-tdb-header.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run', 'test/run.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-check', 'test/run-check.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-corrupt', 'test/run-corrupt.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-die-during-transaction', 'test/run-die-during-transaction.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-endian', 'test/run-endian.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-incompatible', 'test/run-incompatible.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-nested-transactions', 'test/run-nested-transactions.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-nested-traverse', 'test/run-nested-traverse.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-no-lock-during-traverse', 'test/run-no-lock-during-traverse.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-oldhash', 'test/run-oldhash.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-open-during-transaction', 'test/run-open-during-transaction.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-readonly-check', 'test/run-readonly-check.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-rescue', 'test/run-rescue.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-rescue-find_entry', 'test/run-rescue-find_entry.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-rwlock-check', 'test/run-rwlock-check.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-summary', 'test/run-summary.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-transaction-expand', 'test/run-transaction-expand.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-traverse-in-transaction', 'test/run-traverse-in-transaction.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-wronghash-fail', 'test/run-wronghash-fail.c', - 'replace tdb-test-helpers', includes='include', install=False) - bld.SAMBA_BINARY('tdb1-run-zero-append', 'test/run-zero-append.c', - 'replace tdb-test-helpers', includes='include', install=False) - - if not bld.CONFIG_SET('USING_SYSTEM_PYTDB'): - bld.SAMBA_PYTHON('pytdb', - 'pytdb.c', - deps='tdb', - enabled=not bld.env.disable_python, - realname='tdb.so', - cflags='-DPACKAGE_VERSION=\"%s\"' % VERSION) - -def testonly(ctx): - '''run tdb testsuite''' - import Utils, samba_utils, shutil - ecode = 0 - - test_prefix = "%s/st" % (Utils.g_module.blddir) - shutil.rmtree(test_prefix, ignore_errors=True) - os.makedirs(test_prefix) - os.environ['TEST_DATA_PREFIX'] = test_prefix - - env = samba_utils.LOAD_ENVIRONMENT() - # FIXME: This is horrible :( - if env.building_tdb: - # Create scratch directory for tests. - testdir = os.path.join(test_prefix, 'tdb-tests') - samba_utils.mkdir_p(testdir) - # Symlink back to source dir so it can find tests in test/ - link = os.path.join(testdir, 'test') - if not os.path.exists(link): - os.symlink(os.path.abspath(os.path.join(env.cwd, 'test')), link) - - for f in 'tdb1-run-3G-file', 'tdb1-run-bad-tdb-header', 'tdb1-run', 'tdb1-run-check', 'tdb1-run-corrupt', 'tdb1-run-die-during-transaction', 'tdb1-run-endian', 'tdb1-run-incompatible', 'tdb1-run-nested-transactions', 'tdb1-run-nested-traverse', 'tdb1-run-no-lock-during-traverse', 'tdb1-run-oldhash', 'tdb1-run-open-during-transaction', 'tdb1-run-readonly-check', 'tdb1-run-rescue', 'tdb1-run-rescue-find_entry', 'tdb1-run-rwlock-check', 'tdb1-run-summary', 'tdb1-run-transaction-expand', 'tdb1-run-traverse-in-transaction', 'tdb1-run-wronghash-fail', 'tdb1-run-zero-append': - cmd = "cd " + testdir + " && " + os.path.abspath(os.path.join(Utils.g_module.blddir, f)) + " > test-output 2>&1" - print("..." + f) - ret = samba_utils.RUN_COMMAND(cmd) - if ret != 0: - print("%s failed:" % f) - samba_utils.RUN_COMMAND("cat " + os.path.join(testdir, 'test-output')) - ecode = ret - break - - if ecode == 0: - cmd = os.path.join(Utils.g_module.blddir, 'tdbtorture') - ret = samba_utils.RUN_COMMAND(cmd) - print("testsuite returned %d" % ret) - if ret != 0: - ecode = ret - sys.exit(ecode) - -# WAF doesn't build the unit tests for this, maybe because they don't link with tdb? -# This forces it -def test(ctx): - import Scripting - Scripting.commands.append('build') - Scripting.commands.append('testonly') - -def dist(): - '''makes a tarball for distribution''' - samba_dist.dist() - -def reconfigure(ctx): - '''reconfigure if config scripts have changed''' - import samba_utils - samba_utils.reconfigure(ctx)