Browse Source

clear hash tables when put back into the pool (related to #65).
let Compress* and UncompreBlock functions handle hash/chain tables pooling

Pierre.Curto 5 years ago
parent
commit
713b98a3ae
6 changed files with 29 additions and 24 deletions
  1. 1 1
      bench_test.go
  2. 19 6
      internal/lz4block/block.go
  3. 2 2
      internal/lz4block/block_test.go
  4. 3 3
      internal/lz4stream/frame.go
  5. 2 2
      lz4.go
  6. 2 10
      writer.go

+ 1 - 1
bench_test.go

@@ -40,7 +40,7 @@ func BenchmarkCompressHC(b *testing.B) {
 	b.ResetTimer()
 
 	for i := 0; i < b.N; i++ {
-		_, _ = lz4block.CompressBlockHC(pg1661, buf, 16)
+		_, _ = lz4block.CompressBlockHC(pg1661, buf, 16, nil, nil)
 	}
 }
 

+ 19 - 6
internal/lz4block/block.go

@@ -74,7 +74,7 @@ func CompressBlock(src, dst []byte, hashTable []int) (_ int, err error) {
 	}
 
 	if cap(hashTable) < htSize {
-		hashTable = HashTablePool.Get().([]int)
+		hashTable = HashTablePool.Get()
 		defer HashTablePool.Put(hashTable)
 	} else {
 		hashTable = hashTable[:htSize]
@@ -239,7 +239,7 @@ func blockHashHC(x uint32) uint32 {
 	return x * hasher >> (32 - winSizeLog)
 }
 
-func CompressBlockHC(src, dst []byte, depth CompressionLevel) (_ int, err error) {
+func CompressBlockHC(src, dst []byte, depth CompressionLevel, hashTable, chainTable []int) (_ int, err error) {
 	defer recoverBlock(&err)
 
 	// Return 0, nil only if the destination buffer size is < CompressBlockBound.
@@ -251,15 +251,28 @@ func CompressBlockHC(src, dst []byte, depth CompressionLevel) (_ int, err error)
 	const adaptSkipLog = 7
 
 	var si, di, anchor int
-	// hashTable: stores the last position found for a given hash
-	// chainTable: stores previous positions for a given hash
-	var hashTable, chainTable [winSize]int
-
 	sn := len(src) - mfLimit
 	if sn <= 0 {
 		goto lastLiterals
 	}
 
+	// hashTable: stores the last position found for a given hash
+	// chainTable: stores previous positions for a given hash
+	if cap(hashTable) < htSize {
+		hashTable = HashTablePool.Get()
+		defer HashTablePool.Put(hashTable)
+	} else {
+		hashTable = hashTable[:htSize]
+	}
+	_ = hashTable[htSize-1]
+	if cap(chainTable) < htSize {
+		chainTable = HashTablePool.Get()
+		defer HashTablePool.Put(chainTable)
+	} else {
+		chainTable = chainTable[:htSize]
+	}
+	_ = chainTable[htSize-1]
+
 	if depth <= 0 {
 		depth = winSize
 	}

+ 2 - 2
internal/lz4block/block_test.go

@@ -103,7 +103,7 @@ func TestCompressUncompressBlock(t *testing.T) {
 			})
 			t.Run(fmt.Sprintf("%s HC", tc.file), func(t *testing.T) {
 				nhc = run(t, tc, func(src, dst []byte) (int, error) {
-					return lz4.CompressBlockHC(src, dst, 10)
+					return lz4.CompressBlockHC(src, dst, 10, nil, nil)
 				})
 			})
 		})
@@ -144,7 +144,7 @@ func TestCompressCornerCase_CopyDstUpperBound(t *testing.T) {
 	t.Run(fmt.Sprintf("%s HC", file), func(t *testing.T) {
 		t.Parallel()
 		run(src, func(src, dst []byte) (int, error) {
-			return lz4block.CompressBlockHC(src, dst, 16)
+			return lz4block.CompressBlockHC(src, dst, 16, nil, nil)
 		})
 	})
 }

+ 3 - 3
internal/lz4stream/frame.go

@@ -251,14 +251,14 @@ func (b *FrameDataBlock) CloseW(f *Frame) {
 }
 
 // Block compression errors are ignored since the buffer is sized appropriately.
-func (b *FrameDataBlock) Compress(f *Frame, src []byte, ht []int, level lz4block.CompressionLevel) *FrameDataBlock {
+func (b *FrameDataBlock) Compress(f *Frame, src []byte, level lz4block.CompressionLevel) *FrameDataBlock {
 	data := b.data[:len(src)] // trigger the incompressible flag in CompressBlock
 	var n int
 	switch level {
 	case lz4block.Fast:
-		n, _ = lz4block.CompressBlock(src, data, ht)
+		n, _ = lz4block.CompressBlock(src, data, nil)
 	default:
-		n, _ = lz4block.CompressBlockHC(src, data, level)
+		n, _ = lz4block.CompressBlockHC(src, data, level, nil, nil)
 	}
 	if n == 0 {
 		b.Size.UncompressedSet(true)

+ 2 - 2
lz4.go

@@ -68,8 +68,8 @@ func CompressBlock(src, dst []byte, hashTable []int) (int, error) {
 // the compressed size is 0 and no error, then the data is incompressible.
 //
 // An error is returned if the destination buffer is too small.
-func CompressBlockHC(src, dst []byte, depth CompressionLevel) (int, error) {
-	return lz4block.CompressBlockHC(src, dst, lz4block.CompressionLevel(depth))
+func CompressBlockHC(src, dst []byte, depth CompressionLevel, hashTable, chainTable []int) (int, error) {
+	return lz4block.CompressBlockHC(src, dst, lz4block.CompressionLevel(depth), hashTable, chainTable)
 }
 
 const (

+ 2 - 10
writer.go

@@ -32,7 +32,6 @@ type Writer struct {
 	level   lz4block.CompressionLevel // how hard to try
 	num     int                       // concurrency level
 	frame   *lz4stream.Frame          // frame being built
-	ht      []int                     // hash table (set if no concurrency)
 	data    []byte                    // pending data
 	idx     int                       // size of pending data
 	handler func(int)
@@ -68,9 +67,6 @@ func (w *Writer) init() error {
 	size := w.frame.Descriptor.Flags.BlockSizeIndex()
 	w.data = size.Get()
 	w.idx = 0
-	if w.isNotConcurrent() {
-		w.ht = lz4block.HashTablePool.Get().([]int)
-	}
 	return w.frame.Descriptor.Write(w.frame, w.src)
 }
 
@@ -126,7 +122,7 @@ func (w *Writer) Write(buf []byte) (n int, err error) {
 func (w *Writer) write(data []byte, safe bool) error {
 	if w.isNotConcurrent() {
 		block := w.frame.Blocks.Block
-		err := block.Compress(w.frame, data, w.ht, w.level).Write(w.frame, w.src)
+		err := block.Compress(w.frame, data, w.level).Write(w.frame, w.src)
 		w.handler(len(block.Data))
 		return err
 	}
@@ -135,7 +131,7 @@ func (w *Writer) write(data []byte, safe bool) error {
 	w.frame.Blocks.Blocks <- c
 	go func(c chan *lz4stream.FrameDataBlock, data []byte, size lz4block.BlockSizeIndex, safe bool) {
 		b := lz4stream.NewFrameDataBlock(size)
-		c <- b.Compress(w.frame, data, nil, w.level)
+		c <- b.Compress(w.frame, data, w.level)
 		<-c
 		w.handler(len(b.Data))
 		b.CloseW(w.frame)
@@ -167,10 +163,6 @@ func (w *Writer) Close() (err error) {
 		w.idx = 0
 	}
 	err = w.frame.CloseW(w.src, w.num)
-	if w.isNotConcurrent() {
-		lz4block.HashTablePool.Put(w.ht)
-		w.ht = nil
-	}
 	// It is now safe to free the buffer.
 	if w.data != nil {
 		size := w.frame.Descriptor.Flags.BlockSizeIndex()