github.com/janelia-flyem/dvid@v1.0.0/datatype/labelmap/equiv.go (about) 1 // Equivalence maps for each version in DAG. 2 3 package labelmap 4 5 import ( 6 "encoding/json" 7 "fmt" 8 "sync" 9 10 "github.com/dustin/go-humanize" 11 12 "github.com/janelia-flyem/dvid/datastore" 13 "github.com/janelia-flyem/dvid/datatype/common/labels" 14 "github.com/janelia-flyem/dvid/datatype/common/proto" 15 "github.com/janelia-flyem/dvid/dvid" 16 ) 17 18 type instanceMaps struct { 19 maps map[dvid.UUID]*VCache 20 sync.RWMutex 21 } 22 23 var ( 24 iMap instanceMaps 25 ) 26 27 const ( 28 // NumSVMapShards is the number of shards for the supervoxel map. 29 NumSVMapShards = 100 30 ) 31 32 func init() { 33 iMap.maps = make(map[dvid.UUID]*VCache) 34 } 35 36 // returns or creates an SVMap so nil is never returned unless there's an error 37 func getMapping(d dvid.Data, v dvid.VersionID) (*VCache, error) { 38 m := initMapping(d, v) 39 40 m.mappedVersionsMu.RLock() 41 _, found := m.mappedVersions[v] 42 m.mappedVersionsMu.RUnlock() 43 if found { 44 return m, nil // we have already loaded this version and its ancestors 45 } 46 if err := m.initToVersion(d, v, true); err != nil { 47 return nil, err 48 } 49 return m, nil 50 } 51 52 // returns or creates an SVMap for data at a given version 53 func initMapping(d dvid.Data, v dvid.VersionID) *VCache { 54 iMap.Lock() 55 lmap, found := iMap.maps[d.DataUUID()] 56 if !found { 57 lmap = newVCache(NumSVMapShards) 58 iMap.maps[d.DataUUID()] = lmap 59 } 60 iMap.Unlock() 61 return lmap 62 } 63 64 // adds a merge into the equivalence map for a given instance version and also 65 // records the mappings into the log. 66 func addMergeToMapping(d dvid.Data, v dvid.VersionID, mutID, toLabel uint64, supervoxels labels.Set) error { 67 if len(supervoxels) == 0 { 68 return nil 69 } 70 lmap, err := getMapping(d, v) 71 if err != nil { 72 return err 73 } 74 for supervoxel := range supervoxels { 75 lmap.setMapping(v, supervoxel, toLabel) 76 } 77 op := labels.MappingOp{ 78 MutID: mutID, 79 Mapped: toLabel, 80 Original: supervoxels, 81 } 82 return labels.LogMapping(d, v, op) 83 } 84 85 // // adds a renumber into the equivalence map for a given instance version and also 86 // // records the mappings into the log. 87 func addRenumberToMapping(d dvid.Data, v dvid.VersionID, mutID, origLabel, newLabel uint64, supervoxels labels.Set) error { 88 if len(supervoxels) == 0 { 89 return nil 90 } 91 lmap, err := getMapping(d, v) 92 if err != nil { 93 return err 94 } 95 for supervoxel := range supervoxels { 96 lmap.setMapping(v, supervoxel, newLabel) 97 } 98 lmap.setMapping(v, newLabel, 0) 99 op := labels.MappingOp{ 100 MutID: mutID, 101 Mapped: newLabel, 102 Original: supervoxels, 103 } 104 return labels.LogMapping(d, v, op) 105 } 106 107 // adds new arbitrary split into the equivalence map for a given instance version. 108 func addSplitToMapping(d dvid.Data, v dvid.VersionID, op labels.SplitOp) error { 109 lmap, err := getMapping(d, v) 110 if err != nil { 111 return err 112 } 113 114 deleteSupervoxels := make(labels.Set) 115 splitSupervoxels := make(labels.Set) 116 remainSupervoxels := make(labels.Set) 117 118 splits := lmap.splits[v] 119 for supervoxel, svsplit := range op.SplitMap { 120 deleteSupervoxels[supervoxel] = struct{}{} 121 splitSupervoxels[svsplit.Split] = struct{}{} 122 remainSupervoxels[svsplit.Remain] = struct{}{} 123 124 lmap.setMapping(v, svsplit.Split, op.NewLabel) 125 lmap.setMapping(v, svsplit.Remain, op.Target) 126 lmap.setMapping(v, supervoxel, 0) 127 128 rec := proto.SupervoxelSplitOp{ 129 Mutid: op.MutID, 130 Supervoxel: supervoxel, 131 Remainlabel: svsplit.Remain, 132 Splitlabel: svsplit.Split, 133 } 134 splits = append(splits, rec) 135 136 // TODO -- for each split, we log each supervoxel split. 137 } 138 lmap.splitsMu.Lock() 139 lmap.splits[v] = splits 140 lmap.splitsMu.Unlock() 141 142 mapOp := labels.MappingOp{ 143 MutID: op.MutID, 144 Mapped: 0, 145 Original: deleteSupervoxels, 146 } 147 if err := labels.LogMapping(d, v, mapOp); err != nil { 148 dvid.Criticalf("unable to log the mapping of deleted supervoxels %s for split label %d: %v\n", deleteSupervoxels, op.Target, err) 149 return err 150 } 151 mapOp = labels.MappingOp{ 152 MutID: op.MutID, 153 Mapped: op.NewLabel, 154 Original: splitSupervoxels, 155 } 156 if err := labels.LogMapping(d, v, mapOp); err != nil { 157 dvid.Criticalf("unable to log the mapping of split supervoxels %s to split body label %d: %v\n", splitSupervoxels, op.NewLabel, err) 158 return err 159 } 160 mapOp = labels.MappingOp{ 161 MutID: op.MutID, 162 Mapped: op.Target, 163 Original: remainSupervoxels, 164 } 165 return labels.LogMapping(d, v, mapOp) 166 } 167 168 // adds new cleave into the equivalence map for a given instance version and also 169 // records the mappings into the log. 170 func addCleaveToMapping(d dvid.Data, v dvid.VersionID, op labels.CleaveOp) error { 171 lmap, err := getMapping(d, v) 172 if err != nil { 173 return err 174 } 175 if len(op.CleavedSupervoxels) == 0 { 176 return nil 177 } 178 supervoxelSet := make(labels.Set, len(op.CleavedSupervoxels)) 179 for _, supervoxel := range op.CleavedSupervoxels { 180 supervoxelSet[supervoxel] = struct{}{} 181 lmap.setMapping(v, supervoxel, op.CleavedLabel) 182 } 183 lmap.setMapping(v, op.CleavedLabel, 0) 184 mapOp := labels.MappingOp{ 185 MutID: op.MutID, 186 Mapped: op.CleavedLabel, 187 Original: supervoxelSet, 188 } 189 return labels.LogMapping(d, v, mapOp) 190 } 191 192 // adds supervoxel split into the equivalence map for a given instance version and also 193 // records the mappings into the log. 194 func addSupervoxelSplitToMapping(d dvid.Data, v dvid.VersionID, op labels.SplitSupervoxelOp) error { 195 lmap, err := getMapping(d, v) 196 if err != nil { 197 return err 198 } 199 label := op.Supervoxel 200 mapped, found := lmap.MappedLabel(v, op.Supervoxel) 201 if found { 202 label = mapped 203 } 204 205 lmap.setMapping(v, op.SplitSupervoxel, label) 206 lmap.setMapping(v, op.RemainSupervoxel, label) 207 lmap.setMapping(v, op.Supervoxel, 0) 208 209 rec := proto.SupervoxelSplitOp{ 210 Mutid: op.MutID, 211 Supervoxel: op.Supervoxel, 212 Remainlabel: op.RemainSupervoxel, 213 Splitlabel: op.SplitSupervoxel, 214 } 215 lmap.splitsMu.Lock() 216 lmap.splits[v] = append(lmap.splits[v], rec) 217 lmap.splitsMu.Unlock() 218 219 if err := labels.LogSupervoxelSplit(d, v, op); err != nil { 220 return err 221 } 222 223 mapOp := labels.MappingOp{ 224 MutID: op.MutID, 225 Mapped: 0, 226 Original: labels.Set{ 227 op.Supervoxel: struct{}{}, 228 }, 229 } 230 if err := labels.LogMapping(d, v, mapOp); err != nil { 231 return fmt.Errorf("unable to log the mapping of deleted supervoxel %d: %v", op.Supervoxel, err) 232 } 233 newlabels := labels.Set{ 234 op.SplitSupervoxel: struct{}{}, 235 op.RemainSupervoxel: struct{}{}, 236 } 237 mapOp = labels.MappingOp{ 238 MutID: op.MutID, 239 Mapped: label, 240 Original: newlabels, 241 } 242 return labels.LogMapping(d, v, mapOp) 243 } 244 245 // returns true if the given newLabel does not exist as forward mapping key 246 // TODO? Also check if it exists anywhere in mapping, which would probably 247 // 248 // full set of ids. 249 func (d *Data) verifyIsNewLabel(v dvid.VersionID, newLabel uint64) (bool, error) { 250 lmap, err := getMapping(d, v) 251 if err != nil { 252 return false, err 253 } 254 return !lmap.hasMapping(newLabel), nil 255 } 256 257 func (d *Data) ingestMappings(ctx *datastore.VersionedCtx, mappings *proto.MappingOps) error { 258 lmap, err := getMapping(d, ctx.VersionID()) 259 if err != nil { 260 return err 261 } 262 vid := ctx.VersionID() 263 for _, mapOp := range mappings.Mappings { 264 for _, label := range mapOp.Original { 265 lmap.setMapping(vid, label, mapOp.Mapped) 266 } 267 } 268 return labels.LogMappings(d, ctx.VersionID(), mappings) 269 } 270 271 // GetMappedLabels returns an array of mapped labels, which could be the same as the passed slice, 272 // for the given version of the data instance. 273 func (d *Data) GetMappedLabels(v dvid.VersionID, supervoxels []uint64) (mapped []uint64, found []bool, err error) { 274 var svmap *VCache 275 if svmap, err = getMapping(d, v); err != nil { 276 return 277 } 278 return svmap.MappedLabels(v, supervoxels) 279 } 280 281 type mapStats struct { 282 MapEntries uint64 283 MapSize string 284 NumVersions int 285 MaxVersion int 286 } 287 288 // GetMapStats returns JSON describing in-memory mapping stats. 289 func (d *Data) GetMapStats(ctx *datastore.VersionedCtx) (jsonBytes []byte, err error) { 290 stats := make(map[string]mapStats) 291 for dataUUID, vc := range iMap.maps { 292 var ds datastore.DataService 293 if ds, err = datastore.GetDataByDataUUID(dataUUID); err != nil { 294 return 295 } 296 vc.mappedVersionsMu.RLock() 297 maxVersion := 0 298 for v, _ := range vc.mappedVersions { 299 if int(v) > maxVersion { 300 maxVersion = int(v) 301 } 302 } 303 name := string(ds.DataName()) 304 mapEntries, mapBytes := vc.mapStats() 305 stats[name] = mapStats{ 306 MapEntries: mapEntries, 307 MapSize: humanize.Bytes(mapBytes), 308 NumVersions: len(vc.mappedVersions), 309 MaxVersion: maxVersion, 310 } 311 vc.mappedVersionsMu.RUnlock() 312 } 313 return json.Marshal(stats) 314 }