# HG changeset patch # User Ziv Scully # Date 1445280142 14400 # Node ID 1e3ba868f8bf6f76584c7398f67598e11a78162d # Parent f7bc7c11a656e5fd07c758e2e998accad70750b8# Parent 74c7620023522503dd38dc2b9fc62d29a298db4c Merge. diff -r f7bc7c11a656 -r 1e3ba868f8bf CHANGELOG --- a/CHANGELOG Thu Oct 15 00:52:04 2015 -0400 +++ b/CHANGELOG Mon Oct 19 14:42:22 2015 -0400 @@ -1,3 +1,10 @@ +======== +20151018 +======== + +- Applications now reconnect to database server automatically after losing connection. +- Bug fixes and improvements to compatibility, documentation, and error messages + ======== 20150819 ======== diff -r f7bc7c11a656 -r 1e3ba868f8bf configure.ac --- a/configure.ac Thu Oct 15 00:52:04 2015 -0400 +++ b/configure.ac Mon Oct 19 14:42:22 2015 -0400 @@ -1,4 +1,4 @@ -AC_INIT([urweb], [20150819]) +AC_INIT([urweb], [20151018]) WORKING_VERSION=1 AC_USE_SYSTEM_EXTENSIONS diff -r f7bc7c11a656 -r 1e3ba868f8bf include/urweb/urweb_cpp.h --- a/include/urweb/urweb_cpp.h Thu Oct 15 00:52:04 2015 -0400 +++ b/include/urweb/urweb_cpp.h Mon Oct 19 14:42:22 2015 -0400 @@ -40,6 +40,7 @@ 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 -r f7bc7c11a656 -r 1e3ba868f8bf src/c/urweb.c --- a/src/c/urweb.c Thu Oct 15 00:52:04 2015 -0400 +++ b/src/c/urweb.c Mon Oct 19 14:42:22 2015 -0400 @@ -809,12 +809,37 @@ 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 -r f7bc7c11a656 -r 1e3ba868f8bf src/elisp/urweb-mode.el --- a/src/elisp/urweb-mode.el Thu Oct 15 00:52:04 2015 -0400 +++ b/src/elisp/urweb-mode.el Mon Oct 19 14:42:22 2015 -0400 @@ -246,7 +246,7 @@ ("\\<\\(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 @@ (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" "\\Major mode for editing Ur/Web code. This mode runs `urweb-mode-hook' just before exiting. \\{urweb-mode-map}" @@ -409,7 +413,7 @@ (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 -r f7bc7c11a656 -r 1e3ba868f8bf src/mysql.sml --- a/src/mysql.sml Thu Oct 15 00:52:04 2015 -0400 +++ b/src/mysql.sml Mon Oct 19 14:42:22 2015 -0400 @@ -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 @@ 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 @@ 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 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 @@ 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 -r f7bc7c11a656 -r 1e3ba868f8bf src/postgres.sml --- a/src/postgres.sml Thu Oct 15 00:52:04 2015 -0400 +++ b/src/postgres.sml Mon Oct 19 14:42:22 2015 -0400 @@ -617,7 +617,13 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -r f7bc7c11a656 -r 1e3ba868f8bf src/settings.sml --- a/src/settings.sml Thu Oct 15 00:52:04 2015 -0400 +++ b/src/settings.sml Mon Oct 19 14:42:22 2015 -0400 @@ -885,7 +885,7 @@ 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 ^ ")")