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  		for n := oldN >> H; n < newN>>H; n++ {
   119  			tiles = append(tiles, Tile{H: h, L: int(level), N: n, W: 1 << H})
   120  		}
   121  		n := newN >> H
   122  		maxW := int(newN - n<<H)
   123  		minW := 1
   124  		if oldN > n<<H {
   125  			minW = int(oldN - n<<H)
   126  		}
   127  		for w := minW; w <= maxW; w++ {
   128  			tiles = append(tiles, Tile{H: h, L: int(level), N: n, W: w})
   129  		}
   130  	}
   131  	return tiles
   132  }
   133  
   134  
   135  
   136  func ReadTileData(t Tile, r HashReader) ([]byte, error) {
   137  	size := t.W
   138  	if size == 0 {
   139  		size = 1 << uint(t.H)
   140  	}
   141  	start := t.N << uint(t.H)
   142  	indexes := make([]int64, size)
   143  	for i := 0; i < size; i++ {
   144  		indexes[i] = StoredHashIndex(t.H*t.L, start+int64(i))
   145  	}
   146  
   147  	hashes, err := r.ReadHashes(indexes)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	if len(hashes) != len(indexes) {
   152  		return nil, fmt.Errorf("tlog: ReadHashes(%d indexes) = %d hashes", len(indexes), len(hashes))
   153  	}
   154  
   155  	tile := make([]byte, size*HashSize)
   156  	for i := 0; i < size; i++ {
   157  		copy(tile[i*HashSize:], hashes[i][:])
   158  	}
   159  	return tile, nil
   160  }
   161  
   162  
   163  
   164  
   165  
   166  
   167  
   168  const pathBase = 1000
   169  
   170  
   171  func (t Tile) Path() string {
   172  	n := t.N
   173  	nStr := fmt.Sprintf("%03d", n%pathBase)
   174  	for n >= pathBase {
   175  		n /= pathBase
   176  		nStr = fmt.Sprintf("x%03d/%s", n%pathBase, nStr)
   177  	}
   178  	pStr := ""
   179  	if t.W != 1<<uint(t.H) {
   180  		pStr = fmt.Sprintf(".p/%d", t.W)
   181  	}
   182  	var L string
   183  	if t.L == -1 {
   184  		L = "data"
   185  	} else {
   186  		L = fmt.Sprintf("%d", t.L)
   187  	}
   188  	return fmt.Sprintf("tile/%d/%s/%s%s", t.H, L, nStr, pStr)
   189  }
   190  
   191  
   192  func ParseTilePath(path string) (Tile, error) {
   193  	f := strings.Split(path, "/")
   194  	if len(f) < 4 || f[0] != "tile" {
   195  		return Tile{}, &badPathError{path}
   196  	}
   197  	h, err1 := strconv.Atoi(f[1])
   198  	isData := false
   199  	if f[2] == "data" {
   200  		isData = true
   201  		f[2] = "0"
   202  	}
   203  	l, err2 := strconv.Atoi(f[2])
   204  	if err1 != nil || err2 != nil || h < 1 || l < 0 || h > 30 {
   205  		return Tile{}, &badPathError{path}
   206  	}
   207  	w := 1 << uint(h)
   208  	if dotP := f[len(f)-2]; strings.HasSuffix(dotP, ".p") {
   209  		ww, err := strconv.Atoi(f[len(f)-1])
   210  		if err != nil || ww <= 0 || ww >= w {
   211  			return Tile{}, &badPathError{path}
   212  		}
   213  		w = ww
   214  		f[len(f)-2] = dotP[:len(dotP)-len(".p")]
   215  		f = f[:len(f)-1]
   216  	}
   217  	f = f[3:]
   218  	n := int64(0)
   219  	for _, s := range f {
   220  		nn, err := strconv.Atoi(strings.TrimPrefix(s, "x"))
   221  		if err != nil || nn < 0 || nn >= pathBase {
   222  			return Tile{}, &badPathError{path}
   223  		}
   224  		n = n*pathBase + int64(nn)
   225  	}
   226  	if isData {
   227  		l = -1
   228  	}
   229  	t := Tile{H: h, L: l, N: n, W: w}
   230  	if path != t.Path() {
   231  		return Tile{}, &badPathError{path}
   232  	}
   233  	return t, nil
   234  }
   235  
   236  type badPathError struct {
   237  	path string
   238  }
   239  
   240  func (e *badPathError) Error() string {
   241  	return fmt.Sprintf("malformed tile path %q", e.path)
   242  }
   243  
   244  
   245  type TileReader interface {
   246  	
   247  	Height() int
   248  
   249  	
   250  	
   251  	
   252  	
   253  	
   254  	
   255  	
   256  	
   257  	
   258  	
   259  	
   260  	
   261  	
   262  	
   263  	
   264  	ReadTiles(tiles []Tile) (data [][]byte, err error)
   265  
   266  	
   267  	
   268  	
   269  	SaveTiles(tiles []Tile, data [][]byte)
   270  }
   271  
   272  
   273  
   274  
   275  
   276  
   277  
   278  func TileHashReader(tree Tree, tr TileReader) HashReader {
   279  	return &tileHashReader{tree: tree, tr: tr}
   280  }
   281  
   282  type tileHashReader struct {
   283  	tree Tree
   284  	tr   TileReader
   285  }
   286  
   287  
   288  
   289  func tileParent(t Tile, k int, n int64) Tile {
   290  	t.L += k
   291  	t.N >>= uint(k * t.H)
   292  	t.W = 1 << uint(t.H)
   293  	if max := n >> uint(t.L*t.H); t.N<<uint(t.H)+int64(t.W) >= max {
   294  		if t.N<<uint(t.H) >= max {
   295  			return Tile{}
   296  		}
   297  		t.W = int(max - t.N<<uint(t.H))
   298  	}
   299  	return t
   300  }
   301  
   302  func (r *tileHashReader) ReadHashes(indexes []int64) ([]Hash, error) {
   303  	h := r.tr.Height()
   304  
   305  	tileOrder := make(map[Tile]int) 
   306  	var tiles []Tile
   307  
   308  	
   309  	
   310  	stx := subTreeIndex(0, r.tree.N, nil)
   311  	stxTileOrder := make([]int, len(stx))
   312  	for i, x := range stx {
   313  		tile, _, _ := tileForIndex(h, x)
   314  		tile = tileParent(tile, 0, r.tree.N)
   315  		if j, ok := tileOrder[tile]; ok {
   316  			stxTileOrder[i] = j
   317  			continue
   318  		}
   319  		stxTileOrder[i] = len(tiles)
   320  		tileOrder[tile] = len(tiles)
   321  		tiles = append(tiles, tile)
   322  	}
   323  
   324  	
   325  	
   326  	
   327  	
   328  	indexTileOrder := make([]int, len(indexes))
   329  	for i, x := range indexes {
   330  		if x >= StoredHashIndex(0, r.tree.N) {
   331  			return nil, fmt.Errorf("indexes not in tree")
   332  		}
   333  
   334  		tile, _, _ := tileForIndex(h, x)
   335  
   336  		
   337  		
   338  		k := 0
   339  		for ; ; k++ {
   340  			p := tileParent(tile, k, r.tree.N)
   341  			if j, ok := tileOrder[p]; ok {
   342  				if k == 0 {
   343  					indexTileOrder[i] = j
   344  				}
   345  				break
   346  			}
   347  		}
   348  
   349  		
   350  		
   351  		
   352  		
   353  		for k--; k >= 0; k-- {
   354  			p := tileParent(tile, k, r.tree.N)
   355  			if p.W != 1<<uint(p.H) {
   356  				
   357  				
   358  				return nil, fmt.Errorf("bad math in tileHashReader: %d %d %v", r.tree.N, x, p)
   359  			}
   360  			tileOrder[p] = len(tiles)
   361  			if k == 0 {
   362  				indexTileOrder[i] = len(tiles)
   363  			}
   364  			tiles = append(tiles, p)
   365  		}
   366  	}
   367  
   368  	
   369  	data, err := r.tr.ReadTiles(tiles)
   370  	if err != nil {
   371  		return nil, err
   372  	}
   373  	if len(data) != len(tiles) {
   374  		return nil, fmt.Errorf("TileReader returned bad result slice (len=%d, want %d)", len(data), len(tiles))
   375  	}
   376  	for i, tile := range tiles {
   377  		if len(data[i]) != tile.W*HashSize {
   378  			return nil, fmt.Errorf("TileReader returned bad result slice (%v len=%d, want %d)", tile.Path(), len(data[i]), tile.W*HashSize)
   379  		}
   380  	}
   381  
   382  	
   383  	
   384  	
   385  	th, err := HashFromTile(tiles[stxTileOrder[len(stx)-1]], data[stxTileOrder[len(stx)-1]], stx[len(stx)-1])
   386  	if err != nil {
   387  		return nil, err
   388  	}
   389  	for i := len(stx) - 2; i >= 0; i-- {
   390  		h, err := HashFromTile(tiles[stxTileOrder[i]], data[stxTileOrder[i]], stx[i])
   391  		if err != nil {
   392  			return nil, err
   393  		}
   394  		th = NodeHash(h, th)
   395  	}
   396  	if th != r.tree.Hash {
   397  		
   398  		
   399  		return nil, fmt.Errorf("downloaded inconsistent tile")
   400  	}
   401  
   402  	
   403  	for i := len(stx); i < len(tiles); i++ {
   404  		tile := tiles[i]
   405  		p := tileParent(tile, 1, r.tree.N)
   406  		j, ok := tileOrder[p]
   407  		if !ok {
   408  			return nil, fmt.Errorf("bad math in tileHashReader %d %v: lost parent of %v", r.tree.N, indexes, tile)
   409  		}
   410  		h, err := HashFromTile(p, data[j], StoredHashIndex(p.L*p.H, tile.N))
   411  		if err != nil {
   412  			return nil, fmt.Errorf("bad math in tileHashReader %d %v: lost hash of %v: %v", r.tree.N, indexes, tile, err)
   413  		}
   414  		if h != tileHash(data[i]) {
   415  			return nil, fmt.Errorf("downloaded inconsistent tile")
   416  		}
   417  	}
   418  
   419  	
   420  	
   421  	r.tr.SaveTiles(tiles, data)
   422  
   423  	
   424  	hashes := make([]Hash, len(indexes))
   425  	for i, x := range indexes {
   426  		j := indexTileOrder[i]
   427  		h, err := HashFromTile(tiles[j], data[j], x)
   428  		if err != nil {
   429  			return nil, fmt.Errorf("bad math in tileHashReader %d %v: lost hash %v: %v", r.tree.N, indexes, x, err)
   430  		}
   431  		hashes[i] = h
   432  	}
   433  
   434  	return hashes, nil
   435  }
   436  
View as plain text