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" |
11 "strings" | 11 "strings" |
12 | 12 |
13 ds "github.com/luci/gae/service/datastore" | 13 ds "github.com/luci/gae/service/datastore" |
14 "github.com/luci/gae/service/datastore/serialize" | 14 "github.com/luci/gae/service/datastore/serialize" |
15 "github.com/luci/luci-go/common/stringset" | 15 "github.com/luci/luci-go/common/stringset" |
16 ) | 16 ) |
17 | 17 |
| 18 // ErrMissingIndex is returned when the current indexes are not sufficient |
| 19 // for the current query. |
| 20 type ErrMissingIndex struct { |
| 21 ns string |
| 22 Missing *ds.IndexDefinition |
| 23 } |
| 24 |
| 25 func (e *ErrMissingIndex) Error() string { |
| 26 yaml, err := e.Missing.YAMLString() |
| 27 if err != nil { |
| 28 panic(err) |
| 29 } |
| 30 return fmt.Sprintf( |
| 31 "Insufficient indexes. Consider adding:\n%s", yaml) |
| 32 } |
| 33 |
18 // reducedQuery contains only the pieces of the query necessary to iterate for | 34 // reducedQuery contains only the pieces of the query necessary to iterate for |
19 // results. | 35 // results. |
20 // deduplication is applied externally | 36 // deduplication is applied externally |
21 // projection / keysonly / entity retrieval is done externally | 37 // projection / keysonly / entity retrieval is done externally |
22 type reducedQuery struct { | 38 type reducedQuery struct { |
23 ns string | 39 ns string |
24 kind string | 40 kind string |
25 | 41 |
26 // eqFilters indicate the set of all prefix constraints which need to be | 42 // eqFilters indicate the set of all prefix constraints which need to be |
27 // fulfilled in the composite query. All of these will translate into pr
efix | 43 // fulfilled in the composite query. All of these will translate into pr
efix |
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 remains.SortBy = append(remains.SortBy, q.suffixFormat...) | 308 remains.SortBy = append(remains.SortBy, q.suffixFormat...) |
293 last := remains.SortBy[len(remains.SortBy)-1] | 309 last := remains.SortBy[len(remains.SortBy)-1] |
294 if !last.Descending { | 310 if !last.Descending { |
295 // this removes the __key__ column, since it's implicit. | 311 // this removes the __key__ column, since it's implicit. |
296 remains.SortBy = remains.SortBy[:len(remains.SortBy)-1] | 312 remains.SortBy = remains.SortBy[:len(remains.SortBy)-1] |
297 } | 313 } |
298 if remains.Builtin() { | 314 if remains.Builtin() { |
299 impossible( | 315 impossible( |
300 fmt.Errorf("recommended missing index would be a
builtin: %s", remains)) | 316 fmt.Errorf("recommended missing index would be a
builtin: %s", remains)) |
301 } | 317 } |
302 » » return nil, fmt.Errorf( | 318 » » return nil, &ErrMissingIndex{q.ns, remains} |
303 » » » "Your indexes are insufficient! Try adding:\n %s", rema
ins) | |
304 } | 319 } |
305 | 320 |
306 return idxs, nil | 321 return idxs, nil |
307 } | 322 } |
308 | 323 |
309 // generate generates a single iterDefinition for the given index. | 324 // generate generates a single iterDefinition for the given index. |
310 func generate(q *reducedQuery, idx *indexDefinitionSortable, c *constraints) *it
erDefinition { | 325 func generate(q *reducedQuery, idx *indexDefinitionSortable, c *constraints) *it
erDefinition { |
311 def := &iterDefinition{ | 326 def := &iterDefinition{ |
312 c: idx.coll, | 327 c: idx.coll, |
313 start: q.start, | 328 start: q.start, |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
531 if bestIdx == nil { | 546 if bestIdx == nil { |
532 // something is really wrong here... if relevantIdxs is
!nil, then we | 547 // something is really wrong here... if relevantIdxs is
!nil, then we |
533 // should always be able to make progress in this loop. | 548 // should always be able to make progress in this loop. |
534 impossible(fmt.Errorf("deadlock: cannot fulfil query?")) | 549 impossible(fmt.Errorf("deadlock: cannot fulfil query?")) |
535 } | 550 } |
536 ret = append(ret, generate(q, bestIdx, constraints)) | 551 ret = append(ret, generate(q, bestIdx, constraints)) |
537 } | 552 } |
538 | 553 |
539 return ret, nil | 554 return ret, nil |
540 } | 555 } |
OLD | NEW |