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 serialize | 5 package serialize |
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 ds "github.com/luci/gae/service/datastore" | 15 ds "github.com/luci/gae/service/datastore" |
16 "github.com/luci/luci-go/common/cmpbin" | 16 "github.com/luci/luci-go/common/cmpbin" |
| 17 "github.com/luci/luci-go/common/stringset" |
17 ) | 18 ) |
18 | 19 |
19 // MaxIndexColumns is the maximum number of sort columns (e.g. sort orders) that | 20 // MaxIndexColumns is the maximum number of sort columns (e.g. sort orders) that |
20 // ReadIndexDefinition is willing to deserialize. 64 was chosen as | 21 // ReadIndexDefinition is willing to deserialize. 64 was chosen as |
21 // a likely-astronomical number. | 22 // a likely-astronomical number. |
22 const MaxIndexColumns = 64 | 23 const MaxIndexColumns = 64 |
23 | 24 |
24 // WritePropertyMapDeterministic allows tests to make WritePropertyMap | 25 // WritePropertyMapDeterministic allows tests to make WritePropertyMap |
25 // deterministic. | 26 // deterministic. |
26 var WritePropertyMapDeterministic = false | 27 var WritePropertyMapDeterministic = false |
(...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 | 444 |
444 sb, err := ReadIndexColumn(buf) | 445 sb, err := ReadIndexColumn(buf) |
445 panicIf(err) | 446 panicIf(err) |
446 | 447 |
447 i.SortBy = append(i.SortBy, sb) | 448 i.SortBy = append(i.SortBy, sb) |
448 } | 449 } |
449 | 450 |
450 return | 451 return |
451 } | 452 } |
452 | 453 |
| 454 // SerializedPslice is all of the serialized DSProperty values in qASC order. |
| 455 type SerializedPslice [][]byte |
| 456 |
| 457 func (s SerializedPslice) Len() int { return len(s) } |
| 458 func (s SerializedPslice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } |
| 459 func (s SerializedPslice) Less(i, j int) bool { return bytes.Compare(s[i], s[j])
< 0 } |
| 460 |
| 461 // PropertySlice serializes a single row of a DSProperty map. |
| 462 func PropertySlice(vals ds.PropertySlice) SerializedPslice { |
| 463 dups := stringset.New(0) |
| 464 ret := make(SerializedPslice, 0, len(vals)) |
| 465 for _, v := range vals { |
| 466 if v.IndexSetting() == ds.NoIndex { |
| 467 continue |
| 468 } |
| 469 data := ToBytes(v.ForIndex()) |
| 470 dataS := string(data) |
| 471 if !dups.Add(dataS) { |
| 472 continue |
| 473 } |
| 474 ret = append(ret, data) |
| 475 } |
| 476 return ret |
| 477 } |
| 478 |
| 479 // SerializedPmap maps from |
| 480 // prop name -> [<serialized DSProperty>, ...] |
| 481 // includes special values '__key__' and '__ancestor__' which contains all of |
| 482 // the ancestor entries for this key. |
| 483 type SerializedPmap map[string]SerializedPslice |
| 484 |
| 485 // PropertyMapPartially turns a regular PropertyMap into a SerializedPmap. |
| 486 // Essentially all the []Property's become SerializedPslice, using cmpbin and |
| 487 // datastore/serialize's encodings. |
| 488 func PropertyMapPartially(k *ds.Key, pm ds.PropertyMap) (ret SerializedPmap) { |
| 489 ret = make(SerializedPmap, len(pm)+2) |
| 490 if k != nil { |
| 491 ret["__key__"] = [][]byte{ToBytes(ds.MkProperty(k))} |
| 492 for k != nil { |
| 493 ret["__ancestor__"] = append(ret["__ancestor__"], ToByte
s(ds.MkProperty(k))) |
| 494 k = k.Parent() |
| 495 } |
| 496 } |
| 497 for k, vals := range pm { |
| 498 newVals := PropertySlice(vals) |
| 499 if len(newVals) > 0 { |
| 500 ret[k] = newVals |
| 501 } |
| 502 } |
| 503 return |
| 504 } |
| 505 |
453 func toBytesErr(i interface{}, ctx KeyContext) (ret []byte, err error) { | 506 func toBytesErr(i interface{}, ctx KeyContext) (ret []byte, err error) { |
454 buf := &bytes.Buffer{} | 507 buf := &bytes.Buffer{} |
455 switch x := i.(type) { | 508 switch x := i.(type) { |
456 case ds.GeoPoint: | 509 case ds.GeoPoint: |
457 err = WriteGeoPoint(buf, x) | 510 err = WriteGeoPoint(buf, x) |
458 | 511 |
459 case ds.IndexColumn: | 512 case ds.IndexColumn: |
460 err = WriteIndexColumn(buf, x) | 513 err = WriteIndexColumn(buf, x) |
461 | 514 |
462 case ds.IndexDefinition: | 515 case ds.IndexDefinition: |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
540 } | 593 } |
541 } | 594 } |
542 | 595 |
543 func recoverTo(err *error) { | 596 func recoverTo(err *error) { |
544 if r := recover(); r != nil { | 597 if r := recover(); r != nil { |
545 if rerr := r.(parseError); rerr != nil { | 598 if rerr := r.(parseError); rerr != nil { |
546 *err = error(rerr) | 599 *err = error(rerr) |
547 } | 600 } |
548 } | 601 } |
549 } | 602 } |
OLD | NEW |