dbwrap: add dbwrap_parse_record_send/recv
[sfrench/samba-autobuild/.git] / lib / dbwrap / dbwrap.c
index 44e20bce5f48d5b40df895c10c1acea3ba4f05e6..025d463b4bd74827f75aa4d27604166adb902a15 100644 (file)
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
+#include "replace.h"
+#include "lib/util/debug.h"
+#include "lib/util/fault.h"
+#include "lib/util/talloc_stack.h"
 #include "dbwrap/dbwrap.h"
 #include "dbwrap/dbwrap_private.h"
 #include "lib/util/util_tdb.h"
+#include "lib/util/tevent_ntstatus.h"
 
 /*
  * Fall back using fetch if no genuine exists operation is provided
@@ -81,44 +85,22 @@ TDB_DATA dbwrap_record_get_value(const struct db_record *rec)
 NTSTATUS dbwrap_record_store(struct db_record *rec, TDB_DATA data, int flags)
 {
        NTSTATUS status;
-       struct db_context *db;
 
        status = rec->store(rec, data, flags);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
-       db = rec->db;
-       if (db->stored_callback != NULL) {
-               db->stored_callback(db, rec,
-                                   db->stored_callback_private_data);
-       }
        return NT_STATUS_OK;
 }
 
-void dbwrap_set_stored_callback(
-       struct db_context *db,
-       void (*cb)(struct db_context *db, struct db_record *rec,
-                  void *private_data),
-       void *private_data)
-{
-       db->stored_callback = cb;
-       db->stored_callback_private_data = private_data;
-}
-
 NTSTATUS dbwrap_record_delete(struct db_record *rec)
 {
        NTSTATUS status;
-       struct db_context *db;
 
        status = rec->delete_rec(rec);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
-       db = rec->db;
-       if (db->stored_callback != NULL) {
-               db->stored_callback(db, rec,
-                                   db->stored_callback_private_data);
-       }
        return NT_STATUS_OK;
 }
 
@@ -167,16 +149,7 @@ static struct dbwrap_lock_order_state *dbwrap_check_lock_order(
        static struct db_context *locked_dbs[DBWRAP_LOCK_ORDER_MAX];
        struct dbwrap_lock_order_state *state = NULL;
 
-       if (db->lock_order == 0) {
-               /*
-                * lock order 0 is for example for dbwrap_rbt without
-                * real locking. Return state nevertheless to avoid
-                * special cases.
-                */
-               return talloc_zero(mem_ctx, struct dbwrap_lock_order_state);
-       }
-
-       if (db->lock_order > DBWRAP_LOCK_ORDER_MAX) {
+       if (!DBWRAP_LOCK_ORDER_VALID(db->lock_order)) {
                DEBUG(0,("Invalid lock order %d of %s\n",
                         (int)db->lock_order, db->name));
                smb_panic("invalid lock_order\n");
@@ -219,22 +192,21 @@ static struct db_record *dbwrap_fetch_locked_internal(
                                   TDB_DATA key))
 {
        struct db_record *rec;
-       struct dbwrap_lock_order_state *lock_order;
-       TALLOC_CTX *frame = talloc_stackframe();
+       struct dbwrap_lock_order_state *lock_order = NULL;
 
-       lock_order = dbwrap_check_lock_order(db, frame);
-       if (lock_order == NULL) {
-               TALLOC_FREE(frame);
-               return NULL;
+       if (db->lock_order != DBWRAP_LOCK_ORDER_NONE) {
+               lock_order = dbwrap_check_lock_order(db, mem_ctx);
+               if (lock_order == NULL) {
+                       return NULL;
+               }
        }
        rec = db_fn(db, mem_ctx, key);
        if (rec == NULL) {
-               TALLOC_FREE(frame);
+               TALLOC_FREE(lock_order);
                return NULL;
        }
        (void)talloc_steal(rec, lock_order);
        rec->db = db;
-       TALLOC_FREE(frame);
        return rec;
 }
 
@@ -397,6 +369,117 @@ NTSTATUS dbwrap_parse_record(struct db_context *db, TDB_DATA key,
        return db->parse_record(db, key, parser, private_data);
 }
 
+struct dbwrap_parse_record_state {
+       struct db_context *db;
+       TDB_DATA key;
+       uint8_t _keybuf[64];
+};
+
+static void dbwrap_parse_record_done(struct tevent_req *subreq);
+
+struct tevent_req *dbwrap_parse_record_send(
+       TALLOC_CTX *mem_ctx,
+       struct tevent_context *ev,
+       struct db_context *db,
+       TDB_DATA key,
+       void (*parser)(TDB_DATA key, TDB_DATA data, void *private_data),
+       void *private_data,
+       enum dbwrap_req_state *req_state)
+{
+       struct tevent_req *req = NULL;
+       struct tevent_req *subreq = NULL;
+       struct dbwrap_parse_record_state *state = NULL;
+       NTSTATUS status;
+
+       req = tevent_req_create(mem_ctx, &state, struct dbwrap_parse_record_state);
+       if (req == NULL) {
+               *req_state = DBWRAP_REQ_ERROR;
+               return NULL;
+       }
+
+       *state = (struct dbwrap_parse_record_state) {
+               .db = db,
+       };
+
+       if (parser == NULL) {
+               parser = dbwrap_null_parser;
+       }
+
+       *req_state = DBWRAP_REQ_INIT;
+
+       if (db->parse_record_send == NULL) {
+               /*
+                * Backend doesn't implement async version, call sync one
+                */
+               status = db->parse_record(db, key, parser, private_data);
+               if (tevent_req_nterror(req, status)) {
+                       *req_state = DBWRAP_REQ_DONE;
+                       return tevent_req_post(req, ev);
+               }
+
+               *req_state = DBWRAP_REQ_DONE;
+               tevent_req_done(req);
+               return tevent_req_post(req, ev);
+       }
+
+       /*
+        * Copy the key into our state ensuring the key data buffer is always
+        * available to the all dbwrap backend over the entire lifetime of the
+        * async request. Otherwise the caller might have free'd the key buffer.
+        */
+       if (key.dsize > sizeof(state->_keybuf)) {
+               state->key.dptr = talloc_memdup(state, key.dptr, key.dsize);
+               if (tevent_req_nomem(state->key.dptr, req)) {
+                       return tevent_req_post(req, ev);
+               }
+       } else {
+               memcpy(state->_keybuf, key.dptr, key.dsize);
+               state->key.dptr = state->_keybuf;
+       }
+       state->key.dsize = key.dsize;
+
+       subreq = db->parse_record_send(state,
+                                      ev,
+                                      db,
+                                      state->key,
+                                      parser,
+                                      private_data,
+                                      req_state);
+       if (tevent_req_nomem(subreq, req)) {
+               *req_state = DBWRAP_REQ_ERROR;
+               return tevent_req_post(req, ev);
+       }
+
+       tevent_req_set_callback(subreq,
+                               dbwrap_parse_record_done,
+                               req);
+       return req;
+}
+
+static void dbwrap_parse_record_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct dbwrap_parse_record_state *state = tevent_req_data(
+               req, struct dbwrap_parse_record_state);
+       NTSTATUS status;
+
+       status = state->db->parse_record_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return;
+       }
+
+       tevent_req_done(req);
+       return;
+}
+
+NTSTATUS dbwrap_parse_record_recv(struct tevent_req *req)
+{
+       return tevent_req_simple_recv_ntstatus(req);
+}
+
 int dbwrap_wipe(struct db_context *db)
 {
        if (db->wipe == NULL) {
@@ -405,11 +488,6 @@ int dbwrap_wipe(struct db_context *db)
        return db->wipe(db);
 }
 
-int dbwrap_hash_size(struct db_context *db)
-{
-       return db->hash_size;
-}
-
 int dbwrap_check(struct db_context *db)
 {
        if (db->check == NULL) {
@@ -464,9 +542,9 @@ int dbwrap_transaction_cancel(struct db_context *db)
        return db->transaction_cancel(db);
 }
 
-void dbwrap_db_id(struct db_context *db, const uint8_t **id, size_t *idlen)
+size_t dbwrap_db_id(struct db_context *db, uint8_t *id, size_t idlen)
 {
-       db->id(db, id, idlen);
+       return db->id(db, id, idlen);
 }
 
 bool dbwrap_is_persistent(struct db_context *db)