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

     1  package labelmap
     2  
     3  import (
     4  	"bytes"
     5  	"compress/gzip"
     6  	"encoding/binary"
     7  	"encoding/json"
     8  	"fmt"
     9  	"io"
    10  	"math"
    11  	"net/http"
    12  	"os"
    13  	"sort"
    14  	"sync"
    15  	"sync/atomic"
    16  
    17  	pb "google.golang.org/protobuf/proto"
    18  
    19  	"github.com/coocood/freecache"
    20  	"github.com/janelia-flyem/dvid/datastore"
    21  	"github.com/janelia-flyem/dvid/datatype/common/labels"
    22  	"github.com/janelia-flyem/dvid/datatype/common/proto"
    23  	"github.com/janelia-flyem/dvid/dvid"
    24  	"github.com/janelia-flyem/dvid/server"
    25  	"github.com/janelia-flyem/dvid/storage"
    26  	lz4 "github.com/janelia-flyem/go/golz4-updated"
    27  )
    28  
    29  const (
    30  	numIndexShards = 64
    31  )
    32  
    33  var (
    34  	indexCache   *freecache.Cache
    35  	indexMu      [numIndexShards]sync.RWMutex
    36  	metaAttempts uint64
    37  	metaHits     uint64
    38  
    39  	mutcache map[dvid.UUID]storage.OrderedKeyValueDB
    40  )
    41  
    42  // Initialize establishes the in-memory labelmap and other supporting
    43  // data systems if specified in the server configuration:
    44  // - index caching if cache size is specified in the server config.
    45  // - mutation cache for label indices if specified in server config.
    46  func (d *Data) Initialize() {
    47  	numBytes := server.CacheSize("labelmap")
    48  	if indexCache == nil {
    49  		if numBytes > 0 {
    50  			indexCache = freecache.NewCache(numBytes)
    51  			mbs := numBytes >> 20
    52  			dvid.Infof("Created freecache of ~ %d MB for labelmap instances.\n", mbs)
    53  		}
    54  	} else if numBytes == 0 {
    55  		indexCache = nil
    56  	} else {
    57  		indexCache.Clear()
    58  	}
    59  
    60  	mutcachePath := server.MutcachePath(d.DataName())
    61  	if mutcachePath != "" {
    62  		// Setup database support for mutation cache for this instance
    63  		engine := storage.GetEngine("badger")
    64  		var cfg dvid.Config
    65  		cfg.Set("path", mutcachePath)
    66  		store, _, err := engine.NewStore(dvid.StoreConfig{Config: cfg, Engine: "badger"})
    67  		if err != nil {
    68  			dvid.Criticalf("can't initialize Badger: %v\n", err)
    69  		} else {
    70  			okvDB, ok := store.(storage.OrderedKeyValueDB)
    71  			if !ok {
    72  				dvid.Criticalf("can't get proper ordered keyvalue DB for mutation cache %q for data %q\n", mutcachePath, d.DataName())
    73  			} else {
    74  				if mutcache == nil {
    75  					mutcache = make(map[dvid.UUID]storage.OrderedKeyValueDB)
    76  				}
    77  				mutcache[d.DataUUID()] = okvDB
    78  			}
    79  		}
    80  	}
    81  
    82  	ancestry, err := datastore.GetBranchVersions(d.RootUUID(), "")
    83  	if err != nil {
    84  		dvid.Criticalf("Unable to get ancestry of master branch: %v\n", err)
    85  		return
    86  	}
    87  	if len(ancestry) == 0 {
    88  		dvid.Infof("No versions in master branch -- not loading labelmap %q\n", d.DataName())
    89  		return
    90  	}
    91  	masterLeafV, err := datastore.VersionFromUUID(ancestry[0])
    92  	if err != nil {
    93  		dvid.Criticalf("Unable to get version ID from master leaf UUID %s: %v\n", ancestry[0], err)
    94  	}
    95  	if _, err := getMapping(d, masterLeafV); err != nil {
    96  		dvid.Criticalf("Unable to initialize in-memory labelmap for data %q: %v\n", d.DataName(), err)
    97  	}
    98  }
    99  
   100  func (d *Data) getMutcache(v dvid.VersionID, mutID uint64, label uint64) (*labels.Index, error) {
   101  	if mutcache == nil {
   102  		return nil, nil
   103  	}
   104  	db, found := mutcache[d.DataUUID()]
   105  	if !found {
   106  		return nil, nil
   107  	}
   108  	ctx := datastore.NewVersionedCtx(d, v)
   109  	tkey1 := newMutcacheKey(label, mutID)
   110  	tkey2 := newMutcacheKey(label, 0)
   111  	var idx *labels.Index
   112  	db.ProcessRange(ctx, tkey1, tkey2, nil, func(chunk *storage.Chunk) error {
   113  		label, curMutID, err := decodeMutcacheKey(chunk.K)
   114  		if err != nil {
   115  			return err
   116  		}
   117  		idx = new(labels.Index)
   118  		if err := pb.Unmarshal(chunk.V, idx); err != nil {
   119  			return err
   120  		}
   121  		dvid.Infof("Mutcache label %d mutid %d > %d\n", label, mutID, curMutID)
   122  		return fmt.Errorf("found mutcache")
   123  	})
   124  	return idx, nil
   125  }
   126  
   127  func (d *Data) addMutcache(v dvid.VersionID, mutID uint64, indices ...*labels.Index) error {
   128  	if mutcache == nil {
   129  		return nil
   130  	}
   131  	db, found := mutcache[d.DataUUID()]
   132  	if !found {
   133  		return nil
   134  	}
   135  	ctx := datastore.NewVersionedCtx(d, v)
   136  	for _, idx := range indices {
   137  		tkey := newMutcacheKey(idx.Label, mutID)
   138  		idxBytes, err := pb.Marshal(idx)
   139  		if err != nil {
   140  			return fmt.Errorf("unable to marshal index for label %d before caching: %v", idx.Label, err)
   141  		}
   142  		if err := db.Put(ctx, tkey, idxBytes); err != nil {
   143  			return err
   144  		}
   145  	}
   146  	return nil
   147  }
   148  
   149  // indexKey is a three tuple (instance id, version, label)
   150  type indexKey struct {
   151  	data    dvid.Data
   152  	version dvid.VersionID
   153  	label   uint64
   154  }
   155  
   156  func (k indexKey) Bytes() []byte {
   157  	b := make([]byte, 16)
   158  	copy(b[0:4], k.data.InstanceID().Bytes())
   159  	copy(b[4:8], k.version.Bytes())
   160  	binary.LittleEndian.PutUint64(b[8:16], k.label)
   161  	return b
   162  }
   163  
   164  func (k indexKey) VersionedCtx() *datastore.VersionedCtx {
   165  	return datastore.NewVersionedCtx(k.data, k.version)
   166  }
   167  
   168  // TODO -- allow check of the cache as well.
   169  func (d *Data) labelIndexExists(v dvid.VersionID, label uint64) (bool, error) {
   170  	ctx := datastore.NewVersionedCtx(d, v)
   171  	store, err := datastore.GetKeyValueDB(d)
   172  	if err != nil {
   173  		return false, err
   174  	}
   175  	return store.Exists(ctx, NewLabelIndexTKey(label))
   176  }
   177  
   178  // returns nil if no Meta is found.
   179  // should only call getCachedLabelIndex external to this file.
   180  func getLabelIndex(ctx *datastore.VersionedCtx, label uint64) (*labels.Index, error) {
   181  	// timedLog := dvid.NewTimeLog()
   182  	store, err := datastore.GetKeyValueDB(ctx.Data())
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  	compressed, err := store.Get(ctx, NewLabelIndexTKey(label))
   187  	if err != nil {
   188  		return nil, err
   189  	}
   190  	if len(compressed) == 0 {
   191  		// timedLog.Infof("retrieved empty index for label %d", label)
   192  		return nil, nil
   193  	}
   194  	val, _, err := dvid.DeserializeData(compressed, true)
   195  	if err != nil {
   196  		return nil, err
   197  	}
   198  
   199  	idx := new(labels.Index)
   200  	if err := pb.Unmarshal(val, idx); err != nil {
   201  		return nil, err
   202  	}
   203  	if idx.Label == 0 {
   204  		idx.Label = label
   205  	}
   206  	// timedLog.Infof("retrieved label %d index with %d blocks", label, len(idx.Blocks))
   207  	return idx, nil
   208  }
   209  
   210  func getLabelIndexCompressed(store storage.KeyValueGetter, ctx *datastore.VersionedCtx, label uint64) ([]byte, error) {
   211  	compressed, err := store.Get(ctx, NewLabelIndexTKey(label))
   212  	if err != nil {
   213  		return nil, err
   214  	}
   215  	if len(compressed) == 0 {
   216  		// timedLog.Infof("retrieved empty index for label %d", label)
   217  		return nil, nil
   218  	}
   219  	return compressed, nil
   220  }
   221  
   222  func getProtoLabelIndices(ctx *datastore.VersionedCtx, dataIn []byte) (numLabels int, dataOut []byte, err error) {
   223  	var labelList []uint64
   224  	if err = json.Unmarshal(dataIn, &labelList); err != nil {
   225  		err = fmt.Errorf("expected JSON label list: %v", err)
   226  		return
   227  	}
   228  	numLabels = len(labelList)
   229  	if numLabels > 50000 {
   230  		err = fmt.Errorf("only 50,000 label indices can be returned at a time, %d given", len(labelList))
   231  		return
   232  	}
   233  	var indices proto.LabelIndices
   234  	indices.Indices = make([]*proto.LabelIndex, len(labelList))
   235  	for i, label := range labelList {
   236  		var idx *labels.Index
   237  		if idx, err = getLabelIndex(ctx, label); err != nil {
   238  			err = fmt.Errorf("could not get label %d index in position %d: %v", label, i, err)
   239  			return
   240  		}
   241  		if idx != nil {
   242  			indices.Indices[i] = &(idx.LabelIndex)
   243  		} else {
   244  			index := proto.LabelIndex{
   245  				Label: label,
   246  			}
   247  			indices.Indices[i] = &index
   248  		}
   249  	}
   250  	if dataOut, err = pb.Marshal(&indices); err != nil {
   251  		err = fmt.Errorf("could not serialize %d label indices: %v", len(labelList), err)
   252  	}
   253  	return
   254  }
   255  
   256  // batch mode put/delete using protobuf indices without caching
   257  func putProtoLabelIndices(ctx *datastore.VersionedCtx, dataIn []byte) (numAdded, numDeleted int, err error) {
   258  	data := ctx.Data()
   259  	var store storage.KeyValueDB
   260  	if store, err = datastore.GetKeyValueDB(data); err != nil {
   261  		err = fmt.Errorf("data %q had error getting KeyValue store: %v", data.DataName(), err)
   262  		return
   263  	}
   264  	indices := new(proto.LabelIndices)
   265  	if err = pb.Unmarshal(dataIn, indices); err != nil {
   266  		return
   267  	}
   268  	var maxLabel uint64
   269  	for i, protoIdx := range indices.Indices {
   270  		if protoIdx == nil {
   271  			err = fmt.Errorf("indices included a nil index in position %d", i)
   272  			return
   273  		}
   274  		if protoIdx.Label == 0 {
   275  			err = fmt.Errorf("index %d had label 0, which is a reserved label", i)
   276  			return
   277  		}
   278  		if len(protoIdx.Blocks) == 0 {
   279  			if err = deleteLabelIndex(ctx, protoIdx.Label); err != nil {
   280  				return
   281  			}
   282  			numDeleted++
   283  			continue
   284  		}
   285  		numAdded++
   286  		idx := labels.Index{LabelIndex: *protoIdx}
   287  		if err = putLabelIndex(store, ctx, data, &idx); err != nil {
   288  			return
   289  		}
   290  		if idx.Label > maxLabel {
   291  			maxLabel = idx.Label
   292  		}
   293  	}
   294  	// handle updating the max label
   295  	d, ok := data.(*Data)
   296  	if !ok {
   297  		err = fmt.Errorf("unable to update max label during PUT label index due to bad data ptr for %q", data.DataName())
   298  		return
   299  	}
   300  	_, err = d.updateMaxLabel(ctx.VersionID(), maxLabel)
   301  	return
   302  }
   303  
   304  // puts label index and doesn't calc max label
   305  // Note: should only call putCachedLabelIndex external to this file so recent changes get cached.
   306  func putLabelIndex(store storage.KeyValueDB, ctx *datastore.VersionedCtx, data dvid.Data, idx *labels.Index) error {
   307  	tk := NewLabelIndexTKey(idx.Label)
   308  	serialization, err := pb.Marshal(idx)
   309  	if err != nil {
   310  		return fmt.Errorf("error trying to serialize index for label set %d, data %q: %v", idx.Label, data.DataName(), err)
   311  	}
   312  	compressFormat, _ := dvid.NewCompression(dvid.LZ4, dvid.DefaultCompression)
   313  	compressed, err := dvid.SerializeData(serialization, compressFormat, dvid.NoChecksum)
   314  	if err != nil {
   315  		return fmt.Errorf("error trying to LZ4 compress label %d indexing in data %q", idx.Label, data.DataName())
   316  	}
   317  	if err := store.Put(ctx, tk, compressed); err != nil {
   318  		return fmt.Errorf("unable to store indices for label %d, data %s: %v", idx.Label, data.DataName(), err)
   319  	}
   320  	return err
   321  }
   322  
   323  // puts label index and stores max label.
   324  // Note: should only call putCachedLabelIndex external to this file so recent changes get cached.
   325  func putLabelIndexAndMax(ctx *datastore.VersionedCtx, idx *labels.Index) error {
   326  	// timedLog := dvid.NewTimeLog()
   327  	store, err := datastore.GetOrderedKeyValueDB(ctx.Data())
   328  	if err != nil {
   329  		return fmt.Errorf("data %q PutLabelMeta had error initializing store: %v", ctx.Data().DataName(), err)
   330  	}
   331  
   332  	tk := NewLabelIndexTKey(idx.Label)
   333  	serialization, err := pb.Marshal(idx)
   334  	if err != nil {
   335  		return fmt.Errorf("error trying to serialize index for label set %d, data %q: %v", idx.Label, ctx.Data().DataName(), err)
   336  	}
   337  	compressFormat, _ := dvid.NewCompression(dvid.LZ4, dvid.DefaultCompression)
   338  	compressed, err := dvid.SerializeData(serialization, compressFormat, dvid.NoChecksum)
   339  	if err != nil {
   340  		return fmt.Errorf("error trying to LZ4 compress label %d indexing in data %q", idx.Label, ctx.Data().DataName())
   341  	}
   342  	if err := store.Put(ctx, tk, compressed); err != nil {
   343  		return fmt.Errorf("unable to store indices for label %d, data %s: %v", idx.Label, ctx.Data().DataName(), err)
   344  	}
   345  	d, ok := ctx.Data().(*Data)
   346  	if !ok {
   347  		return fmt.Errorf("Unable to update max label during PUT label index due to bad data ptr")
   348  	}
   349  	_, err = d.updateMaxLabel(ctx.VersionID(), idx.Label)
   350  
   351  	// timedLog.Infof("stored label %d index with %d blocks", idx.Label, len(idx.Blocks))
   352  	return err
   353  }
   354  
   355  func deleteLabelIndex(ctx *datastore.VersionedCtx, label uint64) error {
   356  	store, err := datastore.GetOrderedKeyValueDB(ctx.Data())
   357  	if err != nil {
   358  		return fmt.Errorf("data %q delete label set index had error initializing store: %v", ctx.Data().DataName(), err)
   359  	}
   360  
   361  	tk := NewLabelIndexTKey(label)
   362  	if err := store.Delete(ctx, tk); err != nil {
   363  		return fmt.Errorf("unable to delete indices for label %d, data %s: %v", label, ctx.Data().DataName(), err)
   364  	}
   365  	return nil
   366  }
   367  
   368  // only returns error if we can't get index from storage, not if we can't get it from cache
   369  func getCachedLabelIndex(d dvid.Data, v dvid.VersionID, label uint64) (*labels.Index, error) {
   370  	atomic.AddUint64(&metaAttempts, 1)
   371  	k := indexKey{data: d, version: v, label: label}
   372  
   373  	var err error
   374  	var idxBytes []byte
   375  	if indexCache != nil {
   376  		idxBytes, err = indexCache.Get(k.Bytes())
   377  		if err != nil && err != freecache.ErrNotFound {
   378  			dvid.Errorf("cache get of index for label %d failed due to error: %v\n", label, err)
   379  			idxBytes = nil
   380  		}
   381  	}
   382  	var idx *labels.Index
   383  	if idxBytes != nil {
   384  		idx = new(labels.Index)
   385  		if err = pb.Unmarshal(idxBytes, idx); err != nil {
   386  			return nil, err
   387  		}
   388  		atomic.AddUint64(&metaHits, 1)
   389  		return idx, nil
   390  	}
   391  	idx, err = getLabelIndex(k.VersionedCtx(), label)
   392  	if err != nil {
   393  		return nil, err
   394  	}
   395  	if idx == nil {
   396  		return nil, nil
   397  	}
   398  	if indexCache != nil {
   399  		idxBytes, err := pb.Marshal(idx)
   400  		if err != nil {
   401  			dvid.Errorf("unable to marshal label %d index for %q: %v\n", label, d.DataName(), err)
   402  		} else if err := indexCache.Set(k.Bytes(), idxBytes, 0); err != nil {
   403  			dvid.Errorf("unable to set label %d index cache for %q: %v\n", label, d.DataName(), err)
   404  		}
   405  	}
   406  	if idx.Label != label {
   407  		dvid.Criticalf("label index for data %q, label %d has internal label value %d\n", d.DataName(), label, idx.Label)
   408  		idx.Label = label
   409  	}
   410  	return idx, nil
   411  }
   412  
   413  // only returns error if we can't persist index, not if we can't cache
   414  func putCachedLabelIndex(d dvid.Data, v dvid.VersionID, idx *labels.Index) error {
   415  	ctx := datastore.NewVersionedCtx(d, v)
   416  	if err := putLabelIndexAndMax(ctx, idx); err != nil {
   417  		return err
   418  	}
   419  	if indexCache != nil {
   420  		idxBytes, err := pb.Marshal(idx)
   421  		if err != nil {
   422  			dvid.Errorf("unable to marshal index for label %d before caching: %v\n", idx.Label, err)
   423  			return nil
   424  		}
   425  		k := indexKey{data: d, version: v, label: idx.Label}.Bytes()
   426  		if err = indexCache.Set(k, idxBytes, 0); err != nil {
   427  			dvid.Errorf("unable to cache index for label %d: %v\n", idx.Label, err)
   428  		}
   429  	}
   430  	return nil
   431  }
   432  
   433  func deleteCachedLabelIndex(d dvid.Data, v dvid.VersionID, label uint64) error {
   434  	ctx := datastore.NewVersionedCtx(d, v)
   435  	if err := deleteLabelIndex(ctx, label); err != nil {
   436  		return err
   437  	}
   438  	if indexCache != nil {
   439  		k := indexKey{data: d, version: v, label: label}.Bytes()
   440  		indexCache.Del(k)
   441  	}
   442  	return nil
   443  }
   444  
   445  ////////////////////////
   446  //
   447  
   448  ///////////////////////////////////////////////////////////////////////////
   449  // The following public functions are concurrency-safe and support caching.
   450  
   451  // GetSupervoxels returns the set of supervoxel ids that compose the given label.
   452  // Used in other datatypes private interfaces (e.g., tarsupervoxels) and generally useful
   453  // for other packages.
   454  func (d *Data) GetSupervoxels(v dvid.VersionID, label uint64) (labels.Set, error) {
   455  	idx, err := GetLabelIndex(d, v, label, false)
   456  	if err != nil {
   457  		return nil, err
   458  	}
   459  	if idx == nil || len(idx.Blocks) == 0 {
   460  		return nil, err
   461  	}
   462  	return idx.GetSupervoxels(), nil
   463  }
   464  
   465  // GetLabelIndex gets label set index data from storage for a given data instance and version.
   466  // If isSupervoxel is true, the label is interpreted as a supervoxel and the label set index
   467  // containing the given supervoxel is returned.  Concurrency-safe access and supports caching.
   468  // If a label has been mapped to another, a nil Index is returned.
   469  func GetLabelIndex(d dvid.Data, v dvid.VersionID, label uint64, isSupervoxel bool) (*labels.Index, error) {
   470  	if isSupervoxel {
   471  		mapping, err := getMapping(d, v)
   472  		if err != nil {
   473  			return nil, err
   474  		}
   475  		if mapping != nil {
   476  			if mapped, found := mapping.MappedLabel(v, label); found {
   477  				if mapped == 0 {
   478  					return nil, fmt.Errorf("cannot get label for supervoxel %d, which has been split and doesn't exist anymore", label)
   479  				}
   480  				label = mapped
   481  			}
   482  		}
   483  	}
   484  
   485  	shard := label % numIndexShards
   486  	indexMu[shard].RLock()
   487  	idx, err := getCachedLabelIndex(d, v, label)
   488  	indexMu[shard].RUnlock()
   489  	return idx, err
   490  }
   491  
   492  // GetSupervoxelBlocks gets the blocks corresponding to a supervoxel id.
   493  func GetSupervoxelBlocks(d dvid.Data, v dvid.VersionID, supervoxel uint64) (dvid.IZYXSlice, error) {
   494  	idx, err := GetLabelIndex(d, v, supervoxel, true)
   495  	if err != nil {
   496  		return nil, err
   497  	}
   498  	if idx == nil {
   499  		return nil, nil
   500  	}
   501  	var blocks dvid.IZYXSlice
   502  	for zyx, svc := range idx.Blocks {
   503  		if svc != nil && svc.Counts != nil {
   504  			sz, found := svc.Counts[supervoxel]
   505  			if found && sz > 0 {
   506  				blocks = append(blocks, labels.BlockIndexToIZYXString(zyx))
   507  			}
   508  		}
   509  	}
   510  	return blocks, nil
   511  }
   512  
   513  // GetLabelSize returns the # of voxels in the given label.  If isSupervoxel = true, the given
   514  // label is interpreted as a supervoxel id and the size is of a supervoxel.  If a label doesn't
   515  // exist, a zero (not error) is returned.
   516  func GetLabelSize(d dvid.Data, v dvid.VersionID, label uint64, isSupervoxel bool) (uint64, error) {
   517  	idx, err := GetLabelIndex(d, v, label, isSupervoxel)
   518  	if err != nil {
   519  		return 0, err
   520  	}
   521  	if idx == nil {
   522  		return 0, nil
   523  	}
   524  	if isSupervoxel {
   525  		return idx.GetSupervoxelCount(label), nil
   526  	}
   527  	return idx.NumVoxels(), nil
   528  }
   529  
   530  func getSupervoxelSizes(d dvid.Data, v dvid.VersionID, supervoxels []uint64) ([]uint64, error) {
   531  	svmap, err := getMapping(d, v)
   532  	if err != nil {
   533  		return nil, fmt.Errorf("couldn't get mapping for data %q, version %d: %v", d.DataName(), v, err)
   534  	}
   535  	labelsets := make(map[uint64][]uint64) // maps labels -> set of supervoxels in it.
   536  	labels, _, err := svmap.MappedLabels(v, supervoxels)
   537  	if err != nil {
   538  		return nil, err
   539  	}
   540  	for i, label := range labels {
   541  		labelsets[label] = append(labelsets[label], supervoxels[i])
   542  	}
   543  
   544  	sizemap := make(map[uint64]uint64, len(supervoxels))
   545  	for label, svlist := range labelsets {
   546  		idx, err := GetLabelIndex(d, v, label, false)
   547  		if err != nil {
   548  			return nil, err
   549  		}
   550  		if idx == nil {
   551  			for _, sv := range svlist {
   552  				sizemap[sv] = 0
   553  			}
   554  		} else {
   555  			svcounts := idx.GetSupervoxelCounts()
   556  			for _, sv := range svlist {
   557  				sizemap[sv] = svcounts[sv]
   558  			}
   559  		}
   560  	}
   561  	sizes := make([]uint64, len(supervoxels))
   562  	for i, sv := range supervoxels {
   563  		sizes[i] = sizemap[sv]
   564  	}
   565  	return sizes, nil
   566  }
   567  
   568  // GetLabelSizes returns the # of voxels in the given labels.  If isSupervoxel = true, the given
   569  // labels are interpreted as supervoxel ids and the sizes are of a supervoxel.  If a label doesn't
   570  // exist, a zero (not error) is returned.
   571  func GetLabelSizes(d dvid.Data, v dvid.VersionID, labels []uint64, isSupervoxel bool) (sizes []uint64, err error) {
   572  	if isSupervoxel {
   573  		return getSupervoxelSizes(d, v, labels)
   574  	}
   575  	sizes = make([]uint64, len(labels))
   576  	for i, label := range labels {
   577  		idx, err := GetLabelIndex(d, v, label, false)
   578  		if err != nil {
   579  			return nil, err
   580  		}
   581  		if idx == nil {
   582  			sizes[i] = 0
   583  		} else {
   584  			sizes[i] = idx.NumVoxels()
   585  		}
   586  	}
   587  	return sizes, nil
   588  }
   589  
   590  // GetBoundedIndex gets bounded label index data from storage for a given data instance.
   591  func GetBoundedIndex(d dvid.Data, v dvid.VersionID, label uint64, bounds dvid.Bounds, isSupervoxel bool) (*labels.Index, error) {
   592  	idx, err := GetLabelIndex(d, v, label, isSupervoxel)
   593  	if err != nil {
   594  		return nil, err
   595  	}
   596  	if idx == nil {
   597  		return nil, nil
   598  	}
   599  	if bounds.Block != nil && bounds.Block.IsSet() {
   600  		if err = idx.FitToBounds(bounds.Block); err != nil {
   601  			return nil, err
   602  		}
   603  	}
   604  	return idx, nil
   605  }
   606  
   607  // DeleteLabelIndex deletes the index for a given label set.
   608  func DeleteLabelIndex(d dvid.Data, v dvid.VersionID, label uint64) error {
   609  	shard := label % numIndexShards
   610  	indexMu[shard].Lock()
   611  	err := deleteCachedLabelIndex(d, v, label)
   612  	indexMu[shard].Unlock()
   613  	return err
   614  }
   615  
   616  // PutLabelIndex persists a label index data for a given data instance and
   617  // version. If the given index is nil, the index is deleted.  Concurrency-safe
   618  // and supports caching.
   619  func PutLabelIndex(d dvid.Data, v dvid.VersionID, label uint64, idx *labels.Index) error {
   620  	if idx == nil {
   621  		return DeleteLabelIndex(d, v, label)
   622  	}
   623  	shard := label % numIndexShards
   624  	indexMu[shard].Lock()
   625  	idx.Label = label
   626  	err := putCachedLabelIndex(d, v, idx)
   627  	indexMu[shard].Unlock()
   628  	return err
   629  }
   630  
   631  type proximityJSON struct {
   632  	Block    dvid.ChunkPoint3d
   633  	Distance int
   634  }
   635  
   636  // TODO: Flesh out this stub for /proximity endpoint.
   637  func (d *Data) getProximity(ctx *datastore.VersionedCtx, idx1, idx2 *labels.Index) (jsonBytes []byte, err error) {
   638  	// Find all blocks shared by the two indices
   639  
   640  	// For each intersecting block, determine distance between labels and add to output.
   641  	return
   642  }
   643  
   644  // CleaveIndex modifies the label index to remove specified supervoxels and create another
   645  // label index for this cleaved body.
   646  func (d *Data) cleaveIndex(v dvid.VersionID, op labels.CleaveOp, info dvid.ModInfo) (cleavedSize, remainSize uint64, err error) {
   647  	shard := op.Target % numIndexShards
   648  	indexMu[shard].Lock()
   649  	defer indexMu[shard].Unlock()
   650  
   651  	var idx *labels.Index
   652  	if idx, err = getCachedLabelIndex(d, v, op.Target); err != nil {
   653  		return
   654  	}
   655  	if idx == nil {
   656  		err = fmt.Errorf("cannot cleave non-existent label %d", op.Target)
   657  		return
   658  	}
   659  	idx.LastMutId = op.MutID
   660  	idx.LastModUser = info.User
   661  	idx.LastModTime = info.Time
   662  	idx.LastModApp = info.App
   663  
   664  	if err := d.addMutcache(v, op.MutID, idx); err != nil {
   665  		dvid.Criticalf("unable to add cleaved mutid %d index %d: %v\n", op.MutID, op.Target, err)
   666  	}
   667  
   668  	supervoxels := idx.GetSupervoxels()
   669  	for _, supervoxel := range op.CleavedSupervoxels {
   670  		if _, found := supervoxels[supervoxel]; !found {
   671  			err = fmt.Errorf("cannot cleave supervoxel %d, which does not exist in label %d", supervoxel, op.Target)
   672  			return
   673  		}
   674  		delete(supervoxels, supervoxel)
   675  	}
   676  	if len(supervoxels) == 0 {
   677  		err = fmt.Errorf("cannot cleave all supervoxels from the label %d", op.Target)
   678  		return
   679  	}
   680  
   681  	// create a new label index to contain the cleaved supervoxels.
   682  	// we don't have to worry about mutex here because it's a new index.
   683  	var cidx *labels.Index
   684  	cleavedSize, remainSize, cidx = idx.Cleave(op.CleavedLabel, op.CleavedSupervoxels)
   685  	cidx.LastMutId = op.MutID
   686  	cidx.LastModUser = info.User
   687  	cidx.LastModTime = info.Time
   688  	cidx.LastModApp = info.App
   689  	if err = putCachedLabelIndex(d, v, cidx); err != nil {
   690  		return
   691  	}
   692  	err = putCachedLabelIndex(d, v, idx)
   693  	return
   694  }
   695  
   696  // ChangeLabelIndex applies changes to a label's index and then stores the result.
   697  // Supervoxel size changes for blocks should be passed into the function.  The passed
   698  // SupervoxelDelta can contain more supervoxels than the label index.
   699  func ChangeLabelIndex(d dvid.Data, v dvid.VersionID, label uint64, delta labels.SupervoxelChanges) error {
   700  	shard := label % numIndexShards
   701  	indexMu[shard].Lock()
   702  	defer indexMu[shard].Unlock()
   703  
   704  	idx, err := getCachedLabelIndex(d, v, label)
   705  	if err != nil {
   706  		return err
   707  	}
   708  	if idx == nil {
   709  		idx = new(labels.Index)
   710  		idx.Label = label
   711  	}
   712  
   713  	if err := idx.ModifyBlocks(label, delta); err != nil {
   714  		return err
   715  	}
   716  
   717  	if len(idx.Blocks) == 0 {
   718  		return deleteCachedLabelIndex(d, v, label)
   719  	}
   720  	return putCachedLabelIndex(d, v, idx)
   721  }
   722  
   723  // getMergedIndex gets index data for all labels in a set with possible bounds.
   724  func (d *Data) getMergedIndex(v dvid.VersionID, mutID uint64, lbls labels.Set, bounds dvid.Bounds) (*labels.Index, error) {
   725  	if len(lbls) == 0 {
   726  		return nil, nil
   727  	}
   728  	idx := new(labels.Index)
   729  	for label := range lbls {
   730  		idx2, err := GetLabelIndex(d, v, label, false)
   731  		if err != nil {
   732  			return nil, err
   733  		}
   734  		if err := d.addMutcache(v, mutID, idx2); err != nil {
   735  			dvid.Criticalf("unable to add merge mutid %d index %d: %v\n", mutID, label, err)
   736  		}
   737  		if bounds.Block != nil && bounds.Block.IsSet() {
   738  			if err := idx2.FitToBounds(bounds.Block); err != nil {
   739  				return nil, err
   740  			}
   741  		}
   742  		if err := idx.Add(idx2); err != nil {
   743  			return nil, err
   744  		}
   745  	}
   746  	return idx, nil
   747  }
   748  
   749  // given supervoxels with given mapping and whether they were actually in in-memory SVMap, check
   750  // label indices to see if supervoxels really are present in assigned bodies.
   751  func (d *Data) verifyMappings(ctx *datastore.VersionedCtx, supervoxels, mapped []uint64, found []bool) (verified []uint64, err error) {
   752  	numSupervoxels := len(supervoxels)
   753  	if numSupervoxels != len(mapped) {
   754  		return nil, fmt.Errorf("length of supervoxels list (%d) not equal to length of provided mappings (%d)", numSupervoxels, len(mapped))
   755  	}
   756  	if numSupervoxels != len(found) {
   757  		return nil, fmt.Errorf("length of supervoxels list (%d) not equal to length of provided found mappings (%d)", numSupervoxels, len(found))
   758  	}
   759  	bodySupervoxels := make(map[uint64]labels.Set)
   760  	for i, supervoxel := range supervoxels {
   761  		if supervoxel != 0 && !found[i] { // we are uncertain whether this is a real or implicit supervoxel that may not exist
   762  			bodysvs, bodyfound := bodySupervoxels[mapped[i]]
   763  			if !bodyfound {
   764  				bodysvs = labels.Set{supervoxel: struct{}{}}
   765  			} else {
   766  				bodysvs[supervoxel] = struct{}{}
   767  			}
   768  			bodySupervoxels[mapped[i]] = bodysvs
   769  		}
   770  	}
   771  
   772  	wasVerified := make(map[uint64]bool, numSupervoxels)
   773  	for label, bodysvs := range bodySupervoxels {
   774  		shard := label % numIndexShards
   775  		indexMu[shard].RLock()
   776  		idx, err := getCachedLabelIndex(d, ctx.VersionID(), label)
   777  		indexMu[shard].RUnlock()
   778  		if err != nil {
   779  			return nil, err
   780  		}
   781  		svpresent := idx.SupervoxelsPresent(bodysvs)
   782  		for supervoxel, present := range svpresent {
   783  			wasVerified[supervoxel] = present
   784  		}
   785  	}
   786  
   787  	verified = make([]uint64, numSupervoxels)
   788  	for i, label := range mapped {
   789  		if found[i] || wasVerified[supervoxels[i]] {
   790  			verified[i] = label
   791  		} else {
   792  			verified[i] = 0
   793  		}
   794  	}
   795  	return
   796  }
   797  
   798  // computes supervoxel split on a label index, returning the split index and the slice of blocks
   799  // that were modified.
   800  func (d *Data) splitSupervoxelIndex(v dvid.VersionID, info dvid.ModInfo, op labels.SplitSupervoxelOp, idx *labels.Index) (dvid.IZYXSlice, error) {
   801  	idx.LastMutId = op.MutID
   802  	idx.LastModUser = info.User
   803  	idx.LastModTime = info.Time
   804  	idx.LastModApp = info.App
   805  
   806  	// modify the index to reflect old supervoxel -> two new supervoxels.
   807  	var svblocks dvid.IZYXSlice
   808  	for zyx, svc := range idx.Blocks {
   809  		origNumVoxels, found := svc.Counts[op.Supervoxel]
   810  		if found { // split supervoxel is in this block
   811  			delete(svc.Counts, op.Supervoxel)
   812  			izyx := labels.BlockIndexToIZYXString(zyx)
   813  			svblocks = append(svblocks, izyx)
   814  			rles, found := op.Split[izyx]
   815  			if found { // part of split
   816  				splitNumVoxels, _ := rles.Stats()
   817  				svc.Counts[op.SplitSupervoxel] = uint32(splitNumVoxels)
   818  				if splitNumVoxels > uint64(origNumVoxels) {
   819  					return nil, fmt.Errorf("tried to split %d voxels from supervoxel %d, but label index only has %d voxels", splitNumVoxels, op.Supervoxel, origNumVoxels)
   820  				}
   821  				if splitNumVoxels != uint64(origNumVoxels) {
   822  					svc.Counts[op.RemainSupervoxel] = origNumVoxels - uint32(splitNumVoxels)
   823  				}
   824  			} else { // part of remainder
   825  				svc.Counts[op.RemainSupervoxel] = origNumVoxels
   826  			}
   827  		}
   828  	}
   829  	return svblocks, nil
   830  }
   831  
   832  // SplitIndex modifies the split label's index and creates a new index for the split portion.
   833  func (d *Data) splitIndex(v dvid.VersionID, info dvid.ModInfo, op labels.SplitOp, idx *labels.Index, splitMap dvid.BlockRLEs, blockSplits blockSplitsMap) error {
   834  	idx.LastMutId = op.MutID
   835  	idx.LastModUser = info.User
   836  	idx.LastModTime = info.Time
   837  	idx.LastModApp = info.App
   838  
   839  	sidx := new(labels.Index)
   840  	sidx.LastMutId = op.MutID
   841  	sidx.LastModUser = info.User
   842  	sidx.LastModTime = info.Time
   843  	sidx.LastModApp = info.App
   844  	sidx.Label = op.NewLabel
   845  	sidx.Blocks = make(map[uint64]*proto.SVCount, len(blockSplits))
   846  
   847  	for zyx, indexsvc := range idx.Blocks {
   848  		splitCount, inSplitBlock := blockSplits[zyx]
   849  		var splitsvc *proto.SVCount
   850  		if inSplitBlock {
   851  			splitsvc = new(proto.SVCount)
   852  			splitsvc.Counts = make(map[uint64]uint32, len(splitCount))
   853  		}
   854  		for supervoxel, svOrigCount := range indexsvc.Counts {
   855  			var svWasSplit bool
   856  			var svSplitCount labels.SVSplitCount
   857  			if inSplitBlock {
   858  				svSplitCount, svWasSplit = splitCount[supervoxel]
   859  				if svWasSplit {
   860  					if svSplitCount.Voxels > svOrigCount {
   861  						return fmt.Errorf("block %s had %d voxels written over supervoxel %d in label %d split yet this supervoxel only had %d voxels from index", labels.BlockIndexToIZYXString(zyx), svSplitCount.Voxels, supervoxel, op.Target, svOrigCount)
   862  					}
   863  					splitsvc.Counts[svSplitCount.Split] = svSplitCount.Voxels
   864  					if svOrigCount > svSplitCount.Voxels {
   865  						indexsvc.Counts[svSplitCount.Remain] = svOrigCount - svSplitCount.Voxels
   866  					}
   867  					delete(indexsvc.Counts, supervoxel)
   868  				}
   869  			}
   870  			if !svWasSplit {
   871  				// see if split anywhere
   872  				svsplit, found := op.SplitMap[supervoxel]
   873  				if found {
   874  					indexsvc.Counts[svsplit.Remain] = svOrigCount
   875  					delete(indexsvc.Counts, supervoxel)
   876  				}
   877  			}
   878  		}
   879  		if inSplitBlock {
   880  			sidx.Blocks[zyx] = splitsvc
   881  		}
   882  		if len(indexsvc.Counts) == 0 {
   883  			delete(idx.Blocks, zyx)
   884  		}
   885  	}
   886  
   887  	if err := putCachedLabelIndex(d, v, idx); err != nil {
   888  		return fmt.Errorf("modify split index for data %q, label %d: %v", d.DataName(), op.Target, err)
   889  	}
   890  	if err := putCachedLabelIndex(d, v, sidx); err != nil {
   891  		return fmt.Errorf("create new split index for data %q, label %d: %v", d.DataName(), op.NewLabel, err)
   892  	}
   893  	return nil
   894  }
   895  
   896  ///////////////////////////////////////
   897  
   898  // block-level analysis of mutation to get supervoxel changes in a block.  accumulates data for
   899  // a given mutation into a map per mutation which will then be flushed for each supervoxel meta
   900  // k/v pair at end of mutation.
   901  func (d *Data) handleBlockMutate(v dvid.VersionID, ch chan blockChange, mut MutatedBlock) {
   902  	if !d.IndexedLabels {
   903  		return
   904  	}
   905  	bc := blockChange{
   906  		bcoord: mut.BCoord,
   907  	}
   908  	if d.IndexedLabels {
   909  		// if mut.Prev == nil {
   910  		// 	dvid.Infof("block mutate %s has no previous block\n", mut.Prev)
   911  		// } else {
   912  		// 	dvid.Infof("block mutate %s: prev labels %v\n", mut.BCoord, mut.Prev.Labels)
   913  		// }
   914  		bc.delta = mut.Data.CalcNumLabels(mut.Prev)
   915  	}
   916  	ch <- bc
   917  }
   918  
   919  // block-level analysis of label ingest to do indexing
   920  func (d *Data) handleBlockIndexing(v dvid.VersionID, ch chan blockChange, mut IngestedBlock) {
   921  	if !d.IndexedLabels {
   922  		return
   923  	}
   924  	bc := blockChange{
   925  		bcoord: mut.BCoord,
   926  	}
   927  	if d.IndexedLabels {
   928  		bc.delta = mut.Data.CalcNumLabels(nil)
   929  	}
   930  	ch <- bc
   931  }
   932  
   933  // Goroutines accepts block-level changes and segregates all changes by supervoxel, and then
   934  // sends supervoxel-specific changes to concurrency-handling label indexing functions.
   935  
   936  type blockChange struct {
   937  	bcoord dvid.IZYXString
   938  	delta  map[uint64]int32
   939  }
   940  
   941  // goroutine(s) that aggregates supervoxel changes across blocks for one mutation, then calls
   942  // mutex-guarded label index mutation routine.
   943  func (d *Data) aggregateBlockChanges(v dvid.VersionID, svmap *VCache, ch <-chan blockChange) {
   944  	mappedVersions := svmap.getMappedVersionsDist(v)
   945  	labelset := make(labels.Set)
   946  	svChanges := make(labels.SupervoxelChanges)
   947  	var maxLabel uint64
   948  	for change := range ch {
   949  		for supervoxel, delta := range change.delta {
   950  			blockChanges, found := svChanges[supervoxel]
   951  			if !found {
   952  				blockChanges = make(map[dvid.IZYXString]int32)
   953  				svChanges[supervoxel] = blockChanges
   954  			}
   955  			blockChanges[change.bcoord] += delta
   956  			if supervoxel > maxLabel {
   957  				maxLabel = supervoxel
   958  			}
   959  			label, _ := svmap.mapLabel(supervoxel, mappedVersions)
   960  			labelset[label] = struct{}{}
   961  		}
   962  	}
   963  	go func() {
   964  		if _, err := d.updateMaxLabel(v, maxLabel); err != nil {
   965  			dvid.Errorf("max label change during block aggregation for %q: %v\n", d.DataName(), err)
   966  		}
   967  	}()
   968  	if d.IndexedLabels {
   969  		for label := range labelset {
   970  			if err := ChangeLabelIndex(d, v, label, svChanges); err != nil {
   971  				dvid.Errorf("indexing label %d: %v\n", label, err)
   972  			}
   973  		}
   974  	}
   975  }
   976  
   977  type labelBlock struct {
   978  	index dvid.IZYXString
   979  	data  []byte
   980  }
   981  
   982  type rleResult struct {
   983  	runs          uint32
   984  	serialization []byte
   985  }
   986  
   987  // goroutine to process retrieved label data and generate RLEs, could be sharded by block coordinate
   988  func (d *Data) processBlocksToRLEs(lbls labels.Set, bounds dvid.Bounds, in chan labelBlock, out chan rleResult) {
   989  	for {
   990  		lb, more := <-in
   991  		if !more {
   992  			return
   993  		}
   994  		var result rleResult
   995  		data, _, err := dvid.DeserializeData(lb.data, true)
   996  		if err != nil {
   997  			dvid.Errorf("could not deserialize %d bytes in block %s: %v\n", len(lb.data), lb.index, err)
   998  			out <- result
   999  			continue
  1000  		}
  1001  		var block labels.Block
  1002  		if err := block.UnmarshalBinary(data); err != nil {
  1003  			dvid.Errorf("unable to unmarshal label block %s: %v\n", lb.index, err)
  1004  		}
  1005  		blockData, _ := block.MakeLabelVolume()
  1006  
  1007  		var newRuns uint32
  1008  		var serialization []byte
  1009  		if bounds.Exact && bounds.Voxel.IsSet() {
  1010  			serialization, newRuns, err = d.addBoundedRLEs(lb.index, blockData, lbls, bounds.Voxel)
  1011  		} else {
  1012  			serialization, newRuns, err = d.addRLEs(lb.index, blockData, lbls)
  1013  		}
  1014  		if err != nil {
  1015  			dvid.Errorf("could not process %d bytes in block %s to create RLEs: %v\n", len(blockData), lb.index, err)
  1016  		} else {
  1017  			result = rleResult{runs: newRuns, serialization: serialization}
  1018  		}
  1019  		out <- result
  1020  	}
  1021  }
  1022  
  1023  func writeRLE(w io.Writer, start dvid.Point3d, run int32) error {
  1024  	rle := dvid.NewRLE(start, run)
  1025  	serialization, err := rle.MarshalBinary()
  1026  	if err != nil {
  1027  		return err
  1028  	}
  1029  	if _, err := w.Write(serialization); err != nil {
  1030  		return err
  1031  	}
  1032  	return nil
  1033  }
  1034  
  1035  // Scan a block and construct RLEs that will be serialized and added to the given buffer.
  1036  func (d *Data) addRLEs(izyx dvid.IZYXString, data []byte, lbls labels.Set) (serialization []byte, newRuns uint32, err error) {
  1037  	if len(data) != int(d.BlockSize().Prod())*8 {
  1038  		err = fmt.Errorf("deserialized label block %d bytes, not uint64 size times %d block elements",
  1039  			len(data), d.BlockSize().Prod())
  1040  		return
  1041  	}
  1042  	var indexZYX dvid.IndexZYX
  1043  	indexZYX, err = izyx.IndexZYX()
  1044  	if err != nil {
  1045  		return
  1046  	}
  1047  	firstPt := indexZYX.MinPoint(d.BlockSize())
  1048  	lastPt := indexZYX.MaxPoint(d.BlockSize())
  1049  
  1050  	var label uint64
  1051  	var spanStart dvid.Point3d
  1052  	var z, y, x, spanRun int32
  1053  	start := 0
  1054  	buf := new(bytes.Buffer)
  1055  	for z = firstPt.Value(2); z <= lastPt.Value(2); z++ {
  1056  		for y = firstPt.Value(1); y <= lastPt.Value(1); y++ {
  1057  			for x = firstPt.Value(0); x <= lastPt.Value(0); x++ {
  1058  				label = binary.LittleEndian.Uint64(data[start : start+8])
  1059  				start += 8
  1060  
  1061  				// If we are in labels of interest, start or extend run.
  1062  				inSpan := false
  1063  				if label != 0 {
  1064  					_, inSpan = lbls[label]
  1065  				}
  1066  				if inSpan {
  1067  					spanRun++
  1068  					if spanRun == 1 {
  1069  						spanStart = dvid.Point3d{x, y, z}
  1070  					}
  1071  				} else {
  1072  					if spanRun > 0 {
  1073  						newRuns++
  1074  						if err = writeRLE(buf, spanStart, spanRun); err != nil {
  1075  							return
  1076  						}
  1077  					}
  1078  					spanRun = 0
  1079  				}
  1080  			}
  1081  			// Force break of any runs when we finish x scan.
  1082  			if spanRun > 0 {
  1083  				if err = writeRLE(buf, spanStart, spanRun); err != nil {
  1084  					return
  1085  				}
  1086  				newRuns++
  1087  				spanRun = 0
  1088  			}
  1089  		}
  1090  	}
  1091  	serialization = buf.Bytes()
  1092  	return
  1093  }
  1094  
  1095  // Scan a block and construct bounded RLEs that will be serialized and added to the given buffer.
  1096  func (d *Data) addBoundedRLEs(izyx dvid.IZYXString, data []byte, lbls labels.Set, bounds *dvid.OptionalBounds) (serialization []byte, newRuns uint32, err error) {
  1097  	if len(data) != int(d.BlockSize().Prod())*8 {
  1098  		err = fmt.Errorf("deserialized label block %d bytes, not uint64 size times %d block elements",
  1099  			len(data), d.BlockSize().Prod())
  1100  		return
  1101  	}
  1102  	var indexZYX dvid.IndexZYX
  1103  	indexZYX, err = izyx.IndexZYX()
  1104  	if err != nil {
  1105  		return
  1106  	}
  1107  	firstPt := indexZYX.MinPoint(d.BlockSize())
  1108  	lastPt := indexZYX.MaxPoint(d.BlockSize())
  1109  
  1110  	var label uint64
  1111  	var spanStart dvid.Point3d
  1112  	var z, y, x, spanRun int32
  1113  	start := 0
  1114  	buf := new(bytes.Buffer)
  1115  	yskip := int(d.BlockSize().Value(0) * 8)
  1116  	zskip := int(d.BlockSize().Value(1)) * yskip
  1117  	for z = firstPt.Value(2); z <= lastPt.Value(2); z++ {
  1118  		if bounds.OutsideZ(z) {
  1119  			start += zskip
  1120  			continue
  1121  		}
  1122  		for y = firstPt.Value(1); y <= lastPt.Value(1); y++ {
  1123  			if bounds.OutsideY(y) {
  1124  				start += yskip
  1125  				continue
  1126  			}
  1127  			for x = firstPt.Value(0); x <= lastPt.Value(0); x++ {
  1128  				label = binary.LittleEndian.Uint64(data[start : start+8])
  1129  				start += 8
  1130  
  1131  				// If we are in labels of interest, start or extend run.
  1132  				inSpan := false
  1133  				if label != 0 {
  1134  					_, inSpan = lbls[label]
  1135  					if inSpan && bounds.OutsideX(x) {
  1136  						inSpan = false
  1137  					}
  1138  				}
  1139  				if inSpan {
  1140  					spanRun++
  1141  					if spanRun == 1 {
  1142  						spanStart = dvid.Point3d{x, y, z}
  1143  					}
  1144  				} else {
  1145  					if spanRun > 0 {
  1146  						newRuns++
  1147  						if err = writeRLE(buf, spanStart, spanRun); err != nil {
  1148  							return
  1149  						}
  1150  					}
  1151  					spanRun = 0
  1152  				}
  1153  			}
  1154  			// Force break of any runs when we finish x scan.
  1155  			if spanRun > 0 {
  1156  				if err = writeRLE(buf, spanStart, spanRun); err != nil {
  1157  					return
  1158  				}
  1159  				newRuns++
  1160  				spanRun = 0
  1161  			}
  1162  		}
  1163  	}
  1164  	serialization = buf.Bytes()
  1165  	return
  1166  }
  1167  
  1168  // FoundSparseVol returns true if a sparse volume is found for the given label
  1169  // within the given bounds.
  1170  func (d *Data) FoundSparseVol(ctx *datastore.VersionedCtx, label uint64, bounds dvid.Bounds, isSupervoxel bool) (bool, error) {
  1171  	idx, err := GetBoundedIndex(d, ctx.VersionID(), label, bounds, isSupervoxel)
  1172  	if err != nil {
  1173  		return false, err
  1174  	}
  1175  
  1176  	if idx != nil && len(idx.Blocks) > 0 {
  1177  		return true, nil
  1178  	}
  1179  	return false, nil
  1180  }
  1181  
  1182  // encapsulates all we need to know about blocks & supervoxels within scaled, bounded labels
  1183  type labelBlockMetadata struct {
  1184  	label        uint64
  1185  	scale        uint8
  1186  	bounds       dvid.Bounds
  1187  	supervoxels  labels.Set
  1188  	sortedBlocks dvid.IZYXSlice
  1189  }
  1190  
  1191  // use label index to return supervoxels and sorted blocks that meet criteria of scale and bounds
  1192  func (d *Data) constrainLabelIndex(ctx *datastore.VersionedCtx, label uint64, scale uint8, bounds dvid.Bounds, isSupervoxel bool) (blockMeta *labelBlockMetadata, exists bool, err error) {
  1193  	blockMeta = &labelBlockMetadata{label: label, scale: scale, bounds: bounds}
  1194  	var idx *labels.Index
  1195  	if idx, err = GetLabelIndex(d, ctx.VersionID(), label, isSupervoxel); err != nil {
  1196  		return
  1197  	}
  1198  	if idx == nil || len(idx.Blocks) == 0 {
  1199  		exists = false
  1200  		return
  1201  	}
  1202  	blockMeta.supervoxels = idx.GetSupervoxels()
  1203  	var supervoxel uint64
  1204  	if isSupervoxel {
  1205  		supervoxel = label
  1206  		if _, exists = blockMeta.supervoxels[supervoxel]; !exists {
  1207  			return
  1208  		}
  1209  		blockMeta.supervoxels = labels.Set{supervoxel: struct{}{}}
  1210  	}
  1211  
  1212  	if blockMeta.sortedBlocks, err = idx.GetProcessedBlockIndices(scale, bounds, supervoxel); err != nil {
  1213  		return
  1214  	}
  1215  	if len(blockMeta.sortedBlocks) == 0 { // if no blocks are within bounds, regardless of scale
  1216  		exists = false
  1217  		return
  1218  	}
  1219  	sort.Sort(blockMeta.sortedBlocks)
  1220  	exists = true
  1221  	return
  1222  }
  1223  
  1224  // writeBinaryBlocks does a streaming write of an encoded sparse volume given a label.
  1225  // It returns a bool whether the label exists even if there's no data at the given scale and bounds.
  1226  func (d *Data) writeBinaryBlocks(ctx *datastore.VersionedCtx, blockMeta *labelBlockMetadata, compression string, w io.Writer) error {
  1227  	store, err := datastore.GetOrderedKeyValueDB(d)
  1228  	if err != nil {
  1229  		return err
  1230  	}
  1231  	op := labels.NewOutputOp(w)
  1232  	go labels.WriteBinaryBlocks(blockMeta.label, blockMeta.supervoxels, op, blockMeta.bounds)
  1233  	var preErr error
  1234  	for _, izyx := range blockMeta.sortedBlocks {
  1235  		tk := NewBlockTKeyByCoord(blockMeta.scale, izyx)
  1236  		data, err := store.Get(ctx, tk)
  1237  		if err != nil {
  1238  			preErr = err
  1239  			break
  1240  		}
  1241  		if data == nil {
  1242  			preErr = fmt.Errorf("expected block %s @ scale %d to have key-value, but found none", izyx, blockMeta.scale)
  1243  			break
  1244  		}
  1245  		blockData, _, err := dvid.DeserializeData(data, true)
  1246  		if err != nil {
  1247  			preErr = err
  1248  			break
  1249  		}
  1250  		var block labels.Block
  1251  		if err := block.UnmarshalBinary(blockData); err != nil {
  1252  			preErr = err
  1253  			break
  1254  		}
  1255  		pb := labels.PositionedBlock{
  1256  			Block:  block,
  1257  			BCoord: izyx,
  1258  		}
  1259  		op.Process(&pb)
  1260  	}
  1261  	if err = op.Finish(); err != nil {
  1262  		return err
  1263  	}
  1264  
  1265  	dvid.Infof("labelmap %q label %d consisting of %d supervoxels: streamed %d blocks within bounds\n",
  1266  		d.DataName(), blockMeta.label, len(blockMeta.supervoxels), len(blockMeta.sortedBlocks))
  1267  	return preErr
  1268  }
  1269  
  1270  // writeStreamingRLE does a streaming write of an encoded sparse volume given a label.
  1271  // It returns a bool whether the label was found in the given bounds and any error.
  1272  func (d *Data) writeStreamingRLE(ctx *datastore.VersionedCtx, blockMeta *labelBlockMetadata, compression string, w io.Writer) error {
  1273  	store, err := datastore.GetOrderedKeyValueDB(d)
  1274  	if err != nil {
  1275  		return err
  1276  	}
  1277  	op := labels.NewOutputOp(w)
  1278  	go labels.WriteRLEs(blockMeta.supervoxels, op, blockMeta.bounds)
  1279  	for _, izyx := range blockMeta.sortedBlocks {
  1280  		tk := NewBlockTKeyByCoord(blockMeta.scale, izyx)
  1281  		data, err := store.Get(ctx, tk)
  1282  		if err != nil {
  1283  			return err
  1284  		}
  1285  		blockData, _, err := dvid.DeserializeData(data, true)
  1286  		if err != nil {
  1287  			return err
  1288  		}
  1289  		var block labels.Block
  1290  		if err := block.UnmarshalBinary(blockData); err != nil {
  1291  			return err
  1292  		}
  1293  		pb := labels.PositionedBlock{
  1294  			Block:  block,
  1295  			BCoord: izyx,
  1296  		}
  1297  		op.Process(&pb)
  1298  	}
  1299  	if err = op.Finish(); err != nil {
  1300  		return err
  1301  	}
  1302  
  1303  	dvid.Infof("labelmap %q label %d consisting of %d supervoxels: streamed %d blocks within bounds\n",
  1304  		d.DataName(), blockMeta.label, len(blockMeta.supervoxels), len(blockMeta.sortedBlocks))
  1305  	return nil
  1306  }
  1307  
  1308  // Write legacy RLEs to writer. Body can exist but have no data if scale is too low-res.
  1309  //
  1310  // The encoding has the following format where integers are little endian:
  1311  //
  1312  //	byte     Payload descriptor:
  1313  //	           Bit 0 (LSB) - 8-bit grayscale
  1314  //	           Bit 1 - 16-bit grayscale
  1315  //	           Bit 2 - 16-bit normal
  1316  //	           ...
  1317  //	uint8    Number of dimensions
  1318  //	uint8    Dimension of run (typically 0 = X)
  1319  //	byte     Reserved (to be used later)
  1320  //	uint32    0
  1321  //	uint32    # Spans
  1322  //	Repeating unit of:
  1323  //	    int32   Coordinate of run start (dimension 0)
  1324  //	    int32   Coordinate of run start (dimension 1)
  1325  //	    int32   Coordinate of run start (dimension 2)
  1326  //	    int32   Length of run
  1327  //	    bytes   Optional payload dependent on first byte descriptor
  1328  func (d *Data) writeLegacyRLE(ctx *datastore.VersionedCtx, blockMeta *labelBlockMetadata, compression string, w io.Writer) error {
  1329  	buf := new(bytes.Buffer)
  1330  	buf.WriteByte(dvid.EncodingBinary)
  1331  	binary.Write(buf, binary.LittleEndian, uint8(3))  // # of dimensions
  1332  	binary.Write(buf, binary.LittleEndian, byte(0))   // dimension of run (X = 0)
  1333  	buf.WriteByte(byte(0))                            // reserved for later
  1334  	binary.Write(buf, binary.LittleEndian, uint32(0)) // Placeholder for # voxels
  1335  	binary.Write(buf, binary.LittleEndian, uint32(0)) // Placeholder for # spans
  1336  
  1337  	store, err := datastore.GetOrderedKeyValueDB(d)
  1338  	if err != nil {
  1339  		return err
  1340  	}
  1341  	op := labels.NewOutputOp(buf)
  1342  	go labels.WriteRLEs(blockMeta.supervoxels, op, blockMeta.bounds)
  1343  	var numEmpty int
  1344  	for _, izyx := range blockMeta.sortedBlocks {
  1345  		tk := NewBlockTKeyByCoord(blockMeta.scale, izyx)
  1346  		data, err := store.Get(ctx, tk)
  1347  		if err != nil {
  1348  			return err
  1349  		}
  1350  		if len(data) == 0 {
  1351  			numEmpty++
  1352  			if numEmpty < 10 {
  1353  				dvid.Errorf("Block %s included in blocks for labels %s but has no data (%d times)... skipping.\n",
  1354  					izyx, blockMeta.supervoxels, numEmpty)
  1355  			} else if numEmpty == 10 {
  1356  				dvid.Errorf("Over %d blocks included in blocks with no data.  Halting error stream.\n", numEmpty)
  1357  			}
  1358  			continue
  1359  		}
  1360  		blockData, _, err := dvid.DeserializeData(data, true)
  1361  		if err != nil {
  1362  			return err
  1363  		}
  1364  		var block labels.Block
  1365  		if err = block.UnmarshalBinary(blockData); err != nil {
  1366  			return err
  1367  		}
  1368  		pb := labels.PositionedBlock{
  1369  			Block:  block,
  1370  			BCoord: izyx,
  1371  		}
  1372  		op.Process(&pb)
  1373  	}
  1374  	if numEmpty < len(blockMeta.sortedBlocks) {
  1375  		if err := op.Finish(); err != nil {
  1376  			return err
  1377  		}
  1378  	}
  1379  
  1380  	serialization := buf.Bytes()
  1381  	if len(serialization) == 0 {
  1382  		return nil
  1383  	}
  1384  	numRuns := uint32(len(serialization)-12) >> 4
  1385  	if numRuns == 0 {
  1386  		return nil
  1387  	}
  1388  
  1389  	binary.LittleEndian.PutUint32(serialization[8:12], numRuns)
  1390  	dvid.Infof("label %d: sending %d blocks within bounds excluding %d empty blocks, %d runs, serialized %d bytes\n",
  1391  		blockMeta.label, len(blockMeta.sortedBlocks), numEmpty, numRuns, len(serialization))
  1392  
  1393  	switch compression {
  1394  	case "":
  1395  		_, err = w.Write(serialization)
  1396  	case "lz4":
  1397  		compressed := make([]byte, lz4.CompressBound(serialization))
  1398  		var n, outSize int
  1399  		if outSize, err = lz4.Compress(serialization, compressed); err != nil {
  1400  			return err
  1401  		}
  1402  		compressed = compressed[:outSize]
  1403  		n, err = w.Write(compressed)
  1404  		if n != outSize {
  1405  			err = fmt.Errorf("only able to write %d of %d lz4 compressed bytes", n, outSize)
  1406  		}
  1407  	case "gzip":
  1408  		gw := gzip.NewWriter(w)
  1409  		if _, err = gw.Write(serialization); err != nil {
  1410  			return err
  1411  		}
  1412  		err = gw.Close()
  1413  	default:
  1414  		err = fmt.Errorf("unknown compression type %q", compression)
  1415  	}
  1416  	return err
  1417  }
  1418  
  1419  // GetSparseCoarseVol returns an encoded sparse volume given a label.  This will return nil slice
  1420  // if the given label was not found.  The encoding has the following format where integers are
  1421  // little endian and blocks are returned in sorted ZYX order (small Z first):
  1422  //
  1423  //			byte     Set to 0
  1424  //			uint8    Number of dimensions
  1425  //			uint8    Dimension of run (typically 0 = X)
  1426  //			byte     Reserved (to be used later)
  1427  //			uint32    # Blocks [TODO.  0 for now]
  1428  //			uint32    # Spans
  1429  //			Repeating unit of:
  1430  //	    		int32   Block coordinate of run start (dimension 0)
  1431  //	    		int32   Block coordinate of run start (dimension 1)
  1432  //	    		int32   Block coordinate of run start (dimension 2)
  1433  //	    		int32   Length of run
  1434  func (d *Data) GetSparseCoarseVol(ctx *datastore.VersionedCtx, label uint64, bounds dvid.Bounds, isSupervoxel bool) ([]byte, error) {
  1435  	idx, err := GetLabelIndex(d, ctx.VersionID(), label, isSupervoxel)
  1436  	if err != nil {
  1437  		return nil, err
  1438  	}
  1439  	if idx == nil || len(idx.Blocks) == 0 {
  1440  		return nil, nil
  1441  	}
  1442  	var supervoxel uint64
  1443  	if isSupervoxel {
  1444  		supervoxel = label
  1445  		idx, err = idx.LimitToSupervoxel(supervoxel)
  1446  		if err != nil {
  1447  			return nil, err
  1448  		}
  1449  		if idx == nil {
  1450  			return nil, nil
  1451  		}
  1452  	}
  1453  	blocks, err := idx.GetProcessedBlockIndices(0, bounds, supervoxel)
  1454  	if err != nil {
  1455  		return nil, err
  1456  	}
  1457  	sort.Sort(blocks)
  1458  
  1459  	// Create the sparse volume header
  1460  	buf := new(bytes.Buffer)
  1461  	buf.WriteByte(dvid.EncodingBinary)
  1462  	binary.Write(buf, binary.LittleEndian, uint8(3))  // # of dimensions
  1463  	binary.Write(buf, binary.LittleEndian, byte(0))   // dimension of run (X = 0)
  1464  	buf.WriteByte(byte(0))                            // reserved for later
  1465  	binary.Write(buf, binary.LittleEndian, uint32(0)) // Placeholder for # voxels
  1466  	binary.Write(buf, binary.LittleEndian, uint32(0)) // Placeholder for # spans
  1467  
  1468  	spans, err := blocks.WriteSerializedRLEs(buf)
  1469  	if err != nil {
  1470  		return nil, err
  1471  	}
  1472  	serialization := buf.Bytes()
  1473  	binary.LittleEndian.PutUint32(serialization[8:12], spans) // Placeholder for # spans
  1474  
  1475  	return serialization, nil
  1476  }
  1477  
  1478  // WriteSparseCoarseVols returns a stream of sparse volumes with blocks of the given label
  1479  // in encoded RLE format:
  1480  //
  1481  //		uint64   label
  1482  //		<coarse sparse vol as given below>
  1483  //
  1484  //		uint64   label
  1485  //		<coarse sparse vol as given below>
  1486  //
  1487  //		...
  1488  //
  1489  //	The coarse sparse vol has the following format where integers are little endian and the order
  1490  //	of data is exactly as specified below:
  1491  //
  1492  //		int32    # Spans
  1493  //		Repeating unit of:
  1494  //			int32   Block coordinate of run start (dimension 0)
  1495  //			int32   Block coordinate of run start (dimension 1)
  1496  //			int32   Block coordinate of run start (dimension 2)
  1497  //			int32   Length of run
  1498  func (d *Data) WriteSparseCoarseVols(ctx *datastore.VersionedCtx, w io.Writer, begLabel, endLabel uint64, bounds dvid.Bounds) error {
  1499  
  1500  	store, err := datastore.GetOrderedKeyValueDB(d)
  1501  	if err != nil {
  1502  		return err
  1503  	}
  1504  	begTKey := NewLabelIndexTKey(begLabel)
  1505  	endTKey := NewLabelIndexTKey(endLabel)
  1506  
  1507  	err = store.ProcessRange(ctx, begTKey, endTKey, &storage.ChunkOp{}, func(c *storage.Chunk) error {
  1508  		if c == nil || c.TKeyValue == nil {
  1509  			return nil
  1510  		}
  1511  		kv := c.TKeyValue
  1512  		if kv.V == nil {
  1513  			return nil
  1514  		}
  1515  		label, err := DecodeLabelIndexTKey(kv.K)
  1516  		if err != nil {
  1517  			return err
  1518  		}
  1519  		val, _, err := dvid.DeserializeData(kv.V, true)
  1520  		if err != nil {
  1521  			return err
  1522  		}
  1523  		var idx labels.Index
  1524  		if len(val) != 0 {
  1525  			if err := pb.Unmarshal(val, &idx); err != nil {
  1526  				return err
  1527  			}
  1528  			blocks, err := idx.GetProcessedBlockIndices(0, bounds, 0)
  1529  			if err != nil {
  1530  				return err
  1531  			}
  1532  			sort.Sort(blocks)
  1533  			buf := new(bytes.Buffer)
  1534  			spans, err := blocks.WriteSerializedRLEs(buf)
  1535  			if err != nil {
  1536  				return err
  1537  			}
  1538  			binary.Write(w, binary.LittleEndian, label)
  1539  			binary.Write(w, binary.LittleEndian, int32(spans))
  1540  			w.Write(buf.Bytes())
  1541  		}
  1542  		return nil
  1543  	})
  1544  	return err
  1545  }
  1546  
  1547  func (d *Data) countThread(f *os.File, mu *sync.Mutex, wg *sync.WaitGroup, chunkCh chan *storage.Chunk) {
  1548  	for c := range chunkCh {
  1549  		scale, idx, err := DecodeBlockTKey(c.K)
  1550  		if err != nil {
  1551  			dvid.Errorf("Couldn't decode label block key %v for data %q\n", c.K, d.DataName())
  1552  			wg.Done()
  1553  			continue
  1554  		}
  1555  		if scale != 0 {
  1556  			dvid.Errorf("Counts had unexpected error: getting scale %d blocks\n", scale)
  1557  			wg.Done()
  1558  			continue
  1559  		}
  1560  		var data []byte
  1561  		data, _, err = dvid.DeserializeData(c.V, true)
  1562  		if err != nil {
  1563  			dvid.Errorf("Unable to deserialize block %s in data %q: %v\n", idx, d.DataName(), err)
  1564  			wg.Done()
  1565  			continue
  1566  		}
  1567  		var block labels.Block
  1568  		if err := block.UnmarshalBinary(data); err != nil {
  1569  			dvid.Errorf("Unable to unmarshal Block %s in data %q: %v\n", idx, d.DataName(), err)
  1570  			wg.Done()
  1571  			continue
  1572  		}
  1573  		counts := block.CalcNumLabels(nil)
  1574  		for supervoxel, count := range counts {
  1575  			bx, by, bz := idx.Unpack()
  1576  			line := fmt.Sprintf("%d %d %d %d %d\n", supervoxel, bz, by, bx, count)
  1577  			mu.Lock()
  1578  			_, err := f.WriteString(line)
  1579  			mu.Unlock()
  1580  			if err != nil {
  1581  				dvid.Errorf("Unable to write data for block %s, data %q: %v\n", idx, d.DataName(), err)
  1582  				break
  1583  			}
  1584  		}
  1585  		wg.Done()
  1586  	}
  1587  }
  1588  
  1589  // scan all label blocks in this labelmap instance, writing supervoxel counts into a given file
  1590  func (d *Data) writeSVCounts(f *os.File, outPath string, v dvid.VersionID) {
  1591  	timedLog := dvid.NewTimeLog()
  1592  
  1593  	// Start the counting goroutine
  1594  	mu := new(sync.Mutex)
  1595  	wg := new(sync.WaitGroup)
  1596  	chunkCh := make(chan *storage.Chunk, 100)
  1597  	for i := 0; i < 100; i++ {
  1598  		go d.countThread(f, mu, wg, chunkCh)
  1599  	}
  1600  
  1601  	// Iterate through all label blocks and count them.
  1602  	chunkOp := &storage.ChunkOp{Wg: wg}
  1603  
  1604  	store, err := datastore.GetOrderedKeyValueDB(d)
  1605  	if err != nil {
  1606  		dvid.Errorf("problem getting store for data %q: %v\n", d.DataName(), err)
  1607  		return
  1608  	}
  1609  	ctx := datastore.NewVersionedCtx(d, v)
  1610  	begTKey := NewBlockTKeyByCoord(0, dvid.MinIndexZYX.ToIZYXString())
  1611  	endTKey := NewBlockTKeyByCoord(0, dvid.MaxIndexZYX.ToIZYXString())
  1612  	var numBlocks uint64
  1613  	err = store.ProcessRange(ctx, begTKey, endTKey, chunkOp, func(c *storage.Chunk) error {
  1614  		if c == nil {
  1615  			wg.Done()
  1616  			return fmt.Errorf("received nil chunk in count for data %q", d.DataName())
  1617  		}
  1618  		if c.V == nil {
  1619  			wg.Done()
  1620  			return nil
  1621  		}
  1622  		numBlocks++
  1623  		if numBlocks%10000 == 0 {
  1624  			timedLog.Infof("Now counting block %d with chunk channel at %d", numBlocks, len(chunkCh))
  1625  		}
  1626  		chunkCh <- c
  1627  		return nil
  1628  	})
  1629  	if err != nil {
  1630  		dvid.Errorf("problem during process range: %v\n", err)
  1631  	}
  1632  	close(chunkCh)
  1633  	wg.Wait()
  1634  	if err = f.Close(); err != nil {
  1635  		dvid.Errorf("problem closing file %q: %v\n", outPath, err)
  1636  	}
  1637  	timedLog.Infof("Finished counting supervoxels in %d blocks and sent to output file %q", numBlocks, outPath)
  1638  }
  1639  
  1640  func (d *Data) writeFileMappings(f *os.File, outPath string, v dvid.VersionID) {
  1641  	if err := d.writeMappings(f, v, false); err != nil {
  1642  		dvid.Errorf("error writing mapping to file %q: %v\n", outPath, err)
  1643  		return
  1644  	}
  1645  	if err := f.Close(); err != nil {
  1646  		dvid.Errorf("problem closing file %q: %v\n", outPath, err)
  1647  	}
  1648  }
  1649  
  1650  func (d *Data) writeMappings(w io.Writer, v dvid.VersionID, binaryFormat bool) error {
  1651  	timedLog := dvid.NewTimeLog()
  1652  
  1653  	vc, err := getMapping(d, v)
  1654  	if err != nil {
  1655  		return fmt.Errorf("unable to retrieve mappings for data %q, version %d: %v", d.DataName(), v, err)
  1656  	}
  1657  	if !vc.mapUsed {
  1658  		dvid.Infof("no mappings found for data %q\n", d.DataName())
  1659  		return nil
  1660  	}
  1661  	numMappings, err := vc.writeMappings(w, v, binaryFormat)
  1662  
  1663  	timedLog.Infof("Wrote %d mappings: err = %v", numMappings, err)
  1664  	return err
  1665  }
  1666  
  1667  // Streams labels and optionally # voxels for the label to the http.ResponseWriter.
  1668  func (d *Data) listLabels(ctx *datastore.VersionedCtx, start, number uint64, countVoxels bool, w http.ResponseWriter) (numLabels uint64, err error) {
  1669  	if number == 0 {
  1670  		return
  1671  	}
  1672  	var store storage.OrderedKeyValueDB
  1673  	store, err = datastore.GetOrderedKeyValueDB(d)
  1674  	if err != nil {
  1675  		return 0, fmt.Errorf("problem getting store for data %q: %v", d.DataName(), err)
  1676  	}
  1677  	begTKey := NewLabelIndexTKey(start)
  1678  	endTKey := NewLabelIndexTKey(math.MaxUint64)
  1679  	haltFakeErr := fmt.Errorf("terminate range query")
  1680  	err = store.ProcessRange(ctx, begTKey, endTKey, nil, func(c *storage.Chunk) error {
  1681  		if c == nil || c.V == nil || len(c.V) == 0 {
  1682  			return nil
  1683  		}
  1684  		numLabels++
  1685  		label, err := DecodeLabelIndexTKey(c.K)
  1686  		if err != nil {
  1687  			return err
  1688  		}
  1689  		if err = binary.Write(w, binary.LittleEndian, label); err != nil {
  1690  			return err
  1691  		}
  1692  		if countVoxels {
  1693  			var data []byte
  1694  			data, _, err = dvid.DeserializeData(c.V, true)
  1695  			if err != nil {
  1696  				return err
  1697  			}
  1698  			idx := new(labels.Index)
  1699  			if err := pb.Unmarshal(data, idx); err != nil {
  1700  				return err
  1701  			}
  1702  			var numVoxels uint64
  1703  			for _, svc := range idx.Blocks {
  1704  				if svc != nil && len(svc.Counts) != 0 {
  1705  					for _, count := range svc.Counts {
  1706  						numVoxels += uint64(count)
  1707  					}
  1708  				}
  1709  			}
  1710  			if err = binary.Write(w, binary.LittleEndian, numVoxels); err != nil {
  1711  				return err
  1712  			}
  1713  		}
  1714  		if numLabels == number {
  1715  			return haltFakeErr
  1716  		}
  1717  		return nil
  1718  	})
  1719  	if err == haltFakeErr {
  1720  		err = nil
  1721  	}
  1722  	return
  1723  }
  1724  
  1725  func (d *Data) indexThread(f *os.File, mu *sync.Mutex, wg *sync.WaitGroup, chunkCh chan *storage.Chunk) {
  1726  	for c := range chunkCh {
  1727  		label, err := DecodeLabelIndexTKey(c.K)
  1728  		if err != nil {
  1729  			dvid.Errorf("Couldn't decode label index key %v for data %q\n", c.K, d.DataName())
  1730  			wg.Done()
  1731  			continue
  1732  		}
  1733  		var data []byte
  1734  		data, _, err = dvid.DeserializeData(c.V, true)
  1735  		if err != nil {
  1736  			dvid.Errorf("Unable to deserialize label index %d in data %q: %v\n", label, d.DataName(), err)
  1737  			wg.Done()
  1738  			continue
  1739  		}
  1740  		idx := new(labels.Index)
  1741  		if err := pb.Unmarshal(data, idx); err != nil {
  1742  			dvid.Errorf("Unable to unmarshal label index %d in data %q: %v\n", label, d.DataName(), err)
  1743  			wg.Done()
  1744  			continue
  1745  		}
  1746  		if idx.Label == 0 {
  1747  			idx.Label = label
  1748  		}
  1749  		for zyx, svc := range idx.Blocks {
  1750  			bx, by, bz := labels.DecodeBlockIndex(zyx)
  1751  			if svc != nil && len(svc.Counts) != 0 {
  1752  				for supervoxel, count := range svc.Counts {
  1753  					line := fmt.Sprintf("%d %d %d %d %d %d\n", idx.Label, supervoxel, bz, by, bx, count)
  1754  					mu.Lock()
  1755  					_, err := f.WriteString(line)
  1756  					mu.Unlock()
  1757  					if err != nil {
  1758  						dvid.Errorf("Unable to write label index %d line, data %q: %v\n", idx.Label, d.DataName(), err)
  1759  						break
  1760  					}
  1761  				}
  1762  			}
  1763  		}
  1764  		wg.Done()
  1765  	}
  1766  }
  1767  
  1768  // scan all label indices in this labelmap instance, writing Blocks data into a given file
  1769  func (d *Data) writeIndices(f *os.File, outPath string, v dvid.VersionID) {
  1770  	timedLog := dvid.NewTimeLog()
  1771  
  1772  	// Start the counting goroutine
  1773  	mu := new(sync.Mutex)
  1774  	wg := new(sync.WaitGroup)
  1775  	chunkCh := make(chan *storage.Chunk, 100)
  1776  	for i := 0; i < 100; i++ {
  1777  		go d.indexThread(f, mu, wg, chunkCh)
  1778  	}
  1779  
  1780  	// Iterate through all label blocks and count them.
  1781  	chunkOp := &storage.ChunkOp{Wg: wg}
  1782  
  1783  	store, err := datastore.GetOrderedKeyValueDB(d)
  1784  	if err != nil {
  1785  		dvid.Errorf("problem getting store for data %q: %v\n", d.DataName(), err)
  1786  		return
  1787  	}
  1788  	ctx := datastore.NewVersionedCtx(d, v)
  1789  	begTKey := NewLabelIndexTKey(0)
  1790  	endTKey := NewLabelIndexTKey(math.MaxUint64)
  1791  	var numIndices uint64
  1792  	err = store.ProcessRange(ctx, begTKey, endTKey, chunkOp, func(c *storage.Chunk) error {
  1793  		if c == nil {
  1794  			wg.Done()
  1795  			return fmt.Errorf("received nil chunk in dump index for data %q", d.DataName())
  1796  		}
  1797  		if c.V == nil {
  1798  			wg.Done()
  1799  			return nil
  1800  		}
  1801  		numIndices++
  1802  		if numIndices%10000 == 0 {
  1803  			timedLog.Infof("Now dumping label index %d with chunk channel at %d", numIndices, len(chunkCh))
  1804  		}
  1805  		chunkCh <- c
  1806  		return nil
  1807  	})
  1808  	if err != nil {
  1809  		dvid.Errorf("problem during process range: %v\n", err)
  1810  	}
  1811  	close(chunkCh)
  1812  	wg.Wait()
  1813  	if err = f.Close(); err != nil {
  1814  		dvid.Errorf("problem closing file %q: %v\n", outPath, err)
  1815  	}
  1816  	timedLog.Infof("Finished dumping %d label indices to output file %q", numIndices, outPath)
  1817  }