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

     1  package labelblk
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"log"
     7  	"sync"
     8  
     9  	"github.com/janelia-flyem/dvid/datastore"
    10  	"github.com/janelia-flyem/dvid/datatype/common/labels"
    11  	"github.com/janelia-flyem/dvid/datatype/imageblk"
    12  	"github.com/janelia-flyem/dvid/dvid"
    13  	"github.com/janelia-flyem/dvid/server"
    14  	"github.com/janelia-flyem/dvid/storage"
    15  )
    16  
    17  // ComputeTransform determines the block coordinate and beginning + ending voxel points
    18  // for the data corresponding to the given Block.
    19  func (v *Labels) ComputeTransform(block *storage.TKeyValue, blockSize dvid.Point) (blockBeg, dataBeg, dataEnd dvid.Point, err error) {
    20  	var ptIndex *dvid.IndexZYX
    21  	ptIndex, err = DecodeTKey(block.K)
    22  	if err != nil {
    23  		return
    24  	}
    25  
    26  	// Get the bounding voxel coordinates for this block.
    27  	minBlockVoxel := ptIndex.MinPoint(blockSize)
    28  	maxBlockVoxel := ptIndex.MaxPoint(blockSize)
    29  
    30  	// Compute the boundary voxel coordinates for the ExtData and adjust
    31  	// to our block bounds.
    32  	minDataVoxel := v.StartPoint()
    33  	maxDataVoxel := v.EndPoint()
    34  	begVolCoord, _ := minDataVoxel.Max(minBlockVoxel)
    35  	endVolCoord, _ := maxDataVoxel.Min(maxBlockVoxel)
    36  
    37  	// Adjust the DVID volume voxel coordinates for the data so that (0,0,0)
    38  	// is where we expect this slice/subvolume's data to begin.
    39  	dataBeg = begVolCoord.Sub(v.StartPoint())
    40  	dataEnd = endVolCoord.Sub(v.StartPoint())
    41  
    42  	// Compute block coord matching dataBeg
    43  	blockBeg = begVolCoord.Sub(minBlockVoxel)
    44  
    45  	return
    46  }
    47  
    48  // GetImage retrieves a 2d image from a version node given a geometry of labels.
    49  func (d *Data) GetImage(v dvid.VersionID, vox *Labels, roiname dvid.InstanceName) (*dvid.Image, error) {
    50  	r, err := imageblk.GetROI(v, roiname, vox)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  	if err := d.GetLabels(v, vox, r); err != nil {
    55  		return nil, err
    56  	}
    57  	return vox.GetImage2d()
    58  }
    59  
    60  // GetVolume retrieves a n-d volume from a version node given a geometry of labels.
    61  func (d *Data) GetVolume(v dvid.VersionID, vox *Labels, roiname dvid.InstanceName) ([]byte, error) {
    62  	r, err := imageblk.GetROI(v, roiname, vox)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  	if err := d.GetLabels(v, vox, r); err != nil {
    67  		return nil, err
    68  	}
    69  	return vox.Data(), nil
    70  }
    71  
    72  type getOperation struct {
    73  	voxels      *Labels
    74  	blocksInROI map[string]bool
    75  	mapping     *labels.Mapping
    76  }
    77  
    78  // GetLabels copies labels from the storage engine to Labels, a requested subvolume or 2d image.
    79  func (d *Data) GetLabels(v dvid.VersionID, vox *Labels, r *imageblk.ROI) error {
    80  	store, err := datastore.GetOrderedKeyValueDB(d)
    81  	if err != nil {
    82  		return fmt.Errorf("Data type imageblk had error initializing store: %v\n", err)
    83  	}
    84  
    85  	// Only do one request at a time, although each request can start many goroutines.
    86  	if vox.NumVoxels() > 256*256*256 {
    87  		server.LargeMutationMutex.Lock()
    88  		defer server.LargeMutationMutex.Unlock()
    89  	}
    90  
    91  	ctx := datastore.NewVersionedCtx(d, v)
    92  
    93  	iv := dvid.InstanceVersion{d.DataUUID(), v}
    94  	mapping := labels.LabelMap(iv)
    95  
    96  	wg := new(sync.WaitGroup)
    97  
    98  	okv := store.(storage.BufferableOps)
    99  	// extract buffer interface
   100  	req, hasbuffer := okv.(storage.KeyValueRequester)
   101  	if hasbuffer {
   102  		okv = req.NewBuffer(ctx)
   103  	}
   104  
   105  	for it, err := vox.NewIndexIterator(d.BlockSize()); err == nil && it.Valid(); it.NextSpan() {
   106  		indexBeg, indexEnd, err := it.IndexSpan()
   107  		if err != nil {
   108  			return err
   109  		}
   110  		begTKey := NewTKey(indexBeg)
   111  		endTKey := NewTKey(indexEnd)
   112  
   113  		// Get set of blocks in ROI if ROI provided
   114  		var chunkOp *storage.ChunkOp
   115  		if r != nil && r.Iter != nil {
   116  			ptBeg := indexBeg.Duplicate().(dvid.ChunkIndexer)
   117  			ptEnd := indexEnd.Duplicate().(dvid.ChunkIndexer)
   118  			begX := ptBeg.Value(0)
   119  			endX := ptEnd.Value(0)
   120  
   121  			blocksInROI := make(map[string]bool, (endX - begX + 1))
   122  			c := dvid.ChunkPoint3d{begX, ptBeg.Value(1), ptBeg.Value(2)}
   123  			for x := begX; x <= endX; x++ {
   124  				c[0] = x
   125  				curIndex := dvid.IndexZYX(c)
   126  				if r.Iter.InsideFast(curIndex) {
   127  					indexString := string(curIndex.Bytes())
   128  					blocksInROI[indexString] = true
   129  				}
   130  			}
   131  			chunkOp = &storage.ChunkOp{&getOperation{vox, blocksInROI, mapping}, wg}
   132  		} else {
   133  			chunkOp = &storage.ChunkOp{&getOperation{vox, nil, mapping}, wg}
   134  		}
   135  
   136  		if !hasbuffer {
   137  			// Send the entire range of key-value pairs to chunk processor
   138  			err = okv.ProcessRange(ctx, begTKey, endTKey, chunkOp, storage.ChunkFunc(d.ReadChunk))
   139  			if err != nil {
   140  				return fmt.Errorf("Unable to GET data %s: %v", ctx, err)
   141  			}
   142  		} else {
   143  			// Extract block list
   144  			tkeys := make([]storage.TKey, 0)
   145  
   146  			ptBeg := indexBeg.Duplicate().(dvid.ChunkIndexer)
   147  			ptEnd := indexEnd.Duplicate().(dvid.ChunkIndexer)
   148  			begX := ptBeg.Value(0)
   149  			endX := ptEnd.Value(0)
   150  
   151  			c := dvid.ChunkPoint3d{begX, ptBeg.Value(1), ptBeg.Value(2)}
   152  			for x := begX; x <= endX; x++ {
   153  				c[0] = x
   154  				curIndex := dvid.IndexZYX(c)
   155  				currTKey := NewTKey(&curIndex)
   156  				tkeys = append(tkeys, currTKey)
   157  			}
   158  
   159  			err = okv.(storage.RequestBuffer).ProcessList(ctx, tkeys, chunkOp, storage.ChunkFunc(d.ReadChunk))
   160  			if err != nil {
   161  				return fmt.Errorf("Unable to GET data %s: %v", ctx, err)
   162  			}
   163  
   164  		}
   165  	}
   166  
   167  	if hasbuffer {
   168  		// submit the entire buffer to the DB
   169  		err = okv.(storage.RequestBuffer).Flush()
   170  
   171  		if err != nil {
   172  			return fmt.Errorf("Unable to GET data %s: %v", ctx, err)
   173  
   174  		}
   175  	}
   176  
   177  	if err != nil {
   178  		return err
   179  	}
   180  	wg.Wait()
   181  	return nil
   182  }
   183  
   184  type Block struct {
   185  	Pos  dvid.ChunkPoint3d
   186  	Data []byte
   187  }
   188  
   189  // GetBlocks returns any block data along a span in X
   190  func (d *Data) GetBlocks(v dvid.VersionID, start dvid.ChunkPoint3d, span int) ([]Block, error) {
   191  	store, err := datastore.GetOrderedKeyValueDB(d)
   192  	if err != nil {
   193  		return nil, fmt.Errorf("Data type imageblk had error initializing store: %v\n", err)
   194  	}
   195  
   196  	indexBeg := dvid.IndexZYX(start)
   197  	end := start
   198  	end[0] += int32(span - 1)
   199  	indexEnd := dvid.IndexZYX(end)
   200  	begTKey := NewTKey(&indexBeg)
   201  	endTKey := NewTKey(&indexEnd)
   202  
   203  	ctx := datastore.NewVersionedCtx(d, v)
   204  
   205  	iv := dvid.InstanceVersion{d.DataUUID(), v}
   206  	mapping := labels.LabelMap(iv)
   207  
   208  	keyvalues, err := store.GetRange(ctx, begTKey, endTKey)
   209  	if err != nil {
   210  		return nil, err
   211  	}
   212  
   213  	numkv := len(keyvalues)
   214  	blocks := make([]Block, numkv)
   215  
   216  	uncompress := true
   217  	for blocknum, kv := range keyvalues {
   218  		idx, err := DecodeTKey(kv.K)
   219  		if err != nil {
   220  			return nil, err
   221  		}
   222  		blockPos := dvid.ChunkPoint3d(*idx)
   223  		block, _, err := dvid.DeserializeData(kv.V, uncompress)
   224  		if err != nil {
   225  			return nil, fmt.Errorf("Unable to deserialize block, %s (%v): %v", ctx, kv.K, err)
   226  		}
   227  		if mapping != nil {
   228  			n := len(block) / 8
   229  			for i := 0; i < n; i++ {
   230  				orig := binary.LittleEndian.Uint64(block[i*8 : i*8+8])
   231  				mapped, found := mapping.FinalLabel(orig)
   232  				if !found {
   233  					mapped = orig
   234  				}
   235  				binary.LittleEndian.PutUint64(block[i*8:i*8+8], mapped)
   236  			}
   237  		}
   238  		blocks[blocknum].Data = block
   239  		blocks[blocknum].Pos = blockPos
   240  	}
   241  	return blocks, nil
   242  }
   243  
   244  // ReadChunk reads a chunk of data as part of a mapped operation.
   245  // Only some multiple of the # of CPU cores can be used for chunk handling before
   246  // it waits for chunk processing to abate via the buffered server.HandlerToken channel.
   247  func (d *Data) ReadChunk(chunk *storage.Chunk) error {
   248  	server.CheckChunkThrottling()
   249  	go d.readChunk(chunk)
   250  	return nil
   251  }
   252  
   253  func (d *Data) readChunk(chunk *storage.Chunk) {
   254  	defer func() {
   255  		// After processing a chunk, return the token.
   256  		server.HandlerToken <- 1
   257  
   258  		// Notify the requestor that this chunk is done.
   259  		if chunk.Wg != nil {
   260  			chunk.Wg.Done()
   261  		}
   262  	}()
   263  
   264  	op, ok := chunk.Op.(*getOperation)
   265  	if !ok {
   266  		log.Fatalf("Illegal operation passed to readChunk() for data %s\n", d.DataName())
   267  	}
   268  
   269  	// Make sure our received chunk is valid.
   270  	if chunk == nil {
   271  		dvid.Errorf("Received nil chunk in readChunk.  Ignoring chunk.\n")
   272  		return
   273  	}
   274  	if chunk.K == nil {
   275  		dvid.Errorf("Received nil chunk key in readChunk.  Ignoring chunk.\n")
   276  		return
   277  	}
   278  
   279  	// If there's an ROI, if outside ROI, use blank buffer.
   280  	var zeroOut bool
   281  	indexZYX, err := DecodeTKey(chunk.K)
   282  	if err != nil {
   283  		dvid.Errorf("Error processing voxel block: %s\n", err)
   284  		return
   285  	}
   286  	if op.blocksInROI != nil {
   287  		indexString := string(indexZYX.Bytes())
   288  		_, insideROI := op.blocksInROI[indexString]
   289  		if !insideROI {
   290  			zeroOut = true
   291  		}
   292  	}
   293  
   294  	// Initialize the block buffer using the chunk of data.  For voxels, this chunk of
   295  	// data needs to be uncompressed and deserialized.
   296  	var blockData []byte
   297  	if zeroOut || chunk.V == nil {
   298  		blockData = d.BackgroundBlock()
   299  	} else {
   300  		blockData, _, err = dvid.DeserializeData(chunk.V, true)
   301  		if err != nil {
   302  			dvid.Errorf("Unable to deserialize block in '%s': %v\n", d.DataName(), err)
   303  			return
   304  		}
   305  	}
   306  
   307  	// Perform the operation.
   308  	block := &storage.TKeyValue{chunk.K, blockData}
   309  	if op.mapping != nil {
   310  		err := op.voxels.readMappedBlock(block, d.BlockSize(), op.mapping)
   311  		if err != nil {
   312  			dvid.Errorf("readMappedBlock, key %v in %q: %v\n", chunk.K, d.DataName(), err)
   313  		}
   314  	} else {
   315  		err := op.voxels.readBlock(block, d.BlockSize())
   316  		if err != nil {
   317  			dvid.Errorf("readBlock, key %v in %q: %v\n", chunk.K, d.DataName(), err)
   318  		}
   319  	}
   320  }
   321  
   322  func (v *Labels) readMappedBlock(block *storage.TKeyValue, blockSize dvid.Point, m *labels.Mapping) error {
   323  	if blockSize.NumDims() > 3 {
   324  		return fmt.Errorf("DVID voxel blocks currently only supports up to 3d, not 4+ dimensions")
   325  	}
   326  	blockBeg, dataBeg, dataEnd, err := v.ComputeTransform(block, blockSize)
   327  	if err != nil {
   328  		return err
   329  	}
   330  	data := v.Data()
   331  
   332  	// Compute the strides (in bytes)
   333  	bX := int64(blockSize.Value(0)) * 8
   334  	bY := int64(blockSize.Value(1)) * bX
   335  	dX := int64(v.Stride())
   336  
   337  	blockBegX := int64(blockBeg.Value(0))
   338  	blockBegY := int64(blockBeg.Value(1))
   339  	blockBegZ := int64(blockBeg.Value(2))
   340  
   341  	// Do the transfers depending on shape of the external voxels.
   342  	switch {
   343  	case v.DataShape().Equals(dvid.XY):
   344  		dataI := int64(dataBeg.Value(1))*dX + int64(dataBeg.Value(0))*8
   345  		blockI := blockBegZ*bY + blockBegY*bX + blockBegX*8
   346  		for y := int64(dataBeg.Value(1)); y <= int64(dataEnd.Value(1)); y++ {
   347  			bI := blockI
   348  			dI := dataI
   349  			for x := dataBeg.Value(0); x <= dataEnd.Value(0); x++ {
   350  				orig := binary.LittleEndian.Uint64(block.V[bI : bI+8])
   351  				mapped, found := m.FinalLabel(orig)
   352  				if found {
   353  					binary.LittleEndian.PutUint64(data[dI:dI+8], mapped)
   354  				} else {
   355  					copy(data[dI:dI+8], block.V[bI:bI+8])
   356  				}
   357  				bI += 8
   358  				dI += 8
   359  			}
   360  			blockI += bX
   361  			dataI += dX
   362  		}
   363  
   364  	case v.DataShape().Equals(dvid.XZ):
   365  		dataI := int64(dataBeg.Value(2))*dX + int64(dataBeg.Value(0))*8
   366  		blockI := blockBegZ*bY + blockBegY*bX + blockBegX*8
   367  		for y := int64(dataBeg.Value(2)); y <= int64(dataEnd.Value(2)); y++ {
   368  			bI := blockI
   369  			dI := dataI
   370  			for x := dataBeg.Value(0); x <= dataEnd.Value(0); x++ {
   371  				orig := binary.LittleEndian.Uint64(block.V[bI : bI+8])
   372  				mapped, found := m.FinalLabel(orig)
   373  				if found {
   374  					binary.LittleEndian.PutUint64(data[dI:dI+8], mapped)
   375  				} else {
   376  					copy(data[dI:dI+8], block.V[bI:bI+8])
   377  				}
   378  				bI += 8
   379  				dI += 8
   380  			}
   381  			blockI += bY
   382  			dataI += dX
   383  		}
   384  
   385  	case v.DataShape().Equals(dvid.YZ):
   386  		bz := blockBegZ
   387  		for y := int64(dataBeg.Value(2)); y <= int64(dataEnd.Value(2)); y++ {
   388  			dataI := y*dX + int64(dataBeg.Value(1))*8
   389  			blockI := bz*bY + blockBegY*bX + blockBegX*8
   390  			for x := dataBeg.Value(1); x <= dataEnd.Value(1); x++ {
   391  				orig := binary.LittleEndian.Uint64(block.V[blockI : blockI+8])
   392  				mapped, found := m.FinalLabel(orig)
   393  				if found {
   394  					binary.LittleEndian.PutUint64(data[dataI:dataI+8], mapped)
   395  				} else {
   396  					copy(data[dataI:dataI+8], block.V[blockI:blockI+8])
   397  				}
   398  				blockI += bX
   399  				dataI += 8
   400  			}
   401  			bz++
   402  		}
   403  
   404  	case v.DataShape().ShapeDimensions() == 2:
   405  		// TODO: General code for handling 2d ExtData in n-d space.
   406  		return fmt.Errorf("DVID currently does not support 2d in n-d space.")
   407  
   408  	case v.DataShape().Equals(dvid.Vol3d):
   409  		blockOffset := blockBegX * 8
   410  		dX := int64(v.Size().Value(0)) * 8
   411  		dY := int64(v.Size().Value(1)) * dX
   412  		dataOffset := int64(dataBeg.Value(0)) * 8
   413  		blockZ := blockBegZ
   414  
   415  		for dataZ := int64(dataBeg.Value(2)); dataZ <= int64(dataEnd.Value(2)); dataZ++ {
   416  			blockY := blockBegY
   417  			for dataY := int64(dataBeg.Value(1)); dataY <= int64(dataEnd.Value(1)); dataY++ {
   418  				bI := blockZ*bY + blockY*bX + blockOffset
   419  				dI := dataZ*dY + dataY*dX + dataOffset
   420  				for x := dataBeg.Value(0); x <= dataEnd.Value(0); x++ {
   421  					orig := binary.LittleEndian.Uint64(block.V[bI : bI+8])
   422  					mapped, found := m.FinalLabel(orig)
   423  					if found {
   424  						binary.LittleEndian.PutUint64(data[dI:dI+8], mapped)
   425  					} else {
   426  						copy(data[dI:dI+8], block.V[bI:bI+8])
   427  					}
   428  					bI += 8
   429  					dI += 8
   430  				}
   431  				blockY++
   432  			}
   433  			blockZ++
   434  		}
   435  
   436  	default:
   437  		return fmt.Errorf("Cannot readBlock() unsupported voxels data shape %s", v.DataShape())
   438  	}
   439  	return nil
   440  }
   441  
   442  func (v *Labels) readBlock(block *storage.TKeyValue, blockSize dvid.Point) error {
   443  	if blockSize.NumDims() > 3 {
   444  		return fmt.Errorf("DVID voxel blocks currently only supports up to 3d, not 4+ dimensions")
   445  	}
   446  	blockBeg, dataBeg, dataEnd, err := v.ComputeTransform(block, blockSize)
   447  	if err != nil {
   448  		return err
   449  	}
   450  	data := v.Data()
   451  
   452  	// Compute the strides (in bytes)
   453  	bX := int64(blockSize.Value(0)) * 8
   454  	bY := int64(blockSize.Value(1)) * bX
   455  	dX := int64(v.Stride())
   456  
   457  	blockBegX := int64(blockBeg.Value(0))
   458  	blockBegY := int64(blockBeg.Value(1))
   459  	blockBegZ := int64(blockBeg.Value(2))
   460  
   461  	// Do the transfers depending on shape of the external voxels.
   462  	switch {
   463  	case v.DataShape().Equals(dvid.XY):
   464  		dataI := int64(dataBeg.Value(1))*dX + int64(dataBeg.Value(0))*8
   465  		blockI := blockBegZ*bY + blockBegY*bX + blockBegX*8
   466  		bytes := int64(dataEnd.Value(0)-dataBeg.Value(0)+1) * 8
   467  		for y := dataBeg.Value(1); y <= dataEnd.Value(1); y++ {
   468  			copy(data[dataI:dataI+bytes], block.V[blockI:blockI+bytes])
   469  			blockI += bX
   470  			dataI += dX
   471  		}
   472  
   473  	case v.DataShape().Equals(dvid.XZ):
   474  		dataI := int64(dataBeg.Value(2))*dX + int64(dataBeg.Value(0))*8
   475  		blockI := blockBegZ*bY + blockBegY*bX + blockBegX*8
   476  		bytes := int64(dataEnd.Value(0)-dataBeg.Value(0)+1) * 8
   477  		for y := dataBeg.Value(2); y <= dataEnd.Value(2); y++ {
   478  			copy(data[dataI:dataI+bytes], block.V[blockI:blockI+bytes])
   479  			blockI += bY
   480  			dataI += dX
   481  		}
   482  
   483  	case v.DataShape().Equals(dvid.YZ):
   484  		bz := blockBegZ
   485  		for y := int64(dataBeg.Value(2)); y <= int64(dataEnd.Value(2)); y++ {
   486  			dataI := y*dX + int64(dataBeg.Value(1))*8
   487  			blockI := bz*bY + blockBegY*bX + blockBegX*8
   488  			for x := dataBeg.Value(1); x <= dataEnd.Value(1); x++ {
   489  				copy(data[dataI:dataI+8], block.V[blockI:blockI+8])
   490  				blockI += bX
   491  				dataI += 8
   492  			}
   493  			bz++
   494  		}
   495  
   496  	case v.DataShape().ShapeDimensions() == 2:
   497  		// TODO: General code for handling 2d ExtData in n-d space.
   498  		return fmt.Errorf("DVID currently does not support 2d in n-d space.")
   499  
   500  	case v.DataShape().Equals(dvid.Vol3d):
   501  		blockOffset := blockBegX * 8
   502  		dX := int64(v.Size().Value(0)) * 8
   503  		dY := int64(v.Size().Value(1)) * dX
   504  		dataOffset := int64(dataBeg.Value(0)) * 8
   505  		bytes := int64(dataEnd.Value(0)-dataBeg.Value(0)+1) * 8
   506  		blockZ := blockBegZ
   507  
   508  		for dataZ := int64(dataBeg.Value(2)); dataZ <= int64(dataEnd.Value(2)); dataZ++ {
   509  			blockY := blockBegY
   510  			for dataY := int64(dataBeg.Value(1)); dataY <= int64(dataEnd.Value(1)); dataY++ {
   511  				blockI := blockZ*bY + blockY*bX + blockOffset
   512  				dataI := dataZ*dY + dataY*dX + dataOffset
   513  				copy(data[dataI:dataI+bytes], block.V[blockI:blockI+bytes])
   514  				blockY++
   515  			}
   516  			blockZ++
   517  		}
   518  
   519  	default:
   520  		return fmt.Errorf("Cannot readBlock() unsupported voxels data shape %s", v.DataShape())
   521  	}
   522  	return nil
   523  }