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  }