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 datastore | 5 package datastore |
6 | 6 |
7 import ( | 7 import ( |
8 "bytes" | 8 "bytes" |
9 "errors" | 9 "errors" |
10 "fmt" | 10 "fmt" |
11 "sort" | 11 "sort" |
12 "time" | 12 "time" |
13 | 13 |
14 "github.com/luci/gae/service/blobstore" | 14 "github.com/luci/gae/service/blobstore" |
15 "github.com/luci/luci-go/common/cmpbin" | 15 "github.com/luci/luci-go/common/cmpbin" |
16 ) | 16 ) |
17 | 17 |
| 18 // MaxIndexColumns is the maximum number of sort orders you may have on a |
| 19 // single composite index. 64 was chosen as a likely-astronomical number. |
| 20 const MaxIndexColumns = 64 |
| 21 |
18 // WritePropertyMapDeterministic allows tests to make WritePropertyMap | 22 // WritePropertyMapDeterministic allows tests to make WritePropertyMap |
19 // deterministic. | 23 // deterministic. |
20 var WritePropertyMapDeterministic = false | 24 var WritePropertyMapDeterministic = false |
21 | 25 |
22 // ReadPropertyMapReasonableLimit sets a limit on the number of rows and | 26 // ReadPropertyMapReasonableLimit sets a limit on the number of rows and |
23 // number of properties per row which can be read by ReadPropertyMap. The | 27 // number of properties per row which can be read by ReadPropertyMap. The |
24 // total number of Property objects readable by this method is this number | 28 // total number of Property objects readable by this method is this number |
25 // squared (e.g. Limit rows * Limit properties) | 29 // squared (e.g. Limit rows * Limit properties) |
26 const ReadPropertyMapReasonableLimit uint64 = 30000 | 30 const ReadPropertyMapReasonableLimit uint64 = 30000 |
27 | 31 |
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
358 props := make([]Property, 0, numProps) | 362 props := make([]Property, 0, numProps) |
359 for j := uint64(0); j < numProps; j++ { | 363 for j := uint64(0); j < numProps; j++ { |
360 panicIf(prop.Read(buf, context, appid, namespace)) | 364 panicIf(prop.Read(buf, context, appid, namespace)) |
361 props = append(props, prop) | 365 props = append(props, prop) |
362 } | 366 } |
363 pm[name] = props | 367 pm[name] = props |
364 } | 368 } |
365 return | 369 return |
366 } | 370 } |
367 | 371 |
| 372 func (c *IndexColumn) Write(buf Buffer) (err error) { |
| 373 defer recoverTo(&err) |
| 374 |
| 375 if c.Direction == ASCENDING { |
| 376 panicIf(buf.WriteByte(0)) |
| 377 } else { |
| 378 panicIf(buf.WriteByte(1)) |
| 379 } |
| 380 _, err = cmpbin.WriteString(buf, c.Property) |
| 381 return |
| 382 } |
| 383 |
| 384 func (c *IndexColumn) Read(buf Buffer) (err error) { |
| 385 defer recoverTo(&err) |
| 386 |
| 387 dir, err := buf.ReadByte() |
| 388 panicIf(err) |
| 389 |
| 390 switch dir { |
| 391 case 0: |
| 392 c.Direction = ASCENDING |
| 393 default: |
| 394 c.Direction = DESCENDING |
| 395 } |
| 396 c.Property, _, err = cmpbin.ReadString(buf) |
| 397 return err |
| 398 } |
| 399 |
| 400 func (i *IndexDefinition) Write(buf Buffer) (err error) { |
| 401 defer recoverTo(&err) |
| 402 |
| 403 if i.Builtin() { |
| 404 panicIf(buf.WriteByte(0)) |
| 405 } else { |
| 406 panicIf(buf.WriteByte(1)) |
| 407 } |
| 408 _, err = cmpbin.WriteString(buf, i.Kind) |
| 409 panicIf(err) |
| 410 if !i.Ancestor { |
| 411 panicIf(buf.WriteByte(0)) |
| 412 } else { |
| 413 panicIf(buf.WriteByte(1)) |
| 414 } |
| 415 _, err = cmpbin.WriteUint(buf, uint64(len(i.SortBy))) |
| 416 panicIf(err) |
| 417 for _, sb := range i.SortBy { |
| 418 panicIf(sb.Write(buf)) |
| 419 } |
| 420 return |
| 421 } |
| 422 |
| 423 func (i *IndexDefinition) Read(buf Buffer) (err error) { |
| 424 defer recoverTo(&err) |
| 425 |
| 426 // discard builtin/complex byte |
| 427 _, err = buf.ReadByte() |
| 428 panicIf(err) |
| 429 |
| 430 i.Kind, _, err = cmpbin.ReadString(buf) |
| 431 panicIf(err) |
| 432 |
| 433 anc, err := buf.ReadByte() |
| 434 panicIf(err) |
| 435 |
| 436 i.Ancestor = anc == 1 |
| 437 |
| 438 numSorts, _, err := cmpbin.ReadUint(buf) |
| 439 panicIf(err) |
| 440 |
| 441 if numSorts > MaxIndexColumns { |
| 442 return fmt.Errorf("datastore: Got over %d sort orders: %d", |
| 443 MaxIndexColumns, numSorts) |
| 444 } |
| 445 |
| 446 if numSorts > 0 { |
| 447 i.SortBy = make([]IndexColumn, numSorts) |
| 448 for idx := range i.SortBy { |
| 449 panicIf(i.SortBy[idx].Read(buf)) |
| 450 } |
| 451 } |
| 452 |
| 453 return |
| 454 } |
| 455 |
368 type parseError error | 456 type parseError error |
369 | 457 |
370 func panicIf(err error) { | 458 func panicIf(err error) { |
371 if err != nil { | 459 if err != nil { |
372 panic(parseError(err)) | 460 panic(parseError(err)) |
373 } | 461 } |
374 } | 462 } |
375 | 463 |
376 func recoverTo(err *error) { | 464 func recoverTo(err *error) { |
377 if r := recover(); r != nil { | 465 if r := recover(); r != nil { |
378 if rerr := r.(parseError); rerr != nil { | 466 if rerr := r.(parseError); rerr != nil { |
379 *err = error(rerr) | 467 *err = error(rerr) |
380 } | 468 } |
381 } | 469 } |
382 } | 470 } |
OLD | NEW |