Rework transaction
authorJose Bollo <jose.bollo@iot.bzh>
Wed, 8 May 2019 13:12:16 +0000 (15:12 +0200)
committerJose Bollo <jose.bollo@iot.bzh>
Thu, 9 May 2019 13:12:37 +0000 (15:12 +0200)
src/anydb.c
src/anydb.h
src/cyn.c
src/db.c
src/db.h
src/main-cynarad.c
src/memdb.c

index d284610..94a5d58 100644 (file)
@@ -138,6 +138,23 @@ idx_or_none_but_any(
 /******************************************************************************/
 /******************************************************************************/
 
+/** manage atomicity of operations */
+int
+anydb_transaction(
+       anydb_t *db,
+       anydb_transaction_t oper
+) {
+       if (db->itf.transaction)
+               return db->itf.transaction(db->clodb, oper);
+       return -ENOTSUP;
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/*** FOR ALL                                                                ***/
+/******************************************************************************/
+/******************************************************************************/
+
 struct for_all_s
 {
        anydb_t *db;
index 33f0447..abc8c4c 100644 (file)
  */
 typedef uint32_t anydb_idx_t;
 
+/*
+ * Definition of some predefined indexes
+ */
+
+/** The invalid index */
 #define AnyIdx_Invalid ((anydb_idx_t)0xffffffffu)
+
+/**  */
 #define AnyIdx_Any     ((anydb_idx_t)0xfffffffeu)
 #define AnyIdx_Wide    ((anydb_idx_t)0xfffffffdu)
 #define AnyIdx_None    ((anydb_idx_t)0xfffffffcu)
@@ -69,10 +76,19 @@ enum anydb_action
 };
 typedef enum anydb_action anydb_action_t;
 
+enum anydb_transaction
+{
+       Anydb_Transaction_Start = 0,
+       Anydb_Transaction_Commit = 1,
+       Anydb_Transaction_Cancel = 2
+};
+typedef enum anydb_transaction anydb_transaction_t;
+
 struct anydb_itf
 {
        int (*index)(void *clodb, anydb_idx_t *idx, const char *name, bool create);
        const char *(*string)(void *clodb, anydb_idx_t idx);
+       int (*transaction)(void *clodb, anydb_transaction_t atomic_op);
        void (*apply)(void *clodb, anydb_action_t (*oper)(void *closure, const anydb_key_t *key, anydb_value_t *value), void *closure);
        int (*add)(void *clodb, const anydb_key_t *key, const anydb_value_t *value);
        void (*gc)(void *clodb);
@@ -87,6 +103,13 @@ struct anydb
 };
 typedef struct anydb anydb_t;
 
+/** manage atomicity of operations */
+extern
+int
+anydb_transaction(
+       anydb_t *db,
+       anydb_transaction_t oper
+);
 
 /** enumerate */
 extern
index 84d3295..e08c262 100644 (file)
--- a/src/cyn.c
+++ b/src/cyn.c
@@ -155,7 +155,7 @@ cyn_leave(
        const void *magic,
        bool commit
 ) {
-       int rc;
+       int rc, rcp;
        struct callback *c, *e, **p;
 
        if (!magic)
@@ -169,26 +169,24 @@ cyn_leave(
        if (!commit)
                rc = 0;
        else {
-               db_backup();
-               rc = queue_play();
+               rc = db_transaction_begin();
                if (rc == 0) {
-                       db_cleanup(0);
-                       rc = db_sync();
-               }
-               if (rc < 0) {
-                       db_recover();
-                       db_sync();
-               } else {
-                       for (c = observers; c ; c = c->next)
-                               c->on_change_cb(c->closure);
+                       rcp = queue_play();
+                       rc = db_transaction_end(rcp == 0) ?: rcp;
+                       if (rcp == 0) {
+                               for (c = observers; c ; c = c->next)
+                                       c->on_change_cb(c->closure);
+                       }
                }
        }
        queue_clear();
 
+       /* wake up awaiting client */
        e = awaiters;
        if (!e)
                lock = 0;
        else {
+               /* the one to awake is at the end of the list */
                p = &awaiters;
                while(e->next) {
                        p = &e->next;
index 98c96e7..5d28246 100644 (file)
--- a/src/db.c
+++ b/src/db.c
@@ -30,6 +30,7 @@
 #include "anydb.h"
 #include "fdb.h"
 #include "memdb.h"
+#include "db.h"
 
 static anydb_t *memdb;
 
@@ -75,27 +76,40 @@ db_is_empty(
        return fdb_is_empty();
 }
 
-/** synchronize db on files */
+/** enter atomic mode */
 int
-db_sync(
+db_transaction_begin(
 ) {
-       return fdb_sync();
-}
+       int rc1, rc2;
 
-/** make a backup of the database */
-int
-db_backup(
-) {
-       return fdb_backup();
+       rc1 = fdb_backup();
+       rc2 = anydb_transaction(memdb, Anydb_Transaction_Start);
+
+       return rc1 ?: rc2;
 }
 
-/** recover the database from latest backup */
+/** leave atomic mode */
 int
-db_recover(
+db_transaction_end(
+       bool commit
 ) {
-       return fdb_recover();
+       int rc1, rc2, rc3, rc4;
+
+       if (commit) {
+               rc1 = 0;
+               rc2 = anydb_transaction(memdb, Anydb_Transaction_Commit);
+               rc3 = db_cleanup();
+       } else {
+               rc1 = fdb_recover();
+               rc2 = anydb_transaction(memdb, Anydb_Transaction_Cancel);
+               rc3 = 0;
+       }
+       rc4 = fdb_sync();
+
+       return rc1 ?: rc2 ?: rc3 ?: rc4;
 }
 
+
 /** enumerate */
 void
 db_for_all(
index a17d240..995fd65 100644 (file)
--- a/src/db.h
+++ b/src/db.h
@@ -38,22 +38,17 @@ bool
 db_is_empty(
 );
 
-/** sync the database */
+/** enter atomic mode */
 extern
 int
-db_sync(
+db_transaction_begin(
 );
 
-/** make a backup of the database */
+/** leave atomic mode */
 extern
 int
-db_backup(
-);
-
-/** recover the database from latest backup */
-extern
-int
-db_recover(
+db_transaction_end(
+       bool commit
 );
 
 /** enumerate */
index ac8106e..9c51df7 100644 (file)
@@ -322,8 +322,6 @@ int main(int ac, char **av)
        /* initialisation of the database */
        if (db_is_empty()) {
                rc = dbinit_add_file(init);
-               if (rc == 0)
-                       rc = db_sync();
                if (rc < 0) {
                        fprintf(stderr, "can't initialise database: %m\n");
                        return 1;
index 0a1e044..b07928f 100644 (file)
 #include "data.h"
 #include "anydb.h"
 
-#define RBS 20
-#define SBS 30
+#define RBS 20 /**< rule block size */
+#define SBS 30 /**< string bloc size */
+
+#define TCLE 0 /**< tag for clean */
+#define TDEL 1 /**< tag for deleted */
+#define TMOD 2 /**< tag for modified */
 
 struct rule
 {
        anydb_key_t key;
        anydb_value_t value;
+       anydb_value_t saved;
+       uint8_t tag;
 };
 
 struct memdb
@@ -52,6 +58,11 @@ struct memdb
                uint32_t count;
                struct rule *values;
        } rules;
+
+       struct {
+               uint32_t count;
+               bool active;
+       } transaction;
 };
 typedef struct memdb memdb_t;
 
@@ -128,20 +139,87 @@ apply_itf(
 
        ir = 0;
        while (ir < memdb->rules.count) {
-               a = oper(closure, &rules[ir].key, &rules[ir].value);
+               if (memdb->transaction.active && rules[ir].tag == TDEL)
+                       a = Anydb_Action_Continue;
+               else
+                       a = oper(closure, &rules[ir].key, &rules[ir].value);
                switch (a) {
                case Anydb_Action_Continue:
                        ir++;
                        break;
                case Anydb_Action_Update_And_Stop:
+                       if (memdb->transaction.active)
+                               rules[ir].tag = TMOD;
+                       else
+                               rules[ir].saved = rules[ir].value;
                        return;
                case Anydb_Action_Remove_And_Continue:
-                       rules[ir] = rules[--memdb->rules.count];
+                       if (memdb->transaction.active)
+                               rules[ir++].tag = TDEL;
+                       else
+                               rules[ir] = rules[--memdb->rules.count];
                        break;
                }
        }
 }
 
+static
+int
+transaction_itf(
+       void *clodb,
+       anydb_transaction_t oper
+) {
+       memdb_t *memdb = clodb;
+       struct rule *rules;
+       uint32_t ir;
+       uint32_t count;
+
+       switch (oper) {
+       case Anydb_Transaction_Start:
+               if (memdb->transaction.active)
+                       return -EINVAL;
+               memdb->transaction.active = true;
+               memdb->transaction.count = memdb->rules.count;
+               break;
+       case Anydb_Transaction_Commit:
+               if (!memdb->transaction.active)
+                       return -EINVAL;
+               rules = memdb->rules.values;
+               count = memdb->rules.count;
+               ir = 0;
+               while(ir < count) {
+                       switch (rules[ir].tag) {
+                       case TCLE:
+                               ir++;
+                               break;
+                       case TDEL:
+                               rules[ir] = rules[--count];
+                               break;
+                       case TMOD:
+                               rules[ir++].tag = TCLE;
+                               break;
+                       }
+               }
+               memdb->rules.count = count;
+               memdb->transaction.active = false;
+               break;
+       case Anydb_Transaction_Cancel:
+               if (!memdb->transaction.active)
+                       return -EINVAL;
+               rules = memdb->rules.values;
+               count = memdb->rules.count = memdb->transaction.count;
+               for (ir = 0 ; ir < count ; ir++) {
+                       if (rules[ir].tag != TCLE) {
+                               rules[ir].value = rules[ir].saved;
+                               rules[ir].tag = TCLE;
+                       }
+               }
+               memdb->transaction.active = false;
+               break;
+       }
+       return 0;
+}
+
 static
 int
 add_itf(
@@ -150,18 +228,26 @@ add_itf(
        const anydb_value_t *value
 ) {
        memdb_t *memdb = clodb;
-       struct rule *rules = memdb->rules.values;
+       struct rule *rules;
+       uint32_t count;
+       uint32_t alloc;
 
-       if (memdb->rules.count == memdb->rules.alloc) {
-               rules = realloc(rules, (memdb->rules.alloc + RBS) * sizeof *rules);
+       rules = memdb->rules.values;
+       count = memdb->rules.count;
+       alloc = memdb->rules.alloc;
+       if (count == alloc) {
+               alloc += RBS;
+               rules = realloc(rules, alloc * sizeof *rules);
                if (!rules)
                        return -ENOMEM;
-               memdb->rules.alloc += RBS;
+               memdb->rules.alloc = alloc;
                memdb->rules.values = rules;
        }
-       rules[memdb->rules.count].key = *key;
-       rules[memdb->rules.count].value = *value;
-       memdb->rules.count++;
+       rules = &rules[count];
+       rules->key = *key;
+       rules->saved = rules->value = *value;
+       rules->tag = TCLE;
+       memdb->rules.count = count + 1;
        return 0;
 }
 
@@ -248,6 +334,7 @@ init(
 
        memdb->db.itf.index = index_itf;
        memdb->db.itf.string = string_itf;
+       memdb->db.itf.transaction = transaction_itf;
        memdb->db.itf.apply = apply_itf;
        memdb->db.itf.add = add_itf;
        memdb->db.itf.gc = gc_itf;
@@ -260,6 +347,9 @@ init(
        memdb->rules.alloc = 0;
        memdb->rules.count = 0;
        memdb->rules.values = NULL;
+
+       memdb->transaction.count = 0;
+       memdb->transaction.active = false;
 }
 
 int