github.com/janelia-flyem/dvid@v1.0.0/datatype/labelarray/downres.go (about) 1 package labelarray 2 3 import ( 4 "fmt" 5 6 "github.com/janelia-flyem/dvid/datastore" 7 "github.com/janelia-flyem/dvid/datatype/common/downres" 8 "github.com/janelia-flyem/dvid/datatype/common/labels" 9 "github.com/janelia-flyem/dvid/dvid" 10 ) 11 12 // For any lores block, divide it into octants and see if we have mutated the corresponding higher-res blocks. 13 type octantMap map[dvid.IZYXString][8]*labels.Block 14 15 // Group hires blocks by octants so we see when we actually need to GET a lower-res block. 16 func (d *Data) getHiresChanges(hires downres.BlockMap) (octantMap, error) { 17 octants := make(octantMap) 18 19 for hiresZYX, value := range hires { 20 block, ok := value.(*labels.Block) 21 if !ok { 22 return nil, fmt.Errorf("bad changing block %s: expected *labels.Block got %v", hiresZYX, value) 23 } 24 hresCoord, err := hiresZYX.ToChunkPoint3d() 25 if err != nil { 26 return nil, err 27 } 28 downresX := hresCoord[0] >> 1 29 downresY := hresCoord[1] >> 1 30 downresZ := hresCoord[2] >> 1 31 loresZYX := dvid.ChunkPoint3d{downresX, downresY, downresZ}.ToIZYXString() 32 octidx := ((hresCoord[2] % 2) << 2) + ((hresCoord[1] % 2) << 1) + (hresCoord[0] % 2) 33 oct, found := octants[loresZYX] 34 if !found { 35 oct = [8]*labels.Block{} 36 } 37 oct[octidx] = block 38 octants[loresZYX] = oct 39 } 40 41 return octants, nil 42 } 43 44 func (d *Data) StoreDownres(v dvid.VersionID, hiresScale uint8, hires downres.BlockMap) (downres.BlockMap, error) { 45 if hiresScale >= d.MaxDownresLevel { 46 return nil, fmt.Errorf("can't downres %q scale %d since max downres scale is %d", d.DataName(), hiresScale, d.MaxDownresLevel) 47 } 48 octants, err := d.getHiresChanges(hires) 49 if err != nil { 50 return nil, err 51 } 52 blockSize, ok := d.BlockSize().(dvid.Point3d) 53 if !ok { 54 return nil, fmt.Errorf("block size for data %q is not 3d: %v\n", d.DataName(), d.BlockSize()) 55 } 56 57 batcher, err := datastore.GetKeyValueBatcher(d) 58 if err != nil { 59 return nil, err 60 } 61 ctx := datastore.NewVersionedCtx(d, v) 62 batch := batcher.NewBatch(ctx) 63 64 downresBMap := make(downres.BlockMap) 65 for loresZYX, octant := range octants { 66 var numBlocks int 67 for _, block := range octant { 68 if block != nil { 69 numBlocks++ 70 } 71 } 72 73 var loresBlock *labels.Block 74 if numBlocks < 8 { 75 chunkPt, err := loresZYX.ToChunkPoint3d() 76 if err != nil { 77 return nil, err 78 } 79 loresBlock, err = d.GetLabelBlock(v, chunkPt, hiresScale+1) 80 if err != nil { 81 return nil, err 82 } 83 } else { 84 loresBlock = labels.MakeSolidBlock(0, blockSize) 85 } 86 if err := loresBlock.Downres(octant); err != nil { 87 return nil, err 88 } 89 downresBMap[loresZYX] = loresBlock 90 91 compressed, _ := loresBlock.MarshalBinary() 92 serialization, err := dvid.SerializeData(compressed, d.Compression(), d.Checksum()) 93 if err != nil { 94 return nil, fmt.Errorf("Unable to serialize downres block in %q: %v\n", d.DataName(), err) 95 } 96 tk := NewBlockTKeyByCoord(hiresScale+1, loresZYX) 97 batch.Put(tk, serialization) 98 } 99 if err := batch.Commit(); err != nil { 100 return nil, fmt.Errorf("Error on trying to write downres batch of scale %d->%d: %v\n", hiresScale, hiresScale+1, err) 101 } 102 return downresBMap, nil 103 }