@@ -169,15 +169,44 @@ func (t *Table) DecrRef() error {
169169 return nil
170170}
171171
172+ // BlockEvictHandler is used to reuse the byte slice stored in the block on cache eviction.
173+ func BlockEvictHandler (value interface {}) {
174+ if b , ok := value .(* block ); ok {
175+ b .decrRef ()
176+ }
177+ }
178+
172179type block struct {
173180 offset int
174181 data []byte
175182 checksum []byte
176- entriesIndexStart int // start index of entryOffsets list
177- entryOffsets []uint32
178- chkLen int // checksum length
183+ entriesIndexStart int // start index of entryOffsets list
184+ entryOffsets []uint32 // used to binary search an entry in the block.
185+ chkLen int // checksum length.
186+ isReusable bool // used to determine if the blocked should be reused.
187+ ref int32
179188}
180189
190+ func (b * block ) incrRef () {
191+ atomic .AddInt32 (& b .ref , 1 )
192+ }
193+ func (b * block ) decrRef () {
194+ if b == nil {
195+ return
196+ }
197+
198+ p := atomic .AddInt32 (& b .ref , - 1 )
199+ // Insert the []byte into pool only if the block is resuable. When a block
200+ // is reusable a new []byte is used for decompression and this []byte can
201+ // be reused.
202+ // In case of an uncompressed block, the []byte is a reference to the
203+ // table.mmap []byte slice. Any attempt to write data to the mmap []byte
204+ // will lead to SEGFAULT.
205+ if p == 0 && b .isReusable {
206+ blockPool .Put (& b .data )
207+ }
208+ y .AssertTrue (p >= 0 )
209+ }
181210func (b * block ) size () int64 {
182211 return int64 (3 * intSize /* Size of the offset, entriesIndexStart and chkLen */ +
183212 cap (b .data ) + cap (b .checksum ) + cap (b .entryOffsets )* 4 )
@@ -419,8 +448,7 @@ func (t *Table) block(idx int) (*block, error) {
419448 }
420449 }
421450
422- blk .data , err = t .decompressData (blk .data )
423- if err != nil {
451+ if err = t .decompress (blk ); err != nil {
424452 return nil , errors .Wrapf (err ,
425453 "failed to decode compressed data in file: %s at offset: %d, len: %d" ,
426454 t .fd .Name (), blk .offset , ko .Len )
@@ -462,6 +490,7 @@ func (t *Table) block(idx int) (*block, error) {
462490 }
463491 if t .opt .Cache != nil {
464492 key := t .blockCacheKey (idx )
493+ blk .incrRef ()
465494 t .opt .Cache .Set (key , blk , blk .size ())
466495 }
467496 return blk , nil
@@ -563,7 +592,8 @@ func (t *Table) VerifyChecksum() error {
563592 return y .Wrapf (err , "checksum validation failed for table: %s, block: %d, offset:%d" ,
564593 t .Filename (), i , os .Offset )
565594 }
566-
595+ b .incrRef ()
596+ defer b .decrRef ()
567597 // OnBlockRead or OnTableAndBlockRead, we don't need to call verify checksum
568598 // on block, verification would be done while reading block itself.
569599 if ! (t .opt .ChkMode == options .OnBlockRead || t .opt .ChkMode == options .OnTableAndBlockRead ) {
@@ -629,15 +659,28 @@ func NewFilename(id uint64, dir string) string {
629659 return filepath .Join (dir , IDToFilename (id ))
630660}
631661
632- // decompressData decompresses the given data.
633- func (t * Table ) decompressData (data []byte ) ([]byte , error ) {
662+ // decompress decompresses the data stored in a block.
663+ func (t * Table ) decompress (b * block ) error {
664+ var err error
634665 switch t .opt .Compression {
635666 case options .None :
636- return data , nil
667+ // Nothing to be done here.
637668 case options .Snappy :
638- return snappy .Decode (nil , data )
669+ dst := blockPool .Get ().(* []byte )
670+ b .data , err = snappy .Decode (* dst , b .data )
671+ if err != nil {
672+ return errors .Wrap (err , "failed to decompress" )
673+ }
674+ b .isReusable = true
639675 case options .ZSTD :
640- return y .ZSTDDecompress (nil , data )
676+ dst := blockPool .Get ().(* []byte )
677+ b .data , err = y .ZSTDDecompress (* dst , b .data )
678+ if err != nil {
679+ return errors .Wrap (err , "failed to decompress" )
680+ }
681+ b .isReusable = true
682+ default :
683+ return errors .New ("Unsupported compression type" )
641684 }
642- return nil , errors . New ( "Unsupported compression type" )
685+ return nil
643686}
0 commit comments