resolver: preliminary DB integration, autoupdate&script preparation support.
authorKrisztian Litkey <krisztian.litkey@intel.com>
Fri, 7 Sep 2012 17:25:38 +0000 (20:25 +0300)
committerKrisztian Litkey <krisztian.litkey@intel.com>
Fri, 26 Oct 2012 16:00:11 +0000 (19:00 +0300)
19 files changed:
src/Makefile.am
src/resolver/db.c [deleted file]
src/resolver/db.h [deleted file]
src/resolver/fact.c
src/resolver/fact.h
src/resolver/parser-api.h
src/resolver/parser.y
src/resolver/resolver-types.h
src/resolver/resolver.c
src/resolver/resolver.h
src/resolver/scanner.l
src/resolver/scripting/simple/call.c
src/resolver/scripting/simple/call.h
src/resolver/scripting/simple/simple-script.c
src/resolver/target-sorter.c
src/resolver/target.c
src/resolver/target.h
src/resolver/test-input
src/resolver/tests/Makefile.am

index af4e39c..03bb4aa 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS         = . murphy-db \
+SUBDIRS         = murphy-db . \
                  common/tests core/tests daemon/tests resolver/tests
 AM_CFLAGS       = $(WARNING_CFLAGS) -I$(top_builddir) -DLIBDIR=\"@LIBDIR@\"
 MURPHY_CFLAGS   = 
@@ -14,6 +14,7 @@ QUIET_GEN       = $(Q:@=@echo '  GEN   '$@;)
 LEXCOMPILE      = $(LEX) $(LFLAGS) $(AM_LFLAGS)
 YACCCOMPILE     = $(YACC) $(YFLAGS) $(AM_YFLAGS)
 
+INCLUDES        = -Isrc/murphy-db/include
 
 ###################################
 # murphy common library
@@ -281,7 +282,6 @@ libmurphy_resolver_la_REGULAR_SOURCES =                             \
                resolver/scanner.c                              \
                resolver/target.c                               \
                resolver/target-sorter.c                        \
-               resolver/db.c                                   \
                resolver/fact.c                                 \
                $(SIMPLE_SCRIPT_SOURCES)
 
@@ -296,13 +296,19 @@ libmurphy_resolver_la_LDFLAGS =                   \
                -Wl,-version-script=linker-script.resolver \
                -version-info @MURPHY_VERSION_INFO@
 
-libmurphy_resolver_la_LIBADD =     \
-               libmurphy-core.la   \
-               libmurphy-common.la
+libmurphy_resolver_la_LIBADD =         \
+               libmurphy-core.la       \
+               libmurphy-common.la     \
+               murphy-db/mql/libmql.la \
+               murphy-db/mqi/libmqi.la \
+               murphy-db/mdb/libmdb.la
 
-libmurphy_resolver_la_DEPENDENCIES = linker-script.resolver \
-                                    libmurphy-core.la      \
-                                    libmurphy-common.la
+libmurphy_resolver_la_DEPENDENCIES = linker-script.resolver  \
+                                    libmurphy-core.la       \
+                                    libmurphy-common.la     \
+                                    murphy-db/mql/libmql.la \
+                                    murphy-db/mqi/libmqi.la \
+                                    murphy-db/mdb/libmdb.la
 
 # resolver lexical analyser and parser generation
 RESOLVER_PARSER_PREFIX = yy_res_
@@ -473,10 +479,10 @@ murphyd_CFLAGS  =                 \
                $(BUILTIN_CFLAGS)
 
 murphyd_LDADD  =                       \
+               $(BUILTIN_LIBS)         \
                libmurphy-resolver.la   \
                libmurphy-core.la       \
-               libmurphy-common.la     \
-               $(BUILTIN_LIBS)
+               libmurphy-common.la
 
 murphyd_LDFLAGS = -rdynamic
 
diff --git a/src/resolver/db.c b/src/resolver/db.c
deleted file mode 100644 (file)
index 7df055f..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#include <stdint.h>
-
-#include <murphy/common/macros.h>
-
-#include "resolver-types.h"
-#include "resolver.h"
-
-uint32_t start_transaction(mrp_resolver_t *r)
-{
-    return r->stamp++;
-}
-
-
-int commit_transaction(mrp_resolver_t *r)
-{
-    MRP_UNUSED(r);
-
-    return TRUE;
-}
-
-
-int rollback_transaction(mrp_resolver_t *r)
-{
-    r->stamp--;
-
-    return TRUE;
-}
diff --git a/src/resolver/db.h b/src/resolver/db.h
deleted file mode 100644 (file)
index e61d7f3..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __MURPHY_RESOLVER_DB_H__
-#define __MURPHY_RESOLVER_DB_H__
-
-#define INVALID_TX ((uint32_t)-1)
-
-uint32_t start_transaction(mrp_resolver_t *r);
-int commit_transaction(mrp_resolver_t *r);
-int rollback_transaction(mrp_resolver_t *r);
-
-#endif /* __MURPHY_RESOLVER_DB_H__ */
index 635917d..7ac7af2 100644 (file)
@@ -1,32 +1,22 @@
 #include <murphy/common/mm.h>
+#include <murphy/common/log.h>
+#include <murphy-db/mqi.h>
 
 #include "resolver-types.h"
 #include "resolver.h"
+#include "target.h"
 #include "fact.h"
 
-
-int create_facts(mrp_resolver_t *r)
-{
-    target_t *t;
-    int       i, j;
-
-    for (i = 0, t = r->targets; i < r->ntarget; i++, t++) {
-        for (j = 0; i < t->ndepend; j++) {
-            if (*t->depends[j] == '$')
-                if (!create_fact(r, t->depends[j]))
-                    return FALSE;
-        }
-    }
-
-    return TRUE;
-}
-
+static int subscribe_db_events(mrp_resolver_t *r);
+static void unsubscribe_db_events(mrp_resolver_t *r);
 
 int create_fact(mrp_resolver_t *r, char *fact)
 {
     int     i;
     fact_t *f;
 
+    subscribe_db_events(r);
+
     for (i = 0; i < r->nfact; i++) {
         if (!strcmp(r->facts[i].name, fact))
             return TRUE;
@@ -37,7 +27,8 @@ int create_fact(mrp_resolver_t *r, char *fact)
         return FALSE;
 
     f = r->facts + r->nfact++;
-    f->name = mrp_strdup(fact);
+    f->name  = mrp_strdup(fact);
+    f->table = MQI_HANDLE_INVALID;
 
     if (f->name != NULL)
         return TRUE;
@@ -51,6 +42,8 @@ void destroy_facts(mrp_resolver_t *r)
     fact_t *f;
     int     i;
 
+    unsubscribe_db_events(r);
+
     for (i = 0, f = r->facts; i < r->nfact; i++, f++)
         mrp_free(f->name);
 
@@ -58,18 +51,155 @@ void destroy_facts(mrp_resolver_t *r)
 }
 
 
-int fact_changed(mrp_resolver_t *r, int id)
+uint32_t fact_stamp(mrp_resolver_t *r, int id)
 {
+    fact_t   *fact = r->facts + id;
+    uint32_t  stamp;
+
+    if (fact->table != MQI_HANDLE_INVALID)
+        stamp = mqi_get_table_stamp(fact->table);
+    else
+        stamp = 0; /* MQI_NO_STAMP */
+
+    return stamp;
+}
+
+
+fact_t *lookup_fact(mrp_resolver_t *r, const char *name)
+{
+    fact_t *f;
+    int     i;
+
+    for (i = 0, f = r->facts; i < r->nfact; i++, f++)
+        if (!strcmp(f->name, name))
+            return f;
+
+    return NULL;
+}
+
+
+static void update_fact_table(mrp_resolver_t *r, const char *name,
+                              mqi_handle_t tbl)
+{
+    fact_t *f;
+    int     i;
+
+    for (i = 0, f = r->facts; i < r->nfact; i++, f++) {
+        if (!strcmp(f->name + 1, name)) {
+            f->table = tbl;
+            return;
+        }
+    }
+}
+
+
+static void check_fact_tables(mrp_resolver_t *r)
+{
+    fact_t *f;
+    int     i;
+
+    for (i = 0, f = r->facts; i < r->nfact; i++, f++) {
+        if (f->table != MQI_HANDLE_INVALID)
+            mrp_debug("Fact table '%s' stamp: %u.",
+                      f->name, mqi_get_table_stamp(f->table));
+    }
+
+    autoupdate_target(r);
+}
+
+
+static inline int open_db(void)
+{
+    static int opened = FALSE;
+    if (!opened)
+        opened = (mqi_open() == 0);
+
+    return opened;
+}
+
+
+static void table_event(mqi_event_t *e, void *user_data)
+{
+    mrp_resolver_t *r = (mrp_resolver_t *)user_data;
+
+    switch (e->event) {
+    case mqi_table_created:
+        mrp_debug("Received table-created (%s, %u) DB event.",
+                  e->table.table.name, e->table.table.handle);
+        update_fact_table(r, e->table.table.name, e->table.table.handle);
+        break;
+    case mqi_table_dropped:
+        mrp_debug("Received table-dropped (%s, %u) DB event.",
+                  e->table.table.name, e->table.table.handle);
+        update_fact_table(r, e->table.table.name, MQI_HANDLE_INVALID);
+        break;
+    default:
+        break;
+    }
+}
+
+
+static void transaction_event(mqi_event_t *e, void *user_data)
+{
+    mrp_resolver_t *r = (mrp_resolver_t *)user_data;
+
     MRP_UNUSED(r);
-    MRP_UNUSED(id);
 
-    return TRUE;
+    switch (e->event) {
+    case mqi_transaction_end:
+        mrp_debug("Received transaction-end DB event.");
+        check_fact_tables(r);
+        break;
+    case mqi_transaction_start:
+        mrp_debug("Received transaction-start DB event.");
+        break;
+    default:
+        break;
+    }
 }
 
 
-uint32_t fact_stamp(mrp_resolver_t *r, int id)
+static int subscribe_db_events(mrp_resolver_t *r)
+{
+    if (open_db()) {
+        if (mqi_create_table_trigger(table_event, r) == 0) {
+            if (mqi_create_transaction_trigger(transaction_event, r) == 0)
+                return TRUE;
+            else
+                mqi_drop_table_trigger(table_event, r);
+        }
+    }
+
+    return FALSE;
+}
+
+
+static void unsubscribe_db_events(mrp_resolver_t *r)
+{
+    mqi_drop_table_trigger(table_event, r);
+    mqi_drop_transaction_trigger(transaction_event, r);
+}
+
+
+mqi_handle_t start_transaction(mrp_resolver_t *r)
+{
+    MRP_UNUSED(r);
+
+    return mqi_begin_transaction();
+}
+
+
+int commit_transaction(mrp_resolver_t *r, mqi_handle_t tx)
+{
+    MRP_UNUSED(r);
+
+    return mqi_commit_transaction(tx) != -1;
+}
+
+
+int rollback_transaction(mrp_resolver_t *r, mqi_handle_t tx)
 {
-    fact_t *fact = r->facts + id;
+    MRP_UNUSED(r);
 
-    return fact->stamp;
+    return mqi_rollback_transaction(tx) != -1;
 }
index 1821c03..453ec71 100644 (file)
@@ -1,13 +1,20 @@
 #ifndef __MURPHY_RESOLVER_FACT_H__
 #define __MURPHY_RESOLVER_FACT_H__
 
+#include <murphy-db/mqi.h>
 #include "resolver.h"
 
-int create_facts(mrp_resolver_t *r);
 int create_fact(mrp_resolver_t *r, char *name);
 void destroy_facts(mrp_resolver_t *r);
 
 int fact_changed(mrp_resolver_t *r, int id);
 uint32_t fact_stamp(mrp_resolver_t *r, int id);
 
+fact_t *lookup_fact(mrp_resolver_t *r, const char *name);
+
+
+mqi_handle_t start_transaction(mrp_resolver_t *r);
+int commit_transaction(mrp_resolver_t *r, mqi_handle_t tx);
+int rollback_transaction(mrp_resolver_t *r, mqi_handle_t tx);
+
 #endif /* __MURPHY_RESOLVER_FACT_H__ */
index cb3582f..0a71c8b 100644 (file)
@@ -39,6 +39,7 @@ struct yy_res_input_s {
 
 typedef struct {
     mrp_list_hook_t targets;                      /* list of targets */
+    char           *auto_update;                  /* auto-update target */
     char            ringbuf[YY_RES_RINGBUF_SIZE]; /* token ringbuffer */
     int             offs;                         /* buffer insert offset */
     yy_res_input_t *in;                           /* current input */
index b3c5dd6..922bff4 100644 (file)
@@ -35,6 +35,7 @@ static tkn_strarr_t *strarr_append(tkn_strarr_t *arr, char *str);
 %token          KEY_DEPENDS_ON
 %token          KEY_UPDATE_SCRIPT
 %token          KEY_END_SCRIPT
+%token          KEY_AUTOUPDATE
 %token <string> TKN_IDENT
 %token <string> TKN_FACT
 %token <string> TKN_SCRIPT_LINE
@@ -47,12 +48,16 @@ static tkn_strarr_t *strarr_append(tkn_strarr_t *arr, char *str);
 %type  <script> optional_script
 %type  <string> script_source
 
-
 %%
 
-input: targets
+input: optional_autoupdate targets
     ;
 
+optional_autoupdate:
+/* no autoupdate target */ { parser->auto_update = NULL;                 }
+| KEY_AUTOUPDATE TKN_IDENT { parser->auto_update = mrp_strdup($2.value); }
+;
+
 targets:
   target         { mrp_list_append(&parser->targets, &$1->hook); }
 | targets target { mrp_list_append(&parser->targets, &$2->hook); }
@@ -258,6 +263,8 @@ void parser_cleanup(yy_res_parser_t *parser)
         scanner_free_input(ip);
         ip = in;
     }
+
+    mrp_free(parser->auto_update);
 }
 
 
index f62b3d2..6216f45 100644 (file)
@@ -6,6 +6,8 @@
 #include <murphy/common/hashtbl.h>
 #include <murphy/core/scripting.h>
 
+#include <murphy-db/mqi.h>
+
 typedef struct target_s target_t;        /* opaque type for resolver targets */
 typedef struct fact_s   fact_t;          /* opaque type for tracked facts */
 
@@ -19,6 +21,7 @@ struct target_s {
     int              ndepend;            /* number of dependencies */
     int             *update_facts;       /* facts to check when updating */
     int             *update_targets;     /* targets to check when updating */
+    uint32_t        *fact_stamps;        /* stamps of facts at last update */
     mrp_scriptlet_t *script;             /* update script if any, or NULL */
 };
 
@@ -27,8 +30,9 @@ struct target_s {
  * a tracked fact
  */
 struct fact_s {
-    char     *name;                      /* fact name */
-    uint32_t  stamp;                     /* touch-stamp */
+    char         *name;                  /* fact name */
+    mqi_handle_t  table;                 /* associated DB table */
+    uint32_t      stamp;                 /* touch-stamp */
 };
 
 
@@ -37,6 +41,7 @@ struct mrp_resolver_s {
     int                ntarget;          /* number of targets */
     fact_t            *facts;            /* facts tracked as dependencies */
     int                nfact;            /* number of tracked facts */
+    target_t          *auto_update;      /* target to resolve on fact changes */
     uint32_t           stamp;            /* update stamp */
     mrp_context_tbl_t *ctbl;             /* context variable table */
 };
index bcb5558..609ece7 100644 (file)
@@ -41,6 +41,12 @@ mrp_resolver_t *mrp_resolver_parse(const char *path)
 }
 
 
+int mrp_resolver_prepare(mrp_resolver_t *r)
+{
+    return (prepare_target_scripts(r) == 0);
+}
+
+
 void mrp_resolver_destroy(mrp_resolver_t *r)
 {
     if (r != NULL) {
index c79f29d..3bafddb 100644 (file)
@@ -17,6 +17,9 @@ mrp_resolver_t *mrp_resolver_parse(const char *path);
 /** Destroy the given resolver context, freeing all associated resources. */
 void mrp_resolver_destroy(mrp_resolver_t *r);
 
+/** Prepare the targets for resolution (link scriptlets, etc.). */
+int mrp_resolver_prepare(mrp_resolver_t *r);
+
 /** Update the given target. The NULL-terminated variable argument list
     after the target name sepcifies the resolver context variables to
     set during the update. Use a single NULL to omit variables. */
index c19daa3..c72f835 100644 (file)
@@ -256,6 +256,7 @@ COMMENT               #.*
 INCLUDE               ^include{WS}\"[^\"]*\"
 
 TARGET                ^target
+AUTOUPDATE            ^auto-update-target
 DEPENDS_ON            depends\ on
 IDENT                 [a-zA-Z_][a-zA-Z0-9_]+
 FACT                  \${IDENT}(\.{IDENT})*
@@ -268,6 +269,7 @@ SCRIPT_LINE           ^{WS}.*
 %%
 
 {TARGET}              { KEYWORD_TOKEN(TARGET);                         }
+{AUTOUPDATE}          { KEYWORD_TOKEN(AUTOUPDATE);                     }
 {DEPENDS_ON}          { KEYWORD_TOKEN(DEPENDS_ON);                     }
 {IDENT}               { STRING_TOKEN(IDENT);                           }
 {FACT}                { STRING_TOKEN(FACT);                            }
index b8060ff..51249d5 100644 (file)
@@ -110,20 +110,24 @@ void destroy_arguments(arg_t *args, int narg)
 }
 
 
-static int resolve_function(function_call_t *c)
+int link_call(function_call_t *c)
 {
     mrp_plugin_t  *plugin;
     int          (*script_ptr)(mrp_plugin_t *plugin, const char *name,
                                mrp_script_env_t *env);
 
-    if (mrp_import_method(c->name, NULL, NULL, &script_ptr, &plugin) < 0)
-        return FALSE;
-    else {
-        c->script_ptr = script_ptr;
-        c->plugin     = plugin;
-
-        return TRUE;
+    if (c->script_ptr == NULL) {
+        if (mrp_import_method(c->name, NULL, NULL, &script_ptr, &plugin) < 0) {
+            mrp_log_error("Failed to find method '%s'.", c->name);
+            return FALSE;
+        }
+        else {
+            c->script_ptr = script_ptr;
+            c->plugin     = plugin;
+        }
     }
+
+    return TRUE;
 }
 
 int execute_call(function_call_t *c, mrp_context_tbl_t *tbl)
@@ -134,7 +138,7 @@ int execute_call(function_call_t *c, mrp_context_tbl_t *tbl)
     int                narg, n, status;
 
     if (MRP_UNLIKELY(c->script_ptr == NULL)) {
-        if (!resolve_function(c))
+        if (!link_call(c))
             return -ENOENT;
     }
 
index 634dfb5..1fb821a 100644 (file)
@@ -6,6 +6,7 @@
 #include "simple-script.h"
 
 function_call_t *create_call(char *name, arg_t *args, int narg);
+int link_call(function_call_t *c);
 void destroy_call(function_call_t *c);
 void dump_call(FILE *fp, function_call_t *c);
 
index 2fed0ff..d99e95f 100644 (file)
@@ -1,3 +1,5 @@
+#include <errno.h>
+
 #include <murphy/common/macros.h>
 #include <murphy/common/mm.h>
 #include <murphy/common/log.h>
@@ -57,6 +59,31 @@ static int simple_compile(mrp_scriptlet_t *script)
 }
 
 
+static int simple_prepare(mrp_scriptlet_t *s)
+{
+    simple_script_t *ss = s->compiled;
+    mrp_list_hook_t *p, *n;
+    function_call_t *c;
+
+    if (ss != NULL) {
+        mrp_list_foreach(&ss->statements, p, n) {
+            c = mrp_list_entry(p, typeof(*c), hook);
+
+            if (!link_call(c)) {
+                errno = ENOENT;
+                return -1;
+            }
+        }
+
+        return 0;
+    }
+    else {
+        errno = EINVAL;
+        return -1;
+    }
+}
+
+
 static int simple_execute(mrp_scriptlet_t *s, mrp_context_tbl_t *tbl)
 {
     simple_script_t *ss = s->compiled;
@@ -87,4 +114,5 @@ static void simple_cleanup(mrp_scriptlet_t *s)
 }
 
 MRP_REGISTER_INTERPRETER("simple",
-                         simple_compile, simple_execute, simple_cleanup);
+                         simple_compile, simple_prepare,
+                         simple_execute, simple_cleanup);
index ba613c5..e3d6d26 100644 (file)
@@ -398,7 +398,9 @@ static int sort_graph(graph_t *g, int target_idx)
 
         if (nfact > 0) {
             target->update_facts = mrp_alloc_array(int, nfact + 1);
-            if (target->update_facts != NULL) {
+            target->fact_stamps  = mrp_allocz_array(uint32_t, nfact);
+
+            if (target->update_facts != NULL && target->fact_stamps != NULL) {
                 for (i = 0; i < nfact; i++)
                     target->update_facts[i] = L.items[i];
                 target->update_facts[i] = -1;
index 598305f..1e78557 100644 (file)
@@ -9,7 +9,6 @@
 
 #include "resolver-types.h"
 #include "resolver.h"
-#include "db.h"
 #include "fact.h"
 #include "target.h"
 
@@ -19,10 +18,12 @@ int create_targets(mrp_resolver_t *r, yy_res_parser_t *parser)
     mrp_list_hook_t *lp, *ln;
     yy_res_target_t *pt;
     target_t        *t;
-    int              i;
+    int              auto_update, i;
+
+    auto_update = -1;
+    r->ntarget  = 0;
+    r->targets  = NULL;
 
-    r->ntarget = 0;
-    r->targets = NULL;
     mrp_list_foreach(&parser->targets, lp, ln) {
         if (!mrp_reallocz(r->targets, r->ntarget * sizeof(*r->targets),
                           (r->ntarget + 1) * sizeof(*r->targets)))
@@ -59,6 +60,22 @@ int create_targets(mrp_resolver_t *r, yy_res_parser_t *parser)
                 if (!create_fact(r, t->depends[i]))
                     return -1;
         }
+
+        if (parser->auto_update != NULL) {
+            if (!strcmp(parser->auto_update, t->name))
+                auto_update = t - r->targets;
+        }
+    }
+
+    if (auto_update >= 0)
+        r->auto_update = r->targets + auto_update;
+    else {
+        if (parser->auto_update != NULL) {
+            mrp_log_error("Auto-update target '%s' does not exist.",
+                          parser->auto_update);
+            errno = ENOENT;
+            return -1;
+        }
     }
 
     return 0;
@@ -74,6 +91,7 @@ void destroy_targets(mrp_resolver_t *r)
         mrp_free(t->name);
         mrp_free(t->update_facts);
         mrp_free(t->update_targets);
+        mrp_free(t->fact_stamps);
 
         for (j = 0; j < t->ndepend; j++)
             mrp_free(t->depends[j]);
@@ -102,6 +120,22 @@ int compile_target_scripts(mrp_resolver_t *r)
 }
 
 
+int prepare_target_scripts(mrp_resolver_t *r)
+{
+    target_t *t;
+    int       i;
+
+    for (i = 0, t = r->targets; i < r->ntarget; i++, t++) {
+        if (mrp_prepare_script(t->script) < 0) {
+            mrp_log_error("Failed to prepare script for target '%s'.", t->name);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+
 static int older_than_facts(mrp_resolver_t *r, target_t *t)
 {
     int i, id;
@@ -115,11 +149,11 @@ static int older_than_facts(mrp_resolver_t *r, target_t *t)
      * facts have a newer stamp than the target.
      */
 
-    if (t->update_facts != NULL)
+    if (t->update_facts == NULL)
         return TRUE;
     else {
         for (i = 0; (id = t->update_facts[i]) >= 0; i++) {
-            if (fact_stamp(r, id) > t->stamp)
+            if (fact_stamp(r, id) > t->fact_stamps[i])
                 return TRUE;
         }
     }
@@ -151,24 +185,42 @@ static int older_than_targets(mrp_resolver_t *r, target_t *t)
 }
 
 
+static void save_fact_stamps(mrp_resolver_t *r, target_t *t, uint32_t *buf)
+{
+    int id, idx, i;
+
+    if (t->update_facts != NULL) {
+        id  = t - r->targets;
+        idx = id * r->nfact;
+
+        for (i = 0; (id = t->update_facts[i]) >= 0; i++, idx++)
+            buf[idx] = t->fact_stamps[i];
+    }
+}
+
+
+static void restore_fact_stamps(mrp_resolver_t *r, target_t *t, uint32_t *buf)
+{
+    int id, idx, i;
+
+    if (t->update_facts != NULL) {
+        id  = t - r->targets;
+        idx = id * r->nfact;
+
+        for (i = 0; (id = t->update_facts[i]) >= 0; i++, idx++)
+            t->fact_stamps[i] = buf[idx];
+    }
+}
+
+
 static void save_target_stamps(mrp_resolver_t *r, target_t *t, uint32_t *buf)
 {
     target_t *dep;
     int       i, id;
 
-    if (t != NULL) {
-        memset(buf, (uint32_t)-1, r->ntarget * sizeof(*buf));
-
-        for (i = 0; (id = t->update_targets[i]) >= 0; i++) {
-            dep     = r->targets + id;
-            buf[id] = dep->stamp;
-        }
-    }
-    else {
-        for (id = 0; id < r->ntarget; id++) {
-            dep     = r->targets + id;
-            buf[id] = dep->stamp;
-        }
+    for (i = 0; (id = t->update_targets[i]) >= 0; i++) {
+        dep = r->targets + id;
+        save_fact_stamps(r, dep, buf);
     }
 }
 
@@ -178,36 +230,40 @@ static void restore_target_stamps(mrp_resolver_t *r, target_t *t, uint32_t *buf)
     target_t *dep;
     int       i, id;
 
-    if (t != NULL) {
-        memset(buf, (uint32_t)-1, r->ntarget * sizeof(*buf));
-
-        for (i = 0; (id = t->update_targets[i]) >= 0; i++) {
-            dep        = r->targets + id;
-            dep->stamp = buf[id];
-        }
-    }
-    else {
-        for (id = 0; id < r->ntarget; id++) {
-            dep        = r->targets + id;
-            dep->stamp = buf[id];
-        }
+    for (i = 0; (id = t->update_targets[i]) >= 0; i++) {
+        dep = r->targets + id;
+        restore_fact_stamps(r, dep, buf);
     }
 }
 
 
+static void update_target_stamps(mrp_resolver_t *r, target_t *t)
+{
+    int i, id;
+
+    if (t->update_facts != NULL)
+        for (i = 0; (id = t->update_facts[i]) >= 0; i++)
+            t->fact_stamps[i] = fact_stamp(r, id);
+}
+
+
 static int update_target(mrp_resolver_t *r, target_t *t)
 {
-    target_t *dep;
-    uint32_t  stamps[r->ntarget];
-    int       i, id, status, needs_update, tx_owner;
+    mqi_handle_t  tx;
+    target_t     *dep;
+    uint32_t      stamps[r->ntarget * r->nfact];
+    int           i, id, status, needs_update;
 
-    save_target_stamps(r, t, stamps);
-    if (r->stamp == INVALID_TX) {
-        r->stamp = start_transaction(r);
-        tx_owner = TRUE;
+    tx = start_transaction(r);
+
+    if (tx == MQI_HANDLE_INVALID) {
+        if (errno != 0)
+            return -errno;
+        else
+            return -EINVAL;
     }
-    else
-        tx_owner = FALSE;
+
+    save_target_stamps(r, t, stamps);
 
     status       = TRUE;
     needs_update = older_than_facts(r, t);
@@ -226,7 +282,7 @@ static int update_target(mrp_resolver_t *r, target_t *t)
             if (status <= 0)
                 break;
             else
-                dep->stamp = r->stamp;
+                update_target_stamps(r, dep);
         }
     }
 
@@ -234,13 +290,21 @@ static int update_target(mrp_resolver_t *r, target_t *t)
         status = mrp_execute_script(t->script, r->ctbl);
 
         if (status > 0)
-            t->stamp = r->stamp;
+            update_target_stamps(r, t);
     }
 
     if (status <= 0) {
+        rollback_transaction(r, tx);
         restore_target_stamps(r, t, stamps);
-        if (tx_owner)
-            rollback_transaction(r);
+    }
+    else {
+        if (!commit_transaction(r, tx)) {
+            restore_target_stamps(r, t, stamps);
+            if (errno != 0)
+                status = -errno;
+            else
+                status = -EINVAL;
+        }
     }
 
     return status;
@@ -270,6 +334,15 @@ int update_target_by_id(mrp_resolver_t *r, int id)
 }
 
 
+int autoupdate_target(mrp_resolver_t *r)
+{
+    if (r->auto_update != NULL)
+        return mrp_resolver_update_targetl(r, r->auto_update->name, NULL);
+    else
+        return TRUE;
+}
+
+
 void dump_targets(mrp_resolver_t *r, FILE *fp)
 {
     int       i, j, idx;
index dbef40b..5c14796 100644 (file)
@@ -8,9 +8,11 @@
 int create_targets(mrp_resolver_t *r, yy_res_parser_t *parser);
 void destroy_targets(mrp_resolver_t *r);
 int compile_target_scripts(mrp_resolver_t *r);
+int prepare_target_scripts(mrp_resolver_t *r);
 
 int update_target_by_name(mrp_resolver_t *r, const char *name);
 int update_target_by_id(mrp_resolver_t *r, int id);
+int autoupdate_target(mrp_resolver_t *r);
 
 void dump_targets(mrp_resolver_t *r, FILE *fp);
 
index e6a68c5..691eded 100644 (file)
@@ -1,3 +1,5 @@
+auto-update-target all
+
 target all
     depends on video_route audio_route \
                audio_volume audio_cork audio_mute \
index 415cad4..0c6b832 100644 (file)
@@ -4,4 +4,6 @@ AM_CFLAGS       = $(WARNING_CFLAGS) -I$(top_builddir)
 # parser test
 parser_test_SOURCES = parser-test.c
 parser_test_CFLAGS  = $(AM_CFLAGS)
-parser_test_LDADD   = ../../libmurphy-resolver.la
+parser_test_LDADD   = ../../libmurphy-resolver.la   \
+                     ../../murphy-db/mqi/libmqi.la \
+                     ../../murphy-db/mdb/libmdb.la