OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package memory | 5 package memory |
6 | 6 |
7 import ( | 7 import ( |
8 "bytes" | 8 "bytes" |
9 "fmt" | 9 "fmt" |
10 "sort" | 10 "sort" |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 // metadata describing the total number of columns that this query requi
res to | 63 // metadata describing the total number of columns that this query requi
res to |
64 // execute perfectly. | 64 // execute perfectly. |
65 numCols int | 65 numCols int |
66 } | 66 } |
67 | 67 |
68 type indexDefinitionSortable struct { | 68 type indexDefinitionSortable struct { |
69 // eqFilts is the list of ACTUAL prefix columns. Note that it may contai
n | 69 // eqFilts is the list of ACTUAL prefix columns. Note that it may contai
n |
70 // redundant columns! (e.g. (tag, tag) is a perfectly valid prefix, becu
ase | 70 // redundant columns! (e.g. (tag, tag) is a perfectly valid prefix, becu
ase |
71 // (tag=1, tag=2) is a perfectly valid query). | 71 // (tag=1, tag=2) is a perfectly valid query). |
72 eqFilts []ds.IndexColumn | 72 eqFilts []ds.IndexColumn |
73 » coll *memCollection | 73 » coll memCollection |
74 } | 74 } |
75 | 75 |
76 func (i *indexDefinitionSortable) hasAncestor() bool { | 76 func (i *indexDefinitionSortable) hasAncestor() bool { |
77 return len(i.eqFilts) > 0 && i.eqFilts[0].Property == "__ancestor__" | 77 return len(i.eqFilts) > 0 && i.eqFilts[0].Property == "__ancestor__" |
78 } | 78 } |
79 | 79 |
80 func (i *indexDefinitionSortable) numEqHits(c *constraints) int { | 80 func (i *indexDefinitionSortable) numEqHits(c *constraints) int { |
81 ret := 0 | 81 ret := 0 |
82 for _, filt := range i.eqFilts { | 82 for _, filt := range i.eqFilts { |
83 if _, ok := c.constraints[filt.Property]; ok { | 83 if _, ok := c.constraints[filt.Property]; ok { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 // maybeAddDefinition possibly adds a new indexDefinitionSortable to this slice. | 124 // maybeAddDefinition possibly adds a new indexDefinitionSortable to this slice. |
125 // It's only added if it could be useful in servicing q, otherwise this function | 125 // It's only added if it could be useful in servicing q, otherwise this function |
126 // is a noop. | 126 // is a noop. |
127 // | 127 // |
128 // This returns true iff the proposed index is OK and depletes missingTerms to | 128 // This returns true iff the proposed index is OK and depletes missingTerms to |
129 // empty. | 129 // empty. |
130 // | 130 // |
131 // If the proposed index is PERFECT (e.g. contains enough columns to cover all | 131 // If the proposed index is PERFECT (e.g. contains enough columns to cover all |
132 // equality filters, and also has the correct suffix), idxs will be replaced | 132 // equality filters, and also has the correct suffix), idxs will be replaced |
133 // with JUST that index, and this will return true. | 133 // with JUST that index, and this will return true. |
134 func (idxs *indexDefinitionSortableSlice) maybeAddDefinition(q *reducedQuery, s
*memStore, missingTerms stringset.Set, id *ds.IndexDefinition) bool { | 134 func (idxs *indexDefinitionSortableSlice) maybeAddDefinition(q *reducedQuery, s
memStore, missingTerms stringset.Set, id *ds.IndexDefinition) bool { |
135 // Kindless queries are handled elsewhere. | 135 // Kindless queries are handled elsewhere. |
136 if id.Kind != q.kind { | 136 if id.Kind != q.kind { |
137 impossible( | 137 impossible( |
138 fmt.Errorf("maybeAddDefinition given index with wrong ki
nd %q v %q", id.Kind, q.kind)) | 138 fmt.Errorf("maybeAddDefinition given index with wrong ki
nd %q v %q", id.Kind, q.kind)) |
139 } | 139 } |
140 | 140 |
141 // If we're an ancestor query, and the index is compound, but doesn't in
clude | 141 // If we're an ancestor query, and the index is compound, but doesn't in
clude |
142 // an Ancestor field, it doesn't work. Builtin indexes can be used for | 142 // an Ancestor field, it doesn't work. Builtin indexes can be used for |
143 // ancestor queries (and have !Ancestor), assuming that it's only equali
ty | 143 // ancestor queries (and have !Ancestor), assuming that it's only equali
ty |
144 // filters (plus inequality on __key__), or a single inequality. | 144 // filters (plus inequality on __key__), or a single inequality. |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 *idxs = indexDefinitionSortableSlice{toAdd} | 223 *idxs = indexDefinitionSortableSlice{toAdd} |
224 } else { | 224 } else { |
225 *idxs = append(*idxs, toAdd) | 225 *idxs = append(*idxs, toAdd) |
226 } | 226 } |
227 return missingTerms.Len() == 0 | 227 return missingTerms.Len() == 0 |
228 } | 228 } |
229 | 229 |
230 // getRelevantIndexes retrieves the relevant indexes which could be used to | 230 // getRelevantIndexes retrieves the relevant indexes which could be used to |
231 // service q. It returns nil if it's not possible to service q with the current | 231 // service q. It returns nil if it's not possible to service q with the current |
232 // indexes. | 232 // indexes. |
233 func getRelevantIndexes(q *reducedQuery, s *memStore) (indexDefinitionSortableSl
ice, error) { | 233 func getRelevantIndexes(q *reducedQuery, s memStore) (indexDefinitionSortableSli
ce, error) { |
234 missingTerms := stringset.New(len(q.eqFilters)) | 234 missingTerms := stringset.New(len(q.eqFilters)) |
235 for k := range q.eqFilters { | 235 for k := range q.eqFilters { |
236 if k == "__ancestor__" { | 236 if k == "__ancestor__" { |
237 // ancestor is not a prefix which can be satisfied by a
single index. It | 237 // ancestor is not a prefix which can be satisfied by a
single index. It |
238 // must be satisfied by ALL indexes (and has special log
ic for this in | 238 // must be satisfied by ALL indexes (and has special log
ic for this in |
239 // the addDefinition logic) | 239 // the addDefinition logic) |
240 continue | 240 continue |
241 } | 241 } |
242 missingTerms.Add(k) | 242 missingTerms.Add(k) |
243 } | 243 } |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
461 // in ret.original above will be sufficient. | 461 // in ret.original above will be sufficient. |
462 continue | 462 continue |
463 } | 463 } |
464 ret.constraints[prop] = bvals | 464 ret.constraints[prop] = bvals |
465 } | 465 } |
466 return ret | 466 return ret |
467 } | 467 } |
468 | 468 |
469 // getIndexes returns a set of iterator definitions. Iterating over these | 469 // getIndexes returns a set of iterator definitions. Iterating over these |
470 // will result in matching suffixes. | 470 // will result in matching suffixes. |
471 func getIndexes(q *reducedQuery, s *memStore) ([]*iterDefinition, error) { | 471 func getIndexes(q *reducedQuery, s memStore) ([]*iterDefinition, error) { |
472 relevantIdxs := indexDefinitionSortableSlice(nil) | 472 relevantIdxs := indexDefinitionSortableSlice(nil) |
473 if q.kind == "" { | 473 if q.kind == "" { |
474 if coll := s.GetCollection("ents:" + q.ns); coll != nil { | 474 if coll := s.GetCollection("ents:" + q.ns); coll != nil { |
475 relevantIdxs = indexDefinitionSortableSlice{{coll: coll}
} | 475 relevantIdxs = indexDefinitionSortableSlice{{coll: coll}
} |
476 } | 476 } |
477 } else { | 477 } else { |
478 err := error(nil) | 478 err := error(nil) |
479 relevantIdxs, err = getRelevantIndexes(q, s) | 479 relevantIdxs, err = getRelevantIndexes(q, s) |
480 if err != nil { | 480 if err != nil { |
481 return nil, err | 481 return nil, err |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
542 if bestIdx == nil { | 542 if bestIdx == nil { |
543 // something is really wrong here... if relevantIdxs is
!nil, then we | 543 // something is really wrong here... if relevantIdxs is
!nil, then we |
544 // should always be able to make progress in this loop. | 544 // should always be able to make progress in this loop. |
545 impossible(fmt.Errorf("deadlock: cannot fulfil query?")) | 545 impossible(fmt.Errorf("deadlock: cannot fulfil query?")) |
546 } | 546 } |
547 ret = append(ret, generate(q, bestIdx, constraints)) | 547 ret = append(ret, generate(q, bestIdx, constraints)) |
548 } | 548 } |
549 | 549 |
550 return ret, nil | 550 return ret, nil |
551 } | 551 } |
OLD | NEW |