summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Ziv Scully <ziv@mit.edu>2015-10-19 14:42:22 -0400
committerGravatar Ziv Scully <ziv@mit.edu>2015-10-19 14:42:22 -0400
commit9d12f9199103b3b98b3e3990bbf586ee0fd34130 (patch)
treea7863db3f0823fa648f3af83da11fe081aea48d5
parentf425194d947691ceeaad9ec73fdc7c2c176ebfe3 (diff)
parent3256142dc01f7f173289a1910e726b662a877408 (diff)
Merge.
-rw-r--r--CHANGELOG7
-rw-r--r--configure.ac2
-rw-r--r--include/urweb/urweb_cpp.h1
-rw-r--r--src/c/urweb.c31
-rw-r--r--src/elisp/urweb-mode.el10
-rw-r--r--src/mysql.sml32
-rw-r--r--src/postgres.sml56
-rw-r--r--src/settings.sml2
8 files changed, 117 insertions, 24 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 02e9d754..1e87b778 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,4 +1,11 @@
========
+20151018
+========
+
+- Applications now reconnect to database server automatically after losing connection.
+- Bug fixes and improvements to compatibility, documentation, and error messages
+
+========
20150819
========
diff --git a/configure.ac b/configure.ac
index f074ccbf..451fee29 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT([urweb], [20150819])
+AC_INIT([urweb], [20151018])
WORKING_VERSION=1
AC_USE_SYSTEM_EXTENSIONS
diff --git a/include/urweb/urweb_cpp.h b/include/urweb/urweb_cpp.h
index 05e3e4a0..ab2a91c1 100644
--- a/include/urweb/urweb_cpp.h
+++ b/include/urweb/urweb_cpp.h
@@ -40,6 +40,7 @@ uw_loggers* uw_get_loggers(struct uw_context *ctx);
uw_loggers* uw_get_loggers(struct uw_context *ctx);
failure_kind uw_begin(struct uw_context *, char *path);
void uw_ensure_transaction(struct uw_context *);
+void uw_try_reconnecting_and_restarting(struct uw_context *);
failure_kind uw_begin_onError(struct uw_context *, char *msg);
void uw_login(struct uw_context *);
int uw_commit(struct uw_context *);
diff --git a/src/c/urweb.c b/src/c/urweb.c
index 957f158c..cc0eab06 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -809,12 +809,37 @@ failure_kind uw_begin(uw_context ctx, char *path) {
return r;
}
+static void uw_try_reconnecting(uw_context ctx) {
+ // Hm, error starting transaction.
+ // Maybe the database server died but has since come back up.
+ // Let's try starting from scratch.
+ if (ctx->db) {
+ ctx->app->db_close(ctx);
+ ctx->db = NULL;
+ }
+ ctx->app->db_init(ctx);
+
+ if (!ctx->db)
+ uw_error(ctx, FATAL, "Error reopening database connection");
+}
+
+void uw_try_reconnecting_and_restarting(uw_context ctx) {
+ uw_try_reconnecting(ctx);
+ uw_error(ctx, BOUNDED_RETRY, "Restarting transaction after fixing database connection");
+}
+
void uw_ensure_transaction(uw_context ctx) {
if (!ctx->transaction_started && !ctx->at_most_one_query) {
- if (ctx->app->db_begin(ctx, ctx->could_write_db))
- uw_error(ctx, BOUNDED_RETRY, "Error running SQL BEGIN");
+ if (!ctx->db || ctx->app->db_begin(ctx, ctx->could_write_db)) {
+ uw_try_reconnecting(ctx);
+
+ if (ctx->app->db_begin(ctx, ctx->could_write_db))
+ uw_error(ctx, FATAL, "Error running SQL BEGIN");
+ }
+
ctx->transaction_started = 1;
- }
+ } else if (ctx->at_most_one_query && !ctx->db)
+ uw_try_reconnecting(ctx);
}
uw_Basis_client uw_Basis_self(uw_context ctx) {
diff --git a/src/elisp/urweb-mode.el b/src/elisp/urweb-mode.el
index 5eb36bc4..bc71a052 100644
--- a/src/elisp/urweb-mode.el
+++ b/src/elisp/urweb-mode.el
@@ -246,7 +246,7 @@ See doc for the variable `urweb-mode-info'."
("\\<\\(signature\\)\\s-+\\(\\sw+\\)"
(1 font-lock-keyword-face)
(2 (amAttribute font-lock-interface-def-face)))
-
+
(,urweb-keywords-regexp . font-lock-keyword-face)
(,urweb-sql-keywords-regexp . font-lock-sql-face)
(,urweb-cident-regexp . font-lock-cvariable-face))
@@ -377,7 +377,11 @@ See doc for the variable `urweb-mode-info'."
(add-to-list 'auto-mode-alist '("\\.urs?\\'" . urweb-mode))
;;;###autoload
-(define-derived-mode urweb-mode fundamental-mode "Ur/Web"
+(defalias 'urweb-mode-derived-from
+ (if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode))
+
+;;;###autoload
+(define-derived-mode urweb-mode urweb-mode-derived-from "Ur/Web"
"\\<urweb-mode-map>Major mode for editing Ur/Web code.
This mode runs `urweb-mode-hook' just before exiting.
\\{urweb-mode-map}"
@@ -409,7 +413,7 @@ This mode runs `urweb-mode-hook' just before exiting.
(set-syntax-table urweb-mode-syntax-table)
(setq local-abbrev-table urweb-mode-abbrev-table)
;; A paragraph is separated by blank lines or ^L only.
-
+
(set (make-local-variable 'indent-line-function) 'urweb-indent-line)
(set (make-local-variable 'comment-start) "(* ")
(set (make-local-variable 'comment-end) " *)")
diff --git a/src/mysql.sml b/src/mysql.sml
index bb654fee..692be0a2 100644
--- a/src/mysql.sml
+++ b/src/mysql.sml
@@ -1,4 +1,4 @@
-(* Copyright (c) 2009-2010, Adam Chlipala
+(* Copyright (c) 2009-2010, 2015, Adam Chlipala
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -546,7 +546,7 @@ fun init {dbstring, prepared = ss, tables, views, sequences} =
newline,
string "mysql_close(mysql);",
newline,
- string "uw_error(ctx, BOUNDED_RETRY, ",
+ string "uw_error(ctx, FATAL, ",
string "\"Connection to MySQL server failed: %s\", msg);"],
newline,
string "}",
@@ -861,11 +861,17 @@ fun queryCommon {loc, query, cols, doCols} =
end) cols,
newline,
- string "if (mysql_stmt_reset(stmt)) uw_error(ctx, FATAL, \"",
- string (ErrorMsg.spanToString loc),
- string ": Error reseting statement: %s\\n%s\", ",
- query,
- string ", mysql_error(conn->conn));",
+ string "if (mysql_stmt_reset(stmt)) {",
+ box [newline,
+ string "if (mysql_errno(conn->conn) == 2006) uw_try_reconnecting_and_restarting(ctx);",
+ newline,
+ string "uw_error(ctx, FATAL, \"",
+ string (ErrorMsg.spanToString loc),
+ string ": Error reseting statement: %s\\n%s\", ",
+ query,
+ string ", mysql_error(conn->conn));",
+ newline],
+ string "}",
newline,
newline,
@@ -1233,7 +1239,9 @@ fun queryPrepared {loc, id, query, inputs, cols, doCols, nested} =
fun dmlCommon {loc, dml, mode} =
box [string "if (mysql_stmt_execute(stmt)) {",
- box [string "if (mysql_errno(conn->conn) == 1213)",
+ box [string "if (mysql_errno(conn->conn) == 2006) uw_try_reconnecting_and_restarting(ctx);",
+ newline,
+ string "if (mysql_errno(conn->conn) == 1213)",
newline,
box [string "uw_error(ctx, UNLIMITED_RETRY, \"Deadlock detected\");",
newline],
@@ -1540,7 +1548,13 @@ fun nextval {loc, seqE, seqName} =
newline,
newline,
- string "if (mysql_query(conn->conn, insert)) uw_error(ctx, FATAL, \"'nextval' INSERT failed\");",
+ string "if (mysql_query(conn->conn, insert)) {",
+ box [newline,
+ string "if (mysql_errno(conn->conn) == 2006) uw_try_reconnecting_and_restarting(ctx);",
+ newline,
+ string "uw_error(ctx, FATAL, \"'nextval' INSERT failed\");",
+ newline],
+ string "}",
newline,
string "n = mysql_insert_id(conn->conn);",
newline,
diff --git a/src/postgres.sml b/src/postgres.sml
index 6df0331a..bc1238c0 100644
--- a/src/postgres.sml
+++ b/src/postgres.sml
@@ -617,7 +617,13 @@ fun queryCommon {loc, query, cols, doCols} =
newline,
newline,
- string "if (res == NULL) uw_error(ctx, FATAL, \"Out of memory allocating query result.\");",
+ string "if (res == NULL) {",
+ box [newline,
+ string "uw_try_reconnecting_and_restarting(ctx);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Can't allocate query result; database server may be down.\");",
+ newline],
+ string "}",
newline,
newline,
@@ -782,7 +788,13 @@ fun queryPrepared {loc, id, query, inputs, cols, doCols, nested = _} =
string "\""]}]
fun dmlCommon {loc, dml, mode} =
- box [string "if (res == NULL) uw_error(ctx, FATAL, \"Out of memory allocating DML result.\");",
+ box [string "if (res == NULL) {",
+ box [newline,
+ string "uw_try_reconnecting_and_restarting(ctx);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Can't allocate DML result; database server may be down.\");",
+ newline],
+ string "}",
newline,
newline,
@@ -818,7 +830,13 @@ fun dmlCommon {loc, dml, mode} =
string "res = PQexec(conn, \"ROLLBACK TO s\");",
newline,
- string "if (res == NULL) uw_error(ctx, FATAL, \"Out of memory allocating DML result.\");",
+ string "if (res == NULL) {",
+ box [newline,
+ string "uw_try_reconnecting_and_restarting(ctx);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Can't allocate DML ROLLBACK result; database server may be down.\");",
+ newline],
+ string "}",
newline,
newline,
@@ -851,7 +869,13 @@ fun dmlCommon {loc, dml, mode} =
newline,
string "res = PQexec(conn, \"RELEASE s\");",
newline,
- string "if (res == NULL) uw_error(ctx, FATAL, \"Out of memory allocating DML result.\");",
+ string "if (res == NULL) {",
+ box [newline,
+ string "uw_try_reconnecting_and_restarting(ctx);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Can't allocate DML RELEASE result; database server may be down.\");",
+ newline],
+ string "}",
newline,
newline,
@@ -877,7 +901,13 @@ fun makeSavepoint mode =
Error => box []
| None => box [string "res = PQexec(conn, \"SAVEPOINT s\");",
newline,
- string "if (res == NULL) uw_error(ctx, FATAL, \"Out of memory allocating DML result.\");",
+ string "if (res == NULL) {",
+ box [newline,
+ string "uw_try_reconnecting_and_restarting(ctx);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Can't allocate DML SAVEPOINT result; database server may be down.\");",
+ newline],
+ string "}",
newline,
newline,
string "if (PQresultStatus(res) != PGRES_COMMAND_OK) {",
@@ -938,7 +968,13 @@ fun dmlPrepared {loc, id, dml, inputs, mode} =
string "\""], mode = mode}]
fun nextvalCommon {loc, query} =
- box [string "if (res == NULL) uw_error(ctx, FATAL, \"Out of memory allocating nextval result.\");",
+ box [string "if (res == NULL) {",
+ box [newline,
+ string "uw_try_reconnecting_and_restarting(ctx);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Can't allocate NEXTVAL result; database server may be down.\");",
+ newline],
+ string "}",
newline,
newline,
@@ -1020,7 +1056,13 @@ fun nextvalPrepared {loc, id, query} =
string "\""]}]
fun setvalCommon {loc, query} =
- box [string "if (res == NULL) uw_error(ctx, FATAL, \"Out of memory allocating setval result.\");",
+ box [string "if (res == NULL) {",
+ box [newline,
+ string "uw_try_reconnecting_and_restarting(ctx);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Can't allocate SETVAL result; database server may be down.\");",
+ newline],
+ string "}",
newline,
newline,
diff --git a/src/settings.sml b/src/settings.sml
index ecf353cd..3694e1f3 100644
--- a/src/settings.sml
+++ b/src/settings.sml
@@ -885,7 +885,7 @@ fun addFile {Uri, LoadFromFilename} =
in
case SM.find (!files, Uri) of
SOME (path', _) =>
- if path' = path then
+ if OS.Path.mkCanonical path' = OS.Path.mkCanonical path then
()
else
ErrorMsg.error ("Two different files requested for URI " ^ Uri ^ " ( " ^ path' ^ " vs. " ^ path ^ ")")