summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/anydb.c17
-rw-r--r--src/anydb.h23
-rw-r--r--src/cyn.c22
-rw-r--r--src/db.c38
-rw-r--r--src/db.h15
-rw-r--r--src/main-cynarad.c2
-rw-r--r--src/memdb.c112
7 files changed, 182 insertions, 47 deletions
diff --git a/src/anydb.c b/src/anydb.c
index d284610..94a5d58 100644
--- a/src/anydb.c
+++ b/src/anydb.c
@@ -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;
diff --git a/src/anydb.h b/src/anydb.h
index 33f0447..abc8c4c 100644
--- a/src/anydb.h
+++ b/src/anydb.h
@@ -22,7 +22,14 @@
*/
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
diff --git a/src/cyn.c b/src/cyn.c
index 84d3295..e08c262 100644
--- 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;
diff --git a/src/db.c b/src/db.c
index 98c96e7..5d28246 100644
--- 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(
diff --git a/src/db.h b/src/db.h
index a17d240..995fd65 100644
--- 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 */
diff --git a/src/main-cynarad.c b/src/main-cynarad.c
index ac8106e..9c51df7 100644
--- a/src/main-cynarad.c
+++ b/src/main-cynarad.c
@@ -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;
diff --git a/src/memdb.c b/src/memdb.c
index 0a1e044..b07928f 100644
--- a/src/memdb.c
+++ b/src/memdb.c
@@ -25,13 +25,19 @@
#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,15 +139,25 @@ 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;
}
}
@@ -144,24 +165,89 @@ apply_itf(
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(
void *clodb,
const anydb_key_t *key,
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