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

     1  /*
     2  	This file supports keyspaces for label block data types.
     3  */
     4  
     5  package labelmap
     6  
     7  import (
     8  	"encoding/binary"
     9  	"fmt"
    10  	"math"
    11  
    12  	"github.com/janelia-flyem/dvid/datastore"
    13  	"github.com/janelia-flyem/dvid/dvid"
    14  	"github.com/janelia-flyem/dvid/storage"
    15  )
    16  
    17  const (
    18  	// keyUnknown should never be used and is a check for corrupt or incorrectly set keys
    19  	keyUnknown storage.TKeyClass = 0
    20  
    21  	// reserved type-specific key for metadata
    22  	keyProperties = datastore.PropertyTKeyClass
    23  
    24  	// key = scale + block coord
    25  	keyLabelBlock = 186
    26  
    27  	// key = label. value = datatype/common/proto/LabelIndex serialization
    28  	keyLabelIndex = 187
    29  
    30  	// key = label.  value = datatype/common/proto/AffinityTable serialization
    31  	keyAffinities = 188
    32  
    33  	// Used to store max label on commit for each version of the instance.
    34  	keyLabelMax = 237
    35  
    36  	// Stores the single repo-wide max label for the instance.  Used for new labels on split.
    37  	keyRepoLabelMax = 238
    38  
    39  	// Stores the single repo-wide next label for the instance.  Overrides max labels.
    40  	keyRepoNextLabel = 239
    41  
    42  	// mutation cache keys = label + mutid. value = label index just before mutation applied.
    43  	keyMutcache = 240
    44  )
    45  
    46  // DescribeTKeyClass returns a string explanation of what a particular TKeyClass
    47  // is used for.  Implements the datastore.TKeyClassDescriber interface.
    48  func (d *Data) DescribeTKeyClass(tkc storage.TKeyClass) string {
    49  	switch tkc {
    50  	case keyProperties:
    51  		return "labelmap properties key"
    52  	case keyLabelBlock:
    53  		return "labelmap scale + block coord key"
    54  	case keyLabelIndex:
    55  		return "labelmap label index key"
    56  	case keyAffinities:
    57  		return "labelmap affinities key"
    58  	case keyLabelMax:
    59  		return "labelmap label max key"
    60  	case keyRepoLabelMax:
    61  		return "labelmap repo label max key"
    62  	case keyRepoNextLabel:
    63  		return "labelmap next label key"
    64  	case keyMutcache:
    65  		return "labelmap mutation cache key"
    66  	default:
    67  	}
    68  	return "unknown labelmap key"
    69  }
    70  
    71  var (
    72  	maxLabelTKey     = storage.NewTKey(keyLabelMax, nil)
    73  	maxRepoLabelTKey = storage.NewTKey(keyRepoLabelMax, nil)
    74  	nextLabelTKey    = storage.NewTKey(keyRepoNextLabel, nil)
    75  )
    76  
    77  // NewBlockTKey returns a TKey for a label block, which is a slice suitable for
    78  // lexicographical ordering on zyx coordinates.
    79  func NewBlockTKey(scale uint8, idx dvid.Index) storage.TKey {
    80  	izyx := idx.(*dvid.IndexZYX)
    81  	return NewBlockTKeyByCoord(scale, izyx.ToIZYXString())
    82  }
    83  
    84  // NewBlockTKeyByCoord returns a TKey for a block coord in string format.
    85  func NewBlockTKeyByCoord(scale uint8, izyx dvid.IZYXString) storage.TKey {
    86  	buf := make([]byte, 13)
    87  	buf[0] = byte(scale)
    88  	copy(buf[1:], []byte(izyx))
    89  	return storage.NewTKey(keyLabelBlock, buf)
    90  }
    91  
    92  // DecodeBlockTKey returns a spatial index from a label block key.
    93  // TODO: Extend this when necessary to allow any form of spatial indexing like CZYX.
    94  func DecodeBlockTKey(tk storage.TKey) (scale uint8, idx *dvid.IndexZYX, err error) {
    95  	ibytes, err := tk.ClassBytes(keyLabelBlock)
    96  	if err != nil {
    97  		return 0, nil, err
    98  	}
    99  	if len(ibytes) != 13 {
   100  		err = fmt.Errorf("bad labelmap block key of %d bytes: %v", len(ibytes), ibytes)
   101  		return
   102  	}
   103  	scale = uint8(ibytes[0])
   104  	idx = new(dvid.IndexZYX)
   105  	if err = idx.IndexFromBytes(ibytes[1:]); err != nil {
   106  		err = fmt.Errorf("Cannot recover ZYX index from image block key %v: %v\n", tk, err)
   107  	}
   108  	return
   109  }
   110  
   111  // NewLabelIndexTKey returns a TKey corresponding to a label.
   112  func NewLabelIndexTKey(label uint64) storage.TKey {
   113  	buf := make([]byte, 8)
   114  	binary.BigEndian.PutUint64(buf, label)
   115  	return storage.NewTKey(keyLabelIndex, buf)
   116  }
   117  
   118  // DecodeLabelIndexTKey parses a TKey and returns the corresponding label.
   119  func DecodeLabelIndexTKey(tk storage.TKey) (label uint64, err error) {
   120  	var ibytes []byte
   121  	ibytes, err = tk.ClassBytes(keyLabelIndex)
   122  	if err != nil {
   123  		return
   124  	}
   125  	label = binary.BigEndian.Uint64(ibytes[0:8])
   126  	return
   127  }
   128  
   129  // NewAffinitiesTKey returns a TKey corresponding to a label's affinities.
   130  func NewAffinitiesTKey(label uint64) storage.TKey {
   131  	buf := make([]byte, 8)
   132  	binary.BigEndian.PutUint64(buf, label)
   133  	return storage.NewTKey(keyAffinities, buf)
   134  }
   135  
   136  // DecodeAffinitiesTKey parses a TKey and returns the corresponding label.
   137  func DecodeAffinitiesTKey(tk storage.TKey) (label uint64, err error) {
   138  	ibytes, err := tk.ClassBytes(keyAffinities)
   139  	if err != nil {
   140  		return
   141  	}
   142  	label = binary.BigEndian.Uint64(ibytes[0:8])
   143  	return
   144  }
   145  
   146  // -- support for mutation cache keys that should be stored in DB per instance
   147  func newMutcacheKey(label, mutID uint64) storage.TKey {
   148  	buf := make([]byte, 16)
   149  	binary.BigEndian.PutUint64(buf[0:8], label)
   150  	binary.BigEndian.PutUint64(buf[8:16], math.MaxUint64-mutID)
   151  	return storage.NewTKey(keyMutcache, buf)
   152  }
   153  
   154  func decodeMutcacheKey(tk storage.TKey) (label, mutid uint64, err error) {
   155  	var ibytes []byte
   156  	ibytes, err = tk.ClassBytes(keyMutcache)
   157  	if err != nil {
   158  		return
   159  	}
   160  	if len(ibytes) != 16 {
   161  		err = fmt.Errorf("bad key size (%d) for mutation cache key", len(ibytes))
   162  		return
   163  	}
   164  	label = binary.BigEndian.Uint64(ibytes[0:8])
   165  	mutid = math.MaxUint64 - binary.BigEndian.Uint64(ibytes[8:16])
   166  	return
   167  }