*/
#include "private.h"
#include <assert.h>
-#include <ccan/hash/hash.h>
-
-static uint64_t jenkins_hash(const void *key, size_t length, uint64_t seed,
- void *arg)
-{
- uint64_t ret;
- /* hash64_stable assumes lower bits are more important; they are a
- * slightly better hash. We use the upper bits first, so swap them. */
- ret = hash64_stable((const unsigned char *)key, length, seed);
- return (ret >> 32) | (ret << 32);
-}
-
-void tdb_hash_init(struct tdb_context *tdb)
-{
- tdb->hash_fn = jenkins_hash;
-}
uint64_t tdb_hash(struct tdb_context *tdb, const void *ptr, size_t len)
{
#include "private.h"
+#include <ccan/hash/hash.h>
#include <assert.h>
/* all lock info, to detect double-opens (fcntl file don't nest!) */
return TDB_SUCCESS;
}
+enum TDB_ERROR tdb_set_attribute(struct tdb_context *tdb,
+ const union tdb_attribute *attr)
+{
+ switch (attr->base.attr) {
+ case TDB_ATTRIBUTE_LOG:
+ tdb->log_fn = attr->log.fn;
+ tdb->log_data = attr->log.data;
+ break;
+ case TDB_ATTRIBUTE_HASH:
+ case TDB_ATTRIBUTE_SEED:
+ case TDB_ATTRIBUTE_OPENHOOK:
+ return tdb->last_error
+ = tdb_logerr(tdb, TDB_ERR_EINVAL,
+ TDB_LOG_USE_ERROR,
+ "tdb_set_attribute:"
+ " cannot set %s after opening",
+ attr->base.attr == TDB_ATTRIBUTE_HASH
+ ? "TDB_ATTRIBUTE_HASH"
+ : attr->base.attr == TDB_ATTRIBUTE_SEED
+ ? "TDB_ATTRIBUTE_SEED"
+ : "TDB_ATTRIBUTE_OPENHOOK");
+ case TDB_ATTRIBUTE_FLOCK:
+ tdb->lock_fn = attr->flock.lock;
+ tdb->unlock_fn = attr->flock.unlock;
+ tdb->lock_data = attr->flock.data;
+ break;
+ default:
+ return tdb->last_error
+ = tdb_logerr(tdb, TDB_ERR_EINVAL,
+ TDB_LOG_USE_ERROR,
+ "tdb_set_attribute:"
+ " unknown attribute type %u",
+ attr->base.attr);
+ }
+ return TDB_SUCCESS;
+}
+
+static uint64_t jenkins_hash(const void *key, size_t length, uint64_t seed,
+ void *unused)
+{
+ uint64_t ret;
+ /* hash64_stable assumes lower bits are more important; they are a
+ * slightly better hash. We use the upper bits first, so swap them. */
+ ret = hash64_stable((const unsigned char *)key, length, seed);
+ return (ret >> 32) | (ret << 32);
+}
+
+enum TDB_ERROR tdb_get_attribute(struct tdb_context *tdb,
+ union tdb_attribute *attr)
+{
+ switch (attr->base.attr) {
+ case TDB_ATTRIBUTE_LOG:
+ if (!tdb->log_fn)
+ return tdb->last_error = TDB_ERR_NOEXIST;
+ attr->log.fn = tdb->log_fn;
+ attr->log.data = tdb->log_data;
+ break;
+ case TDB_ATTRIBUTE_HASH:
+ attr->hash.fn = tdb->hash_fn;
+ attr->hash.data = tdb->hash_data;
+ break;
+ case TDB_ATTRIBUTE_SEED:
+ attr->seed.seed = tdb->hash_seed;
+ break;
+ case TDB_ATTRIBUTE_OPENHOOK:
+ return tdb->last_error
+ = tdb_logerr(tdb, TDB_ERR_EINVAL,
+ TDB_LOG_USE_ERROR,
+ "tdb_get_attribute:"
+ " cannot get TDB_ATTRIBUTE_OPENHOOK");
+ case TDB_ATTRIBUTE_STATS:
+ /* FIXME */
+ return TDB_ERR_EINVAL;
+ case TDB_ATTRIBUTE_FLOCK:
+ attr->flock.lock = tdb->lock_fn;
+ attr->flock.unlock = tdb->unlock_fn;
+ attr->flock.data = tdb->lock_data;
+ break;
+ default:
+ return tdb->last_error
+ = tdb_logerr(tdb, TDB_ERR_EINVAL,
+ TDB_LOG_USE_ERROR,
+ "tdb_get_attribute:"
+ " unknown attribute type %u",
+ attr->base.attr);
+ }
+ attr->base.next = NULL;
+ return TDB_SUCCESS;
+}
+
+void tdb_unset_attribute(struct tdb_context *tdb,
+ enum tdb_attribute_type type)
+{
+ switch (type) {
+ case TDB_ATTRIBUTE_LOG:
+ tdb->log_fn = NULL;
+ break;
+ case TDB_ATTRIBUTE_HASH:
+ case TDB_ATTRIBUTE_SEED:
+ case TDB_ATTRIBUTE_OPENHOOK:
+ tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
+ "tdb_unset_attribute: cannot unset %s after opening",
+ type == TDB_ATTRIBUTE_HASH
+ ? "TDB_ATTRIBUTE_HASH"
+ : type == TDB_ATTRIBUTE_SEED
+ ? "TDB_ATTRIBUTE_SEED"
+ : "TDB_ATTRIBUTE_OPENHOOK");
+ break;
+ case TDB_ATTRIBUTE_STATS:
+ /* FIXME */
+ break;
+ case TDB_ATTRIBUTE_FLOCK:
+ tdb->lock_fn = tdb_fcntl_lock;
+ tdb->unlock_fn = tdb_fcntl_unlock;
+ break;
+ default:
+ tdb_logerr(tdb, TDB_ERR_EINVAL,
+ TDB_LOG_USE_ERROR,
+ "tdb_unset_attribute: unknown attribute type %u",
+ type);
+ }
+}
+
struct tdb_context *tdb_open(const char *name, int tdb_flags,
int open_flags, mode_t mode,
union tdb_attribute *attr)
tdb->access = NULL;
tdb->last_error = TDB_SUCCESS;
tdb->file = NULL;
- tdb->lock_fn = fcntl_lock;
- tdb->unlock_fn = fcntl_unlock;
- tdb_hash_init(tdb);
+ tdb->lock_fn = tdb_fcntl_lock;
+ tdb->unlock_fn = tdb_fcntl_unlock;
+ tdb->hash_fn = jenkins_hash;
tdb_io_init(tdb);
while (attr) {
switch (attr->base.attr) {
- case TDB_ATTRIBUTE_LOG:
- tdb->log_fn = attr->log.fn;
- tdb->log_data = attr->log.data;
- break;
case TDB_ATTRIBUTE_HASH:
tdb->hash_fn = attr->hash.fn;
tdb->hash_data = attr->hash.data;
case TDB_ATTRIBUTE_OPENHOOK:
openhook = &attr->openhook;
break;
- case TDB_ATTRIBUTE_FLOCK:
- tdb->lock_fn = attr->flock.lock;
- tdb->unlock_fn = attr->flock.unlock;
- tdb->lock_data = attr->flock.data;
- break;
default:
- ecode = tdb_logerr(tdb, TDB_ERR_EINVAL,
- TDB_LOG_USE_ERROR,
- "tdb_open:"
- " unknown attribute type %u",
- attr->base.attr);
- goto fail;
+ /* These are set as normal. */
+ ecode = tdb_set_attribute(tdb, attr);
+ if (ecode != TDB_SUCCESS)
+ goto fail;
}
attr = attr->base.next;
}
internal prototypes
*/
/* hash.c: */
-void tdb_hash_init(struct tdb_context *tdb);
-
tdb_bool_err first_in_hash(struct tdb_context *tdb,
struct traverse_info *tinfo,
TDB_DATA *kbuf, size_t *dlen);
*/
void tdb_remove_flag(struct tdb_context *tdb, unsigned flag);
+/**
+ * enum tdb_attribute_type - descriminator for union tdb_attribute.
+ */
+enum tdb_attribute_type {
+ TDB_ATTRIBUTE_LOG = 0,
+ TDB_ATTRIBUTE_HASH = 1,
+ TDB_ATTRIBUTE_SEED = 2,
+ TDB_ATTRIBUTE_STATS = 3,
+ TDB_ATTRIBUTE_OPENHOOK = 4,
+ TDB_ATTRIBUTE_FLOCK = 5
+};
+
+/**
+ * tdb_get_attribute - get an attribute for an existing tdb
+ * @tdb: the tdb context returned from tdb_open()
+ * @attr: the union tdb_attribute to set.
+ *
+ * This gets an attribute from a TDB which has previously been set (or
+ * may return the default values). Set @attr.base.attr to the
+ * attribute type you want get.
+ *
+ * Currently this does not work for TDB_ATTRIBUTE_OPENHOOK.
+ */
+enum TDB_ERROR tdb_get_attribute(struct tdb_context *tdb,
+ union tdb_attribute *attr);
+
+/**
+ * tdb_set_attribute - set an attribute for an existing tdb
+ * @tdb: the tdb context returned from tdb_open()
+ * @attr: the union tdb_attribute to set.
+ *
+ * This sets an attribute on a TDB, overriding any previous attribute
+ * of the same type. It returns TDB_ERR_EINVAL if the attribute is
+ * unknown or invalid.
+ *
+ * Note that TDB_ATTRIBUTE_HASH, TDB_ATTRIBUTE_SEED and
+ * TDB_ATTRIBUTE_OPENHOOK cannot currently be set after tdb_open.
+ */
+enum TDB_ERROR tdb_set_attribute(struct tdb_context *tdb,
+ const union tdb_attribute *attr);
+
+/**
+ * tdb_unset_attribute - reset an attribute for an existing tdb
+ * @tdb: the tdb context returned from tdb_open()
+ * @type: the attribute type to unset.
+ *
+ * This unsets an attribute on a TDB, returning it to the defaults
+ * (where applicable).
+ *
+ * Note that it only makes sense for TDB_ATTRIBUTE_LOG and TDB_ATTRIBUTE_FLOCK
+ * to be unset.
+ */
+void tdb_unset_attribute(struct tdb_context *tdb,
+ enum tdb_attribute_type type);
+
/**
* tdb_name - get the name of a tdb
* @tdb: the tdb context returned from tdb_open()
*/
int tdb_fd(const struct tdb_context *tdb);
-/**
- * enum tdb_attribute_type - descriminator for union tdb_attribute.
- */
-enum tdb_attribute_type {
- TDB_ATTRIBUTE_LOG = 0,
- TDB_ATTRIBUTE_HASH = 1,
- TDB_ATTRIBUTE_SEED = 2,
- TDB_ATTRIBUTE_STATS = 3,
- TDB_ATTRIBUTE_OPENHOOK = 4,
- TDB_ATTRIBUTE_FLOCK = 5
-};
-
/**
* struct tdb_attribute_base - common fields for all tdb attributes.
*/
#include <stdbool.h>
/* FIXME: Check these! */
-#define INITIAL_TDB_MALLOC "open.c", 200, FAILTEST_MALLOC
-#define URANDOM_OPEN "open.c", 44, FAILTEST_OPEN
-#define URANDOM_READ "open.c", 24, FAILTEST_READ
+#define INITIAL_TDB_MALLOC "open.c", 324, FAILTEST_MALLOC
+#define URANDOM_OPEN "open.c", 45, FAILTEST_OPEN
+#define URANDOM_READ "open.c", 25, FAILTEST_READ
bool exit_check_log(struct failtest_call *history, unsigned num);
bool failmatch(const struct failtest_call *call,
--- /dev/null
+#include <ccan/tdb2/tdb.c>
+#include <ccan/tdb2/open.c>
+#include <ccan/tdb2/free.c>
+#include <ccan/tdb2/lock.c>
+#include <ccan/tdb2/io.c>
+#include <ccan/tdb2/hash.c>
+#include <ccan/tdb2/check.c>
+#include <ccan/tdb2/transaction.c>
+#include <ccan/tdb2/traverse.c>
+#include <ccan/tap/tap.h>
+#include "logging.h"
+
+static int mylock(int fd, int rw, off_t off, off_t len, bool waitflag,
+ void *unused)
+{
+ return 0;
+}
+
+static int myunlock(int fd, int rw, off_t off, off_t len, void *unused)
+{
+ return 0;
+}
+
+static uint64_t hash_fn(const void *key, size_t len, uint64_t seed,
+ void *priv)
+{
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned int i;
+ struct tdb_context *tdb;
+ int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
+ TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT };
+ union tdb_attribute seed_attr;
+ union tdb_attribute hash_attr;
+ union tdb_attribute lock_attr;
+
+ hash_attr.base.attr = TDB_ATTRIBUTE_HASH;
+ hash_attr.base.next = &seed_attr;
+ hash_attr.hash.fn = hash_fn;
+ hash_attr.hash.data = &hash_attr;
+
+ seed_attr.base.attr = TDB_ATTRIBUTE_SEED;
+ seed_attr.base.next = &lock_attr;
+ seed_attr.seed.seed = 100;
+
+ lock_attr.base.attr = TDB_ATTRIBUTE_FLOCK;
+ lock_attr.base.next = &tap_log_attr;
+ lock_attr.flock.lock = mylock;
+ lock_attr.flock.unlock = myunlock;
+ lock_attr.flock.data = &lock_attr;
+
+ plan_tests(sizeof(flags) / sizeof(flags[0]) * 50);
+
+ for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
+ union tdb_attribute attr;
+
+ /* First open with no attributes. */
+ tdb = tdb_open("run-90-get-set-attributes.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, NULL);
+ ok1(tdb);
+
+ /* Get log on no attributes will fail */
+ attr.base.attr = TDB_ATTRIBUTE_LOG;
+ ok1(tdb_get_attribute(tdb, &attr) == TDB_ERR_NOEXIST);
+ /* These always work. */
+ attr.base.attr = TDB_ATTRIBUTE_HASH;
+ ok1(tdb_get_attribute(tdb, &attr) == 0);
+ ok1(attr.base.attr == TDB_ATTRIBUTE_HASH);
+ ok1(attr.hash.fn == jenkins_hash);
+ attr.base.attr = TDB_ATTRIBUTE_FLOCK;
+ ok1(tdb_get_attribute(tdb, &attr) == 0);
+ ok1(attr.base.attr == TDB_ATTRIBUTE_FLOCK);
+ ok1(attr.flock.lock == tdb_fcntl_lock);
+ ok1(attr.flock.unlock == tdb_fcntl_unlock);
+ attr.base.attr = TDB_ATTRIBUTE_SEED;
+ ok1(tdb_get_attribute(tdb, &attr) == 0);
+ ok1(attr.base.attr == TDB_ATTRIBUTE_SEED);
+ /* This is possible, just astronomically unlikely. */
+ ok1(attr.seed.seed != 0);
+
+ /* Unset attributes. */
+ tdb_unset_attribute(tdb, TDB_ATTRIBUTE_LOG);
+ tdb_unset_attribute(tdb, TDB_ATTRIBUTE_FLOCK);
+
+ /* Set them. */
+ ok1(tdb_set_attribute(tdb, &tap_log_attr) == 0);
+ ok1(tdb_set_attribute(tdb, &lock_attr) == 0);
+ /* These should fail. */
+ ok1(tdb_set_attribute(tdb, &seed_attr) == TDB_ERR_EINVAL);
+ ok1(tap_log_messages == 1);
+ ok1(tdb_set_attribute(tdb, &hash_attr) == TDB_ERR_EINVAL);
+ ok1(tap_log_messages == 2);
+ tap_log_messages = 0;
+
+ /* Getting them should work as expected. */
+ attr.base.attr = TDB_ATTRIBUTE_LOG;
+ ok1(tdb_get_attribute(tdb, &attr) == 0);
+ ok1(attr.base.attr == TDB_ATTRIBUTE_LOG);
+ ok1(attr.log.fn == tap_log_attr.log.fn);
+ ok1(attr.log.data == tap_log_attr.log.data);
+
+ attr.base.attr = TDB_ATTRIBUTE_FLOCK;
+ ok1(tdb_get_attribute(tdb, &attr) == 0);
+ ok1(attr.base.attr == TDB_ATTRIBUTE_FLOCK);
+ ok1(attr.flock.lock == mylock);
+ ok1(attr.flock.unlock == myunlock);
+ ok1(attr.flock.data == &lock_attr);
+
+ /* Unset them again. */
+ tdb_unset_attribute(tdb, TDB_ATTRIBUTE_FLOCK);
+ ok1(tap_log_messages == 0);
+ tdb_unset_attribute(tdb, TDB_ATTRIBUTE_LOG);
+ ok1(tap_log_messages == 0);
+
+ tdb_close(tdb);
+ ok1(tap_log_messages == 0);
+
+ /* Now open with all attributes. */
+ tdb = tdb_open("run-90-get-set-attributes.tdb", flags[i],
+ O_RDWR|O_CREAT|O_TRUNC, 0600, &hash_attr);
+ ok1(tdb);
+
+ /* Get will succeed */
+ attr.base.attr = TDB_ATTRIBUTE_LOG;
+ ok1(tdb_get_attribute(tdb, &attr) == 0);
+ ok1(attr.base.attr == TDB_ATTRIBUTE_LOG);
+ ok1(attr.log.fn == tap_log_attr.log.fn);
+ ok1(attr.log.data == tap_log_attr.log.data);
+
+ attr.base.attr = TDB_ATTRIBUTE_HASH;
+ ok1(tdb_get_attribute(tdb, &attr) == 0);
+ ok1(attr.base.attr == TDB_ATTRIBUTE_HASH);
+ ok1(attr.hash.fn == hash_fn);
+ ok1(attr.hash.data == &hash_attr);
+
+ attr.base.attr = TDB_ATTRIBUTE_FLOCK;
+ ok1(tdb_get_attribute(tdb, &attr) == 0);
+ ok1(attr.base.attr == TDB_ATTRIBUTE_FLOCK);
+ ok1(attr.flock.lock == mylock);
+ ok1(attr.flock.unlock == myunlock);
+ ok1(attr.flock.data == &lock_attr);
+
+ attr.base.attr = TDB_ATTRIBUTE_SEED;
+ ok1(tdb_get_attribute(tdb, &attr) == 0);
+ ok1(attr.base.attr == TDB_ATTRIBUTE_SEED);
+ ok1(attr.seed.seed == seed_attr.seed.seed);
+
+ /* Unset attributes. */
+ tdb_unset_attribute(tdb, TDB_ATTRIBUTE_HASH);
+ ok1(tap_log_messages == 1);
+ tdb_unset_attribute(tdb, TDB_ATTRIBUTE_SEED);
+ ok1(tap_log_messages == 2);
+ tdb_unset_attribute(tdb, TDB_ATTRIBUTE_FLOCK);
+ tdb_unset_attribute(tdb, TDB_ATTRIBUTE_LOG);
+ ok1(tap_log_messages == 2);
+ tap_log_messages = 0;
+
+ tdb_close(tdb);
+
+ }
+ return exit_status();
+}