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 }