]> git.ozlabs.org Git - ccan/blobdiff - ccan/tdb2/open.c
tdb2: tdb_foreach()
[ccan] / ccan / tdb2 / open.c
index 68f707b920ec8cf72bcf66b9788c1abd25bc26c0..555df9512608c1ba0269461e6f5dc823de9ab4f6 100644 (file)
 #include <ccan/hash/hash.h>
 #include <assert.h>
 
-/* all lock info, to detect double-opens (fcntl file don't nest!) */
-static struct tdb_file *files = NULL;
+/* all tdbs, to detect double-opens (fcntl file don't nest!) */
+static struct tdb_context *tdbs = NULL;
 
 static struct tdb_file *find_file(dev_t device, ino_t ino)
 {
-       struct tdb_file *i;
+       struct tdb_context *i;
 
-       for (i = files; i; i = i->next) {
-               if (i->device == device && i->inode == ino) {
-                       i->refcnt++;
-                       break;
+       for (i = tdbs; i; i = i->next) {
+               if (i->file->device == device && i->file->inode == ino) {
+                       i->file->refcnt++;
+                       return i->file;
                }
        }
-       return i;
+       return NULL;
 }
 
 static bool read_all(int fd, void *buf, size_t len)
@@ -270,11 +270,11 @@ enum TDB_ERROR tdb_get_attribute(struct tdb_context *tdb,
                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");
+               if (!tdb->openhook)
+                       return tdb->last_error = TDB_ERR_NOEXIST;
+               attr->openhook.fn = tdb->openhook;
+               attr->openhook.data = tdb->openhook_data;
+               break;
        case TDB_ATTRIBUTE_STATS: {
                size_t size = attr->stats.size;
                if (size > tdb->stats.size)
@@ -306,16 +306,16 @@ void tdb_unset_attribute(struct tdb_context *tdb,
        case TDB_ATTRIBUTE_LOG:
                tdb->log_fn = NULL;
                break;
+       case TDB_ATTRIBUTE_OPENHOOK:
+               tdb->openhook = 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");
+                          : "TDB_ATTRIBUTE_SEED");
                break;
        case TDB_ATTRIBUTE_STATS:
                tdb_logerr(tdb, TDB_ERR_EINVAL,
@@ -347,7 +347,6 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
        ssize_t rlen;
        struct tdb_header hdr;
        struct tdb_attribute_seed *seed = NULL;
-       struct tdb_attribute_openhook *openhook = NULL;
        tdb_bool_err berr;
        enum TDB_ERROR ecode;
        int openlock;
@@ -372,6 +371,7 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
        tdb->open_flags = open_flags;
        tdb->last_error = TDB_SUCCESS;
        tdb->file = NULL;
+       tdb->openhook = NULL;
        tdb->lock_fn = tdb_fcntl_lock;
        tdb->unlock_fn = tdb_fcntl_unlock;
        tdb->hash_fn = jenkins_hash;
@@ -390,7 +390,8 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
                        seed = &attr->seed;
                        break;
                case TDB_ATTRIBUTE_OPENHOOK:
-                       openhook = &attr->openhook;
+                       tdb->openhook = attr->openhook.fn;
+                       tdb->openhook_data = attr->openhook.data;
                        break;
                default:
                        /* These are set as normal. */
@@ -482,7 +483,6 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
                        goto fail;
                }
 
-               tdb->file->next = files;
                tdb->file->fd = fd;
                tdb->file->device = st.st_dev;
                tdb->file->inode = st.st_ino;
@@ -498,8 +498,8 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
        }
 
        /* call their open hook if they gave us one. */
-       if (openhook) {
-               ecode = openhook->fn(tdb->file->fd, openhook->data);
+       if (tdb->openhook) {
+               ecode = tdb->openhook(tdb->file->fd, tdb->openhook_data);
                if (ecode != TDB_SUCCESS) {
                        tdb_logerr(tdb, ecode, TDB_LOG_ERROR,
                                   "tdb_open: open hook failed");
@@ -595,9 +595,8 @@ struct tdb_context *tdb_open(const char *name, int tdb_flags,
                goto fail;
        }
 
-       /* Add to linked list if we're new. */
-       if (tdb->file->refcnt == 1)
-               files = tdb->file;
+       tdb->next = tdbs;
+       tdbs = tdb;
        return tdb;
 
  fail:
@@ -652,6 +651,7 @@ fail_errno:
 int tdb_close(struct tdb_context *tdb)
 {
        int ret = 0;
+       struct tdb_context **i;
 
        tdb_trace(tdb, "tdb_close");
 
@@ -666,24 +666,22 @@ int tdb_close(struct tdb_context *tdb)
                        tdb_munmap(tdb->file);
        }
        if (tdb->file) {
-               struct tdb_file **i;
-
                tdb_lock_cleanup(tdb);
                if (--tdb->file->refcnt == 0) {
                        ret = close(tdb->file->fd);
-
-                       /* Remove from files list */
-                       for (i = &files; *i; i = &(*i)->next) {
-                               if (*i == tdb->file) {
-                                       *i = tdb->file->next;
-                                       break;
-                               }
-                       }
                        free(tdb->file->lockrecs);
                        free(tdb->file);
                }
        }
 
+       /* Remove from tdbs list */
+       for (i = &tdbs; *i; i = &(*i)->next) {
+               if (*i == tdb) {
+                       *i = tdb->next;
+                       break;
+               }
+       }
+
 #ifdef TDB_TRACE
        close(tdb->tracefd);
 #endif
@@ -691,3 +689,13 @@ int tdb_close(struct tdb_context *tdb)
 
        return ret;
 }
+
+void tdb_foreach_(int (*fn)(struct tdb_context *, void *), void *p)
+{
+       struct tdb_context *i;
+
+       for (i = tdbs; i; i = i->next) {
+               if (fn(i, p) != 0)
+                       break;
+       }
+}