Mercurial > urweb
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; +}