diff --git a/libc3/env.c b/libc3/env.c
index 80982a5..e07c93c 100644
--- a/libc3/env.c
+++ b/libc3/env.c
@@ -34,6 +34,7 @@
#include "error_handler.h"
#include "facts.h"
#include "facts_cursor.h"
+#include "facts_transaction.h"
#include "facts_with.h"
#include "facts_with_cursor.h"
#include "file.h"
@@ -1070,8 +1071,11 @@ bool env_eval_ident (s_env *env, const s_ident *ident, s_tag *dest)
s_ident tmp_ident;
assert(env);
assert(ident);
- if (! (tag = env_frames_get(env, ident->sym)) &&
- env_ident_resolve_module(env, ident, &tmp_ident) &&
+ if ((tag = env_frames_get(env, ident->sym))) {
+ tag_init_copy(dest, tag);
+ return true;
+ }
+ if (env_ident_resolve_module(env, ident, &tmp_ident) &&
! (tag = env_ident_get(env, &tmp_ident, &tmp))) {
err_write_1("env_eval_ident: unbound ident: ");
err_inspect_ident(ident);
@@ -1079,7 +1083,7 @@ bool env_eval_ident (s_env *env, const s_ident *ident, s_tag *dest)
assert(! "env_eval_ident: unbound ident");
return false;
}
- tag_init_copy(dest, tag);
+ *dest = *tag;
return true;
}
@@ -2164,8 +2168,10 @@ bool env_module_load (s_env *env, const s_sym *module)
goto rollback;
tag_clean(&tag_time);
env_module_is_loading_set(env, module, false);
+ facts_transaction_end(&env->facts, &transaction);
return true;
rollback:
+ str_clean(&path);
if (! facts_transaction_rollback(&env->facts, &transaction)) {
abort();
return false;
diff --git a/libc3/facts.c b/libc3/facts.c
index a0962ec..9e61ad4 100644
--- a/libc3/facts.c
+++ b/libc3/facts.c
@@ -286,21 +286,22 @@ s_facts * facts_init (s_facts *facts)
{
const u8 max_height = 10;
const double spacing = 2.7;
+ s_facts tmp = {0};
assert(facts);
- set_init__tag(&facts->tags, 1024);
- set_init__fact(&facts->facts, 1024);
- facts->index_spo = skiplist_new__fact(max_height, spacing);
- assert(facts->index_spo);
- facts->index_spo->compare = compare_fact;
- facts->index_pos = skiplist_new__fact(max_height, spacing);
- assert(facts->index_pos);
- facts->index_pos->compare = compare_fact_pos;
- facts->index_osp = skiplist_new__fact(max_height, spacing);
- assert(facts->index_osp);
- facts->index_osp->compare = compare_fact_osp;
- facts->log = NULL;
+ set_init__tag(&tmp.tags, 1024);
+ set_init__fact(&tmp.facts, 1024);
+ tmp.index_spo = skiplist_new__fact(max_height, spacing);
+ assert(tmp.index_spo);
+ tmp.index_spo->compare = compare_fact;
+ tmp.index_pos = skiplist_new__fact(max_height, spacing);
+ assert(tmp.index_pos);
+ tmp.index_pos->compare = compare_fact_pos;
+ tmp.index_osp = skiplist_new__fact(max_height, spacing);
+ assert(tmp.index_osp);
+ tmp.index_osp->compare = compare_fact_osp;
facts_lock_init(facts);
- facts->next_id = 1;
+ tmp.next_id = 1;
+ *facts = tmp;
return facts;
}
@@ -812,7 +813,7 @@ const s_fact * facts_replace_tags (s_facts *facts, const s_tag *subject,
}
facts_cursor_clean(&cursor);
fact = facts_add_tags(facts, subject, predicate, object);
- facts_transaction_clean(&transaction);
+ facts_transaction_end(facts, &transaction);
facts_lock_unlock_w(facts);
return fact;
}
diff --git a/libc3/facts_transaction.c b/libc3/facts_transaction.c
index 7e663a0..70adcef 100644
--- a/libc3/facts_transaction.c
+++ b/libc3/facts_transaction.c
@@ -12,10 +12,12 @@
*/
#include <stdlib.h>
#include "assert.h"
+#include "fact.h"
#include "fact_action.h"
#include "facts.h"
#include "facts_transaction.h"
#include "list.h"
+#include "types.h"
s_facts_transaction * facts_transaction_clean
(s_facts_transaction *transaction)
@@ -25,43 +27,89 @@ s_facts_transaction * facts_transaction_clean
return transaction->next;
}
-s_facts * facts_transaction_rollback
-(s_facts *facts, const s_facts_transaction *transaction)
+void facts_transaction_end (s_facts *facts,
+ s_facts_transaction *transaction)
+{
+ assert(facts);
+ assert(transaction);
+ if (facts->transaction != transaction) {
+ err_puts("facts_transaction_end: transaction mismatch");
+ assert(! "facts_transaction_end: transaction mismatch");
+ abort();
+ }
+ facts->transaction = facts_transaction_clean(transaction);
+}
+
+bool facts_transaction_find (s_facts *facts,
+ const s_facts_transaction *transaction)
{
- bool b;
- s_fact_action *log;
const s_facts_transaction *t;
t = facts->transaction;
while (t) {
if (t == transaction)
- goto rollback;
+ return true;
t = t->next;
}
- err_puts("facts_transaction_rollback: transaction not found");
- assert(! "facts_transaction_rollback: transaction not found");
- return NULL;
- rollback:
+ err_puts("facts_transaction_find: transaction not found");
+ assert(! "facts_transaction_find: transaction not found");
+ return false;
+}
+
+s_facts_transaction * facts_transaction_init
+(s_facts_transaction *transaction)
+{
+ s_facts_transaction tmp = {0};
+ *transaction = tmp;
+ return transaction;
+}
+
+s_facts * facts_transaction_rollback
+(s_facts *facts, const s_facts_transaction *transaction)
+{
+ bool b;
+ s_fact fact;
+ s_fact_action *log;
+ s_facts_transaction *t;
+ if (! facts_transaction_find(facts, transaction))
+ return NULL;
+ t = facts->transaction;
while (t) {
log = t->log;
while (log) {
- if (log->remove) {
- if (! facts_add_fact(facts, &log->fact))
- return NULL;
- }
- else {
+ switch (log->action) {
+ case FACT_ACTION_ADD:
if (! facts_remove_fact(facts, &log->fact, &b) ||
- ! b)
- return NULL;
+ ! b) {
+ abort();
+ return NULL;
+ }
+ break;
+ case FACT_ACTION_REMOVE:
+ if (! facts_add_fact(facts, &log->fact)) {
+ abort();
+ return NULL;
+ }
+ break;
+ case FACT_ACTION_REPLACE:
+ fact_init(&fact, log->fact.subject, log->fact.predicate,
+ &log->object);
+ if (! facts_replace_fact(facts, &fact)) {
+ abort();
+ return NULL;
+ }
}
log = log->next;
}
- if (t == transaction)
+ if (t == transaction) {
+ facts_transaction_end(facts, t);
return facts;
- t = t->next;
+ }
+ facts_transaction_end(facts, t);
+ t = facts->transaction;
}
- err_puts("facts_transaction_rollback: unknown error");
- assert(! "facts_transaction_rollback: unknown error");
- exit(1);
+ err_puts("facts_transaction_rollback: no transaction in facts");
+ assert(! "facts_transaction_rollback: no transaction in facts");
+ abort();
return NULL;
}
diff --git a/libc3/facts_transaction.h b/libc3/facts_transaction.h
index fb139a0..372eb2c 100644
--- a/libc3/facts_transaction.h
+++ b/libc3/facts_transaction.h
@@ -15,14 +15,19 @@
#include "types.h"
-/* Stack allocation compatible functions */
+/* Stack allocation compatible functions, call
+ facts_transaction_clean after use. */
s_facts_transaction * facts_transaction_clean
(s_facts_transaction *transaction);
+s_facts_transaction * facts_transaction_init
+(s_facts_transaction *transaction);
/* Operators. */
-s_facts * facts_transaction_rollback
+void facts_transaction_end
+(s_facts *facts, s_facts_transaction *transaction);
+s_facts * facts_transaction_rollback
(s_facts *facts, const s_facts_transaction *transaction);
-void facts_transaction_start
+void facts_transaction_start
(s_facts *facts, s_facts_transaction *transaction);
#endif /* LIBC3_FACTS_TRANSACTION_H */
diff --git a/libc3/types.h b/libc3/types.h
index 86f7579..c7c875d 100644
--- a/libc3/types.h
+++ b/libc3/types.h
@@ -89,6 +89,12 @@ typedef enum {
} e_bool;
typedef enum {
+ FACT_ACTION_ADD,
+ FACT_ACTION_REMOVE,
+ FACT_ACTION_REPLACE
+} e_fact_action;
+
+typedef enum {
TAG_VOID = 0,
TAG_ARRAY,
TAG_BLOCK,
@@ -344,12 +350,6 @@ struct buf {
uw wpos;
};
-struct fact_action {
- bool remove;
- s_fact fact;
- s_fact_action *next;
-};
-
struct facts_spec_cursor {
p_facts_spec spec;
const s_tag *subject;
@@ -524,6 +524,13 @@ struct error_handler
s_tag tag;
};
+struct fact_action {
+ e_fact_action action;
+ s_fact fact;
+ s_tag object;
+ s_fact_action *next;
+};
+
struct fact_w {
s_tag subject;
s_tag predicate;