# HG changeset patch # User Ziv Scully # Date 1401239653 14400 # Node ID 01c8aceac48054b581b3fe4fe23c654ccbc6f482 # Parent 39faa4a037f467574713151e85fe91230b01c2d5 Finishes initial prototype, caching parameterless pages with table-match-based invalidation. Still has problems parsing non-Postgres SQL dialects properly. diff -r 39faa4a037f4 -r 01c8aceac480 caching-tests/test.db Binary file caching-tests/test.db has changed diff -r 39faa4a037f4 -r 01c8aceac480 caching-tests/test.sql --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/caching-tests/test.sql Tue May 27 21:14:13 2014 -0400 @@ -0,0 +1,11 @@ +CREATE TABLE uw_Test_foo01(uw_id integer NOT NULL, uw_bar text NOT NULL, + PRIMARY KEY (uw_id) + + ); + + CREATE TABLE uw_Test_foo10(uw_id integer NOT NULL, uw_bar text NOT NULL, + PRIMARY KEY (uw_id) + + ); + + \ No newline at end of file diff -r 39faa4a037f4 -r 01c8aceac480 caching-tests/test.ur --- a/caching-tests/test.ur Tue Mar 25 02:04:06 2014 -0400 +++ b/caching-tests/test.ur Tue May 27 21:14:13 2014 -0400 @@ -1,81 +1,53 @@ table foo01 : {Id : int, Bar : string} PRIMARY KEY Id table foo10 : {Id : int, Bar : string} PRIMARY KEY Id -(* val query = (SELECT * FROM foo WHERE foo.Bar = "baz") *) -(* val insert = (INSERT INTO foo (Id, Bar) VALUES (42, "baz")) *) +fun flush01 () : transaction page = + dml (INSERT INTO foo01 (Id, Bar) VALUES (42, "baz01")); + dml (UPDATE foo01 SET Bar = "baz01" WHERE Id = 42); + return + Flushed 1! + -fun flush01 () : transaction page= - dml (INSERT INTO foo01 (Id, Bar) VALUES (42, "baz")); - return - - - Flushed 1! - - +fun flush10 () : transaction page = + dml (UPDATE foo10 SET Bar = "baz10" WHERE Id = 42); + return + Flushed 2! + -fun flush10 () : transaction page= - dml (INSERT INTO foo10 (Id, Bar) VALUES (42, "baz")); - return - - - Flushed 2! - - - -fun flush11 () : transaction page= - dml (INSERT INTO foo01 (Id, Bar) VALUES (42, "baz")); - dml (INSERT INTO foo10 (Id, Bar) VALUES (42, "baz")); - return - - - Flushed 1 and 2! - - +fun flush11 () : transaction page = + dml (UPDATE foo01 SET Bar = "baz11" WHERE Id = 42); + dml (UPDATE foo10 SET Bar = "baz11" WHERE Id = 42); + return + Flushed 1 and 2! + fun cache01 () : transaction page = - res <- oneOrNoRows (SELECT foo01.Id, foo01.Bar - FROM foo01 - WHERE foo01.Bar = "baz"); - return - - - Reading 1. - {case res of - None => - | Some row => {[row.Foo01.Bar]}} - - + res <- oneOrNoRows (SELECT foo01.Bar FROM foo01 WHERE foo01.Id = 42); + return + Reading 1. + {case res of + None => + | Some row => {[row.Foo01.Bar]}} + fun cache10 () : transaction page = - res <- oneOrNoRows (SELECT foo10.Id, foo10.Bar - FROM foo10 - WHERE foo10.Bar = "baz"); - return - - - Reading 2. - {case res of - None => - | Some row => {[row.Foo10.Bar]}} - - + res <- oneOrNoRows (SELECT foo10.Bar FROM foo10 WHERE foo10.Id = 42); + return + Reading 2. + {case res of + None => + | Some row => {[row.Foo10.Bar]}} + fun cache11 () : transaction page = - res <- oneOrNoRows (SELECT foo01.Id, foo01.Bar - FROM foo01 - WHERE foo01.Bar = "baz"); - bla <- oneOrNoRows (SELECT foo10.Id, foo10.Bar - FROM foo10 - WHERE foo10.Bar = "baz"); - return - - - Reading 1 and 2. - {case res of - None => - | Some row => {[row.Foo01.Bar]}} - {case bla of - None => - | Some row => {[row.Foo10.Bar]}} - - + res <- oneOrNoRows (SELECT foo01.Bar FROM foo01 WHERE foo01.Id = 42); + bla <- oneOrNoRows (SELECT foo10.Bar FROM foo10 WHERE foo10.Id = 42); + return + Reading 1 and 2. + {case res of + None => + | Some row => {[row.Foo01.Bar]}} + {case bla of + None => + | Some row => {[row.Foo10.Bar]}} + diff -r 39faa4a037f4 -r 01c8aceac480 caching-tests/test.urp --- a/caching-tests/test.urp Tue Mar 25 02:04:06 2014 -0400 +++ b/caching-tests/test.urp Tue May 27 21:14:13 2014 -0400 @@ -1,4 +1,5 @@ -database dbname=test +database test.db +sql test.sql safeGet Test/flush01 safeGet Test/flush10 safeGet Test/flush11 diff -r 39faa4a037f4 -r 01c8aceac480 include/urweb/urweb_cpp.h --- a/include/urweb/urweb_cpp.h Tue Mar 25 02:04:06 2014 -0400 +++ b/include/urweb/urweb_cpp.h Tue May 27 21:14:13 2014 -0400 @@ -75,6 +75,10 @@ void uw_write(struct uw_context *, const char*); +// For caching. +void uw_recordingStart(struct uw_context *); +char *uw_recordingRead(struct uw_context *); + uw_Basis_source uw_Basis_new_client_source(struct uw_context *, uw_Basis_string); uw_unit uw_Basis_set_client_source(struct uw_context *, uw_Basis_source, uw_Basis_string); diff -r 39faa4a037f4 -r 01c8aceac480 src/c/urweb.c --- a/src/c/urweb.c Tue Mar 25 02:04:06 2014 -0400 +++ b/src/c/urweb.c Tue May 27 21:14:13 2014 -0400 @@ -477,6 +477,9 @@ char *output_buffer; size_t output_buffer_size; + + // For caching. + char *recording; }; size_t uw_headers_max = SIZE_MAX; @@ -560,6 +563,8 @@ ctx->output_buffer = malloc(1); ctx->output_buffer_size = 1; + ctx->recording = 0; + return ctx; } @@ -1636,6 +1641,19 @@ *ctx->page.front = 0; } +void uw_recordingStart(uw_context ctx) { + // TODO: remove following debug statement. + uw_write(ctx, ""); + ctx->recording = ctx->page.front; +} + +char *uw_recordingRead(uw_context ctx) { + char *recording = strdup(ctx->recording); + // TODO: remove following debug statement. + uw_write(ctx, ""); + return recording; +} + char *uw_Basis_attrifyInt(uw_context ctx, uw_Basis_int n) { char *result; int len; diff -r 39faa4a037f4 -r 01c8aceac480 src/cjr_print.sml --- a/src/cjr_print.sml Tue Mar 25 02:04:06 2014 -0400 +++ b/src/cjr_print.sml Tue May 27 21:14:13 2014 -0400 @@ -16,7 +16,7 @@ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN @@ -734,7 +734,7 @@ string (Int.toString (size has_arg)), string ", ((*request)[0] == '/' ? ++*request : NULL), ", newline, - + if unboxable then unurlify' "(*request)" (#1 t) else @@ -914,7 +914,7 @@ space, string "4, ((*request)[0] == '/' ? ++*request : NULL), ", newline, - + string "({", newline, p_typ env (t, loc), @@ -1188,7 +1188,7 @@ string "(ctx,", space, string "it", - string (Int.toString level), + string (Int.toString level), string ");", newline] else @@ -1388,7 +1388,7 @@ string (Int.toString level), string ");", newline]) - + | _ => (ErrorMsg.errorAt loc "Unable to choose a URL encoding function"; space) in @@ -1578,7 +1578,7 @@ newline], string "tmp;", newline, - string "})"] + string "})"] end | ENone _ => string "NULL" | ESome (t, e) => @@ -2078,7 +2078,7 @@ space, p_exp' false false (E.pushERel (E.pushERel env "r" (TRecord rnum, loc)) - "acc" state) + "acc" state) body, string ";", newline] @@ -2102,7 +2102,7 @@ newline, string "uw_ensure_transaction(ctx);", newline, - + case prepared of NONE => box [string "char *query = ", @@ -2187,7 +2187,7 @@ string "uw_ensure_transaction(ctx);", newline, newline, - + #dmlPrepared (Settings.currentDbms ()) {loc = loc, id = id, dml = dml', @@ -3378,6 +3378,50 @@ newline, newline, + (* For caching. *) + box (List.map + (fn index => + let val i = Int.toString index + in box [string "static char *cache", + string i, + string " = NULL;", + newline, + string "static uw_Basis_bool uw_Cache_check", + string i, + string "(uw_context ctx) { puts(\"Checked ", + string i, + string "\"); if (cache", + string i, + string " == NULL) { uw_recordingStart(ctx); return uw_Basis_False; } else { uw_write(ctx, cache", + string i, + string "); return uw_Basis_True; } };", + newline, + string "static uw_unit uw_Cache_store", + string i, + string "(uw_context ctx) { cache", + string i, + string " = uw_recordingRead(ctx); puts(\"Stored ", + string i, + string "\"); return uw_unit_v; };", + newline, + string "static uw_unit uw_Cache_flush", + string i, + string "(uw_context ctx) { free(cache", + string i, + string "); cache", + string i, + string " = NULL; puts(\"Flushed ", + string i, + string "\"); return uw_unit_v; };", + newline, + string "static uw_unit uw_Cache_ready", + string i, + string "(uw_context ctx) { return uw_unit_v; };", + newline, + newline] + end) + (!SqlCache.ffiIndices)), + newline, p_list_sep newline (fn x => x) pds, newline, @@ -3433,7 +3477,7 @@ makeChecker ("uw_check_envVar", Settings.getEnvVarRules ()), newline, - + string "extern void uw_sign(const char *in, char *out);", newline, string "extern int uw_hash_blocksize;", @@ -3480,7 +3524,7 @@ newline, string ("uw_write_header(ctx, \"Last-modified: " ^ Date.fmt rfcFmt nowD ^ "\\r\\n\");"), newline, - string ("uw_write_header(ctx, \"Cache-Control: max-age=31536000, public\\r\\n\");"), + string ("uw_write_header(ctx, \"Cache-Control: max-age=31536000, public\\r\\n\");"), newline, string "uw_write(ctx, jslib);", newline, diff -r 39faa4a037f4 -r 01c8aceac480 src/compiler.sml --- a/src/compiler.sml Tue Mar 25 02:04:06 2014 -0400 +++ b/src/compiler.sml Tue May 27 21:14:13 2014 -0400 @@ -606,7 +606,7 @@ filterEnv = rev (!env), sources = sources, protocol = !protocol, - dbms = !dbms, + dbms = (*!dbms*) SOME "sqlite", sigFile = !sigFile, safeGets = rev (!safeGets), onError = !onError, diff -r 39faa4a037f4 -r 01c8aceac480 src/sources --- a/src/sources Tue Mar 25 02:04:06 2014 -0400 +++ b/src/sources Tue May 27 21:14:13 2014 -0400 @@ -186,8 +186,13 @@ $(SRC)/fuse.sig $(SRC)/fuse.sml +$(SRC)/sql.sig $(SRC)/sql.sml +$(SRC)/multimap_fn.sml + +$(SRC)/sql_cache.sml + $(SRC)/iflow.sig $(SRC)/iflow.sml diff -r 39faa4a037f4 -r 01c8aceac480 src/sql.sig --- a/src/sql.sig Tue Mar 25 02:04:06 2014 -0400 +++ b/src/sql.sig Tue May 27 21:14:13 2014 -0400 @@ -1,10 +1,8 @@ signature SQL = sig -val fu : Mono.file -> unit - val debug : bool ref -type lvar +type lvar = int datatype func = DtCon0 of string @@ -41,7 +39,13 @@ | Reln of reln * exp list | Cond of exp * prop -datatype ('a, 'b) sum = inl of 'a | inr of 'b +datatype chunk = + String of string + | Exp of Mono.exp + +type 'a parser = chunk list -> ('a * chunk list) option + +val parse : 'a parser -> Mono.exp -> 'a option datatype Rel = Exps of exp * exp -> prop @@ -61,19 +65,27 @@ | Unmodeled | Null +datatype ('a,'b) sum = inl of 'a | inr of 'b + datatype sitem = SqField of string * string | SqExp of sqexp * string -type query1 +type query1 = {Select : sitem list, + From : (string * string) list, + Where : sqexp option} datatype query = Query1 of query1 | Union of query * query +val query : query parser + datatype dml = Insert of string * (string * sqexp) list | Delete of string * sqexp | Update of string * (string * sqexp) list * sqexp +val dml : dml parser + end diff -r 39faa4a037f4 -r 01c8aceac480 src/sql.sml --- a/src/sql.sml Tue Mar 25 02:04:06 2014 -0400 +++ b/src/sql.sml Tue May 27 21:14:13 2014 -0400 @@ -1,4 +1,4 @@ -structure Sql = struct +structure Sql :> SQL = struct open Mono diff -r 39faa4a037f4 -r 01c8aceac480 src/sql_cache.sml --- a/src/sql_cache.sml Tue Mar 25 02:04:06 2014 -0400 +++ b/src/sql_cache.sml Tue May 27 21:14:13 2014 -0400 @@ -10,6 +10,10 @@ structure SM = BinaryMapFn (StringKey) structure SIMM = MultimapFn (structure KeyMap = SM structure ValSet = IS) +val ffiIndices : int list ref = ref [] +val rs : int list ref = ref [] +val ws : int list ref = ref [] + val rec tablesRead = fn Query1 {From=tablePairs, ...} => SS.fromList (map #1 tablePairs) | Union (q1,q2) => SS.union (tablesRead q1, tablesRead q2) @@ -54,8 +58,8 @@ loc) fun boolTyp loc = (TFfi ("Basis", "int"), loc) -fun ffiAppExp (module, func, arg, loc) = - (EFfiApp (module, func, [(intExp (arg, loc), intTyp loc)]), loc) +fun ffiAppExp (module, func, index, loc) = + (EFfiApp (module, func ^ Int.toString index, []), loc) fun sequence (befores, center, afters, loc) = List.foldr (fn (exp, seq) => (ESeq (exp, seq), loc)) @@ -173,6 +177,9 @@ val {readers, writers} = handlerIndices file val (fileWithChecks, tablesToIndices) = addCacheChecking (file, readers) in + rs := IS.listItems readers; + ws := IS.listItems writers; + ffiIndices := IS.listItems readers; addCacheFlushing (fileWithChecks, tablesToIndices, writers) end