changeset 1131:94e83c5533d2

Handling errors during commit
author Adam Chlipala <adamc@hcoop.net>
date Tue, 26 Jan 2010 14:59:19 -0500
parents 67d875c8ac71
children d4cd54a4ea06
files Makefile.in include/urweb.h lib/ur/string.ur lib/ur/string.urs src/c/request.c src/c/urweb.c
diffstat 6 files changed, 81 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.in	Tue Jan 26 09:04:55 2010 -0500
+++ b/Makefile.in	Tue Jan 26 14:59:19 2010 -0500
@@ -92,6 +92,10 @@
 	libtool --silent --mode=install install -c lib/c/liburweb_http.la $(LIB)/../liburweb_http.la
 	libtool --silent --mode=install install -c lib/c/liburweb_cgi.la $(LIB)/../liburweb_cgi.la
 	libtool --silent --mode=install install -c lib/c/liburweb_fastcgi.la $(LIB)/../liburweb_fastcgi.la
+	libtool --silent --finish $(LIB)/../liburweb.la
+	libtool --silent --finish $(LIB)/../liburweb_http.la
+	libtool --silent --finish $(LIB)/../liburweb_cgi.la
+	libtool --silent --finish $(LIB)/../liburweb_fastcgi.la
 
 package:
 	hg archive -t tgz -X tests /tmp/urweb.tgz
--- a/include/urweb.h	Tue Jan 26 09:04:55 2010 -0500
+++ b/include/urweb.h	Tue Jan 26 14:59:19 2010 -0500
@@ -42,7 +42,8 @@
 
 __attribute__((noreturn)) void uw_error(uw_context, failure_kind, const char *fmt, ...);
 char *uw_error_message(uw_context);
-void uw_set_error_message(uw_context, const char *);
+void uw_set_error_message(uw_context, const char *fmt, ...);
+int uw_has_error(uw_context);
 void uw_push_cleanup(uw_context, void (*func)(void *), void *arg);
 void uw_pop_cleanup(uw_context);
 
--- a/lib/ur/string.ur	Tue Jan 26 09:04:55 2010 -0500
+++ b/lib/ur/string.ur	Tue Jan 26 14:59:19 2010 -0500
@@ -38,6 +38,17 @@
         al 0
     end
 
+fun mp f s =
+    let
+        fun mp' i acc =
+            if i < 0 then
+                acc
+            else
+                mp' (i - 1) (str (f (sub s i)) ^ acc)
+    in
+        mp' (length s - 1) ""
+    end
+
 fun newlines [ctx] [[Body] ~ ctx] s : xml ([Body] ++ ctx) [] [] =
     case split s #"\n" of
         None => cdata s
--- a/lib/ur/string.urs	Tue Jan 26 09:04:55 2010 -0500
+++ b/lib/ur/string.urs	Tue Jan 26 14:59:19 2010 -0500
@@ -20,5 +20,6 @@
 val msplit : {Haystack : t, Needle : t} -> option (string * char * string)
 
 val all : (char -> bool) -> string -> bool
+val mp : (char -> char) -> string -> string
 
 val newlines : ctx ::: {Unit} -> [[Body] ~ ctx] => string -> xml ([Body] ++ ctx) [] []
--- a/src/c/request.c	Tue Jan 26 09:04:55 2010 -0500
+++ b/src/c/request.c	Tue Jan 26 14:59:19 2010 -0500
@@ -339,7 +339,20 @@
     fk = uw_begin(ctx, rc->path_copy);
     if (fk == SUCCESS || fk == RETURN_INDIRECTLY) {
       uw_commit(ctx);
-      return SERVED;
+      if (uw_has_error(ctx)) {
+        log_error(logger_data, "Fatal error: %s\n", uw_error_message(ctx));
+
+        uw_reset_keep_error_message(ctx);
+        on_failure(ctx);
+        uw_write_header(ctx, "Content-type: text/html\r\n");
+        uw_write(ctx, "<html><head><title>Fatal Error</title></head><body>");
+        uw_write(ctx, "Fatal error: ");
+        uw_write(ctx, uw_error_message(ctx));
+        uw_write(ctx, "\n</body></html>");
+        
+        return FAILED;
+      } else
+        return SERVED;
     } else if (fk == BOUNDED_RETRY) {
       if (retries_left) {
         log_debug(logger_data, "Error triggers bounded retry: %s\n", uw_error_message(ctx));
--- a/src/c/urweb.c	Tue Jan 26 09:04:55 2010 -0500
+++ b/src/c/urweb.c	Tue Jan 26 14:59:19 2010 -0500
@@ -613,6 +613,10 @@
   vsnprintf(ctx->error_message, ERROR_BUF_LEN, fmt, ap);
 }
 
+int uw_has_error(uw_context ctx) {
+  return ctx->error_message[0] != 0;
+}
+
 __attribute__((noreturn)) void uw_error(uw_context ctx, failure_kind fk, const char *fmt, ...) {
   cleanup *cl;
 
@@ -2888,21 +2892,61 @@
   return uw_unit_v;
 }
 
+int uw_rollback(uw_context ctx) {
+  int i;
+  cleanup *cl;
+
+  if (ctx->client)
+    release_client(ctx->client);
+
+  for (cl = ctx->cleanup; cl < ctx->cleanup_front; ++cl)
+    cl->func(cl->arg);
+
+  ctx->cleanup_front = ctx->cleanup;
+
+  for (i = ctx->used_transactionals-1; i >= 0; --i)
+    if (ctx->transactionals[i].rollback != NULL)
+      ctx->transactionals[i].rollback(ctx->transactionals[i].data);
+
+  for (i = ctx->used_transactionals-1; i >= 0; --i)
+    if (ctx->transactionals[i].free)
+      ctx->transactionals[i].free(ctx->transactionals[i].data);
+
+  return ctx->app->db_rollback(ctx);
+}
+
 void uw_commit(uw_context ctx) {
   int i;
 
+  if (uw_has_error(ctx)) {
+    uw_rollback(ctx);
+    return;
+  }
+
   for (i = ctx->used_transactionals-1; i >= 0; --i)
     if (ctx->transactionals[i].rollback != NULL)
-      if (ctx->transactionals[i].commit)
+      if (ctx->transactionals[i].commit) {
         ctx->transactionals[i].commit(ctx->transactionals[i].data);
+        if (uw_has_error(ctx)) {
+          uw_rollback(ctx);
+          return;
+        }
+      }
 
   for (i = ctx->used_transactionals-1; i >= 0; --i)
     if (ctx->transactionals[i].rollback == NULL)
-      if (ctx->transactionals[i].commit)
+      if (ctx->transactionals[i].commit) {
         ctx->transactionals[i].commit(ctx->transactionals[i].data);
-
-  if (ctx->app->db_commit(ctx))
-    uw_error(ctx, FATAL, "Error running SQL COMMIT");
+        if (uw_has_error(ctx)) {
+          uw_rollback(ctx);
+          return;
+        }
+      }
+
+  if (ctx->app->db_commit(ctx)) {
+    uw_set_error_message(ctx, "Error running SQL COMMIT");
+    return;
+  }
 
   for (i = 0; i < ctx->used_deltas; ++i) {
     delta *d = &ctx->deltas[i];
@@ -2954,28 +2998,6 @@
   }
 }
 
-int uw_rollback(uw_context ctx) {
-  int i;
-  cleanup *cl;
-
-  if (ctx->client)
-    release_client(ctx->client);
-
-  for (cl = ctx->cleanup; cl < ctx->cleanup_front; ++cl)
-    cl->func(cl->arg);
-
-  ctx->cleanup_front = ctx->cleanup;
-
-  for (i = ctx->used_transactionals-1; i >= 0; --i)
-    if (ctx->transactionals[i].rollback != NULL)
-      ctx->transactionals[i].rollback(ctx->transactionals[i].data);
-
-  for (i = ctx->used_transactionals-1; i >= 0; --i)
-    if (ctx->transactionals[i].free)
-      ctx->transactionals[i].free(ctx->transactionals[i].data);
-
-  return ctx->app->db_rollback(ctx);
-}
 
 size_t uw_transactionals_max = SIZE_MAX;