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 }