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 }