1
2
3
4
5 package tlog
6
7 import (
8 "fmt"
9 "strconv"
10 "strings"
11 )
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 type Tile struct {
40 H int
41 L int
42 N int64
43 W int
44 }
45
46
47
48
49
50 func TileForIndex(h int, index int64) Tile {
51 if h <= 0 {
52 panic(fmt.Sprintf("TileForIndex: invalid height %d", h))
53 }
54 t, _, _ := tileForIndex(h, index)
55 return t
56 }
57
58
59
60
61 func tileForIndex(h int, index int64) (t Tile, start, end int) {
62 level, n := SplitStoredHashIndex(index)
63 t.H = h
64 t.L = level / h
65 level -= t.L * h
66 t.N = n << uint(level) >> uint(t.H)
67 n -= t.N << uint(t.H) >> uint(level)
68 t.W = int((n + 1) << uint(level))
69 return t, int(n<<uint(level)) * HashSize, int((n+1)<<uint(level)) * HashSize
70 }
71
72
73
74
75 func HashFromTile(t Tile, data []byte, index int64) (Hash, error) {
76 if t.H < 1 || t.H > 30 || t.L < 0 || t.L >= 64 || t.W < 1 || t.W > 1<<uint(t.H) {
77 return Hash{}, fmt.Errorf("invalid tile %v", t.Path())
78 }
79 if len(data) < t.W*HashSize {
80 return Hash{}, fmt.Errorf("data len %d too short for tile %v", len(data), t.Path())
81 }
82 t1, start, end := tileForIndex(t.H, index)
83 if t.L != t1.L || t.N != t1.N || t.W < t1.W {
84 return Hash{}, fmt.Errorf("index %v is in %v not %v", index, t1.Path(), t.Path())
85 }
86 return tileHash(data[start:end]), nil
87 }
88
89
90 func tileHash(data []byte) Hash {
91 if len(data) == 0 {
92 panic("bad math in tileHash")
93 }
94 if len(data) == HashSize {
95 var h Hash
96 copy(h[:], data)
97 return h
98 }
99 n := len(data) / 2
100 return NodeHash(tileHash(data[:n]), tileHash(data[n:]))
101 }
102
103
104
105
106
107
108
109 func NewTiles(h int, oldTreeSize, newTreeSize int64) []Tile {
110 if h <= 0 {
111 panic(fmt.Sprintf("NewTiles: invalid height %d", h))
112 }
113 H := uint(h)
114 var tiles []Tile
115 for level := uint(0); newTreeSize>>(H*level) > 0; level++ {
116 oldN := oldTreeSize >> (H * level)
117 newN := newTreeSize >> (H * level)
118 if oldN == newN {
119 continue
120 }
121 for n := oldN >> H; n < newN>>H; n++ {
122 tiles = append(tiles, Tile{H: h, L: int(level), N: n, W: 1 << H})
123 }
124 n := newN >> H
125 if w := int(newN - n<<H); w > 0 {
126 tiles = append(tiles, Tile{H: h, L: int(level), N: n, W: w})
127 }
128 }
129 return tiles
130 }
131
132
133
134 func ReadTileData(t Tile, r HashReader) ([]byte, error) {
135 size := t.W
136 if size == 0 {
137 size = 1 << uint(t.H)
138 }
139 start := t.N << uint(t.H)
140 indexes := make([]int64, size)
141 for i := 0; i < size; i++ {
142 indexes[i] = StoredHashIndex(t.H*t.L, start+int64(i))
143 }
144
145 hashes, err := r.ReadHashes(indexes)
146 if err != nil {
147 return nil, err
148 }
149 if len(hashes) != len(indexes) {
150 return nil, fmt.Errorf("tlog: ReadHashes(%d indexes) = %d hashes", len(indexes), len(hashes))
151 }
152
153 tile := make([]byte, size*HashSize)
154 for i := 0; i < size; i++ {
155 copy(tile[i*HashSize:], hashes[i][:])
156 }
157 return tile, nil
158 }
159
160
161
162
163
164
165
166 const pathBase = 1000
167
168
169 func (t Tile) Path() string {
170 n := t.N
171 nStr := fmt.Sprintf("%03d", n%pathBase)
172 for n >= pathBase {
173 n /= pathBase
174 nStr = fmt.Sprintf("x%03d/%s", n%pathBase, nStr)
175 }
176 pStr := ""
177 if t.W != 1<<uint(t.H) {
178 pStr = fmt.Sprintf(".p/%d", t.W)
179 }
180 var L string
181 if t.L == -1 {
182 L = "data"
183 } else {
184 L = fmt.Sprintf("%d", t.L)
185 }
186 return fmt.Sprintf("tile/%d/%s/%s%s", t.H, L, nStr, pStr)
187 }
188
189
190 func ParseTilePath(path string) (Tile, error) {
191 f := strings.Split(path, "/")
192 if len(f) < 4 || f[0] != "tile" {
193 return Tile{}, &badPathError{path}
194 }
195 h, err1 := strconv.Atoi(f[1])
196 isData := false
197 if f[2] == "data" {
198 isData = true
199 f[2] = "0"
200 }
201 l, err2 := strconv.Atoi(f[2])
202 if err1 != nil || err2 != nil || h < 1 || l < 0 || h > 30 {
203 return Tile{}, &badPathError{path}
204 }
205 w := 1 << uint(h)
206 if dotP := f[len(f)-2]; strings.HasSuffix(dotP, ".p") {
207 ww, err := strconv.Atoi(f[len(f)-1])
208 if err != nil || ww <= 0 || ww >= w {
209 return Tile{}, &badPathError{path}
210 }
211 w = ww
212 f[len(f)-2] = dotP[:len(dotP)-len(".p")]
213 f = f[:len(f)-1]
214 }
215 f = f[3:]
216 n := int64(0)
217 for _, s := range f {
218 nn, err := strconv.Atoi(strings.TrimPrefix(s, "x"))
219 if err != nil || nn < 0 || nn >= pathBase {
220 return Tile{}, &badPathError{path}
221 }
222 n = n*pathBase + int64(nn)
223 }
224 if isData {
225 l = -1
226 }
227 t := Tile{H: h, L: l, N: n, W: w}
228 if path != t.Path() {
229 return Tile{}, &badPathError{path}
230 }
231 return t, nil
232 }
233
234 type badPathError struct {
235 path string
236 }
237
238 func (e *badPathError) Error() string {
239 return fmt.Sprintf("malformed tile path %q", e.path)
240 }
241
242
243 type TileReader interface {
244
245 Height() int
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262 ReadTiles(tiles []Tile) (data [][]byte, err error)
263
264
265
266
267 SaveTiles(tiles []Tile, data [][]byte)
268 }
269
270
271
272
273
274
275
276 func TileHashReader(tree Tree, tr TileReader) HashReader {
277 return &tileHashReader{tree: tree, tr: tr}
278 }
279
280 type tileHashReader struct {
281 tree Tree
282 tr TileReader
283 }
284
285
286
287 func tileParent(t Tile, k int, n int64) Tile {
288 t.L += k
289 t.N >>= uint(k * t.H)
290 t.W = 1 << uint(t.H)
291 if max := n >> uint(t.L*t.H); t.N<<uint(t.H)+int64(t.W) >= max {
292 if t.N<<uint(t.H) >= max {
293 return Tile{}
294 }
295 t.W = int(max - t.N<<uint(t.H))
296 }
297 return t
298 }
299
300 func (r *tileHashReader) ReadHashes(indexes []int64) ([]Hash, error) {
301 h := r.tr.Height()
302
303 tileOrder := make(map[Tile]int)
304 var tiles []Tile
305
306
307
308 stx := subTreeIndex(0, r.tree.N, nil)
309 stxTileOrder := make([]int, len(stx))
310 for i, x := range stx {
311 tile, _, _ := tileForIndex(h, x)
312 tile = tileParent(tile, 0, r.tree.N)
313 if j, ok := tileOrder[tile]; ok {
314 stxTileOrder[i] = j
315 continue
316 }
317 stxTileOrder[i] = len(tiles)
318 tileOrder[tile] = len(tiles)
319 tiles = append(tiles, tile)
320 }
321
322
323
324
325
326 indexTileOrder := make([]int, len(indexes))
327 for i, x := range indexes {
328 if x >= StoredHashIndex(0, r.tree.N) {
329 return nil, fmt.Errorf("indexes not in tree")
330 }
331
332 tile, _, _ := tileForIndex(h, x)
333
334
335
336 k := 0
337 for ; ; k++ {
338 p := tileParent(tile, k, r.tree.N)
339 if j, ok := tileOrder[p]; ok {
340 if k == 0 {
341 indexTileOrder[i] = j
342 }
343 break
344 }
345 }
346
347
348
349
350
351 for k--; k >= 0; k-- {
352 p := tileParent(tile, k, r.tree.N)
353 if p.W != 1<<uint(p.H) {
354
355
356 return nil, fmt.Errorf("bad math in tileHashReader: %d %d %v", r.tree.N, x, p)
357 }
358 tileOrder[p] = len(tiles)
359 if k == 0 {
360 indexTileOrder[i] = len(tiles)
361 }
362 tiles = append(tiles, p)
363 }
364 }
365
366
367 data, err := r.tr.ReadTiles(tiles)
368 if err != nil {
369 return nil, err
370 }
371 if len(data) != len(tiles) {
372 return nil, fmt.Errorf("TileReader returned bad result slice (len=%d, want %d)", len(data), len(tiles))
373 }
374 for i, tile := range tiles {
375 if len(data[i]) != tile.W*HashSize {
376 return nil, fmt.Errorf("TileReader returned bad result slice (%v len=%d, want %d)", tile.Path(), len(data[i]), tile.W*HashSize)
377 }
378 }
379
380
381
382
383 th, err := HashFromTile(tiles[stxTileOrder[len(stx)-1]], data[stxTileOrder[len(stx)-1]], stx[len(stx)-1])
384 if err != nil {
385 return nil, err
386 }
387 for i := len(stx) - 2; i >= 0; i-- {
388 h, err := HashFromTile(tiles[stxTileOrder[i]], data[stxTileOrder[i]], stx[i])
389 if err != nil {
390 return nil, err
391 }
392 th = NodeHash(h, th)
393 }
394 if th != r.tree.Hash {
395
396
397 return nil, fmt.Errorf("downloaded inconsistent tile")
398 }
399
400
401 for i := len(stx); i < len(tiles); i++ {
402 tile := tiles[i]
403 p := tileParent(tile, 1, r.tree.N)
404 j, ok := tileOrder[p]
405 if !ok {
406 return nil, fmt.Errorf("bad math in tileHashReader %d %v: lost parent of %v", r.tree.N, indexes, tile)
407 }
408 h, err := HashFromTile(p, data[j], StoredHashIndex(p.L*p.H, tile.N))
409 if err != nil {
410 return nil, fmt.Errorf("bad math in tileHashReader %d %v: lost hash of %v: %v", r.tree.N, indexes, tile, err)
411 }
412 if h != tileHash(data[i]) {
413 return nil, fmt.Errorf("downloaded inconsistent tile")
414 }
415 }
416
417
418
419 r.tr.SaveTiles(tiles, data)
420
421
422 hashes := make([]Hash, len(indexes))
423 for i, x := range indexes {
424 j := indexTileOrder[i]
425 h, err := HashFromTile(tiles[j], data[j], x)
426 if err != nil {
427 return nil, fmt.Errorf("bad math in tileHashReader %d %v: lost hash %v: %v", r.tree.N, indexes, x, err)
428 }
429 hashes[i] = h
430 }
431
432 return hashes, nil
433 }
434
View as plain text