summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/urweb.h4
-rw-r--r--src/c/driver.c31
-rw-r--r--src/c/urweb.c22
-rw-r--r--src/cjr_print.sml77
-rw-r--r--src/compiler.sml2
5 files changed, 104 insertions, 32 deletions
diff --git a/include/urweb.h b/include/urweb.h
index 3ca2a966..641893de 100644
--- a/include/urweb.h
+++ b/include/urweb.h
@@ -7,10 +7,14 @@ int lw_really_send(int sock, void *buf, ssize_t len);
extern lw_unit lw_unit_v;
lw_context lw_init(size_t page_len, size_t heap_len);
+void lw_set_db(lw_context, void*);
+void *lw_get_db(lw_context);
void lw_free(lw_context);
void lw_reset(lw_context);
void lw_reset_keep_request(lw_context);
void lw_reset_keep_error_message(lw_context);
+
+failure_kind lw_begin_init(lw_context);
failure_kind lw_begin(lw_context, char *path);
void lw_error(lw_context, failure_kind, const char *fmt, ...);
diff --git a/src/c/driver.c b/src/c/driver.c
index 5300371d..365566c9 100644
--- a/src/c/driver.c
+++ b/src/c/driver.c
@@ -52,8 +52,37 @@ static pthread_cond_t queue_cond = PTHREAD_COND_INITIALIZER;
#define MAX_RETRIES 5
static void *worker(void *data) {
- int me = *(int *)data;
+ int me = *(int *)data, retries_left = MAX_RETRIES;;
lw_context ctx = lw_init(1024, 1024);
+
+ while (1) {
+ failure_kind fk = lw_begin_init(ctx);
+
+ if (fk == SUCCESS) {
+ lw_db_init(ctx);
+ printf("Database connection initialized.\n");
+ break;
+ } else if (fk == BOUNDED_RETRY) {
+ if (retries_left) {
+ printf("Initialization error triggers bounded retry: %s\n", lw_error_message(ctx));
+ --retries_left;
+ } else {
+ printf("Fatal initialization error (out of retries): %s\n", lw_error_message(ctx));
+ lw_free(ctx);
+ return NULL;
+ }
+ } else if (fk == UNLIMITED_RETRY)
+ printf("Initialization error triggers unlimited retry: %s\n", lw_error_message(ctx));
+ else if (fk == FATAL) {
+ printf("Fatal initialization error: %s\n", lw_error_message(ctx));
+ lw_free(ctx);
+ return NULL;
+ } else {
+ printf("Unknown lw_handle return code!\n");
+ lw_free(ctx);
+ return NULL;
+ }
+ }
while (1) {
char buf[lw_bufsize+1], *back = buf, *s;
diff --git a/src/c/urweb.c b/src/c/urweb.c
index 3d79e1a3..cc6e4f0b 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -16,6 +16,8 @@ struct lw_context {
char *heap, *heap_front, *heap_back;
char **inputs;
+ void *db;
+
jmp_buf jmp_buf;
char error_message[ERROR_BUF_LEN];
@@ -34,11 +36,21 @@ lw_context lw_init(size_t page_len, size_t heap_len) {
ctx->inputs = calloc(lw_inputs_len, sizeof(char *));
+ ctx->db = NULL;
+
ctx->error_message[0] = 0;
return ctx;
}
+void lw_set_db(lw_context ctx, void *db) {
+ ctx->db = db;
+}
+
+void *lw_get_db(lw_context ctx) {
+ return ctx->db;
+}
+
void lw_free(lw_context ctx) {
free(ctx->page);
free(ctx->heap);
@@ -63,8 +75,18 @@ void lw_reset(lw_context ctx) {
memset(ctx->inputs, 0, lw_inputs_len * sizeof(char *));
}
+void lw_db_init(lw_context);
void lw_handle(lw_context, char *);
+failure_kind lw_begin_init(lw_context ctx) {
+ int r = setjmp(ctx->jmp_buf);
+
+ if (r == 0)
+ lw_db_init(ctx);
+
+ return r;
+}
+
failure_kind lw_begin(lw_context ctx, char *path) {
int r = setjmp(ctx->jmp_buf);
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index cefcad44..fd534c4a 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -533,7 +533,10 @@ fun p_exp' par env (e, loc) =
newline,
p_typ env t,
space,
- p_rel env 0,
+ string "__lwr_",
+ string x,
+ string "_",
+ string (Int.toString (E.countERels env)),
space,
string "=",
space,
@@ -546,31 +549,7 @@ fun p_exp' par env (e, loc) =
string "})"]
| EQuery {exps, tables, rnum, state, query, body, initial} =>
- box [string "query[",
- p_list (fn (x, t) => box [string x, space, string ":", space, p_typ env t]) exps,
- string "] [",
- p_list (fn (x, xts) => box [string x,
- space,
- string ":",
- space,
- string "{",
- p_list (fn (x, t) => box [string x, space, string ":", space, p_typ env t]) xts,
- string "}"]) tables,
- string "] [",
- p_typ env state,
- string "] [",
- string (Int.toString rnum),
- string "]",
- space,
- p_exp env query,
- space,
- string "initial",
- space,
- p_exp env initial,
- space,
- string "in",
- space,
- p_exp (E.pushERel (E.pushERel env "r" dummyt) "acc" dummyt) body]
+ string "(lw_error(ctx, FATAL, \"I would have run a query.\"), NULL)"
and p_exp env = p_exp' false env
@@ -709,9 +688,41 @@ fun p_decl env (dAll as (d, _) : decl) =
p_list_sep newline (p_fun env) vis,
newline]
end
- | DDatabase s => box [string "database",
- space,
- string s]
+ | DDatabase s => box [string "void lw_db_init(lw_context ctx) {",
+ newline,
+ string "PGconn *conn = PQconnectdb(\"",
+ string (String.toString s),
+ string "\");",
+ newline,
+ string "if (conn == NULL) lw_error(ctx, BOUNDED_RETRY, ",
+ string "\"libpq can't allocate a connection.\");",
+ newline,
+ string "if (PQstatus(conn) != CONNECTION_OK) {",
+ newline,
+ box [string "char msg[1024];",
+ newline,
+ string "strncpy(msg, PQerrorMessage(conn), 1024);",
+ newline,
+ string "msg[1023] = 0;",
+ newline,
+ string "PQfinish(conn);",
+ newline,
+ string "lw_error(ctx, BOUNDED_RETRY, ",
+ string "\"Connection to Postgres server failed: %s\", msg);"],
+ newline,
+ string "}",
+ newline,
+ string "lw_set_db(ctx, conn);",
+ newline,
+ string "}",
+ newline,
+ newline,
+ string "void lw_db_close(lw_context ctx) {",
+ newline,
+ string "PQfinish(lw_get_db(ctx));",
+ newline,
+ string "}",
+ newline]
datatype 'a search =
Found of 'a
@@ -1172,7 +1183,9 @@ fun p_file env (ds, ps) =
string "(",
p_list_sep (box [string ",", space])
(fn x => x)
- (string "ctx" :: ListUtil.mapi (fn (i, _) => string ("arg" ^ Int.toString i)) ts),
+ (string "ctx"
+ :: ListUtil.mapi (fn (i, _) => string ("arg" ^ Int.toString i)) ts
+ @ [string "lw_unit_v"]),
inputsVar,
string ");",
newline,
@@ -1190,6 +1203,10 @@ fun p_file env (ds, ps) =
newline,
string "#include <stdlib.h>",
newline,
+ string "#include <string.h>",
+ newline,
+ string "#include <postgresql/libpq-fe.h>",
+ newline,
newline,
string "#include \"urweb.h\"",
newline,
diff --git a/src/compiler.sml b/src/compiler.sml
index 07bfecc2..93eeebb7 100644
--- a/src/compiler.sml
+++ b/src/compiler.sml
@@ -417,7 +417,7 @@ val toCjrize = transform cjrize "cjrize" o toMono_opt2
fun compileC {cname, oname, ename} =
let
val compile = "gcc -O3 -I include -c " ^ cname ^ " -o " ^ oname
- val link = "gcc -pthread -O3 clib/urweb.o " ^ oname ^ " clib/driver.o -o " ^ ename
+ val link = "gcc -O3 -pthread -lpq clib/urweb.o " ^ oname ^ " clib/driver.o -o " ^ ename
in
if not (OS.Process.isSuccess (OS.Process.system compile)) then
print "C compilation failed\n"