diff src/sqlcache.sml @ 2286:0bdfec16a01d

Fix issue with one-element caches. Locking still WIP.
author Ziv Scully <ziv@mit.edu>
date Fri, 13 Nov 2015 01:04:32 -0500
parents b7615e0ac4b0
children 98f96a976ede
line wrap: on
line diff
--- a/src/sqlcache.sml	Thu Nov 12 16:36:35 2015 -0500
+++ b/src/sqlcache.sml	Fri Nov 13 01:04:32 2015 -0500
@@ -1,6 +1,9 @@
 structure Sqlcache :> SQLCACHE = struct
 
-open Mono
+
+(*********************)
+(* General Utilities *)
+(*********************)
 
 structure IK = struct type ord_key = int val compare = Int.compare end
 structure IS = IntBinarySet
@@ -8,10 +11,9 @@
 structure SK = struct type ord_key = string val compare = String.compare end
 structure SS = BinarySetFn(SK)
 structure SM = BinaryMapFn(SK)
+structure IIMM = MultimapFn(structure KeyMap = IM structure ValSet = IS)
 structure SIMM = MultimapFn(structure KeyMap = SM structure ValSet = IS)
 
-(* ASK: how do we deal with heap reallocation? *)
-
 fun id x = x
 
 fun iterate f n x = if n < 0
@@ -20,6 +22,35 @@
                     then x
                     else iterate f (n-1) (f x)
 
+(* From the MLton wiki. *)
+infix  3 <\     fun x <\ f = fn y => f (x, y)     (* Left section      *)
+infix  3 \>     fun f \> y = f y                  (* Left application  *)
+
+fun mapFst f (x, y) = (f x, y)
+
+(* Option monad. *)
+fun obind (x, f) = Option.mapPartial f x
+fun oguard (b, x) = if b then x else NONE
+fun omap f = fn SOME x => SOME (f x) | _ => NONE
+fun omap2 f = fn (SOME x, SOME y) => SOME (f (x,y)) | _ => NONE
+fun osequence ys = List.foldr (omap2 op::) (SOME []) ys
+
+fun indexOf test =
+    let
+        fun f n =
+         fn [] => NONE
+          | (x::xs) => if test x then SOME n else f (n+1) xs
+    in
+        f 0
+    end
+
+
+(************)
+(* Settings *)
+(************)
+
+open Mono
+
 (* Filled in by [addFlushing]. *)
 val ffiInfoRef : {index : int, params : int} list ref = ref []
 
@@ -59,6 +90,11 @@
 fun setAlwaysConsolidate b = alwaysConsolidateRef := b
 fun getAlwaysConsolidate () = !alwaysConsolidateRef
 
+
+(************************)
+(* Really Useful Things *)
+(************************)
+
 (* Used to have type context for local variables in MonoUtil functions. *)
 val doBind =
  fn (env, MonoUtil.Exp.RelE (x, t)) => MonoEnv.pushERel env x t NONE
@@ -79,36 +115,26 @@
                        NONE => (printer (); NONE)
                      | y => y
 
-(*********************)
-(* General Utilities *)
-(*********************)
-
-(* From the MLton wiki. *)
-infix  3 <\     fun x <\ f = fn y => f (x, y)     (* Left section      *)
-infix  3 \>     fun f \> y = f y                  (* Left application  *)
-
-fun mapFst f (x, y) = (f x, y)
-
-(* Option monad. *)
-fun obind (x, f) = Option.mapPartial f x
-fun oguard (b, x) = if b then x else NONE
-fun omap f = fn SOME x => SOME (f x) | _ => NONE
-fun omap2 f = fn (SOME x, SOME y) => SOME (f (x,y)) | _ => NONE
-fun osequence ys = List.foldr (omap2 op::) (SOME []) ys
-
-fun indexOf test =
-    let
-        fun f n =
-         fn [] => NONE
-          | (x::xs) => if test x then SOME n else f (n+1) xs
-    in
-        f 0
-    end
 
 (*******************)
 (* Effect Analysis *)
 (*******************)
 
+(* TODO: test this. *)
+fun transitiveAnalysis doVal state (decls, _) =
+    let
+        val doDecl =
+         fn ((DVal v, _), state) => doVal (v, state)
+          (* Pass over the list of values a number of times equal to its size,
+             making sure whatever property we're testing propagates everywhere
+             it should. This is analagous to the Bellman-Ford algorithm. *)
+          | ((DValRec vs, _), state) =>
+            iterate (fn state => List.foldl doVal state vs) (length vs) state
+          | (_, state) => state
+    in
+        List.foldl doDecl state decls
+    end
+
 (* Makes an exception for [EWrite] (which is recorded when caching). *)
 fun effectful (effs : IS.set) =
     let
@@ -151,24 +177,13 @@
     end
 
 (* TODO: test this. *)
-fun effectfulDecls (decls, _) =
-    let
-        fun doVal ((_, name, _, e, _), effs) =
-            if effectful effs MonoEnv.empty e
-            then IS.add (effs, name)
-            else effs
-        val doDecl =
-         fn ((DVal v, _), effs) => doVal (v, effs)
-          (* Repeat the list of declarations a number of times equal to its size,
-             making sure effectfulness propagates everywhere it should. This is
-             analagous to the Bellman-Ford algorithm. *)
-          | ((DValRec vs, _), effs) =>
-            List.foldl doVal effs (List.concat (List.map (fn _ => vs) vs))
-          (* ASK: any other cases? *)
-          | (_, effs) => effs
-    in
-        List.foldl doDecl IS.empty decls
-    end
+fun effectfulDecls file =
+    transitiveAnalysis (fn ((_, name, _, e, _), effs) =>
+                           if effectful effs MonoEnv.empty e
+                           then IS.add (effs, name)
+                           else effs)
+                       IS.empty
+                       file
 
 
 (*********************************)
@@ -1080,9 +1095,7 @@
   | ERecord fields => SOME (TRecord (map (fn (s, _, t) => (s, t)) fields), dummyLoc)
   | EField (e, s) => (case typOfExp env e of
                           SOME (TRecord fields, _) =>
-                          (case List.find (fn (s', _) => s = s') fields of
-                               SOME (_, t) => SOME t
-                             | _ => NONE)
+                          omap #2 (List.find (fn (s', _) => s = s') fields)
                         | _ => NONE)
   | ECase (_, _, {result, ...}) => SOME result
   | EStrcat _ => SOME (TFfi ("Basis", "string"), dummyLoc)
@@ -1414,6 +1427,46 @@
     end
 
 
+(***********)
+(* Locking *)
+(***********)
+
+(* TODO: do this less evil-ly by not relying on specific FFI names, please? *)
+fun locksNeeded file =
+    transitiveAnalysis
+        (fn ((_, name, _, e, _), state) =>
+            MonoUtil.Exp.fold
+                {typ = #2,
+                 exp = fn (EFfiApp ("Sqlcache", x, _), state as {store, flush}) =>
+                          (case Int.fromString (String.extract (x, 5, NONE)) of
+                               NONE => raise Match
+                             | SOME index =>
+                               if String.isPrefix "store" x
+                               then {store = IIMM.insert (store, name, index), flush = flush}
+                               else if String.isPrefix "flush" x
+                               then {store = store, flush = IIMM.insert (flush, name, index)}
+                               else state)
+                        | _ => state}
+                state
+                e)
+        {store = IIMM.empty, flush = IIMM.empty}
+        file
+
+fun exports (decls, _) =
+    List.foldl (fn ((DExport (_, _, n, _, _, _), _), ns) => IS.add (ns, n)
+                 | ((DTask _, _), _) => raise Fail "Sqlcache doesn't yet support tasks."
+                 | (_, ns) => ns)
+               IS.empty
+               decls
+
+(* fun addLocking file = *)
+(*     let *)
+(*         val whichLocks = locksNeeded file *)
+(*         val needsLocks = exports file *)
+(*     in *)
+
+(*     end *)
+
 (************************)
 (* Compiler Entry Point *)
 (************************)