Mercurial > urweb
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 |