| OLD | NEW |
| 1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package bigtable | 5 package bigtable |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "bytes" | 8 "bytes" |
| 9 "crypto/sha256" | 9 "crypto/sha256" |
| 10 "encoding/base64" | 10 "encoding/base64" |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 func (rkb *rowKeyBuffers) value() string { | 84 func (rkb *rowKeyBuffers) value() string { |
| 85 return string(rkb.key[:rkb.size]) | 85 return string(rkb.key[:rkb.size]) |
| 86 } | 86 } |
| 87 | 87 |
| 88 // rowKey is a BigTable row key. | 88 // rowKey is a BigTable row key. |
| 89 // | 89 // |
| 90 // The row key is formed from a Path and its Index. The goal: | 90 // The row key is formed from a Path and its Index. The goal: |
| 91 // - Rows with the same path should be clustered. | 91 // - Rows with the same path should be clustered. |
| 92 // - Rows with the same path should be sorted according to index. | 92 // - Rows with the same path should be sorted according to index. |
| 93 // | 93 // |
| 94 // The row key index is the index of the LAST entry in the row. Therefore, a |
| 95 // row for a given row key will span log indexes [index-count+1..index]. |
| 96 // |
| 94 // Since BigTable rows must be valid UTF8, and since paths are effectively | 97 // Since BigTable rows must be valid UTF8, and since paths are effectively |
| 95 // unbounded, the row key will be formed by composing: | 98 // unbounded, the row key will be formed by composing: |
| 96 // | 99 // |
| 97 // [ base64(sha256(path)) ] + '~' + [ hex(cmpbin(index)) ] + '~' + | 100 // [ base64(sha256(path)) ] + '~' + [ hex(cmpbin(index)) ] + '~' + |
| 98 // [hex(cmpbin(count)] | 101 // [hex(cmpbin(count)] |
| 99 type rowKey struct { | 102 type rowKey struct { |
| 100 pathHash []byte | 103 pathHash []byte |
| 101 index int64 | 104 index int64 |
| 102 count int64 | 105 count int64 |
| 103 } | 106 } |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 // than any hex-encoded row index, so this key will always be larger. | 195 // than any hex-encoded row index, so this key will always be larger. |
| 193 func (rk *rowKey) pathPrefixUpperBound() (v string) { | 196 func (rk *rowKey) pathPrefixUpperBound() (v string) { |
| 194 withRowKeyBuffers(func(rkb *rowKeyBuffers) { | 197 withRowKeyBuffers(func(rkb *rowKeyBuffers) { |
| 195 rkb.appendPathPrefix(rk.pathHash) | 198 rkb.appendPathPrefix(rk.pathHash) |
| 196 rkb.appendBytes([]byte("~~")) | 199 rkb.appendBytes([]byte("~~")) |
| 197 v = rkb.value() | 200 v = rkb.value() |
| 198 }) | 201 }) |
| 199 return | 202 return |
| 200 } | 203 } |
| 201 | 204 |
| 205 // firstIndex returns the first log entry index represented by this row key. |
| 206 func (rk *rowKey) firstIndex() int64 { return rk.index - rk.count + 1 } |
| 207 |
| 202 // sharesPrefixWith tests if the "path" component of the row key "rk" matches | 208 // sharesPrefixWith tests if the "path" component of the row key "rk" matches |
| 203 // the "path" component of "o". | 209 // the "path" component of "o". |
| 204 func (rk *rowKey) sharesPathWith(o *rowKey) bool { | 210 func (rk *rowKey) sharesPathWith(o *rowKey) bool { |
| 205 return bytes.Equal(rk.pathHash, o.pathHash) | 211 return bytes.Equal(rk.pathHash, o.pathHash) |
| 206 } | 212 } |
| 207 | 213 |
| 208 func readHexInt64(v string) (int64, error) { | 214 func readHexInt64(v string) (int64, error) { |
| 209 d, err := hex.DecodeString(v) | 215 d, err := hex.DecodeString(v) |
| 210 if err != nil { | 216 if err != nil { |
| 211 return 0, errMalformedRowKey | 217 return 0, errMalformedRowKey |
| 212 } | 218 } |
| 213 | 219 |
| 214 dr := bytes.NewReader(d) | 220 dr := bytes.NewReader(d) |
| 215 value, _, err := cmpbin.ReadInt(dr) | 221 value, _, err := cmpbin.ReadInt(dr) |
| 216 if err != nil { | 222 if err != nil { |
| 217 return 0, errMalformedRowKey | 223 return 0, errMalformedRowKey |
| 218 } | 224 } |
| 219 | 225 |
| 220 // There should be no more data. | 226 // There should be no more data. |
| 221 if dr.Len() > 0 { | 227 if dr.Len() > 0 { |
| 222 return 0, errMalformedRowKey | 228 return 0, errMalformedRowKey |
| 223 } | 229 } |
| 224 | 230 |
| 225 return value, nil | 231 return value, nil |
| 226 } | 232 } |
| OLD | NEW |