changeset 771:eac1974924bb

FFI transactionals
author Adam Chlipala <adamc@hcoop.net>
date Sat, 02 May 2009 18:41:21 -0400
parents c125df6fabfc
children 8ed1261f838c
files include/types.h include/urweb.h src/c/urweb.c tests/cffi.ur tests/clib.urp tests/test.c tests/test.h tests/test.urs
diffstat 8 files changed, 89 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/include/types.h	Sat May 02 18:20:15 2009 -0400
+++ b/include/types.h	Sat May 02 18:41:21 2009 -0400
@@ -45,4 +45,6 @@
 #define FLOATS_MAX 100
 #define TIMES_MAX 100
 
+typedef void (*uw_callback)(void *);
+
 #endif
--- a/include/urweb.h	Sat May 02 18:20:15 2009 -0400
+++ b/include/urweb.h	Sat May 02 18:41:21 2009 -0400
@@ -183,4 +183,6 @@
 
 __attribute__((noreturn)) void uw_return_blob(uw_context, uw_Basis_blob, uw_Basis_string mimeType);
 
+void uw_register_transactional(uw_context, void *data, uw_callback commit, uw_callback rollback, uw_callback free);
+
 #endif
--- a/src/c/urweb.c	Sat May 02 18:20:15 2009 -0400
+++ b/src/c/urweb.c	Sat May 02 18:41:21 2009 -0400
@@ -304,6 +304,11 @@
   } data;
 } input;
 
+typedef struct {
+  void *data;
+  uw_callback commit, rollback, free;
+} transactional;
+
 struct uw_context {
   char *headers, *headers_end;
 
@@ -332,6 +337,9 @@
 
   client *client;
 
+  transactional *transactionals;
+  size_t n_transactionals, used_transactionals;
+
   char error_message[ERROR_BUF_LEN];
 };
 
@@ -377,6 +385,9 @@
 
   ctx->error_message[0] = 0;
 
+  ctx->transactionals = malloc(0);
+  ctx->n_transactionals = ctx->used_transactionals = 0;
+
   return ctx;
 }
 
@@ -398,6 +409,7 @@
   free(ctx->inputs);
   free(ctx->subinputs);
   free(ctx->cleanup);
+  free(ctx->transactionals);
 
   for (i = 0; i < ctx->n_deltas; ++i)
     buf_free(&ctx->deltas[i].msgs);
@@ -419,6 +431,7 @@
   ctx->used_deltas = 0;
   ctx->client = NULL;
   ctx->cur_container = NULL;
+  ctx->used_transactionals = 0;
 }
 
 void uw_reset_keep_request(uw_context ctx) {
@@ -2339,7 +2352,15 @@
 void uw_commit(uw_context ctx) {
   unsigned i;
 
-  if (uw_db_commit(ctx)) 
+  for (i = 0; i < ctx->used_transactionals; ++i)
+    if (ctx->transactionals[i].rollback != NULL)
+      ctx->transactionals[i].commit(ctx->transactionals[i].data);
+
+  for (i = 0; i < ctx->used_transactionals; ++i)
+    if (ctx->transactionals[i].rollback == NULL)
+      ctx->transactionals[i].commit(ctx->transactionals[i].data);
+
+  if (uw_db_commit(ctx))
     uw_error(ctx, FATAL, "Error running SQL COMMIT");
 
   for (i = 0; i < ctx->used_deltas; ++i) {
@@ -2353,15 +2374,43 @@
 
   if (ctx->client)
     release_client(ctx->client);
+
+  for (i = 0; i < ctx->used_transactionals; ++i)
+    ctx->transactionals[i].free(ctx->transactionals[i].data);
 }
 
 int uw_rollback(uw_context ctx) {
+  size_t i;
+
   if (ctx->client)
     release_client(ctx->client);
 
+  for (i = 0; i < ctx->used_transactionals; ++i)
+    if (ctx->transactionals[i].rollback != NULL)
+      ctx->transactionals[i].rollback(ctx->transactionals[i].data);
+
+  for (i = 0; i < ctx->used_transactionals; ++i)
+    ctx->transactionals[i].free(ctx->transactionals[i].data);
+
   return uw_db_rollback(ctx);
 }
 
+void uw_register_transactional(uw_context ctx, void *data, uw_callback commit, uw_callback rollback,
+                               uw_callback free) {
+  if (commit == NULL)
+    uw_error(ctx, FATAL, "uw_register_transactional: NULL commit callback");
+
+  if (ctx->used_transactionals >= ctx->n_transactionals) {
+    ctx->transactionals = realloc(ctx->transactionals, ctx->used_transactionals+1);
+    ++ctx->n_transactionals;
+  }
+
+  ctx->transactionals[ctx->used_transactionals].data = data;
+  ctx->transactionals[ctx->used_transactionals].commit = commit;
+  ctx->transactionals[ctx->used_transactionals].rollback = rollback;
+  ctx->transactionals[ctx->used_transactionals++].free = free;
+}
+
 
 // "Garbage collection"
 
--- a/tests/cffi.ur	Sat May 02 18:20:15 2009 -0400
+++ b/tests/cffi.ur	Sat May 02 18:41:21 2009 -0400
@@ -8,7 +8,22 @@
     <button value="Either" onclick={Test.print}/>
   </body></xml>
 
+fun xact () =
+  Test.transactional;
+  return <xml><body>
+    All good.
+  </body></xml>
+
+fun xact2 () =
+  Test.transactional;
+  error <xml>Failure</xml>;
+  return <xml><body>
+    All gooder.
+  </body></xml>
+
 fun main () = return <xml><body>
   {[Test.out (Test.frob (Test.create "Hello ") "world!")]}
   <form><submit action={effect}/></form>
+  <form><submit action={xact}/></form>
+  <form><submit action={xact2}/></form>
 </body></xml>
--- a/tests/clib.urp	Sat May 02 18:20:15 2009 -0400
+++ b/tests/clib.urp	Sat May 02 18:41:21 2009 -0400
@@ -5,5 +5,6 @@
 effectful Test.print
 serverOnly Test.foo
 clientOnly Test.bar
+effectful Test.transactional
 jsFunc Test.print=print
 jsFunc Test.bar=bar
--- a/tests/test.c	Sat May 02 18:20:15 2009 -0400
+++ b/tests/test.c	Sat May 02 18:41:21 2009 -0400
@@ -25,3 +25,18 @@
   printf("FOO!\n");
   return uw_unit_v;
 }
+
+static void commit(void *data) {
+  printf("Commit: %s\n", data);
+}
+static void rollback(void *data) {
+  printf("Rollback: %s\n", data);
+}
+static void free(void *data) {
+  printf("Free: %s\n", data);
+}
+
+uw_Basis_unit uw_Test_transactional(uw_context ctx) {
+  uw_register_transactional(ctx, "Beppo", commit, rollback, free);
+  return uw_unit_v;
+}
--- a/tests/test.h	Sat May 02 18:20:15 2009 -0400
+++ b/tests/test.h	Sat May 02 18:41:21 2009 -0400
@@ -8,3 +8,5 @@
 
 uw_Basis_unit uw_Test_print(uw_context);
 uw_Basis_unit uw_Test_foo(uw_context);
+
+uw_Basis_unit uw_Test_transactional(uw_context);
--- a/tests/test.urs	Sat May 02 18:20:15 2009 -0400
+++ b/tests/test.urs	Sat May 02 18:41:21 2009 -0400
@@ -7,3 +7,5 @@
 
 val foo : transaction unit
 val bar : string -> transaction unit
+
+val transactional : transaction unit