github.com/janelia-flyem/dvid@v1.0.0/datatype/imagetile/keys.go (about)

     1  /*
     2  	This file supports imagetile-specific keys.
     3  */
     4  
     5  package imagetile
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"net/http"
    11  	"strconv"
    12  
    13  	"github.com/janelia-flyem/dvid/datastore"
    14  	"github.com/janelia-flyem/dvid/dvid"
    15  	"github.com/janelia-flyem/dvid/storage"
    16  )
    17  
    18  // TODO -- Introduce imagetile key type to allow for expansion in future.  Since we currently
    19  // have datasets using old keys, hold off on upgrade until a breaking change is introduced for all keys.
    20  
    21  const (
    22  	// keyUnknown should never be used and is a check for corrupt or incorrectly set keys
    23  	keyUnknown storage.TKeyClass = iota
    24  
    25  	// reserved type-specific key for metadata
    26  	keyProperties = datastore.PropertyTKeyClass
    27  
    28  	// key = legacy tile.  Must be 3.
    29  	keyLegacyTile = 3
    30  )
    31  
    32  func describeTKeyClass(tkc storage.TKeyClass) string {
    33  	switch tkc {
    34  	case keyLegacyTile:
    35  		return "imagetile tile key"
    36  	default:
    37  		return "unknown imagetile key class"
    38  	}
    39  }
    40  
    41  // DescribeTKeyClass returns a string explanation of what a particular TKeyClass
    42  // is used for.  Implements the datastore.TKeyClassDescriber interface.
    43  func (d *Data) DescribeTKeyClass(tkc storage.TKeyClass) string {
    44  	return describeTKeyClass(tkc)
    45  }
    46  
    47  // NewTKey returns an imagetile-specific key component based on the components of a tile request.
    48  func NewTKey(tile dvid.ChunkPoint3d, plane dvid.DataShape, scale Scaling) (tk storage.TKey, err error) {
    49  	// NOTE: For legacy reasons, first two bytes must be 3 and then 2.  The current storage.TKey
    50  	// formatting has a TKeyClass for first byte and then 1 for second, but this second byte is only
    51  	// used for min/max key generation, so using 2 is ok as well.
    52  	var buf bytes.Buffer
    53  	buf.Write(plane.Bytes())
    54  
    55  	buf.WriteByte(byte(scale))
    56  	buf.WriteByte(byte(3))
    57  	idx := dvid.IndexZYX(tile)
    58  	buf.Write(idx.Bytes())
    59  	return buf.Bytes(), nil
    60  }
    61  
    62  // NewTKeyByTileReq returns an imagetile-specific key component based on a tile request.
    63  func NewTKeyByTileReq(req TileReq) (storage.TKey, error) {
    64  	return NewTKey(req.tile, req.plane, req.scale)
    65  }
    66  
    67  // DecodeTKey returns the components of a tile request based on an imagetile-specific key component.
    68  func DecodeTKey(tk storage.TKey) (tile dvid.ChunkPoint3d, plane dvid.DataShape, scale Scaling, err error) {
    69  	if len(tk) != 21 {
    70  		err = fmt.Errorf("expected 21 bytes for imagetile type-specific key, got %d bytes instead", len(tk))
    71  		return
    72  	}
    73  	plane, err = dvid.BytesToDataShape(tk[0:dvid.DataShapeBytes])
    74  	if err != nil {
    75  		return
    76  	}
    77  	scale = Scaling(tk[dvid.DataShapeBytes])
    78  	var idx dvid.IndexZYX
    79  	if err = idx.IndexFromBytes(tk[dvid.DataShapeBytes+2:]); err != nil {
    80  		return
    81  	}
    82  	tile = dvid.ChunkPoint3d(idx)
    83  	return
    84  }
    85  
    86  type TileReq struct {
    87  	tile  dvid.ChunkPoint3d
    88  	plane dvid.DataShape
    89  	scale Scaling
    90  }
    91  
    92  func (d *Data) ParseTileReq(r *http.Request, parts []string) (TileReq, error) {
    93  	if len(parts) < 7 {
    94  		return TileReq{}, fmt.Errorf("'tile' request must be following by plane, scale level, and tile coordinate")
    95  	}
    96  	shapeStr, scalingStr, coordStr := parts[4], parts[5], parts[6]
    97  
    98  	// Construct the index for this tile
    99  	planeStr := dvid.DataShapeString(shapeStr)
   100  	plane, err := planeStr.DataShape()
   101  	if err != nil {
   102  		err = fmt.Errorf("Illegal tile plane: %s (%v)", planeStr, err)
   103  		return TileReq{}, err
   104  	}
   105  	scale, err := strconv.ParseUint(scalingStr, 10, 8)
   106  	if err != nil {
   107  		err = fmt.Errorf("Illegal tile scale: %s (%v)", scalingStr, err)
   108  		return TileReq{}, err
   109  	}
   110  	tileCoord, err := dvid.StringToChunkPoint3d(coordStr, "_")
   111  	if err != nil {
   112  		err = fmt.Errorf("Illegal tile coordinate: %s (%v)", coordStr, err)
   113  		return TileReq{}, err
   114  	}
   115  	return TileReq{tileCoord, plane, Scaling(scale)}, nil
   116  }
   117  
   118  func NewTileReq(tile dvid.ChunkPoint3d, plane dvid.DataShape, scale Scaling) TileReq {
   119  	return TileReq{tile, plane, scale}
   120  }