Skip to content

Commit 28848d0

Browse files
authored
fix: avoid on stack allocation of lz4 compression context (#4322)
Fixes #4245 Signed-off-by: Roman Gershman <roman@dragonflydb.io>
1 parent 1fa9a47 commit 28848d0

File tree

4 files changed

+43
-10
lines changed

4 files changed

+43
-10
lines changed

src/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ add_third_party(
8484

8585
add_third_party(
8686
lz4
87-
URL https://github.com/lz4/lz4/archive/refs/tags/v1.9.4.tar.gz
87+
URL https://github.com/lz4/lz4/archive/refs/tags/v1.10.0.tar.gz
8888

8989
BUILD_IN_SOURCE 1
9090
CONFIGURE_COMMAND echo skip

src/server/detail/compressor.cc

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,32 +52,47 @@ io::Result<io::Bytes> ZstdCompressor::Compress(io::Bytes data) {
5252
class Lz4Compressor : public CompressorImpl {
5353
public:
5454
Lz4Compressor() {
55-
lz4_pref_.compressionLevel = compression_level_;
55+
LZ4F_errorCode_t code = LZ4F_createCompressionContext(&cctx_, LZ4F_VERSION);
56+
CHECK(!LZ4F_isError(code));
5657
}
5758

5859
~Lz4Compressor() {
60+
LZ4F_errorCode_t code = LZ4F_freeCompressionContext(cctx_);
61+
CHECK(!LZ4F_isError(code));
5962
}
6063

6164
// compress a string of data
6265
io::Result<io::Bytes> Compress(io::Bytes data);
6366

6467
private:
65-
LZ4F_preferences_t lz4_pref_ = LZ4F_INIT_PREFERENCES;
68+
LZ4F_cctx* cctx_;
6669
};
6770

6871
io::Result<io::Bytes> Lz4Compressor::Compress(io::Bytes data) {
69-
lz4_pref_.frameInfo.contentSize = data.size();
70-
size_t buf_size = LZ4F_compressFrameBound(data.size(), &lz4_pref_);
72+
LZ4F_preferences_t lz4_pref = LZ4F_INIT_PREFERENCES;
73+
lz4_pref.compressionLevel = compression_level_;
74+
lz4_pref.frameInfo.contentSize = data.size();
75+
76+
size_t buf_size = LZ4F_compressFrameBound(data.size(), &lz4_pref);
7177
if (compr_buf_.capacity() < buf_size) {
7278
compr_buf_.reserve(buf_size);
7379
}
7480

81+
// TODO: to remove LZ4F_compressFrame code once we confirm this code actually works.
82+
#if 1
83+
size_t frame_size =
84+
LZ4F_compressFrame_usingCDict(cctx_, compr_buf_.data(), compr_buf_.capacity(), data.data(),
85+
data.size(), nullptr /* dict */, &lz4_pref);
86+
#else
7587
size_t frame_size = LZ4F_compressFrame(compr_buf_.data(), compr_buf_.capacity(), data.data(),
76-
data.size(), &lz4_pref_);
88+
data.size(), &lz4_pref);
89+
#endif
90+
7791
if (LZ4F_isError(frame_size)) {
7892
LOG(ERROR) << "LZ4F_compressFrame failed with error " << LZ4F_getErrorName(frame_size);
7993
return nonstd::make_unexpected(make_error_code(errc::operation_not_supported));
8094
}
95+
8196
compressed_size_total_ += frame_size;
8297
uncompressed_size_total_ += data.size();
8398
return io::Bytes(compr_buf_.data(), frame_size);

src/server/rdb_save.cc

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,13 +1604,20 @@ void SerializerBase::CompressBlob() {
16041604
}
16051605

16061606
AllocateCompressorOnce();
1607-
// Compress the data
1608-
auto ec = compressor_impl_->Compress(blob_to_compress);
1609-
if (!ec) {
1607+
1608+
// Compress the data. We copy compressed data once into the internal buffer of compressor_impl_
1609+
// and then we copy it again into the mem_buf_.
1610+
//
1611+
// TODO: it is possible to avoid double copying here by changing the compressor interface,
1612+
// so that the compressor will accept the output buffer and return the final size. This requires
1613+
// exposing the additional compress bound interface as well.
1614+
io::Result<io::Bytes> res = compressor_impl_->Compress(blob_to_compress);
1615+
if (!res) {
16101616
++compression_stats_->compression_failed;
16111617
return;
16121618
}
1613-
Bytes compressed_blob = *ec;
1619+
1620+
Bytes compressed_blob = *res;
16141621
if (compressed_blob.length() > blob_size * kMinCompressionReductionPrecentage) {
16151622
++compression_stats_->compression_no_effective;
16161623
return;

src/server/rdb_test.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ class RdbTest : public BaseFamilyTest {
4242
protected:
4343
void SetUp();
4444

45+
static void SetUpTestSuite() {
46+
static bool init = true;
47+
if (exchange(init, false)) {
48+
fb2::SetDefaultStackResource(&fb2::std_malloc_resource, 32_KB);
49+
}
50+
BaseFamilyTest::SetUpTestSuite();
51+
}
52+
4553
io::FileSource GetSource(string name);
4654

4755
std::error_code LoadRdb(const string& filename) {
@@ -56,6 +64,7 @@ class RdbTest : public BaseFamilyTest {
5664

5765
void RdbTest::SetUp() {
5866
InitWithDbFilename();
67+
CHECK_EQ(zmalloc_used_memory_tl, 0);
5968
max_memory_limit = 40000000;
6069
}
6170

@@ -457,6 +466,8 @@ TEST_F(RdbTest, JsonTest) {
457466
class HllRdbTest : public RdbTest, public testing::WithParamInterface<string> {};
458467

459468
TEST_P(HllRdbTest, Hll) {
469+
LOG(INFO) << " max memory: " << max_memory_limit
470+
<< " used_mem_current: " << used_mem_current.load();
460471
auto ec = LoadRdb("hll.rdb");
461472

462473
ASSERT_FALSE(ec) << ec.message();

0 commit comments

Comments
 (0)