Skip to content

Commit e6dfca8

Browse files
committed
Initial commit for change supporting streaming dictionary compression
1 parent d682a90 commit e6dfca8

File tree

4 files changed

+97
-6
lines changed

4 files changed

+97
-6
lines changed

ext/zstdruby/streaming_compress.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,11 @@ rb_streaming_compress_initialize(int argc, VALUE *argv, VALUE obj)
5858
rb_scan_args(argc, argv, "01:", &compression_level_value, &kwargs);
5959
int compression_level = convert_compression_level(compression_level_value);
6060

61-
ID kwargs_keys[1];
61+
ID kwargs_keys[2];
6262
kwargs_keys[0] = rb_intern("no_gvl");
63-
VALUE kwargs_values[1];
64-
rb_get_kwargs(kwargs, kwargs_keys, 0, 1, kwargs_values);
63+
kwargs_keys[1] = rb_intern("dict");
64+
VALUE kwargs_values[2];
65+
rb_get_kwargs(kwargs, kwargs_keys, 0, 2, kwargs_values);
6566

6667
struct streaming_compress_t* sc;
6768
TypedData_Get_Struct(obj, struct streaming_compress_t, &streaming_compress_type, sc);
@@ -72,6 +73,14 @@ rb_streaming_compress_initialize(int argc, VALUE *argv, VALUE obj)
7273
if (ctx == NULL) {
7374
rb_raise(rb_eRuntimeError, "%s", "ZSTD_createCCtx error");
7475
}
76+
if (kwargs_values[1] != Qundef && kwargs_values[1] != Qnil) {
77+
char* dict_buffer = RSTRING_PTR(kwargs_values[1]);
78+
size_t dict_size = RSTRING_LEN(kwargs_values[1]);
79+
size_t load_dict_ret = ZSTD_CCtx_loadDictionary(ctx, dict_buffer, dict_size);
80+
if (ZSTD_isError(load_dict_ret)) {
81+
rb_raise(rb_eRuntimeError, "%s", "ZSTD_CCtx_loadDictionary failed");
82+
}
83+
}
7584
ZSTD_CCtx_setParameter(ctx, ZSTD_c_compressionLevel, compression_level);
7685
sc->ctx = ctx;
7786
sc->buf = rb_str_new(NULL, buffOutSize);

ext/zstdruby/streaming_decompress.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,11 @@ rb_streaming_decompress_initialize(int argc, VALUE *argv, VALUE obj)
5555
VALUE kwargs;
5656
rb_scan_args(argc, argv, "00:", &kwargs);
5757

58-
ID kwargs_keys[1];
58+
ID kwargs_keys[2];
5959
kwargs_keys[0] = rb_intern("no_gvl");
60-
VALUE kwargs_values[1];
61-
rb_get_kwargs(kwargs, kwargs_keys, 0, 1, kwargs_values);
60+
kwargs_keys[1] = rb_intern("dict");
61+
VALUE kwargs_values[2];
62+
rb_get_kwargs(kwargs, kwargs_keys, 0, 2, kwargs_values);
6263

6364
struct streaming_decompress_t* sd;
6465
TypedData_Get_Struct(obj, struct streaming_decompress_t, &streaming_decompress_type, sd);
@@ -69,6 +70,14 @@ rb_streaming_decompress_initialize(int argc, VALUE *argv, VALUE obj)
6970
if (ctx == NULL) {
7071
rb_raise(rb_eRuntimeError, "%s", "ZSTD_createDCtx error");
7172
}
73+
if (kwargs_values[1] != Qundef && kwargs_values[1] != Qnil) {
74+
char* dict_buffer = RSTRING_PTR(kwargs_values[1]);
75+
size_t dict_size = RSTRING_LEN(kwargs_values[1]);
76+
size_t load_dict_ret = ZSTD_DCtx_loadDictionary(ctx, dict_buffer, dict_size);
77+
if (ZSTD_isError(load_dict_ret)) {
78+
rb_raise(rb_eRuntimeError, "%s", "ZSTD_DCtx_loadDictionary failed");
79+
}
80+
}
7281
sd->ctx = ctx;
7382
sd->buf = rb_str_new(NULL, buffOutSize);
7483
sd->buf_size = buffOutSize;

spec/zstd-ruby-streaming-compress_spec.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,41 @@
5353
end
5454
end
5555

56+
describe 'dictionary' do
57+
let(:dictionary) do
58+
IO.read("#{__dir__}/dictionary")
59+
end
60+
let(:user_json) do
61+
IO.read("#{__dir__}/user_springmt.json")
62+
end
63+
it 'shoud work' do
64+
dict_stream = Zstd::StreamingCompress.new(5, dict: dictionary, no_gvl: no_gvl)
65+
dict_stream << user_json
66+
dict_res = dict_stream.finish
67+
stream = Zstd::StreamingCompress.new(5, no_gvl: no_gvl)
68+
stream << user_json
69+
res = stream.finish
70+
71+
expect(dict_res.length).to be < res.length
72+
end
73+
end
74+
75+
describe 'nil dictionary' do
76+
let(:user_json) do
77+
IO.read("#{__dir__}/user_springmt.json")
78+
end
79+
it 'shoud work' do
80+
dict_stream = Zstd::StreamingCompress.new(5, dict: nil, no_gvl: no_gvl)
81+
dict_stream << user_json
82+
dict_res = dict_stream.finish
83+
stream = Zstd::StreamingCompress.new(5, no_gvl: no_gvl)
84+
stream << user_json
85+
res = stream.finish
86+
87+
expect(dict_res.length).to eq(res.length)
88+
end
89+
end
90+
5691
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.0.0')
5792
describe 'Ractor' do
5893
it 'should be supported' do

spec/zstd-ruby-streaming-decompress_spec.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,44 @@
3232
end
3333
end
3434

35+
describe 'dictionary streaming decompress + GC.compact' do
36+
let(:dictionary) do
37+
IO.read("#{__dir__}/dictionary")
38+
end
39+
let(:user_json) do
40+
IO.read("#{__dir__}/user_springmt.json")
41+
end
42+
it 'shoud work' do
43+
compressed_json = Zstd.compress_using_dict(user_json, dictionary)
44+
stream = Zstd::StreamingDecompress.new(dict: dictionary, no_gvl: no_gvl)
45+
result = ''
46+
result << stream.decompress(compressed_json[0, 5])
47+
result << stream.decompress(compressed_json[5, 5])
48+
GC.compact
49+
result << stream.decompress(compressed_json[10..-1])
50+
expect(result).to eq(user_json)
51+
end
52+
end
53+
54+
describe 'nil dictionary streaming decompress + GC.compact' do
55+
let(:dictionary) do
56+
IO.read("#{__dir__}/dictionary")
57+
end
58+
let(:user_json) do
59+
IO.read("#{__dir__}/user_springmt.json")
60+
end
61+
it 'shoud work' do
62+
compressed_json = Zstd.compress(user_json)
63+
stream = Zstd::StreamingDecompress.new(dict: nil, no_gvl: no_gvl)
64+
result = ''
65+
result << stream.decompress(compressed_json[0, 5])
66+
result << stream.decompress(compressed_json[5, 5])
67+
GC.compact
68+
result << stream.decompress(compressed_json[10..-1])
69+
expect(result).to eq(user_json)
70+
end
71+
end
72+
3573
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.0.0')
3674
describe 'Ractor' do
3775
it 'should be supported' do

0 commit comments

Comments
 (0)