summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/types.h1
-rw-r--r--include/urweb.h4
-rw-r--r--src/c/request.c16
-rw-r--r--src/c/urweb.c17
-rw-r--r--tests/transact.ur13
-rw-r--r--tests/transact.urp5
-rw-r--r--tests/transact.urs1
-rw-r--r--tests/transactional.c12
-rw-r--r--tests/transactional.h3
-rw-r--r--tests/transactional.urp4
-rw-r--r--tests/transactional.urs1
11 files changed, 59 insertions, 18 deletions
diff --git a/include/types.h b/include/types.h
index ac70c34f..e5edab96 100644
--- a/include/types.h
+++ b/include/types.h
@@ -51,6 +51,7 @@ typedef struct input *uw_input;
#define TIMES_MAX 100
typedef void (*uw_callback)(void *);
+typedef void (*uw_callback_with_retry)(void *, int will_retry);
typedef void (*uw_logger)(void*, const char *fmt, ...);
typedef struct {
diff --git a/include/urweb.h b/include/urweb.h
index 4816537a..f63b3f4c 100644
--- a/include/urweb.h
+++ b/include/urweb.h
@@ -39,7 +39,7 @@ failure_kind uw_begin(uw_context, char *path);
failure_kind uw_begin_onError(uw_context, char *msg);
void uw_login(uw_context);
void uw_commit(uw_context);
-int uw_rollback(uw_context);
+int uw_rollback(uw_context, int will_retry);
__attribute__((noreturn)) void uw_error(uw_context, failure_kind, const char *fmt, ...);
char *uw_error_message(uw_context);
@@ -228,7 +228,7 @@ uw_Basis_time uw_Basis_now(uw_context);
uw_Basis_time uw_Basis_minusSeconds(uw_context, uw_Basis_time, uw_Basis_int);
extern const uw_Basis_time uw_Basis_minTime;
-void uw_register_transactional(uw_context, void *data, uw_callback commit, uw_callback rollback, uw_callback free);
+void uw_register_transactional(uw_context, void *data, uw_callback commit, uw_callback rollback, uw_callback_with_retry free);
void uw_check_heap(uw_context, size_t extra);
char *uw_heap_front(uw_context);
diff --git a/src/c/request.c b/src/c/request.c
index 52006e85..ae46326d 100644
--- a/src/c/request.c
+++ b/src/c/request.c
@@ -19,8 +19,8 @@
void *memmem(const void *b1, size_t len1, const void *b2, size_t len2);
-static int try_rollback(uw_context ctx, void *logger_data, uw_logger log_error) {
- int r = uw_rollback(ctx);
+static int try_rollback(uw_context ctx, int will_retry, void *logger_data, uw_logger log_error) {
+ int r = uw_rollback(ctx, will_retry);
if (r) {
log_error(logger_data, "Error running SQL ROLLBACK\n");
@@ -102,13 +102,13 @@ void uw_request_init(uw_app *app, void *logger_data, uw_logger log_error, uw_log
for (fk = uw_initialize(ctx); fk == UNLIMITED_RETRY; fk = uw_initialize(ctx)) {
log_debug(logger_data, "Unlimited retry during init: %s\n", uw_error_message(ctx));
- uw_rollback(ctx);
+ uw_rollback(ctx, 1);
uw_reset(ctx);
}
if (fk != SUCCESS) {
log_error(logger_data, "Failed to initialize database! %s\n", uw_error_message(ctx));
- uw_rollback(ctx);
+ uw_rollback(ctx, 0);
exit(1);
}
@@ -403,7 +403,7 @@ request_result uw_request(uw_request_context rc, uw_context ctx,
else {
log_error(logger_data, "Fatal error (out of retries): %s\n", uw_error_message(ctx));
- try_rollback(ctx, logger_data, log_error);
+ try_rollback(ctx, 0, logger_data, log_error);
if (!had_error && uw_get_app(ctx)->on_error) {
had_error = 1;
@@ -424,7 +424,7 @@ request_result uw_request(uw_request_context rc, uw_context ctx,
else if (fk == FATAL) {
log_error(logger_data, "Fatal error: %s\n", uw_error_message(ctx));
- try_rollback(ctx, logger_data, log_error);
+ try_rollback(ctx, 0, logger_data, log_error);
if (uw_get_app(ctx)->on_error && !had_error) {
had_error = 1;
@@ -443,7 +443,7 @@ request_result uw_request(uw_request_context rc, uw_context ctx,
} else {
log_error(logger_data, "Unknown uw_handle return code!\n");
- try_rollback(ctx, logger_data, log_error);
+ try_rollback(ctx, 0, logger_data, log_error);
if (uw_get_app(ctx)->on_error && !had_error) {
had_error = 1;
@@ -458,7 +458,7 @@ request_result uw_request(uw_request_context rc, uw_context ctx,
}
}
- if (try_rollback(ctx, logger_data, log_error))
+ if (try_rollback(ctx, 1, logger_data, log_error))
return FAILED;
uw_reset_keep_request(ctx);
diff --git a/src/c/urweb.c b/src/c/urweb.c
index bdaa877f..91c6f6b3 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -390,7 +390,8 @@ typedef struct input {
typedef struct {
void *data;
- uw_callback commit, rollback, free;
+ uw_callback commit, rollback;
+ uw_callback_with_retry free;
} transactional;
typedef struct {
@@ -2902,7 +2903,7 @@ uw_unit uw_Basis_send(uw_context ctx, uw_Basis_channel chn, uw_Basis_string msg)
return uw_unit_v;
}
-int uw_rollback(uw_context ctx) {
+int uw_rollback(uw_context ctx, int will_retry) {
int i;
cleanup *cl;
@@ -2920,7 +2921,7 @@ int uw_rollback(uw_context ctx) {
for (i = ctx->used_transactionals-1; i >= 0; --i)
if (ctx->transactionals[i].free)
- ctx->transactionals[i].free(ctx->transactionals[i].data);
+ ctx->transactionals[i].free(ctx->transactionals[i].data, will_retry);
return ctx->app ? ctx->app->db_rollback(ctx) : 0;
}
@@ -2929,7 +2930,7 @@ void uw_commit(uw_context ctx) {
int i;
if (uw_has_error(ctx)) {
- uw_rollback(ctx);
+ uw_rollback(ctx, 0);
return;
}
@@ -2938,7 +2939,7 @@ void uw_commit(uw_context ctx) {
if (ctx->transactionals[i].commit) {
ctx->transactionals[i].commit(ctx->transactionals[i].data);
if (uw_has_error(ctx)) {
- uw_rollback(ctx);
+ uw_rollback(ctx, 0);
return;
}
}
@@ -2948,7 +2949,7 @@ void uw_commit(uw_context ctx) {
if (ctx->transactionals[i].commit) {
ctx->transactionals[i].commit(ctx->transactionals[i].data);
if (uw_has_error(ctx)) {
- uw_rollback(ctx);
+ uw_rollback(ctx, 0);
return;
}
}
@@ -2972,7 +2973,7 @@ void uw_commit(uw_context ctx) {
for (i = ctx->used_transactionals-1; i >= 0; --i)
if (ctx->transactionals[i].free)
- ctx->transactionals[i].free(ctx->transactionals[i].data);
+ ctx->transactionals[i].free(ctx->transactionals[i].data, 0);
// Splice script data into appropriate part of page
if (ctx->returning_indirectly || ctx->script_header[0] == 0) {
@@ -3012,7 +3013,7 @@ void uw_commit(uw_context ctx) {
size_t uw_transactionals_max = SIZE_MAX;
void uw_register_transactional(uw_context ctx, void *data, uw_callback commit, uw_callback rollback,
- uw_callback free) {
+ uw_callback_with_retry free) {
if (ctx->used_transactionals >= ctx->n_transactionals) {
if (ctx->used_transactionals+1 > uw_transactionals_max)
uw_error(ctx, FATAL, "Exceeded limit on number of transactionals");
diff --git a/tests/transact.ur b/tests/transact.ur
new file mode 100644
index 00000000..baf8ab94
--- /dev/null
+++ b/tests/transact.ur
@@ -0,0 +1,13 @@
+fun listHell n =
+ if n <= 0 then
+ []
+ else
+ n :: List.append (listHell (n-1)) (listHell (n-1))
+
+fun doit r =
+ Transactional.foo;
+ return <xml>{[listHell (readError r.N)]}</xml>
+
+fun main () = return <xml><body>
+ <form> <textbox{#N}/> <submit action={doit}/> </form>
+</body></xml>
diff --git a/tests/transact.urp b/tests/transact.urp
new file mode 100644
index 00000000..dcd84854
--- /dev/null
+++ b/tests/transact.urp
@@ -0,0 +1,5 @@
+library transactional
+rewrite all Transact/*
+
+$/list
+transact
diff --git a/tests/transact.urs b/tests/transact.urs
new file mode 100644
index 00000000..6ac44e0b
--- /dev/null
+++ b/tests/transact.urs
@@ -0,0 +1 @@
+val main : unit -> transaction page
diff --git a/tests/transactional.c b/tests/transactional.c
new file mode 100644
index 00000000..54e26874
--- /dev/null
+++ b/tests/transactional.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+#include "/usr/local/include/urweb/urweb.h"
+
+static void do_free(void *data, int will_retry) {
+ printf("will_retry = %d\n", will_retry);
+}
+
+uw_unit uw_Transactional_foo(uw_context ctx) {
+ printf("Registering....\n");
+ uw_register_transactional(ctx, NULL, NULL, NULL, do_free);
+}
diff --git a/tests/transactional.h b/tests/transactional.h
new file mode 100644
index 00000000..afb15327
--- /dev/null
+++ b/tests/transactional.h
@@ -0,0 +1,3 @@
+#include "/usr/local/include/urweb/types.h"
+
+uw_unit uw_Transactional_foo(uw_context);
diff --git a/tests/transactional.urp b/tests/transactional.urp
new file mode 100644
index 00000000..4ff1fea7
--- /dev/null
+++ b/tests/transactional.urp
@@ -0,0 +1,4 @@
+ffi transactional
+include transactional.h
+link transactional.o
+effectful Transactional.foo
diff --git a/tests/transactional.urs b/tests/transactional.urs
new file mode 100644
index 00000000..8dea9bca
--- /dev/null
+++ b/tests/transactional.urs
@@ -0,0 +1 @@
+val foo : transaction {}