comparison src/sqlcache.sml @ 2237:e79ef5792c8b

Fix bug in redundancy checking and use finer formula for UPDATE statements.
author Ziv Scully <ziv@mit.edu>
date Sun, 05 Jul 2015 23:57:28 -0700
parents fab8c1f131a5
children f70a91f7810d
comparison
equal deleted inserted replaced
2236:fab8c1f131a5 2237:e79ef5792c8b
172 | _ => f :: acc) 172 | _ => f :: acc)
173 [] 173 []
174 (map flatten fs)) 174 (map flatten fs))
175 | f => f 175 | f => f
176 176
177 fun normPlz (junc : junctionType) = 177 fun normalize' (simplify : 'a list list -> 'a list list)
178 fn Atom x => [[x]] 178 (negate : 'a -> 'a)
179 | Combo (j, fs) =>
180 let
181 val fss = map (normPlz junc) fs
182 in
183 if j = junc
184 then List.concat fss
185 else map List.concat (cartesianProduct fss)
186 end
187 (* Excluded by pushNegate. *)
188 | Negate _ => raise Match
189
190 fun normalize' ((simplifyLists, simplifyAtoms, negate)
191 : ('a list list -> 'a list list)
192 * ('a list -> 'a list)
193 * ('a -> 'a))
194 (junc : junctionType) = 179 (junc : junctionType) =
195 let 180 let
196 fun simplify junc = simplifyLists o map simplifyAtoms
197 fun norm junc = 181 fun norm junc =
198 simplify junc 182 simplify
199 o (fn Atom x => [[x]] 183 o (fn Atom x => [[x]]
200 | Negate f => map (map negate) (norm (flipJt junc) f) 184 | Negate f => map (map negate) (norm (flipJt junc) f)
201 | Combo (j, fs) => 185 | Combo (j, fs) =>
202 let 186 let
203 val fss = map (norm junc) fs 187 val fss = map (norm junc) fs
208 end) 192 end)
209 in 193 in
210 norm junc 194 norm junc
211 end 195 end
212 196
213 fun normalize (simplifyLists, simplifyAtoms, negate, junc) = 197 fun normalize simplify negate junc =
214 (normalize' (simplifyLists, simplifyAtoms, negate) junc) 198 normalize' simplify negate junc
215 o flatten 199 o flatten
216 o pushNegate negate false 200 o pushNegate negate false
217 201
218 fun mapFormula mf = 202 fun mapFormula mf =
219 fn Atom x => Atom (mf x) 203 fn Atom x => Atom (mf x)
245 | (_, Sql.Gt) => GREATER 229 | (_, Sql.Gt) => GREATER
246 | (Sql.Ge, Sql.Ge) => EQUAL 230 | (Sql.Ge, Sql.Ge) => EQUAL
247 231
248 end 232 end
249 233
250 234 (*
251 functor ListKeyFn (K : ORD_KEY) : ORD_KEY = struct 235 functor ListKeyFn (K : ORD_KEY) : ORD_KEY = struct
252 236
253 type ord_key = K.ord_key list 237 type ord_key = K.ord_key list
254 238
255 val rec compare = 239 val rec compare =
259 | (x :: xs, y :: ys) => (case K.compare (x, y) of 243 | (x :: xs, y :: ys) => (case K.compare (x, y) of
260 EQUAL => compare (xs, ys) 244 EQUAL => compare (xs, ys)
261 | ord => ord) 245 | ord => ord)
262 246
263 end 247 end
248 *)
264 249
265 functor OptionKeyFn (K : ORD_KEY) : ORD_KEY = struct 250 functor OptionKeyFn (K : ORD_KEY) : ORD_KEY = struct
266 251
267 type ord_key = K.ord_key option 252 type ord_key = K.ord_key option
268 253
291 end 276 end
292 277
293 val rec chooseTwos : 'a list -> ('a * 'a) list = 278 val rec chooseTwos : 'a list -> ('a * 'a) list =
294 fn [] => [] 279 fn [] => []
295 | x :: ys => map (fn y => (x, y)) ys @ chooseTwos ys 280 | x :: ys => map (fn y => (x, y)) ys @ chooseTwos ys
281
282 fun removeRedundant madeRedundantBy zs =
283 let
284 fun removeRedundant' (xs, ys) =
285 case xs of
286 [] => ys
287 | x :: xs' =>
288 removeRedundant' (xs',
289 if List.exists (fn y => madeRedundantBy (x, y)) (xs' @ ys)
290 then ys
291 else x :: ys)
292 in
293 removeRedundant' (zs, [])
294 end
296 295
297 datatype atomExp = 296 datatype atomExp =
298 QueryArg of int 297 QueryArg of int
299 | DmlRel of int 298 | DmlRel of int
300 | Prim of Prim.t 299 | Prim of Prim.t
327 326
328 structure TK = TripleKeyFn(structure I = CmpKey 327 structure TK = TripleKeyFn(structure I = CmpKey
329 structure J = OptionKeyFn(AtomExpKey) 328 structure J = OptionKeyFn(AtomExpKey)
330 structure K = OptionKeyFn(AtomExpKey)) 329 structure K = OptionKeyFn(AtomExpKey))
331 structure TS = BinarySetFn(TK) 330 structure TS = BinarySetFn(TK)
332 structure TLS = BinarySetFn(ListKeyFn(TK)) 331 (* structure TLS = BinarySetFn(ListKeyFn(TK)) *)
333 332
334 val toKnownEquality = 333 val toKnownEquality =
335 (* [NONE] here means unkown. Anything that isn't a comparison between two 334 (* [NONE] here means unkown. Anything that isn't a comparison between two
336 knowns shouldn't be used, and simply dropping unused terms is okay in 335 knowns shouldn't be used, and simply dropping unused terms is okay in
337 disjunctive normal form. *) 336 disjunctive normal form. *)
363 | ((Prim p, QueryArg n), SOME eqs) => SOME (addToEqs (eqs, n, Prim p)) 362 | ((Prim p, QueryArg n), SOME eqs) => SOME (addToEqs (eqs, n, Prim p))
364 | ((DmlRel r, QueryArg n), SOME eqs) => SOME (addToEqs (eqs, n, DmlRel r)) 363 | ((DmlRel r, QueryArg n), SOME eqs) => SOME (addToEqs (eqs, n, DmlRel r))
365 (* TODO: deal with equalities between [DmlRel]s and [Prim]s. 364 (* TODO: deal with equalities between [DmlRel]s and [Prim]s.
366 This would involve guarding the invalidation with a check for the 365 This would involve guarding the invalidation with a check for the
367 relevant comparisons. *) 366 relevant comparisons. *)
368 (* DEBUG: remove these print statements. *)
369 (* | ((DmlRel r, Prim p), eqso) => (print ("sadness " ^ Int.toString r ^ " = " ^ Prim.toString p ^ "\n"); eqso) *)
370 (* | ((Prim p, DmlRel r), eqso) => (print ("sadness " ^ Int.toString r ^ " = " ^ Prim.toString p ^ "\n"); eqso) *)
371 | (_, eqso) => eqso 367 | (_, eqso) => eqso
372 368
373 val eqsOfClass : atomExp list -> atomExp IM.map option = 369 val eqsOfClass : atomExp list -> atomExp IM.map option =
374 List.foldl accumulateEqs (SOME IM.empty) 370 List.foldl accumulateEqs (SOME IM.empty)
375 o chooseTwos 371 o chooseTwos
414 List.foldr (fn (SOME eqs, SOME acc) => SOME (IM.unionWith #1 (eqs, acc)) | _ => NONE) 410 List.foldr (fn (SOME eqs, SOME acc) => SOME (IM.unionWith #1 (eqs, acc)) | _ => NONE)
415 (SOME IM.empty) 411 (SOME IM.empty)
416 412
417 fun dnf (fQuery, fDml) = 413 fun dnf (fQuery, fDml) =
418 let 414 let
419 val isStar = 415 val simplify =
420 (* TODO: decide if this is okay and, if so, factor out magic 416 map TS.listItems
421 string "*" to a common location. *) 417 o removeRedundant (fn (x, y) => TS.isSubset (y, x))
422 (* First guess: definitely okay for conservative approximation, 418 o map (fn xs => TS.addList (TS.empty, xs))
423 though information lost might be useful even in current
424 implementation for finding an extra equality. *)
425 fn SOME (Field (_, field)) => String.isSuffix "*" field
426 | _ => false
427 fun canIgnore (_, a1, a2) = isStar a1 orelse isStar a2
428 fun simplifyLists xs = TLS.listItems (TLS.addList (TLS.empty, xs))
429 fun simplifyAtoms xs = TS.listItems (TS.addList (TS.empty, xs))
430 in 419 in
431 normalize (simplifyLists, simplifyAtoms, negateCmp, Disj) 420 normalize simplify negateCmp Disj (Combo (Conj, [markQuery fQuery, markDml fDml]))
432 (Combo (Conj, [markQuery fQuery, markDml fDml]))
433 end 421 end
434 422
435 val conflictMaps = List.mapPartial (mergeEqs o map eqsOfClass o equivClasses) o dnf 423 val conflictMaps = List.mapPartial (mergeEqs o map eqsOfClass o equivClasses) o dnf
436 424
437 end 425 end
476 | Sql.Delete (table, wher) => renameTables [(table, "T")] (sqexpToFormula wher) 464 | Sql.Delete (table, wher) => renameTables [(table, "T")] (sqexpToFormula wher)
477 | Sql.Update (table, vals, wher) => 465 | Sql.Update (table, vals, wher) =>
478 let 466 let
479 val fWhere = sqexpToFormula wher 467 val fWhere = sqexpToFormula wher
480 val fVals = valsToFormula (table, vals) 468 val fVals = valsToFormula (table, vals)
469 val modifiedFields = SS.addList (SS.empty, map #1 vals)
481 (* TODO: don't use field name hack. *) 470 (* TODO: don't use field name hack. *)
482 val markField = 471 val markField =
483 fn Sql.Field (t, v) => Sql.Field (t, v ^ "*") 472 fn e as Sql.Field (t, v) => if SS.member (modifiedFields, v)
473 then Sql.Field (t, v ^ "'")
474 else e
484 | e => e 475 | e => e
485 val mark = mapFormula (fn (cmp, e1, e2) => (cmp, markField e1, markField e2)) 476 val mark = mapFormula (fn (cmp, e1, e2) => (cmp, markField e1, markField e2))
486 in 477 in
487 renameTables [(table, "T")] 478 renameTables [(table, "T")]
488 (Combo (Disj, [Combo (Conj, [fVals, mark fWhere]), 479 (Combo (Disj, [Combo (Conj, [fVals, mark fWhere]),
671 662
672 (* Tests if [ys] makes [xs] a redundant cache invalidation. [NONE] here 663 (* Tests if [ys] makes [xs] a redundant cache invalidation. [NONE] here
673 represents unknown, which means a wider invalidation. *) 664 represents unknown, which means a wider invalidation. *)
674 val rec madeRedundantBy : atomExp option list * atomExp option list -> bool = 665 val rec madeRedundantBy : atomExp option list * atomExp option list -> bool =
675 fn ([], []) => true 666 fn ([], []) => true
676 | (NONE :: xs, _ :: ys) => madeRedundantBy (xs, ys) 667 | (_ :: xs, NONE :: ys) => madeRedundantBy (xs, ys)
677 | (SOME x :: xs, SOME y :: ys) => (case AtomExpKey.compare (x, y) of 668 | (SOME x :: xs, SOME y :: ys) => (case AtomExpKey.compare (x, y) of
678 EQUAL => madeRedundantBy (xs, ys) 669 EQUAL => madeRedundantBy (xs, ys)
679 | _ => false) 670 | _ => false)
680 | _ => false 671 | _ => false
681 672
682 fun removeRedundant' (xss, yss) =
683 case xss of
684 [] => yss
685 | xs :: xss' =>
686 removeRedundant' (xss',
687 if List.exists (fn ys => madeRedundantBy (xs, ys)) (xss' @ yss)
688 then yss
689 else xs :: yss)
690
691 fun removeRedundant xss = removeRedundant' (xss, [])
692
693 fun eqss (query, dml) = conflictMaps (queryToFormula query, dmlToFormula dml) 673 fun eqss (query, dml) = conflictMaps (queryToFormula query, dmlToFormula dml)
694 674
695 fun invalidations ((query, numArgs), dml) = 675 fun invalidations ((query, numArgs), dml) =
696 (map (map optionAtomExpToExp) 676 (map (map optionAtomExpToExp)
697 o removeRedundant 677 o removeRedundant madeRedundantBy
698 o map (eqsToInvalidation numArgs) 678 o map (eqsToInvalidation numArgs)
699 o eqss) 679 o eqss)
700 (query, dml) 680 (query, dml)
701 681
702 end 682 end