ruby-zstds 1.0.3 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e2279b518a90a526dd82247626f5969d01f6786de10b91802c5b6b7f3391ac26
4
- data.tar.gz: 854b6e8d08c7cc2fa464e3acc25cf45ea6ff204809b5b2cb08cea94217e34b1f
3
+ metadata.gz: 882ef3555df6569fdb51a8689d2e7b8e710255f98a08a631e023ae0160d3ad86
4
+ data.tar.gz: 233e455b9819cab316812fd7c977735972ad5ff2eeee1a816c329e7a5b7661f1
5
5
  SHA512:
6
- metadata.gz: 68781c24292733752c2e59022d71c31d15d73e73f7b5297374e720fc88e06100e1513772304b7591f16652bfef38b4991b9128949355fd0746bbae9d671eff67
7
- data.tar.gz: dab52302d4ce11b2392d7578fd824c4e4b725c3a7d7c853454d05b7291eeb7a93b024fce8c8d475ea965202bb7795db9a3d59764a5aea012fea49d712a59ae4e
6
+ metadata.gz: 69ce6c1b92687ca88e87619a3314acf3b8c0584c56a1694730e5e5bf7139d5db3c7c280f01df79e1fb010a3c61c0c46af76a82bb1f4815b481421fb7b885f3d4
7
+ data.tar.gz: b77df0f6f9b98523ca3e611bbab7d5655a94c7e637fc61511096da614cb95672fab113894de375f6f406015aebc6eded0d0dabb5025644891775bec8a04cadda
data/README.md CHANGED
@@ -1,14 +1,14 @@
1
1
  # Ruby bindings for zstd library
2
2
 
3
- | Travis | AppVeyor | Cirrus | Circle | Codecov |
4
- | :---: | :---: | :---: | :---: | :---: |
5
- | [![Travis test status](https://travis-ci.com/andrew-aladev/ruby-zstds.svg?branch=master)](https://travis-ci.com/andrew-aladev/ruby-zstds) | [![AppVeyor test status](https://ci.appveyor.com/api/projects/status/github/andrew-aladev/ruby-zstds?branch=master&svg=true)](https://ci.appveyor.com/project/andrew-aladev/ruby-zstds/branch/master) | [![Cirrus test status](https://api.cirrus-ci.com/github/andrew-aladev/ruby-zstds.svg?branch=master)](https://cirrus-ci.com/github/andrew-aladev/ruby-zstds) | [![Circle test status](https://circleci.com/gh/andrew-aladev/ruby-zstds/tree/master.svg?style=shield)](https://circleci.com/gh/andrew-aladev/ruby-zstds/tree/master) | [![Codecov](https://codecov.io/gh/andrew-aladev/ruby-zstds/branch/master/graph/badge.svg)](https://codecov.io/gh/andrew-aladev/ruby-zstds) |
3
+ | AppVeyor | Circle | Github actions | Codecov | Gem |
4
+ | :------: | :----: | :------------: | :-----: | :--: |
5
+ | [![AppVeyor test status](https://ci.appveyor.com/api/projects/status/github/andrew-aladev/ruby-zstds?branch=master&svg=true)](https://ci.appveyor.com/project/andrew-aladev/ruby-zstds/branch/master) | [![Circle test status](https://circleci.com/gh/andrew-aladev/ruby-zstds/tree/master.svg?style=shield)](https://circleci.com/gh/andrew-aladev/ruby-zstds/tree/master) | [![Github Actions test status](https://github.com/andrew-aladev/ruby-zstds/workflows/test/badge.svg?branch=master)](https://github.com/andrew-aladev/ruby-zstds/actions) | [![Codecov](https://codecov.io/gh/andrew-aladev/ruby-zstds/branch/master/graph/badge.svg)](https://codecov.io/gh/andrew-aladev/ruby-zstds) | [![Gem](https://img.shields.io/gem/v/ruby-zstds.svg)](https://rubygems.org/gems/ruby-zstds) |
6
6
 
7
7
  See [zstd library](https://github.com/facebook/zstd).
8
8
 
9
9
  ## Installation
10
10
 
11
- Please install zstd library first, use latest 1.4.3+ version.
11
+ Please install zstd library first, use latest 1.4.0+ version.
12
12
 
13
13
  ```sh
14
14
  gem install ruby-zstds
@@ -21,6 +21,8 @@ rake gem
21
21
  gem install pkg/ruby-zstds-*.gem
22
22
  ```
23
23
 
24
+ You can also use [overlay](https://github.com/andrew-aladev/overlay) for gentoo.
25
+
24
26
  ## Usage
25
27
 
26
28
  There are simple APIs: `String` and `File`. Also you can use generic streaming API: `Stream::Writer` and `Stream::Reader`.
@@ -36,6 +38,27 @@ ZSTDS::File.decompress "file.txt.zst", "file.txt"
36
38
 
37
39
  ZSTDS::Stream::Writer.open("file.txt.zst") { |writer| writer << "sample string" }
38
40
  puts ZSTDS::Stream::Reader.open("file.txt.zst") { |reader| reader.read }
41
+
42
+ writer = ZSTDS::Stream::Writer.new output_socket
43
+ begin
44
+ bytes_written = writer.write_nonblock "sample string"
45
+ # handle "bytes_written"
46
+ rescue IO::WaitWritable
47
+ # handle wait
48
+ ensure
49
+ writer.close
50
+ end
51
+
52
+ reader = ZSTDS::Stream::Reader.new input_socket
53
+ begin
54
+ puts reader.read_nonblock(512)
55
+ rescue IO::WaitReadable
56
+ # handle wait
57
+ rescue ::EOFError
58
+ # handle eof
59
+ ensure
60
+ reader.close
61
+ end
39
62
  ```
40
63
 
41
64
  You can create dictionary using `ZSTDS::Dictionary`.
@@ -47,16 +70,16 @@ require "zstds"
47
70
  samples = (Array.new(8) { ::SecureRandom.random_bytes(1 << 8) } + ["sample string"]).shuffle
48
71
 
49
72
  dictionary = ZSTDS::Dictionary.train samples
50
- File.write "dictionary.bin", dictionary.buffer
73
+ File.write "dictionary.bin", dictionary.buffer, :mode => "wb"
51
74
 
52
- dictionary_buffer = File.read "dictionary.bin"
75
+ dictionary_buffer = File.read "dictionary.bin", :mode => "rb"
53
76
  dictionary = ZSTDS::Dictionary.new dictionary_buffer
54
77
 
55
78
  data = ZSTDS::String.compress "sample string", :dictionary => dictionary
56
79
  puts ZSTDS::String.decompress(data, :dictionary => dictionary)
57
80
  ```
58
81
 
59
- You can create and read `tar.zst` archives with `minitar` for example.
82
+ You can create and read `tar.zst` archives with [minitar](https://github.com/halostatue/minitar).
60
83
 
61
84
  ```ruby
62
85
  require "zstds"
@@ -78,160 +101,96 @@ ZSTDS::Stream::Reader.open "file.tar.zst" do |reader|
78
101
  end
79
102
  ```
80
103
 
81
- ## Options
82
-
83
- Each API supports several options:
84
-
85
- ```
86
- :source_buffer_length
87
- :destination_buffer_length
88
- ```
89
-
90
- There are internal buffers for compressed and decompressed data.
91
- For example you want to use 1 KB as source buffer length for compressor - please use 256 B as destination buffer length.
92
- You want to use 256 B as source buffer length for decompressor - please use 1 KB as destination buffer length.
93
-
94
- Values: 0 - infinity, default value: 0.
95
- 0 means automatic buffer length selection.
96
-
97
- ```
98
- :compression_level
99
- ```
100
-
101
- Values: `ZSTDS::Option::MIN_COMPRESSION_LEVEL` - `ZSTDS::Option::MAX_COMPRESSION_LEVEL`, default value: `0`.
102
-
103
- ```
104
- :window_log
105
- ```
106
-
107
- Values: `ZSTDS::Option::MIN_WINDOW_LOG` - `ZSTDS::Option::MAX_WINDOW_LOG`, default value: `0`.
108
-
109
- ```
110
- :hash_log
111
- ```
112
-
113
- Values: `ZSTDS::Option::MIN_HASH_LOG` - `ZSTDS::Option::MAX_HASH_LOG`, default value: `0`.
114
-
115
- ```
116
- :chain_log
117
- ```
118
-
119
- Values: `ZSTDS::Option::MIN_CHAIN_LOG` - `ZSTDS::Option::MAX_CHAIN_LOG`, default value: `0`.
120
-
121
- ```
122
- :search_log
123
- ```
124
-
125
- Values: `ZSTDS::Option::MIN_SEARCH_LOG` - `ZSTDS::Option::MAX_SEARCH_LOG`, default value: `0`.
126
-
127
- ```
128
- :min_match
129
- ```
130
-
131
- Values: `ZSTDS::Option::MIN_MIN_MATCH` - `ZSTDS::Option::MAX_MIN_MATCH`, default value: `0`.
132
-
133
- ```
134
- :target_length
135
- ```
136
-
137
- Values: `ZSTDS::Option::MIN_TARGET_LENGTH` - `ZSTDS::Option::MAX_TARGET_LENGTH`, default value: `0`.
138
-
139
- ```
140
- :strategy
141
- ```
142
-
143
- Values: `ZSTDS::Option::STRATEGIES`, default value: none.
144
-
145
- ```
146
- :enable_long_distance_matching
147
- ```
148
-
149
- Values: true/false, default value: none.
150
-
151
- ```
152
- :ldm_hash_log
153
- ```
154
-
155
- Values: `ZSTDS::Option::MIN_LDM_HASH_LOG` - `ZSTDS::Option::MAX_LDM_HASH_LOG`, default value: `0`.
156
-
157
- ```
158
- :ldm_min_match
159
- ```
160
-
161
- Values: `ZSTDS::Option::MIN_LDM_MIN_MATCH` - `ZSTDS::Option::MAX_LDM_MIN_MATCH`, default value: `0`.
162
-
163
- ```
164
- :ldm_bucket_size_log
165
- ```
166
-
167
- Values: `ZSTDS::Option::MIN_LDM_BUCKET_SIZE_LOG` - `ZSTDS::Option::MAX_LDM_BUCKET_SIZE_LOG`, default value: `0`.
104
+ You can also use `Content-Encoding: zstd` with [sinatra](http://sinatrarb.com):
168
105
 
169
- ```
170
- :ldm_hash_rate_log
171
- ```
172
-
173
- Values: `ZSTDS::Option::MIN_LDM_HASH_RATE_LOG` - `ZSTDS::Option::MAX_LDM_HASH_RATE_LOG`, default value: `0`.
174
-
175
- ```
176
- :content_size_flag
177
- ```
178
-
179
- Values: true/false, default value: true.
180
-
181
- ```
182
- :checksum_flag
183
- ```
184
-
185
- Values: true/false, default value: false.
186
-
187
- ```
188
- :dict_id_flag
189
- ```
190
-
191
- Values: true/false, default value: true.
192
-
193
- ```
194
- :nb_workers
195
- ```
196
-
197
- Values: `ZSTDS::Option::MIN_NB_WORKERS` - `ZSTDS::Option::MAX_NB_WORKERS`, default value: `0`.
106
+ ```ruby
107
+ require "zstds"
108
+ require "sinatra"
198
109
 
199
- ```
200
- :job_size
110
+ get "/" do
111
+ headers["Content-Encoding"] = "zstd"
112
+ ZSTDS::String.compress "sample string"
113
+ end
201
114
  ```
202
115
 
203
- Values: `ZSTDS::Option::MIN_JOB_SIZE` - `ZSTDS::Option::MAX_JOB_SIZE`, default value: `0`.
204
-
205
- ```
206
- :overlap_log
207
- ```
116
+ All functionality (including streaming) can be used inside multiple threads with [parallel](https://github.com/grosser/parallel).
117
+ This code will provide heavy load for your CPU.
208
118
 
209
- Values: `ZSTDS::Option::MIN_OVERLAP_LOG` - `ZSTDS::Option::MAX_OVERLAP_LOG`, default value: `0`.
119
+ ```ruby
120
+ require "zstds"
121
+ require "parallel"
210
122
 
211
- ```
212
- :window_log_max
123
+ Parallel.each large_datas do |large_data|
124
+ ZSTDS::String.compress large_data
125
+ end
213
126
  ```
214
127
 
215
- Values: `ZSTDS::Option::MIN_WINDOW_LOG_MAX` - `ZSTDS::Option::MAX_WINDOW_LOG_MAX`, default value: `0`.
128
+ ## Options
216
129
 
217
- ```
218
- :dictionary
219
- ```
130
+ | Option | Values | Default | Description |
131
+ |---------------------------------|----------------|------------|-------------|
132
+ | `source_buffer_length` | 0 - inf | 0 (auto) | internal buffer length for source data |
133
+ | `destination_buffer_length` | 0 - inf | 0 (auto) | internal buffer length for description data |
134
+ | `gvl` | true/false | false | enables global VM lock where possible |
135
+ | `compression_level` | -131072 - 22 | 0 (auto) | compression level |
136
+ | `window_log` | 10 - 31 | 0 (auto) | maximum back-reference distance (power of 2) |
137
+ | `hash_log` | 6 - 30 | 0 (auto) | size of the initial probe table (power of 2) |
138
+ | `chain_log` | 6 - 30 | 0 (auto) | size of the multi-probe search table (power of 2) |
139
+ | `search_log` | 1 - 30 | 0 (auto) | number of search attempts (power of 2) |
140
+ | `min_match` | 3 - 7 | 0 (auto) | minimum size of searched matches |
141
+ | `target_length` | 0 - 131072 | 0 (auto) | distance between match sampling (for `:fast` strategy), length of match considered "good enough" for (for other strategies) |
142
+ | `strategy` | `STRATEGIES` | nil (auto) | choses strategy |
143
+ | `enable_long_distance_matching` | true/false | nil (auto) | enables long distance matching |
144
+ | `ldm_hash_log` | 6 - 30 | 0 (auto) | size of the table for long distance matching (power of 2) |
145
+ | `ldm_min_match` | 4 - 4096 | 0 (auto) | minimum match size for long distance matcher |
146
+ | `ldm_bucket_size_log` | 1 - 8 | 0 (auto) | log size of each bucket in the LDM hash table for collision resolution |
147
+ | `ldm_hash_rate_log` | 0 - 25 | 0 (auto) | frequency of inserting/looking up entries into the LDM hash table |
148
+ | `content_size_flag` | true/false | true | enables writing of content size into frame header (if known) |
149
+ | `checksum_flag` | true/false | false | enables writing of 32-bits checksum of content at end of frame |
150
+ | `dict_id_flag` | true/false | true | enables writing of dictionary id into frame header |
151
+ | `nb_workers` | 0 - 200 | 0 (auto) | number of threads spawned in parallel |
152
+ | `job_size` | 0 - 1073741824 | 0 (auto) | size of job (nb_workers >= 1) |
153
+ | `overlap_log` | 0 - 9 | 0 (auto) | overlap size, as a fraction of window size |
154
+ | `window_log_max` | 10 - 31 | 0 (auto) | size limit (power of 2) |
155
+ | `dictionary` | `Dictionary` | nil | chose dictionary |
156
+ | `pledged_size` | 0 - inf | 0 (auto) | size of input (if known) |
220
157
 
221
- Special option for dictionary, default value: none.
158
+ There are internal buffers for compressed and decompressed data.
159
+ For example you want to use 1 KB as `source_buffer_length` for compressor - please use 256 B as `destination_buffer_length`.
160
+ You want to use 256 B as `source_buffer_length` for decompressor - please use 1 KB as `destination_buffer_length`.
222
161
 
223
- ```
224
- :pledged_size
225
- ```
162
+ `gvl` is disabled by default, this mode allows running multiple compressors/decompressors in different threads simultaneously.
163
+ Please consider enabling `gvl` if you don't want to launch processors in separate threads.
164
+ If `gvl` is enabled ruby won't waste time on acquiring/releasing VM lock.
226
165
 
227
- Values: 0 - infinity, default value: 0.
228
- It is reasonable to provide size of input (if known) for streaming api.
229
166
  `String` and `File` will set `:pledged_size` automaticaly.
230
167
 
231
- Please read zstd docs for more info about options.
168
+ You can also read zstd docs for more info about options.
169
+
170
+ | Option | Related constants |
171
+ |-----------------------|-------------------|
172
+ | `compression_level` | `ZSTDS::Option::MIN_COMPRESSION_LEVEL` = -131072, `ZSTDS::Option::MAX_COMPRESSION_LEVEL` = 22 |
173
+ | `window_log` | `ZSTDS::Option::MIN_WINDOW_LOG` = 10, `ZSTDS::Option::MAX_WINDOW_LOG` = 31 |
174
+ | `hash_log` | `ZSTDS::Option::MIN_HASH_LOG` = 6, `ZSTDS::Option::MAX_HASH_LOG` = 30 |
175
+ | `chain_log` | `ZSTDS::Option::MIN_CHAIN_LOG` = 6, `ZSTDS::Option::MAX_CHAIN_LOG` = 30 |
176
+ | `search_log` | `ZSTDS::Option::MIN_SEARCH_LOG` = 1, `ZSTDS::Option::MAX_SEARCH_LOG` = 30 |
177
+ | `min_match` | `ZSTDS::Option::MIN_MIN_MATCH` = 3, `ZSTDS::Option::MAX_MIN_MATCH` = 7 |
178
+ | `target_length` | `ZSTDS::Option::MIN_TARGET_LENGTH` = 0, `ZSTDS::Option::MAX_TARGET_LENGTH` = 131072 |
179
+ | `strategy` | `ZSTDS::Option::STRATEGIES` = `%i[fast dfast greedy lazy lazy2 btlazy2 btopt btultra btultra2]` |
180
+ | `ldm_hash_log` | `ZSTDS::Option::MIN_LDM_HASH_LOG` = 6, `ZSTDS::Option::MAX_LDM_HASH_LOG` = 30 |
181
+ | `ldm_min_match` | `ZSTDS::Option::MIN_LDM_MIN_MATCH` = 4, `ZSTDS::Option::MAX_LDM_MIN_MATCH` = 4096 |
182
+ | `ldm_bucket_size_log` | `ZSTDS::Option::MIN_LDM_BUCKET_SIZE_LOG` = 1, `ZSTDS::Option::MAX_LDM_BUCKET_SIZE_LOG` = 8 |
183
+ | `ldm_hash_rate_log` | `ZSTDS::Option::MIN_LDM_HASH_RATE_LOG` = 0, `ZSTDS::Option::MAX_LDM_HASH_RATE_LOG` = 25 |
184
+ | `nb_workers` | `ZSTDS::Option::MIN_NB_WORKERS` = 0, `ZSTDS::Option::MAX_NB_WORKERS` = 200 |
185
+ | `job_size` | `ZSTDS::Option::MIN_JOB_SIZE` = 0, `ZSTDS::Option::MAX_JOB_SIZE` = 1073741824 |
186
+ | `overlap_log` | `ZSTDS::Option::MIN_OVERLAP_LOG` = 0, `ZSTDS::Option::MAX_OVERLAP_LOG` = 9 |
187
+ | `window_log_max` | `ZSTDS::Option::MIN_WINDOW_LOG_MAX` = 10, `ZSTDS::Option::MAX_WINDOW_LOG_MAX` = 31 |
232
188
 
233
189
  Possible compressor options:
234
190
  ```
191
+ :source_buffer_length
192
+ :destination_buffer_length
193
+ :gvl
235
194
  :compression_level
236
195
  :window_log
237
196
  :hash_log
@@ -257,6 +216,9 @@ Possible compressor options:
257
216
 
258
217
  Possible decompressor options:
259
218
  ```
219
+ :source_buffer_length
220
+ :destination_buffer_length
221
+ :gvl
260
222
  :window_log_max
261
223
  :dictionary
262
224
  ```
@@ -270,18 +232,6 @@ data = ZSTDS::String.compress "sample string", :compression_level => 5
270
232
  puts ZSTDS::String.decompress(data, :window_log_max => 11)
271
233
  ```
272
234
 
273
- HTTP encoding (`Content-Encoding: zstd`) using default options:
274
-
275
- ```ruby
276
- require "zstds"
277
- require "sinatra"
278
-
279
- get "/" do
280
- headers["Content-Encoding"] = "zstd"
281
- ZSTDS::String.compress "sample string"
282
- end
283
- ```
284
-
285
235
  ## String
286
236
 
287
237
  String maintains destination buffer only, so it accepts `destination_buffer_length` option only.
@@ -306,7 +256,7 @@ File maintains both source and destination buffers, it accepts both `source_buff
306
256
 
307
257
  ## Stream::Writer
308
258
 
309
- Its behaviour is similar to builtin [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipWriter.html).
259
+ Its behaviour is similar to builtin [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipWriter.html).
310
260
 
311
261
  Writer maintains destination buffer only, so it accepts `destination_buffer_length` option only.
312
262
 
@@ -344,7 +294,7 @@ Set another encodings, `nil` is just for compatibility with `IO`.
344
294
  #tell
345
295
  ```
346
296
 
347
- See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
297
+ See [`IO`](https://ruby-doc.org/core/IO.html) docs.
348
298
 
349
299
  ```
350
300
  #write(*objects)
@@ -354,7 +304,7 @@ See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
354
304
  #closed?
355
305
  ```
356
306
 
357
- See [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipWriter.html) docs.
307
+ See [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipWriter.html) docs.
358
308
 
359
309
  ```
360
310
  #write_nonblock(object, *options)
@@ -368,6 +318,9 @@ Special asynchronous methods missing in `Zlib::GzipWriter`.
368
318
  So it is possible to have asynchronous variants for these synchronous methods.
369
319
  Behaviour is the same as `IO#write_nonblock` method.
370
320
 
321
+ All nonblock operations for file will raise `EBADF` error on Windows.
322
+ Setting file into nonblocking mode is [not available on Windows](https://github.com/ruby/ruby/blob/master/win32/win32.c#L4388).
323
+
371
324
  ```
372
325
  #<<(object)
373
326
  #print(*objects)
@@ -376,11 +329,11 @@ Behaviour is the same as `IO#write_nonblock` method.
376
329
  #puts(*objects)
377
330
  ```
378
331
 
379
- Typical helpers, see [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipWriter.html) docs.
332
+ Typical helpers, see [`Zlib::GzipWriter`](https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipWriter.html) docs.
380
333
 
381
334
  ## Stream::Reader
382
335
 
383
- Its behaviour is similar to builtin [`Zlib::GzipReader`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipReader.html).
336
+ Its behaviour is similar to builtin [`Zlib::GzipReader`](https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipReader.html).
384
337
 
385
338
  Reader maintains both source and destination buffers, it accepts both `source_buffer_length` and `destination_buffer_length` options.
386
339
 
@@ -415,7 +368,7 @@ Set another encodings.
415
368
  #tell
416
369
  ```
417
370
 
418
- See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
371
+ See [`IO`](https://ruby-doc.org/core/IO.html) docs.
419
372
 
420
373
  ```
421
374
  #read(bytes_to_read = nil, out_buffer = nil)
@@ -425,14 +378,14 @@ See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
425
378
  #closed?
426
379
  ```
427
380
 
428
- See [`Zlib::GzipReader`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipReader.html) docs.
381
+ See [`Zlib::GzipReader`](https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipReader.html) docs.
429
382
 
430
383
  ```
431
384
  #readpartial(bytes_to_read = nil, out_buffer = nil)
432
385
  #read_nonblock(bytes_to_read, out_buffer = nil, *options)
433
386
  ```
434
387
 
435
- See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
388
+ See [`IO`](https://ruby-doc.org/core/IO.html) docs.
436
389
 
437
390
  ```
438
391
  #getbyte
@@ -455,7 +408,7 @@ See [`IO`](https://ruby-doc.org/core-2.7.0/IO.html) docs.
455
408
  #ungetline(line)
456
409
  ```
457
410
 
458
- Typical helpers, see [`Zlib::GzipReader`](https://ruby-doc.org/stdlib-2.7.0/libdoc/zlib/rdoc/Zlib/GzipReader.html) docs.
411
+ Typical helpers, see [`Zlib::GzipReader`](https://ruby-doc.org/stdlib/libdoc/zlib/rdoc/Zlib/GzipReader.html) docs.
459
412
 
460
413
  ## Dictionary
461
414
 
@@ -487,14 +440,24 @@ Please use regular constructor to create dictionary from buffer.
487
440
 
488
441
  Read dictionary id from buffer.
489
442
 
443
+ ## Thread safety
444
+
445
+ `:gvl` option is disabled by default, you can use bindings effectively in multiple threads.
446
+ Please be careful: bindings are not thread safe.
447
+ You should lock all shared data between threads.
448
+
449
+ For example: you should not use same compressor/decompressor inside multiple threads.
450
+ Please verify that you are using each processor inside single thread at the same time.
451
+
452
+ ## Operating systems
453
+
454
+ GNU/Linux, FreeBSD, OSX, Windows (MinGW).
455
+
490
456
  ## CI
491
457
 
492
- See universal test script [scripts/ci_test.sh](scripts/ci_test.sh) for CI.
493
458
  Please visit [scripts/test-images](scripts/test-images).
494
- You can run this test script using many native and cross images.
495
-
496
- Cirrus CI uses `x86_64-pc-linux-gnu` image, Circle CI - `x86_64-gentoo-linux-musl` image.
459
+ See universal test script [scripts/ci_test.sh](scripts/ci_test.sh) for CI.
497
460
 
498
461
  ## License
499
462
 
500
- MIT license, see LICENSE and AUTHORS.
463
+ MIT license, see [LICENSE](LICENSE) and [AUTHORS](AUTHORS).