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

     1  package labelarray
     2  
     3  import (
     4  	"bytes"
     5  	"compress/gzip"
     6  	"encoding/binary"
     7  	"fmt"
     8  	"io"
     9  	"sort"
    10  	"sync"
    11  	"sync/atomic"
    12  	"time"
    13  
    14  	"github.com/coocood/freecache"
    15  	"github.com/janelia-flyem/dvid/datastore"
    16  	"github.com/janelia-flyem/dvid/datatype/common/labels"
    17  	"github.com/janelia-flyem/dvid/dvid"
    18  	"github.com/janelia-flyem/dvid/server"
    19  	"github.com/janelia-flyem/dvid/storage"
    20  	lz4 "github.com/janelia-flyem/go/golz4-updated"
    21  )
    22  
    23  const (
    24  	numIndexShards = 64
    25  )
    26  
    27  var (
    28  	indexCache   *freecache.Cache
    29  	indexMu      [numIndexShards]sync.RWMutex
    30  	metaAttempts uint64
    31  	metaHits     uint64
    32  )
    33  
    34  // Initialize makes sure index caching is initialized if cache size is specified
    35  // in the server configuration.
    36  func (d *Data) Initialize() {
    37  	numBytes := server.CacheSize("labelarray")
    38  	if indexCache == nil {
    39  		if numBytes > 0 {
    40  			indexCache = freecache.NewCache(numBytes)
    41  			mbs := numBytes >> 20
    42  			dvid.Infof("Created freecache of ~ %d MB for labelarray instances.\n", mbs)
    43  		}
    44  	} else if numBytes == 0 {
    45  		indexCache = nil
    46  	} else {
    47  		indexCache.Clear()
    48  	}
    49  }
    50  
    51  // indexKey is a three tuple (instance id, version, label)
    52  type indexKey struct {
    53  	data    dvid.Data
    54  	version dvid.VersionID
    55  	label   uint64
    56  }
    57  
    58  func (k indexKey) Bytes() []byte {
    59  	b := make([]byte, 16)
    60  	copy(b[0:4], k.data.InstanceID().Bytes())
    61  	copy(b[4:8], k.version.Bytes())
    62  	binary.LittleEndian.PutUint64(b[8:16], k.label)
    63  	return b
    64  }
    65  
    66  func (k indexKey) VersionedCtx() *datastore.VersionedCtx {
    67  	return datastore.NewVersionedCtx(k.data, k.version)
    68  }
    69  
    70  // returns nil if no Meta is found.
    71  // should not be called concurrently since label meta could have race condition
    72  func getLabelMeta(ctx *datastore.VersionedCtx, label uint64) (*Meta, error) {
    73  	store, err := datastore.GetKeyValueDB(ctx.Data())
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  	compressed, err := store.Get(ctx, NewLabelIndexTKey(label))
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  	if len(compressed) == 0 {
    82  		return nil, nil
    83  	}
    84  	val, _, err := dvid.DeserializeData(compressed, true)
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  	if len(val) == 0 {
    89  		return nil, err
    90  	}
    91  
    92  	var meta Meta
    93  	if err := meta.UnmarshalBinary(val); err != nil {
    94  		return nil, err
    95  	}
    96  	return &meta, nil
    97  }
    98  
    99  func putLabelMeta(ctx *datastore.VersionedCtx, label uint64, meta *Meta) error {
   100  	store, err := datastore.GetOrderedKeyValueDB(ctx.Data())
   101  	if err != nil {
   102  		return fmt.Errorf("data %q PutLabelMeta had error initializing store: %v", ctx.Data().DataName(), err)
   103  	}
   104  
   105  	tk := NewLabelIndexTKey(label)
   106  	serialization, err := meta.MarshalBinary()
   107  	if err != nil {
   108  		return fmt.Errorf("error trying to serialize meta for label %d, data %q: %v", label, ctx.Data().DataName(), err)
   109  	}
   110  	compressFormat, _ := dvid.NewCompression(dvid.LZ4, dvid.DefaultCompression)
   111  	compressed, err := dvid.SerializeData(serialization, compressFormat, dvid.NoChecksum)
   112  	if err != nil {
   113  		return fmt.Errorf("error trying to LZ4 compress label %d indexing in data %q", label, ctx.Data().DataName())
   114  	}
   115  	if err := store.Put(ctx, tk, compressed); err != nil {
   116  		return fmt.Errorf("unable to store indices for label %d, data %s: %v", label, ctx.Data().DataName(), err)
   117  	}
   118  	return nil
   119  }
   120  
   121  func deleteLabelMeta(ctx *datastore.VersionedCtx, label uint64) error {
   122  	store, err := datastore.GetOrderedKeyValueDB(ctx.Data())
   123  	if err != nil {
   124  		return fmt.Errorf("data %q DeleteLabelMeta had error initializing store: %v", ctx.Data().DataName(), err)
   125  	}
   126  
   127  	tk := NewLabelIndexTKey(label)
   128  	if err := store.Delete(ctx, tk); err != nil {
   129  		return fmt.Errorf("unable to delete indices for label %d, data %s: %v", label, ctx.Data().DataName(), err)
   130  	}
   131  	return nil
   132  }
   133  
   134  // GetLabelIndex gets label index data from storage for a given data instance
   135  // and version. Concurrency-safe access and supports caching.
   136  func GetLabelIndex(d dvid.Data, v dvid.VersionID, label uint64) (*Meta, error) {
   137  	atomic.AddUint64(&metaAttempts, 1)
   138  	k := indexKey{data: d, version: v, label: label}
   139  
   140  	shard := label % numIndexShards
   141  	indexMu[shard].RLock()
   142  	defer indexMu[shard].RUnlock()
   143  
   144  	var metaBytes []byte
   145  	var err error
   146  	if indexCache != nil {
   147  		metaBytes, err = indexCache.Get(k.Bytes())
   148  		if err != nil && err != freecache.ErrNotFound {
   149  			return nil, err
   150  		}
   151  	}
   152  	if metaBytes != nil {
   153  		var m Meta
   154  		if err := m.UnmarshalBinary(metaBytes); err != nil {
   155  			return nil, err
   156  		}
   157  		atomic.AddUint64(&metaHits, 1)
   158  		return &m, nil
   159  	}
   160  	m, err := getLabelMeta(k.VersionedCtx(), label)
   161  	if err != nil {
   162  		return nil, err
   163  	}
   164  	if indexCache != nil && m != nil {
   165  		metaBytes, err := m.MarshalBinary()
   166  		if err != nil {
   167  			dvid.Errorf("unable to marshal label %d index for %q: %v\n", label, d.DataName(), err)
   168  		} else if err := indexCache.Set(k.Bytes(), metaBytes, 0); err != nil {
   169  			dvid.Errorf("unable to set label %d index cache for %q: %v\n", label, d.DataName(), err)
   170  		}
   171  	}
   172  	return m, err
   173  }
   174  
   175  // GetLabelProcessedIndex gets label index data from storage for a given data instance
   176  // and version with scaling and/or bounds. Concurrency-safe access and supports caching.
   177  // If scale > 0, then the number of voxels is set to zero since an accurate count is not
   178  // available without more processing.
   179  func GetLabelProcessedIndex(d dvid.Data, v dvid.VersionID, label uint64, scale uint8, bounds dvid.Bounds) (*Meta, error) {
   180  	meta, err := GetLabelIndex(d, v, label)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  	if meta == nil {
   185  		return nil, nil
   186  	}
   187  	voxels := meta.Voxels
   188  	blocks := meta.Blocks
   189  	if scale > 0 {
   190  		if blocks, err = blocks.Downres(scale); err != nil {
   191  			return nil, err
   192  		}
   193  	}
   194  	if bounds.Block != nil && bounds.Block.IsSet() {
   195  		blocks, err = meta.Blocks.FitToBounds(bounds.Block)
   196  		if err != nil {
   197  			return nil, err
   198  		}
   199  		voxels = 0
   200  	}
   201  
   202  	newMeta := Meta{Voxels: voxels, Blocks: blocks}
   203  	return &newMeta, nil
   204  }
   205  
   206  // GetMappedLabelIndex gets index data for all labels potentially merged to the
   207  // given label, allowing scaling and bounds. If bounds are used, the returned Meta
   208  // will not include a voxel count.  Concurrency-safe access and supports caching.
   209  func GetMappedLabelIndex(d dvid.Data, v dvid.VersionID, label uint64, scale uint8, bounds dvid.Bounds) (*Meta, labels.Set, error) {
   210  	iv := dvid.InstanceVersion{Data: d.DataUUID(), Version: v}
   211  	mapping := labels.LabelMap(iv)
   212  	if mapping != nil {
   213  		// Check if this label has been merged.
   214  		if _, found := mapping.FinalLabel(label); found {
   215  			return nil, nil, nil
   216  		}
   217  	}
   218  
   219  	// Get set of all labels that have been merged to this given label.
   220  	var lbls labels.Set
   221  	if mapping == nil {
   222  		lbls = labels.Set{label: struct{}{}}
   223  	} else {
   224  		lbls = mapping.ConstituentLabels(label)
   225  	}
   226  
   227  	// Get the block indices for the set of labels.
   228  	var voxels uint64
   229  	var blocks dvid.IZYXSlice
   230  	for label := range lbls {
   231  		meta, err := GetLabelIndex(d, v, label)
   232  		if err != nil {
   233  			return nil, nil, err
   234  		}
   235  		if meta != nil {
   236  			if len(lbls) == 1 {
   237  				blocks = meta.Blocks
   238  				voxels = meta.Voxels
   239  			} else if len(meta.Blocks) > 0 {
   240  				voxels += meta.Voxels
   241  				blocks.Merge(meta.Blocks)
   242  			}
   243  		}
   244  	}
   245  
   246  	var err error
   247  	if bounds.Block != nil && bounds.Block.IsSet() {
   248  		blocks, err = blocks.FitToBounds(bounds.Block)
   249  		if err != nil {
   250  			return nil, nil, err
   251  		}
   252  		voxels = 0
   253  	}
   254  
   255  	if scale > 0 {
   256  		if blocks, err = blocks.Downres(scale); err != nil {
   257  			return nil, nil, err
   258  		}
   259  	}
   260  
   261  	meta := Meta{Voxels: voxels, Blocks: blocks}
   262  	return &meta, lbls, nil
   263  }
   264  
   265  // GetMappedLabelSetIndex gets index data for all labels potentially merged to the
   266  // given labels, allowing scaling and bounds. If bounds are used, the returned Meta
   267  // will not include a voxel count.  Concurrency-safe access and supports caching.
   268  func GetMappedLabelSetIndex(d dvid.Data, v dvid.VersionID, lbls labels.Set, scale uint8, bounds dvid.Bounds) (*Meta, labels.Set, error) {
   269  	iv := dvid.InstanceVersion{Data: d.DataUUID(), Version: v}
   270  	mapping := labels.LabelMap(iv)
   271  	if mapping != nil {
   272  		// Check if this label has been merged.
   273  		for label := range lbls {
   274  			if mapped, found := mapping.FinalLabel(label); found {
   275  				return nil, nil, fmt.Errorf("label %d has already been merged into label %d", label, mapped)
   276  			}
   277  		}
   278  	}
   279  
   280  	// Expand set of all labels based on mappings.
   281  	var lbls2 labels.Set
   282  	if mapping == nil {
   283  		lbls2 = lbls
   284  	} else {
   285  		lbls2 = make(labels.Set)
   286  		for label := range lbls {
   287  			mappedlbls := mapping.ConstituentLabels(label)
   288  			for label2 := range mappedlbls {
   289  				lbls2[label2] = struct{}{}
   290  			}
   291  		}
   292  	}
   293  
   294  	// Get the block indices for the set of labels.
   295  	var voxels uint64
   296  	var blocks dvid.IZYXSlice
   297  	for label := range lbls2 {
   298  		meta, err := GetLabelIndex(d, v, label)
   299  		if err != nil {
   300  			return nil, nil, err
   301  		}
   302  		if meta != nil {
   303  			if len(lbls) == 1 {
   304  				blocks = meta.Blocks
   305  				voxels = meta.Voxels
   306  			} else if len(meta.Blocks) > 0 {
   307  				voxels += meta.Voxels
   308  				blocks.Merge(meta.Blocks)
   309  			}
   310  		}
   311  	}
   312  
   313  	var err error
   314  	if bounds.Block != nil && bounds.Block.IsSet() {
   315  		blocks, err = blocks.FitToBounds(bounds.Block)
   316  		if err != nil {
   317  			return nil, nil, err
   318  		}
   319  		voxels = 0
   320  	}
   321  
   322  	if scale > 0 {
   323  		if blocks, err = blocks.Downres(scale); err != nil {
   324  			return nil, nil, err
   325  		}
   326  	}
   327  
   328  	meta := Meta{Voxels: voxels, Blocks: blocks}
   329  	return &meta, lbls2, nil
   330  }
   331  
   332  // DeleteLabelIndex deletes the index for a given label.
   333  func DeleteLabelIndex(d dvid.Data, v dvid.VersionID, label uint64) error {
   334  	shard := label % numIndexShards
   335  	indexMu[shard].Lock()
   336  	defer indexMu[shard].Unlock()
   337  
   338  	ctx := datastore.NewVersionedCtx(d, v)
   339  	if err := deleteLabelMeta(ctx, label); err != nil {
   340  		return err
   341  	}
   342  	if indexCache != nil {
   343  		k := indexKey{data: d, version: v, label: label}.Bytes()
   344  		indexCache.Del(k)
   345  	}
   346  	return nil
   347  }
   348  
   349  // SetLabelIndex sets label index data from storage for a given data instance and
   350  // version. If the given Meta is nil, the label index is deleted.  Concurrency-safe
   351  // and supports caching.
   352  func SetLabelIndex(d dvid.Data, v dvid.VersionID, label uint64, m *Meta) error {
   353  	if m == nil {
   354  		return DeleteLabelIndex(d, v, label)
   355  	}
   356  	shard := label % numIndexShards
   357  	indexMu[shard].Lock()
   358  	defer indexMu[shard].Unlock()
   359  
   360  	ctx := datastore.NewVersionedCtx(d, v)
   361  	if err := putLabelMeta(ctx, label, m); err != nil {
   362  		return err
   363  	}
   364  	metaBytes, err := m.MarshalBinary()
   365  	if err != nil {
   366  		return err
   367  	}
   368  	if indexCache != nil {
   369  		k := indexKey{data: d, version: v, label: label}.Bytes()
   370  		if err := indexCache.Set(k, metaBytes, 0); err != nil {
   371  			return err
   372  		}
   373  	}
   374  	return nil
   375  }
   376  
   377  // ChangeLabelIndex applies changes to a label's index and then stores the result.
   378  // Concurrency-safe and supports caching.
   379  func ChangeLabelIndex(d dvid.Data, v dvid.VersionID, label uint64, delta blockDiffMap) error {
   380  	atomic.AddUint64(&metaAttempts, 1)
   381  	k := indexKey{data: d, version: v, label: label}
   382  
   383  	shard := label % numIndexShards
   384  	indexMu[shard].RLock()
   385  	defer indexMu[shard].RUnlock()
   386  
   387  	var metaBytes []byte
   388  	var err error
   389  	if indexCache != nil {
   390  		metaBytes, err = indexCache.Get(k.Bytes())
   391  		if err != nil && err != freecache.ErrNotFound {
   392  			return err
   393  		}
   394  	}
   395  	m := new(Meta)
   396  	if metaBytes != nil {
   397  		if err = m.UnmarshalBinary(metaBytes); err != nil {
   398  			return err
   399  		}
   400  		atomic.AddUint64(&metaHits, 1)
   401  	} else {
   402  		var mret *Meta
   403  		if mret, err = getLabelMeta(k.VersionedCtx(), label); err != nil {
   404  			return err
   405  		}
   406  		if mret != nil {
   407  			m = mret
   408  		}
   409  	}
   410  	if err := m.applyChanges(delta); err != nil {
   411  		return err
   412  	}
   413  
   414  	ctx := datastore.NewVersionedCtx(d, v)
   415  	if len(m.Blocks) == 0 { // Delete this label's index
   416  		if err := deleteLabelMeta(ctx, label); err != nil {
   417  			return err
   418  		}
   419  		if indexCache != nil {
   420  			k := indexKey{data: d, version: v, label: label}.Bytes()
   421  			indexCache.Del(k)
   422  		}
   423  	} else {
   424  		if err = putLabelMeta(ctx, label, m); err != nil {
   425  			return err
   426  		}
   427  		if indexCache != nil && m != nil {
   428  			metaBytes, err = m.MarshalBinary()
   429  			if err != nil {
   430  				return err
   431  			}
   432  			k := indexKey{data: d, version: v, label: label}.Bytes()
   433  			if err := indexCache.Set(k, metaBytes, 0); err != nil {
   434  				return err
   435  			}
   436  		}
   437  	}
   438  	return nil
   439  }
   440  
   441  // Meta gives a high-level overview of a label's voxels including a block index.
   442  // Some properties are only used if the associated data instance has features enabled, e.g.,
   443  // size tracking.
   444  type Meta struct {
   445  	Voxels uint64         // Total # of voxels in label.
   446  	Blocks dvid.IZYXSlice // Sorted block coordinates occupied by label.
   447  
   448  	LastModTime time.Time
   449  	LastModUser string
   450  }
   451  
   452  // MarshalBinary implements the encoding.BinaryMarshaler interface
   453  func (m Meta) MarshalBinary() ([]byte, error) {
   454  	buf := make([]byte, len(m.Blocks)*12+8)
   455  	binary.LittleEndian.PutUint64(buf[0:8], m.Voxels)
   456  	off := 8
   457  	for _, izyx := range m.Blocks {
   458  		copy(buf[off:off+12], string(izyx))
   459  		off += 12
   460  	}
   461  	return buf, nil
   462  }
   463  
   464  // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
   465  func (m *Meta) UnmarshalBinary(b []byte) error {
   466  	if len(b) < 8 {
   467  		return fmt.Errorf("cannot unmarshal %d bytes into Meta", len(b))
   468  	}
   469  	m.Voxels = binary.LittleEndian.Uint64(b[0:8])
   470  	numBlocks := (len(b) - 8) / 12
   471  	if err := m.Blocks.UnmarshalBinary(b[8 : 8+numBlocks*12]); err != nil {
   472  		return err
   473  	}
   474  	return nil
   475  }
   476  
   477  // change the block presence map
   478  func (m *Meta) applyChanges(bdm blockDiffMap) error {
   479  	var present dvid.IZYXSlice
   480  	var absent dvid.IZYXSlice
   481  	for block, diff := range bdm {
   482  		m.Voxels = uint64(int64(m.Voxels) + int64(diff.delta))
   483  		if diff.present {
   484  			present = append(present, block)
   485  		} else {
   486  			absent = append(absent, block)
   487  		}
   488  	}
   489  	if len(present) > 1 {
   490  		sort.Sort(present)
   491  	}
   492  	if len(absent) > 1 {
   493  		sort.Sort(absent)
   494  	}
   495  
   496  	m.Blocks.Delete(absent)
   497  	m.Blocks.Merge(present)
   498  	return nil
   499  }
   500  
   501  type sld struct { // sortable labelDiff
   502  	bcoord dvid.IZYXString
   503  	labelDiff
   504  }
   505  
   506  type slds []sld
   507  
   508  func (s slds) Len() int {
   509  	return len(s)
   510  }
   511  
   512  func (s slds) Swap(i, j int) {
   513  	s[i], s[j] = s[j], s[i]
   514  }
   515  
   516  func (s slds) Less(i, j int) bool {
   517  	return s[i].bcoord < s[j].bcoord
   518  }
   519  
   520  const presentOld = uint8(0x01) // bit flag for label presence in old block
   521  const presentNew = uint8(0x02) // bit flag for label presence in new block
   522  
   523  // block-level analysis of mutation to get label changes in a block.  accumulates data for
   524  // a given mutation into a map per mutation which will then be flushed for each label meta
   525  // k/v pair at end of mutation.
   526  func (d *Data) handleBlockMutate(v dvid.VersionID, ch chan blockChange, mut MutatedBlock) {
   527  	if !d.IndexedLabels && !d.CountLabels {
   528  		return
   529  	}
   530  	bc := blockChange{
   531  		bcoord: mut.BCoord,
   532  	}
   533  	if d.IndexedLabels {
   534  		bc.present = make(map[uint64]uint8)
   535  		for _, label := range mut.Prev.Labels {
   536  			if label != 0 {
   537  				bc.present[label] |= presentOld
   538  			}
   539  		}
   540  		for _, label := range mut.Data.Labels {
   541  			if label != 0 {
   542  				bc.present[label] |= presentNew
   543  			}
   544  		}
   545  	}
   546  	if d.CountLabels {
   547  		bc.delta = mut.Data.CalcNumLabels(mut.Prev)
   548  	}
   549  	ch <- bc
   550  }
   551  
   552  // block-level analysis of label ingest to do indexing
   553  func (d *Data) handleBlockIndexing(v dvid.VersionID, ch chan blockChange, mut IngestedBlock) {
   554  	if !d.IndexedLabels && !d.CountLabels {
   555  		return
   556  	}
   557  	bc := blockChange{
   558  		bcoord: mut.BCoord,
   559  	}
   560  	if d.IndexedLabels {
   561  		bc.present = make(map[uint64]uint8)
   562  		for _, label := range mut.Data.Labels {
   563  			if label != 0 {
   564  				bc.present[label] |= presentNew
   565  			}
   566  		}
   567  	}
   568  	if d.CountLabels {
   569  		bc.delta = mut.Data.CalcNumLabels(nil)
   570  	}
   571  	ch <- bc
   572  }
   573  
   574  // Goroutines accepts block-level changes and segregates all changes by label, and then
   575  // sends label-specific changes to concurrency-handling label indexing functions.
   576  
   577  type blockChange struct {
   578  	bcoord  dvid.IZYXString
   579  	present map[uint64]uint8
   580  	delta   map[uint64]int32
   581  }
   582  
   583  // goroutine(s) that accepts label change data for a block, then consolidates it and writes label
   584  // indexing.
   585  func (d *Data) aggregateBlockChanges(v dvid.VersionID, ch <-chan blockChange) {
   586  	var maxLabel uint64
   587  	ldm := make(map[uint64]blockDiffMap)
   588  	for change := range ch {
   589  		for label, flag := range change.present {
   590  			bdm, found := ldm[label]
   591  			if !found {
   592  				bdm = make(blockDiffMap)
   593  				ldm[label] = bdm
   594  			}
   595  			var diff labelDiff
   596  			switch flag {
   597  			case presentOld: // we no longer have this label in the block
   598  				diff.present = false
   599  				bdm[change.bcoord] = diff
   600  			case presentNew: // this is a new label in this block
   601  				diff.present = true
   602  				bdm[change.bcoord] = diff
   603  				if label > maxLabel {
   604  					maxLabel = label
   605  				}
   606  			case presentOld | presentNew: // no change
   607  				diff.present = true
   608  				bdm[change.bcoord] = diff
   609  			}
   610  		}
   611  		for label, delta := range change.delta {
   612  			bdm, found := ldm[label]
   613  			if !found {
   614  				bdm = make(blockDiffMap)
   615  				ldm[label] = bdm
   616  			}
   617  			diff := bdm[change.bcoord]
   618  			diff.delta += delta
   619  		}
   620  	}
   621  	go func() {
   622  		if err := d.updateMaxLabel(v, maxLabel); err != nil {
   623  			dvid.Errorf("max label change during block aggregation for %q: %v\n", d.DataName(), err)
   624  		}
   625  	}()
   626  
   627  	if d.IndexedLabels {
   628  		for label, bdm := range ldm {
   629  			ChangeLabelIndex(d, v, label, bdm)
   630  		}
   631  	}
   632  }
   633  
   634  type labelDiff struct {
   635  	delta   int32 // change in # voxels
   636  	present bool
   637  }
   638  type blockDiffMap map[dvid.IZYXString]labelDiff
   639  
   640  type labelBlock struct {
   641  	index dvid.IZYXString
   642  	data  []byte
   643  }
   644  
   645  type rleResult struct {
   646  	runs          uint32
   647  	serialization []byte
   648  }
   649  
   650  // goroutine to process retrieved label data and generate RLEs, could be sharded by block coordinate
   651  func (d *Data) processBlocksToRLEs(lbls labels.Set, bounds dvid.Bounds, in chan labelBlock, out chan rleResult) {
   652  	for {
   653  		lb, more := <-in
   654  		if !more {
   655  			return
   656  		}
   657  		var result rleResult
   658  		data, _, err := dvid.DeserializeData(lb.data, true)
   659  		if err != nil {
   660  			dvid.Errorf("could not deserialize %d bytes in block %s: %v\n", len(lb.data), lb.index, err)
   661  			out <- result
   662  			continue
   663  		}
   664  		var block labels.Block
   665  		if err := block.UnmarshalBinary(data); err != nil {
   666  			dvid.Errorf("unable to unmarshal label block %s: %v\n", lb.index, err)
   667  		}
   668  		blockData, _ := block.MakeLabelVolume()
   669  
   670  		var newRuns uint32
   671  		var serialization []byte
   672  		if bounds.Exact && bounds.Voxel.IsSet() {
   673  			serialization, newRuns, err = d.addBoundedRLEs(lb.index, blockData, lbls, bounds.Voxel)
   674  		} else {
   675  			serialization, newRuns, err = d.addRLEs(lb.index, blockData, lbls)
   676  		}
   677  		if err != nil {
   678  			dvid.Errorf("could not process %d bytes in block %s to create RLEs: %v\n", len(blockData), lb.index, err)
   679  		} else {
   680  			result = rleResult{runs: newRuns, serialization: serialization}
   681  		}
   682  		out <- result
   683  	}
   684  }
   685  
   686  func writeRLE(w io.Writer, start dvid.Point3d, run int32) error {
   687  	rle := dvid.NewRLE(start, run)
   688  	serialization, err := rle.MarshalBinary()
   689  	if err != nil {
   690  		return err
   691  	}
   692  	if _, err := w.Write(serialization); err != nil {
   693  		return err
   694  	}
   695  	return nil
   696  }
   697  
   698  // Scan a block and construct RLEs that will be serialized and added to the given buffer.
   699  func (d *Data) addRLEs(izyx dvid.IZYXString, data []byte, lbls labels.Set) (serialization []byte, newRuns uint32, err error) {
   700  	if len(data) != int(d.BlockSize().Prod())*8 {
   701  		err = fmt.Errorf("Deserialized label block %d bytes, not uint64 size times %d block elements\n",
   702  			len(data), d.BlockSize().Prod())
   703  		return
   704  	}
   705  	var indexZYX dvid.IndexZYX
   706  	indexZYX, err = izyx.IndexZYX()
   707  	if err != nil {
   708  		return
   709  	}
   710  	firstPt := indexZYX.MinPoint(d.BlockSize())
   711  	lastPt := indexZYX.MaxPoint(d.BlockSize())
   712  
   713  	var label uint64
   714  	var spanStart dvid.Point3d
   715  	var z, y, x, spanRun int32
   716  	start := 0
   717  	buf := new(bytes.Buffer)
   718  	for z = firstPt.Value(2); z <= lastPt.Value(2); z++ {
   719  		for y = firstPt.Value(1); y <= lastPt.Value(1); y++ {
   720  			for x = firstPt.Value(0); x <= lastPt.Value(0); x++ {
   721  				label = binary.LittleEndian.Uint64(data[start : start+8])
   722  				start += 8
   723  
   724  				// If we are in labels of interest, start or extend run.
   725  				inSpan := false
   726  				if label != 0 {
   727  					_, inSpan = lbls[label]
   728  				}
   729  				if inSpan {
   730  					spanRun++
   731  					if spanRun == 1 {
   732  						spanStart = dvid.Point3d{x, y, z}
   733  					}
   734  				} else {
   735  					if spanRun > 0 {
   736  						newRuns++
   737  						if err = writeRLE(buf, spanStart, spanRun); err != nil {
   738  							return
   739  						}
   740  					}
   741  					spanRun = 0
   742  				}
   743  			}
   744  			// Force break of any runs when we finish x scan.
   745  			if spanRun > 0 {
   746  				if err = writeRLE(buf, spanStart, spanRun); err != nil {
   747  					return
   748  				}
   749  				newRuns++
   750  				spanRun = 0
   751  			}
   752  		}
   753  	}
   754  	serialization = buf.Bytes()
   755  	return
   756  }
   757  
   758  // Scan a block and construct bounded RLEs that will be serialized and added to the given buffer.
   759  func (d *Data) addBoundedRLEs(izyx dvid.IZYXString, data []byte, lbls labels.Set, bounds *dvid.OptionalBounds) (serialization []byte, newRuns uint32, err error) {
   760  	if len(data) != int(d.BlockSize().Prod())*8 {
   761  		err = fmt.Errorf("Deserialized label block %d bytes, not uint64 size times %d block elements\n",
   762  			len(data), d.BlockSize().Prod())
   763  		return
   764  	}
   765  	var indexZYX dvid.IndexZYX
   766  	indexZYX, err = izyx.IndexZYX()
   767  	if err != nil {
   768  		return
   769  	}
   770  	firstPt := indexZYX.MinPoint(d.BlockSize())
   771  	lastPt := indexZYX.MaxPoint(d.BlockSize())
   772  
   773  	var label uint64
   774  	var spanStart dvid.Point3d
   775  	var z, y, x, spanRun int32
   776  	start := 0
   777  	buf := new(bytes.Buffer)
   778  	yskip := int(d.BlockSize().Value(0) * 8)
   779  	zskip := int(d.BlockSize().Value(1)) * yskip
   780  	for z = firstPt.Value(2); z <= lastPt.Value(2); z++ {
   781  		if bounds.OutsideZ(z) {
   782  			start += zskip
   783  			continue
   784  		}
   785  		for y = firstPt.Value(1); y <= lastPt.Value(1); y++ {
   786  			if bounds.OutsideY(y) {
   787  				start += yskip
   788  				continue
   789  			}
   790  			for x = firstPt.Value(0); x <= lastPt.Value(0); x++ {
   791  				label = binary.LittleEndian.Uint64(data[start : start+8])
   792  				start += 8
   793  
   794  				// If we are in labels of interest, start or extend run.
   795  				inSpan := false
   796  				if label != 0 {
   797  					_, inSpan = lbls[label]
   798  					if inSpan && bounds.OutsideX(x) {
   799  						inSpan = false
   800  					}
   801  				}
   802  				if inSpan {
   803  					spanRun++
   804  					if spanRun == 1 {
   805  						spanStart = dvid.Point3d{x, y, z}
   806  					}
   807  				} else {
   808  					if spanRun > 0 {
   809  						newRuns++
   810  						if err = writeRLE(buf, spanStart, spanRun); err != nil {
   811  							return
   812  						}
   813  					}
   814  					spanRun = 0
   815  				}
   816  			}
   817  			// Force break of any runs when we finish x scan.
   818  			if spanRun > 0 {
   819  				if err = writeRLE(buf, spanStart, spanRun); err != nil {
   820  					return
   821  				}
   822  				newRuns++
   823  				spanRun = 0
   824  			}
   825  		}
   826  	}
   827  	serialization = buf.Bytes()
   828  	return
   829  }
   830  
   831  // FoundSparseVol returns true if a sparse volume is found for the given label
   832  // within the given bounds.
   833  func (d *Data) FoundSparseVol(ctx *datastore.VersionedCtx, label uint64, bounds dvid.Bounds) (bool, error) {
   834  	m, _, err := GetMappedLabelIndex(d, ctx.VersionID(), label, 0, bounds)
   835  	if err != nil {
   836  		return false, err
   837  	}
   838  
   839  	if m != nil && len(m.Blocks) > 0 {
   840  		return true, nil
   841  	}
   842  	return false, nil
   843  }
   844  
   845  // writeBinaryBlocks does a streaming write of an encoded sparse volume given a label.
   846  // It returns a bool whether the label was found in the given bounds and any error.
   847  func (d *Data) writeBinaryBlocks(ctx *datastore.VersionedCtx, label uint64, scale uint8, bounds dvid.Bounds, compression string, w io.Writer) (bool, error) {
   848  	meta, lbls, err := GetMappedLabelIndex(d, ctx.VersionID(), label, scale, bounds)
   849  	if err != nil {
   850  		return false, err
   851  	}
   852  	if meta == nil || len(meta.Blocks) == 0 || len(lbls) == 0 {
   853  		return false, err
   854  	}
   855  
   856  	indices, err := getBoundedBlockIndices(meta, bounds)
   857  	if err != nil {
   858  		return false, err
   859  	}
   860  	sort.Sort(indices)
   861  
   862  	store, err := datastore.GetOrderedKeyValueDB(d)
   863  	if err != nil {
   864  		return false, err
   865  	}
   866  	op := labels.NewOutputOp(w)
   867  	go labels.WriteBinaryBlocks(label, lbls, op, bounds)
   868  	var preErr error
   869  	for _, izyx := range indices {
   870  		tk := NewBlockTKeyByCoord(scale, izyx)
   871  		data, err := store.Get(ctx, tk)
   872  		if err != nil {
   873  			preErr = err
   874  			break
   875  		}
   876  		if data == nil {
   877  			preErr = fmt.Errorf("expected block %s @ scale %d to have key-value, but found none", izyx, scale)
   878  			break
   879  		}
   880  		blockData, _, err := dvid.DeserializeData(data, true)
   881  		if err != nil {
   882  			preErr = err
   883  			break
   884  		}
   885  		var block labels.Block
   886  		if err := block.UnmarshalBinary(blockData); err != nil {
   887  			preErr = err
   888  			break
   889  		}
   890  		pb := labels.PositionedBlock{
   891  			Block:  block,
   892  			BCoord: izyx,
   893  		}
   894  		op.Process(&pb)
   895  	}
   896  	if err = op.Finish(); err != nil {
   897  		return false, err
   898  	}
   899  
   900  	dvid.Infof("[%s] label %d with %d constituent labels: streamed %d of %d blocks within bounds\n", ctx, label, len(lbls), len(indices), len(meta.Blocks))
   901  	return true, preErr
   902  }
   903  
   904  // writeStreamingRLE does a streaming write of an encoded sparse volume given a label.
   905  // It returns a bool whether the label was found in the given bounds and any error.
   906  func (d *Data) writeStreamingRLE(ctx *datastore.VersionedCtx, label uint64, scale uint8, bounds dvid.Bounds, compression string, w io.Writer) (bool, error) {
   907  	meta, lbls, err := GetMappedLabelIndex(d, ctx.VersionID(), label, scale, bounds)
   908  	if err != nil {
   909  		return false, err
   910  	}
   911  	if meta == nil || len(meta.Blocks) == 0 || len(lbls) == 0 {
   912  		return false, err
   913  	}
   914  
   915  	indices, err := getBoundedBlockIndices(meta, bounds)
   916  	if err != nil {
   917  		return false, err
   918  	}
   919  
   920  	store, err := datastore.GetOrderedKeyValueDB(d)
   921  	if err != nil {
   922  		return false, err
   923  	}
   924  	op := labels.NewOutputOp(w)
   925  	go labels.WriteRLEs(lbls, op, bounds)
   926  	for _, izyx := range indices {
   927  		tk := NewBlockTKeyByCoord(scale, izyx)
   928  		data, err := store.Get(ctx, tk)
   929  		if err != nil {
   930  			return false, err
   931  		}
   932  		blockData, _, err := dvid.DeserializeData(data, true)
   933  		if err != nil {
   934  			return false, err
   935  		}
   936  		var block labels.Block
   937  		if err := block.UnmarshalBinary(blockData); err != nil {
   938  			return false, err
   939  		}
   940  		pb := labels.PositionedBlock{
   941  			Block:  block,
   942  			BCoord: izyx,
   943  		}
   944  		op.Process(&pb)
   945  	}
   946  	if err = op.Finish(); err != nil {
   947  		return false, err
   948  	}
   949  
   950  	dvid.Infof("[%s] label %d with %d constituent labels: streamed %d of %d blocks within bounds\n", ctx, label, len(lbls), len(indices), len(meta.Blocks))
   951  	return true, nil
   952  }
   953  
   954  func (d *Data) writeLegacyRLE(ctx *datastore.VersionedCtx, label uint64, scale uint8, b dvid.Bounds, compression string, w io.Writer) (found bool, err error) {
   955  	var data []byte
   956  	data, err = d.getLegacyRLE(ctx, label, scale, b)
   957  	if err != nil {
   958  		return
   959  	}
   960  	if len(data) == 0 {
   961  		found = false
   962  		return
   963  	}
   964  	found = true
   965  	switch compression {
   966  	case "":
   967  		_, err = w.Write(data)
   968  	case "lz4":
   969  		compressed := make([]byte, lz4.CompressBound(data))
   970  		var n, outSize int
   971  		if outSize, err = lz4.Compress(data, compressed); err != nil {
   972  			return
   973  		}
   974  		compressed = compressed[:outSize]
   975  		n, err = w.Write(compressed)
   976  		if n != outSize {
   977  			err = fmt.Errorf("only able to write %d of %d lz4 compressed bytes", n, outSize)
   978  		}
   979  	case "gzip":
   980  		gw := gzip.NewWriter(w)
   981  		if _, err = gw.Write(data); err != nil {
   982  			return
   983  		}
   984  		err = gw.Close()
   985  	default:
   986  		err = fmt.Errorf("unknown compression type %q", compression)
   987  	}
   988  	return
   989  }
   990  
   991  // The encoding has the following format where integers are little endian:
   992  //
   993  //	byte     Payload descriptor:
   994  //	           Bit 0 (LSB) - 8-bit grayscale
   995  //	           Bit 1 - 16-bit grayscale
   996  //	           Bit 2 - 16-bit normal
   997  //	           ...
   998  //	uint8    Number of dimensions
   999  //	uint8    Dimension of run (typically 0 = X)
  1000  //	byte     Reserved (to be used later)
  1001  //	uint32    0
  1002  //	uint32    # Spans
  1003  //	Repeating unit of:
  1004  //	    int32   Coordinate of run start (dimension 0)
  1005  //	    int32   Coordinate of run start (dimension 1)
  1006  //	    int32   Coordinate of run start (dimension 2)
  1007  //	    int32   Length of run
  1008  //	    bytes   Optional payload dependent on first byte descriptor
  1009  func (d *Data) getLegacyRLE(ctx *datastore.VersionedCtx, label uint64, scale uint8, bounds dvid.Bounds) ([]byte, error) {
  1010  	meta, lbls, err := GetMappedLabelIndex(d, ctx.VersionID(), label, scale, bounds)
  1011  	if err != nil {
  1012  		return nil, err
  1013  	}
  1014  	if meta == nil || len(meta.Blocks) == 0 || len(lbls) == 0 {
  1015  		return nil, err
  1016  	}
  1017  	indices, err := getBoundedBlockIndices(meta, bounds)
  1018  	if err != nil {
  1019  		return nil, err
  1020  	}
  1021  	store, err := datastore.GetOrderedKeyValueDB(d)
  1022  	if err != nil {
  1023  		return nil, err
  1024  	}
  1025  
  1026  	buf := new(bytes.Buffer)
  1027  	buf.WriteByte(dvid.EncodingBinary)
  1028  	binary.Write(buf, binary.LittleEndian, uint8(3))  // # of dimensions
  1029  	binary.Write(buf, binary.LittleEndian, byte(0))   // dimension of run (X = 0)
  1030  	buf.WriteByte(byte(0))                            // reserved for later
  1031  	binary.Write(buf, binary.LittleEndian, uint32(0)) // Placeholder for # voxels
  1032  	binary.Write(buf, binary.LittleEndian, uint32(0)) // Placeholder for # spans
  1033  
  1034  	op := labels.NewOutputOp(buf)
  1035  	go labels.WriteRLEs(lbls, op, bounds)
  1036  	var numEmpty int
  1037  	for _, izyx := range indices {
  1038  		tk := NewBlockTKeyByCoord(scale, izyx)
  1039  		data, err := store.Get(ctx, tk)
  1040  		if err != nil {
  1041  			return nil, err
  1042  		}
  1043  		if len(data) == 0 {
  1044  			numEmpty++
  1045  			if numEmpty < 10 {
  1046  				dvid.Errorf("Block %s included in indices for labels %s but has no data (%d times)... skipping.\n", izyx, lbls, numEmpty)
  1047  			} else if numEmpty == 10 {
  1048  				dvid.Errorf("Over %d blocks included in indices with no data.  Halting error stream.\n", numEmpty)
  1049  			}
  1050  			continue
  1051  		}
  1052  		blockData, _, err := dvid.DeserializeData(data, true)
  1053  		if err != nil {
  1054  			return nil, err
  1055  		}
  1056  		var block labels.Block
  1057  		if err := block.UnmarshalBinary(blockData); err != nil {
  1058  			return nil, err
  1059  		}
  1060  		pb := labels.PositionedBlock{
  1061  			Block:  block,
  1062  			BCoord: izyx,
  1063  		}
  1064  		op.Process(&pb)
  1065  	}
  1066  	if numEmpty < len(indices) {
  1067  		if err = op.Finish(); err != nil {
  1068  			return nil, err
  1069  		}
  1070  	}
  1071  
  1072  	serialization := buf.Bytes()
  1073  	numRuns := uint32(len(serialization)-12) >> 4
  1074  	if numRuns == 0 {
  1075  		return nil, nil // Couldn't find this out until we did voxel-level clipping
  1076  	}
  1077  
  1078  	binary.LittleEndian.PutUint32(serialization[8:12], numRuns)
  1079  	dvid.Infof("[%s] labels %v: found %d of %d blocks within bounds excluding %d empty blocks, %d runs, serialized %d bytes\n", ctx, lbls, len(indices), len(meta.Blocks), numEmpty, numRuns, len(serialization))
  1080  	return serialization, nil
  1081  }
  1082  
  1083  // apply bounds to list of block indices.
  1084  func getBoundedBlockIndices(meta *Meta, bounds dvid.Bounds) (dvid.IZYXSlice, error) {
  1085  	indices := make(dvid.IZYXSlice, len(meta.Blocks))
  1086  	totBlocks := 0
  1087  	for _, izyx := range meta.Blocks {
  1088  		if bounds.Block.BoundedX() || bounds.Block.BoundedY() || bounds.Block.BoundedZ() {
  1089  			blockX, blockY, blockZ, err := izyx.Unpack()
  1090  			if err != nil {
  1091  				return nil, fmt.Errorf("Error decoding block %v: %v\n", izyx, err)
  1092  			}
  1093  			if bounds.Block.OutsideX(blockX) || bounds.Block.OutsideY(blockY) || bounds.Block.OutsideZ(blockZ) {
  1094  				continue
  1095  			}
  1096  		}
  1097  		indices[totBlocks] = izyx
  1098  		totBlocks++
  1099  	}
  1100  	if totBlocks == 0 {
  1101  		return nil, nil
  1102  	}
  1103  	return indices[:totBlocks], nil
  1104  }
  1105  
  1106  // GetSparseCoarseVol returns an encoded sparse volume given a label.  This will return nil slice
  1107  // if the given label was not found.  The encoding has the following format where integers are
  1108  // little endian:
  1109  //
  1110  //			byte     Set to 0
  1111  //			uint8    Number of dimensions
  1112  //			uint8    Dimension of run (typically 0 = X)
  1113  //			byte     Reserved (to be used later)
  1114  //			uint32    # Blocks [TODO.  0 for now]
  1115  //			uint32    # Spans
  1116  //			Repeating unit of:
  1117  //	    		int32   Block coordinate of run start (dimension 0)
  1118  //	    		int32   Block coordinate of run start (dimension 1)
  1119  //	    		int32   Block coordinate of run start (dimension 2)
  1120  //	    		int32   Length of run
  1121  func (d *Data) GetSparseCoarseVol(ctx *datastore.VersionedCtx, label uint64, bounds dvid.Bounds) ([]byte, error) {
  1122  	meta, _, err := GetMappedLabelIndex(d, ctx.VersionID(), label, 0, bounds)
  1123  	if err != nil {
  1124  		return nil, err
  1125  	}
  1126  
  1127  	if meta == nil || len(meta.Blocks) == 0 {
  1128  		return nil, nil
  1129  	}
  1130  
  1131  	// Create the sparse volume header
  1132  	buf := new(bytes.Buffer)
  1133  	buf.WriteByte(dvid.EncodingBinary)
  1134  	binary.Write(buf, binary.LittleEndian, uint8(3))  // # of dimensions
  1135  	binary.Write(buf, binary.LittleEndian, byte(0))   // dimension of run (X = 0)
  1136  	buf.WriteByte(byte(0))                            // reserved for later
  1137  	binary.Write(buf, binary.LittleEndian, uint32(0)) // Placeholder for # voxels
  1138  	binary.Write(buf, binary.LittleEndian, uint32(0)) // Placeholder for # spans
  1139  
  1140  	spans, err := meta.Blocks.WriteSerializedRLEs(buf)
  1141  	if err != nil {
  1142  		return nil, err
  1143  	}
  1144  	serialization := buf.Bytes()
  1145  	binary.LittleEndian.PutUint32(serialization[8:12], spans) // Placeholder for # spans
  1146  
  1147  	return serialization, nil
  1148  }
  1149  
  1150  // WriteSparseCoarseVols returns a stream of sparse volumes with blocks of the given label
  1151  // in encoded RLE format:
  1152  //
  1153  //		uint64   label
  1154  //		<coarse sparse vol as given below>
  1155  //
  1156  //		uint64   label
  1157  //		<coarse sparse vol as given below>
  1158  //
  1159  //		...
  1160  //
  1161  //	The coarse sparse vol has the following format where integers are little endian and the order
  1162  //	of data is exactly as specified below:
  1163  //
  1164  //		int32    # Spans
  1165  //		Repeating unit of:
  1166  //			int32   Block coordinate of run start (dimension 0)
  1167  //			int32   Block coordinate of run start (dimension 1)
  1168  //			int32   Block coordinate of run start (dimension 2)
  1169  //			int32   Length of run
  1170  func (d *Data) WriteSparseCoarseVols(ctx *datastore.VersionedCtx, w io.Writer, begLabel, endLabel uint64, bounds dvid.Bounds) error {
  1171  
  1172  	store, err := datastore.GetOrderedKeyValueDB(d)
  1173  	if err != nil {
  1174  		return err
  1175  	}
  1176  	begTKey := NewLabelIndexTKey(begLabel)
  1177  	endTKey := NewLabelIndexTKey(endLabel)
  1178  
  1179  	err = store.ProcessRange(ctx, begTKey, endTKey, &storage.ChunkOp{}, func(c *storage.Chunk) error {
  1180  		if c == nil || c.TKeyValue == nil {
  1181  			return nil
  1182  		}
  1183  		kv := c.TKeyValue
  1184  		if kv.V == nil {
  1185  			return nil
  1186  		}
  1187  		label, err := DecodeLabelIndexTKey(kv.K)
  1188  		if err != nil {
  1189  			return err
  1190  		}
  1191  		val, _, err := dvid.DeserializeData(kv.V, true)
  1192  		if err != nil {
  1193  			return err
  1194  		}
  1195  		var meta Meta
  1196  		if len(val) != 0 {
  1197  			if err := meta.UnmarshalBinary(val); err != nil {
  1198  				return err
  1199  			}
  1200  			blocks := meta.Blocks
  1201  			if bounds.Block != nil && bounds.Block.IsSet() {
  1202  				blocks, err = blocks.FitToBounds(bounds.Block)
  1203  				if err != nil {
  1204  					return err
  1205  				}
  1206  			}
  1207  
  1208  			buf := new(bytes.Buffer)
  1209  			spans, err := meta.Blocks.WriteSerializedRLEs(buf)
  1210  			if err != nil {
  1211  				return err
  1212  			}
  1213  			binary.Write(w, binary.LittleEndian, label)
  1214  			binary.Write(w, binary.LittleEndian, int32(spans))
  1215  			w.Write(buf.Bytes())
  1216  		}
  1217  		return nil
  1218  	})
  1219  	return err
  1220  }