From 335bd0ac0a7d6d188fbe1dedc23258686d6d6ef8 Mon Sep 17 00:00:00 2001
From: Aliaksandr Valialkin <valyala@gmail.com>
Date: Mon, 23 Dec 2019 18:04:57 +0200
Subject: [PATCH] lib/encoding/zstd: prevent from possible encoder leak when
 concurrent goroutines create encoders for the same compressionLevel

Thanks to @klauspost for the pointer to this issue. See https://github.com/klauspost/compress/issues/195 for details.
---
 lib/encoding/zstd/zstd_pure.go | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/lib/encoding/zstd/zstd_pure.go b/lib/encoding/zstd/zstd_pure.go
index 2ae2d66ced..ba7662f8da 100644
--- a/lib/encoding/zstd/zstd_pure.go
+++ b/lib/encoding/zstd/zstd_pure.go
@@ -53,14 +53,16 @@ func getEncoder(compressionLevel int) *zstd.Encoder {
 	mu.Lock()
 	// Create the encoder under lock in order to prevent from wasted work
 	// when concurrent goroutines create encoder for the same compressionLevel.
-	e = newEncoder(compressionLevel)
 	r1 := av.Load().(registry)
-	r2 := make(registry)
-	for k, v := range r1 {
-		r2[k] = v
+	if e = r1[compressionLevel]; e == nil {
+		e = newEncoder(compressionLevel)
+		r2 := make(registry)
+		for k, v := range r1 {
+			r2[k] = v
+		}
+		r2[compressionLevel] = e
+		av.Store(r2)
 	}
-	r2[compressionLevel] = e
-	av.Store(r2)
 	mu.Unlock()
 
 	return e