# HG changeset patch # User Adam Chlipala # Date 1387814357 0 # Node ID d02c1a0d8082d8906d6c823621aa8435d12f03cc # Parent 94f9570671f06f056c93e26f70a22582b106c155 Proper handling of serialization failures during SQL COMMIT diff -r 94f9570671f0 -r d02c1a0d8082 include/urweb/urweb_cpp.h --- a/include/urweb/urweb_cpp.h Tue Dec 17 20:12:33 2013 -0500 +++ b/include/urweb/urweb_cpp.h Mon Dec 23 15:59:17 2013 +0000 @@ -40,7 +40,8 @@ void uw_ensure_transaction(struct uw_context *); failure_kind uw_begin_onError(struct uw_context *, char *msg); void uw_login(struct uw_context *); -void uw_commit(struct uw_context *); +int uw_commit(struct uw_context *); +// ^-- returns nonzero if the transaction should be restarted int uw_rollback(struct uw_context *, int will_retry); __attribute__((noreturn)) void uw_error(struct uw_context *, failure_kind, const char *fmt, ...); diff -r 94f9570671f0 -r d02c1a0d8082 src/c/cgi.c --- a/src/c/cgi.c Tue Dec 17 20:12:33 2013 -0500 +++ b/src/c/cgi.c Mon Dec 23 15:59:17 2013 +0000 @@ -134,9 +134,10 @@ } void uw_do_expunge(uw_context ctx, uw_Basis_client cli, void *data) { - uw_ensure_transaction(ctx); - uw_get_app(ctx)->expunger(ctx, cli); - uw_commit(ctx); + do { + uw_ensure_transaction(ctx); + uw_get_app(ctx)->expunger(ctx, cli); + } while (uw_commit(ctx) && (uw_rollback(ctx, 1), 1)); } void uw_post_expunge(uw_context ctx, void *data) { diff -r 94f9570671f0 -r d02c1a0d8082 src/c/fastcgi.c --- a/src/c/fastcgi.c Tue Dec 17 20:12:33 2013 -0500 +++ b/src/c/fastcgi.c Mon Dec 23 15:59:17 2013 +0000 @@ -632,9 +632,10 @@ } void uw_do_expunge(uw_context ctx, uw_Basis_client cli, void *data) { - uw_ensure_transaction(ctx); - uw_get_app(ctx)->expunger(ctx, cli); - uw_commit(ctx); + do { + uw_ensure_transaction(ctx); + uw_get_app(ctx)->expunger(ctx, cli); + } while (uw_commit(ctx) && (uw_rollback(ctx, 1), 1)); } void uw_post_expunge(uw_context ctx, void *data) { diff -r 94f9570671f0 -r d02c1a0d8082 src/c/http.c --- a/src/c/http.c Tue Dec 17 20:12:33 2013 -0500 +++ b/src/c/http.c Mon Dec 23 15:59:17 2013 +0000 @@ -447,9 +447,10 @@ } void uw_do_expunge(uw_context ctx, uw_Basis_client cli, void *data) { - uw_ensure_transaction(ctx); - uw_get_app(ctx)->expunger(ctx, cli); - uw_commit(ctx); + do { + uw_ensure_transaction(ctx); + uw_get_app(ctx)->expunger(ctx, cli); + } while (uw_commit(ctx) && (uw_rollback(ctx, 1), 1)); } void uw_post_expunge(uw_context ctx, void *data) { diff -r 94f9570671f0 -r d02c1a0d8082 src/c/request.c --- a/src/c/request.c Tue Dec 17 20:12:33 2013 -0500 +++ b/src/c/request.c Mon Dec 23 15:59:17 2013 +0000 @@ -116,8 +116,10 @@ return NULL; } while (r == UNLIMITED_RETRY || (r == BOUNDED_RETRY && retries_left > 0)); - if (r != FATAL && r != BOUNDED_RETRY) - uw_commit(ctx); + if (r != FATAL && r != BOUNDED_RETRY) { + if (uw_commit(ctx)) + r = UNLIMITED_RETRY; + } sleep(p->pdic.period); }; diff -r 94f9570671f0 -r d02c1a0d8082 src/c/urweb.c --- a/src/c/urweb.c Tue Dec 17 20:12:33 2013 -0500 +++ b/src/c/urweb.c Mon Dec 23 15:59:17 2013 +0000 @@ -3253,13 +3253,13 @@ return s; } -void uw_commit(uw_context ctx) { +int uw_commit(uw_context ctx) { int i; char *sig; if (uw_has_error(ctx)) { uw_rollback(ctx, 0); - return; + return 0; } for (i = ctx->used_transactionals-1; i >= 0; --i) @@ -3268,7 +3268,7 @@ ctx->transactionals[i].commit(ctx->transactionals[i].data); if (uw_has_error(ctx)) { uw_rollback(ctx, 0); - return; + return 0; } } @@ -3278,13 +3278,26 @@ ctx->transactionals[i].commit(ctx->transactionals[i].data); if (uw_has_error(ctx)) { uw_rollback(ctx, 0); - return; + return 0; } } - if (ctx->transaction_started && ctx->app->db_commit(ctx)) { - uw_set_error_message(ctx, "Error running SQL COMMIT"); - return; + if (ctx->transaction_started) { + int code =ctx->app->db_commit(ctx); + + if (code) { + if (code == -1) { + uw_rollback(ctx, 1); + return 1; + } + + for (i = ctx->used_transactionals-1; i >= 0; --i) + if (ctx->transactionals[i].free) + ctx->transactionals[i].free(ctx->transactionals[i].data, 0); + + uw_set_error_message(ctx, "Error running SQL COMMIT"); + return 0; + } } for (i = 0; i < ctx->used_deltas; ++i) { @@ -3390,6 +3403,8 @@ } while (sig); } } + + return 0; } diff -r 94f9570671f0 -r d02c1a0d8082 src/postgres.sml --- a/src/postgres.sml Tue Dec 17 20:12:33 2013 -0500 +++ b/src/postgres.sml Mon Dec 23 15:59:17 2013 +0000 @@ -438,7 +438,23 @@ newline, newline, string "if (PQresultStatus(res) != PGRES_COMMAND_OK) {", - box [string "PQclear(res);", + box [string "if (!strcmp(PQresultErrorField(res, PG_DIAG_SQLSTATE), \"40001\")) {", + box [newline, + string "PQclear(res);", + newline, + string "return -1;", + newline], + string "}", + newline, + string "if (!strcmp(PQresultErrorField(res, PG_DIAG_SQLSTATE), \"40P01\")) {", + box [newline, + string "PQclear(res);", + newline, + string "return -1;", + newline], + string "}", + newline, + string "PQclear(res);", newline, string "return 1;", newline],