murphy-db: added mqi and mdb support for table stamping.
authorKrisztian Litkey <krisztian.litkey@intel.com>
Thu, 6 Sep 2012 11:44:35 +0000 (14:44 +0300)
committerKrisztian Litkey <krisztian.litkey@intel.com>
Fri, 26 Oct 2012 16:00:10 +0000 (19:00 +0300)
Each table has now a modification stamp. The modification stamp
is a monotonically increasing integer that is incremented every
time a new transaction modifies a table, ie. the stamp is the
number of transactions that have modified the table (and have
eventually been fully committed). Stamps are preserved across
commits and rolled back during rollbacks. Stamps can be queried
by table handle.

13 files changed:
src/murphy-db/include/murphy-db/mdb.h
src/murphy-db/include/murphy-db/mqi.h
src/murphy-db/mdb/linker-script.mdb
src/murphy-db/mdb/log.c
src/murphy-db/mdb/log.h
src/murphy-db/mdb/table.c
src/murphy-db/mdb/table.h
src/murphy-db/mdb/transaction.c
src/murphy-db/mqi/db.h
src/murphy-db/mqi/linker-script.mqi
src/murphy-db/mqi/mdb-backend.c
src/murphy-db/mqi/mqi.c
src/murphy-db/tests/check-libmqi.c

index e725141..c9d6422 100644 (file)
@@ -45,6 +45,7 @@ int mdb_table_get_size(mdb_table_t *);
 char *mdb_table_get_column_name(mdb_table_t *, int);
 mqi_data_type_t mdb_table_get_column_type(mdb_table_t *, int);
 int mdb_table_get_column_size(mdb_table_t *, int);
+uint32_t mdb_table_get_stamp(mdb_table_t *);
 int mdb_table_print_rows(mdb_table_t *, char *, int);
 
 
index 5ed4386..3581aec 100644 (file)
@@ -163,6 +163,7 @@ int mqi_get_table_size(mqi_handle_t);
 char *mqi_get_column_name(mqi_handle_t, int);
 mqi_data_type_t mqi_get_column_type(mqi_handle_t, int);
 int mqi_get_column_size(mqi_handle_t, int);
+uint32_t mqi_get_table_stamp(mqi_handle_t);
 int mqi_print_rows(mqi_handle_t, char *, int);
 
 
index cefa538..7b22f54 100644 (file)
@@ -40,6 +40,7 @@
         mdb_table_get_column_size;
         mdb_table_get_column_type;
         mdb_table_get_size;
+        mdb_table_get_stamp;
         mdb_table_insert;
         mdb_table_print_rows;
         mdb_table_register_handle;
index 77da619..9f33b19 100644 (file)
@@ -41,7 +41,10 @@ typedef struct {
     mdb_dlist_t     link;
     mdb_log_type_t  type;
     mqi_bitfld_t    colmask;
-    mdb_row_t      *before;
+    union {
+        mdb_row_t  *before;
+        uint32_t    stamp;
+    };
     mdb_row_t      *after;
 } change_t;
 
@@ -375,11 +378,22 @@ static tbl_log_t *get_tbl_log(mdb_dlist_t *vhead,
                               mdb_table_t *tbl)
 {
     tbl_log_t *log;
+    change_t  *change;
 
     if (!(log = (tbl_log_t *)get_last_vlog(vhead)) || depth > log->depth) {
         if ((log = (tbl_log_t *)new_log(vhead, hhead, depth, sizeof(*log)))) {
             log->table = tbl;
             MDB_DLIST_INIT(log->changes);
+
+            if (!(change = calloc(1, sizeof(change_t)))) {
+                errno = ENOMEM;
+                return NULL;
+            }
+
+            change->type  = mdb_log_stamp;
+            change->stamp = tbl->stamp++;
+
+            MDB_DLIST_PREPEND(change_t, link, change, &log->changes);
         }
     }
 
index a6c6dc9..a193918 100644 (file)
@@ -26,13 +26,17 @@ typedef enum {
     mdb_log_insert,
     mdb_log_delete,
     mdb_log_update,
+    mdb_log_stamp
 } mdb_log_type_t;
 
 typedef struct {
     mdb_table_t    *table;
     mdb_log_type_t  change;
     mqi_bitfld_t    colmask;
-    mdb_row_t      *before;
+    union {
+        mdb_row_t  *before;
+        uint32_t    stamp;
+    };
     mdb_row_t      *after;
 } mdb_log_entry_t;
 
index 4b18702..1a85286 100644 (file)
@@ -142,6 +142,7 @@ mdb_table_t *mdb_table_create(char *name,
 
     tbl->handle  = MQI_HANDLE_INVALID;
     tbl->name    = strdup(name);
+    tbl->stamp   = 1;
     tbl->chash   = chash;
     tbl->ncolumn = ncolumn;
     tbl->columns = columns;
@@ -450,6 +451,11 @@ int mdb_table_get_column_size(mdb_table_t *tbl, int colidx)
     return tbl->columns[colidx].length;
 }
 
+uint32_t mdb_table_get_stamp(mdb_table_t *tbl)
+{
+    return tbl->stamp;
+}
+
 int mdb_table_print_rows(mdb_table_t *tbl, char *buf, int len)
 {
     mdb_row_t *row;
@@ -550,6 +556,7 @@ static int table_print_info(mdb_table_t *tbl, char *buf, int len)
     *buf = '\0';
 
     PRINT("table name  : '%s'\n", tbl->name);
+    PRINT("table stamp : %u\n"  , tbl->stamp);
     PRINT("row length  : %d\n"  , tbl->dlgh);
     PRINT("no of column: %d\n"  , tbl->ncolumn);
     PRINT("    index name             type     offset length\n"
index 5b8db23..54b51ef 100644 (file)
@@ -14,6 +14,7 @@
 struct mdb_table_s {
     mqi_handle_t  handle;
     char         *name;
+    uint32_t      stamp;
     mdb_index_t   index;
     mdb_hash_t   *chash;         /* hash table for column names */
     int           ncolumn;
index f72f123..505702c 100644 (file)
@@ -21,6 +21,7 @@ static int destroy_row(mdb_table_t *, mdb_row_t *);
 static int remove_row(mdb_table_t *, mdb_row_t *);
 static int add_row(mdb_table_t *, mdb_row_t *);
 static int copy_row(mdb_table_t *, mdb_row_t *, mdb_row_t *);
+static int restore_stamp(mdb_table_t *, uint32_t);
 
 
 uint32_t mdb_transaction_begin(void)
@@ -74,6 +75,10 @@ int mdb_transaction_commit(uint32_t depth)
             s = destroy_row(en->table, en->before);
             break;
 
+        case mdb_log_stamp:
+            s = 0;
+            break;
+
         default:
             s = -1;
             break;
@@ -109,6 +114,7 @@ int mdb_transaction_rollback(uint32_t depth)
         case mdb_log_insert:  s = remove_row(tbl, en->after);            break;
         case mdb_log_delete:  s = add_row(tbl, en->before);              break;
         case mdb_log_update:  s = copy_row(tbl, en->after, en->before);  break;
+        case mdb_log_stamp:   s = restore_stamp(tbl, en->stamp);         break;
         default:              s = -1;                                    break;
         }
 
@@ -134,6 +140,7 @@ int mdb_transaction_drop_table(mdb_table_t *tbl)
         case mdb_log_insert:  s = 0;                                     break;
         case mdb_log_delete:
         case mdb_log_update:  s = destroy_row(en->table, en->before);    break;
+        case mdb_log_stamp:   s = 0;                                     break;
         default:              s = -1;                                    break;
         }
 
@@ -193,6 +200,13 @@ static int copy_row(mdb_table_t *tbl, mdb_row_t *dst, mdb_row_t *src)
 }
 
 
+static int restore_stamp(mdb_table_t *tbl, uint32_t stamp)
+{
+    tbl->stamp = stamp;
+
+    return 0;
+}
+
 /*
  * Local Variables:
  * c-basic-offset: 4
index 9128378..e82b81e 100644 (file)
@@ -31,6 +31,7 @@ typedef struct {
     void *(*find_table)(char *);
     int (*get_column_index)(void *, char *);
     int (*get_table_size)(void *);
+    uint32_t (*get_table_stamp)(void *);
     char *(*get_column_name)(void *, int);
     mqi_data_type_t (*get_column_type)(void *, int);
     int (*get_column_size)(void *, int);
index 5a326ad..9a7ed7d 100644 (file)
@@ -22,6 +22,7 @@
         mqi_get_column_type;
         mqi_get_table_handle;
         mqi_get_table_size;
+        mqi_get_table_stamp;
         mqi_get_transaction_handle;
         mqi_insert_into;
         mqi_open;
index 2de336a..d89be95 100644 (file)
@@ -42,6 +42,7 @@ static int      delete_from(void *, mqi_cond_entry_t *);
 static void *   find_table(char *);
 static int      get_column_index(void *, char *);
 static int      get_table_size(void *);
+static uint32_t get_table_stamp(void *);
 static char *   get_column_name(void *, int);
 static mqi_data_type_t get_column_type(void *, int);
 static int      get_column_size(void *, int);
@@ -73,6 +74,7 @@ static mqi_db_functbl_t functbl = {
     find_table,
     get_column_index,
     get_table_size,
+    get_table_stamp,
     get_column_name,
     get_column_type,
     get_column_size,
@@ -248,6 +250,11 @@ static int get_table_size(void *t)
     return  mdb_table_get_size((mdb_table_t *)t);
 }
 
+static uint32_t get_table_stamp(void *t)
+{
+    return mdb_table_get_stamp((mdb_table_t *)t);
+}
+
 static char *get_column_name(void *t, int colidx)
 {
     return  mdb_table_get_column_name((mdb_table_t *)t, colidx);
index defac38..2844a97 100644 (file)
@@ -679,6 +679,19 @@ int mqi_get_table_size(mqi_handle_t h)
     return  ftb->get_table_size(tbl);
 }
 
+uint32_t mqi_get_table_stamp(mqi_handle_t h)
+{
+    mqi_db_functbl_t *ftb;
+    void             *tbl;
+
+    MDB_CHECKARG(h != MDB_HANDLE_INVALID, -1);
+    MDB_PREREQUISITE(dbs && ndb > 0, -1);
+
+    GET_TABLE(tbl, ftb, h, -1);
+
+    return  ftb->get_table_stamp(tbl);
+}
+
 char *mqi_get_column_name(mqi_handle_t h, int colidx)
 {
     mqi_db_functbl_t *ftb;
index 1fd8eee..6d9f89e 100644 (file)
@@ -92,7 +92,7 @@ static record_t *artists[] = {&chuck, &gary, &elvis, &tom, &greta, &rita,NULL};
 
 
 static int          verbose;
-static mqi_handle_t transactions[10];
+static mqi_handle_t transactions[MQI_TXDEPTH_MAX - 1];
 static int          txdepth;
 static mqi_handle_t persons = MQI_HANDLE_INVALID;
 static int          columns_no_in_persons = -1;
@@ -100,6 +100,8 @@ static int          rows_no_in_persons = -1;
 
 static int          ntrigger;
 static trigger_t    triggers[256];
+static int          nseq = 32;
+static int          nnest = MQI_TXDEPTH_MAX - 1;
 
 
 static Suite *libmqi_suite(void);
@@ -122,14 +124,24 @@ int main(int argc, char **argv)
     for (i = 1;  i < argc;  i++) {
         if (!strcmp("-v", argv[i]))
             verbose = 1;
-        else if (!strcmp("-f", argv[1]))
+        else if (!strcmp("-f", argv[i]))
             srunner_set_fork_status(sr, CK_NOFORK);
+        else if (!strcmp("-nseq", argv[i]) && i < argc - 1) {
+            nseq = atoi(argv[i + 1]);
+            i++;
+        }
+        else if (!strcmp("-nnest", argv[i]) && i < argc - 1) {
+            nnest = atoi(argv[i + 1]);
+            i++;
+        }
         else {
             printf("Usage: %s [-h] [-v] [-f]\n"
-                   "  -h  prints this message\n"
-                   "  -v  sets verbose mode\n"
-                   "  -f  forces no-forking mode\n",
-                   basename(argv[0]));
+                   "  -h     prints this message\n"
+                   "  -v     sets verbose mode\n"
+                   "  -f     forces no-forking mode\n"
+                   "  -nseq  number of sequential transactions\n"
+                   "  -nnest number of nested transactions (1 - %d)\n",
+                   basename(argv[0]), MQI_TXDEPTH_MAX - 1);
             exit(strcmp("-h", argv[i]) ? 1 : 0);
         }
     }
@@ -511,6 +523,22 @@ START_TEST(delete_from_persons)
 END_TEST
 
 
+START_TEST(delete_all_persons)
+{
+    query_t rows[32];
+    int     nrow, n;
+
+    nrow = MQI_SELECT(persons_select_columns, persons, MQI_ALL, rows);
+    fail_if(nrow < 0, "select for checking failed (%s)", strerror(errno));
+
+    n = MQI_DELETE(persons, MQI_ALL);
+    fail_if(n != nrow, "deleted %d rows instead of the expected %d", n, nrow);
+
+    n = MQI_SELECT(persons_select_columns, persons, MQI_ALL, rows);
+    fail_if(n != 0, "verification select failed (%s)", strerror(errno));
+}
+END_TEST
+
 
 START_TEST(transaction_rollback)
 {
@@ -731,6 +759,87 @@ START_TEST(column_trigger)
 }
 END_TEST
 
+START_TEST(sequential_transactions)
+{
+    mqi_handle_t  trh;
+    int           sts, i;
+    const char   *kind;
+
+    PREREQUISITE(create_table_persons);
+
+    for (i = 0; i < nseq; i++) {
+        trh = mqi_begin_transaction();
+
+        fail_if(trh == MQI_HANDLE_INVALID,
+                "failed to create %d. transaction : errno (%s)",
+                i + 1, strerror(errno));
+
+        if (i & 0x1)
+            PREREQUISITE(delete_all_persons);
+        else
+            PREREQUISITE(insert_into_persons);
+
+        if (!(i & 0x3)) {
+            kind = "rollback";
+            sts  = mqi_rollback_transaction(trh);
+        }
+        else {
+            kind = "commit";
+            sts  = mqi_commit_transaction(trh);
+        }
+
+        fail_if(sts < 0, "%s failed: errno (%s)", kind, strerror(errno));
+    }
+}
+END_TEST
+
+
+START_TEST(nested_transactions)
+{
+    mqi_handle_t  txids[MQI_TXDEPTH_MAX - 1];
+    mqi_handle_t  trh;
+    int           sts, tx, i, cnt;
+    const char   *kind;
+
+    PREREQUISITE(create_table_persons);
+
+    if (nnest > sizeof(txids) / sizeof(txids[0]))
+        nnest = sizeof(txids) / sizeof(txids[0]);
+
+    for (cnt = 0; cnt < 16; cnt++) {
+        for (tx = 0; tx < nnest; tx++) {
+            trh = txids[tx] = mqi_begin_transaction();
+
+            fail_if(trh == MQI_HANDLE_INVALID,
+                    "couldn't create transaction: errno (%s)", strerror(errno));
+
+            for (i = 0; i < nseq; i++) {
+                if (i & 0x1)
+                    PREREQUISITE(delete_all_persons);
+                else
+                    PREREQUISITE(insert_into_persons);
+            }
+        }
+
+        for (tx = nnest - 1; tx >= 0; tx--) {
+            trh = txids[tx];
+
+            if (!(tx & 0x1) && 0) {
+                kind = "rollback";
+                sts = mqi_rollback_transaction(trh);
+            }
+            else {
+                kind = "commit";
+                sts = mqi_commit_transaction(trh);
+            }
+
+            fail_if(sts < 0, "%s %u failed: errno (%s)", kind, trh,
+                    strerror(errno));
+        }
+    }
+}
+END_TEST
+
 
 
 static Suite *libmqi_suite(void)
@@ -764,6 +873,8 @@ static TCase *basic_tests(void)
     tcase_add_test(tc, table_trigger);
     tcase_add_test(tc, row_trigger);
     tcase_add_test(tc, column_trigger);
+    tcase_add_test(tc, sequential_transactions);
+    tcase_add_test(tc, nested_transactions);
 
     return tc;
 }