From ed91352e50be1efcfa70e04f8d7e0761690837b9 Mon Sep 17 00:00:00 2001 From: Jose Bollo Date: Wed, 8 May 2019 15:12:16 +0200 Subject: Rework transaction --- src/anydb.c | 17 ++++++++ src/anydb.h | 23 +++++++++++ src/cyn.c | 22 +++++------ src/db.c | 38 ++++++++++++------ src/db.h | 15 +++---- src/main-cynarad.c | 2 - src/memdb.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++------ 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,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 -- cgit 1.2.3-korg