Skip to content

Commit ab9d76f

Browse files
authored
s2: Clarify EncodeBuffer usage (#384)
EncodeBuffer cannot safely reuse the buffer in concurrent usage.
1 parent d172db7 commit ab9d76f

File tree

2 files changed

+107
-1
lines changed

2 files changed

+107
-1
lines changed

s2/encode.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,9 @@ func (w *Writer) ReadFrom(r io.Reader) (n int64, err error) {
487487
// EncodeBuffer will add a buffer to the stream.
488488
// This is the fastest way to encode a stream,
489489
// but the input buffer cannot be written to by the caller
490-
// until this function, Flush or Close has been called.
490+
// until Flush or Close has been called when concurrency != 1.
491+
//
492+
// If you cannot control that, use the regular Write function.
491493
//
492494
// Note that input is not buffered.
493495
// This means that each write will result in discrete blocks being created.

s2/encode_test.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,110 @@ func TestWriterPadding(t *testing.T) {
277277
}
278278
}
279279

280+
func TestBigRegularWrites(t *testing.T) {
281+
var buf [maxBlockSize * 2]byte
282+
dst := bytes.NewBuffer(nil)
283+
enc := NewWriter(dst, WriterBestCompression())
284+
max := uint8(10)
285+
if testing.Short() {
286+
max = 4
287+
}
288+
for n := uint8(0); n < max; n++ {
289+
for i := range buf[:] {
290+
buf[i] = n
291+
}
292+
// Writes may not keep a reference to the data beyond the Write call.
293+
_, err := enc.Write(buf[:])
294+
if err != nil {
295+
t.Fatal(err)
296+
}
297+
}
298+
err := enc.Close()
299+
if err != nil {
300+
t.Fatal(err)
301+
}
302+
303+
dec := NewReader(dst)
304+
_, err = io.Copy(ioutil.Discard, dec)
305+
if err != nil {
306+
t.Fatal(err)
307+
}
308+
}
309+
310+
func TestBigEncodeBuffer(t *testing.T) {
311+
const blockSize = 1 << 20
312+
var buf [blockSize * 2]byte
313+
dst := bytes.NewBuffer(nil)
314+
enc := NewWriter(dst, WriterBlockSize(blockSize), WriterBestCompression())
315+
max := uint8(10)
316+
if testing.Short() {
317+
max = 4
318+
}
319+
for n := uint8(0); n < max; n++ {
320+
// Change the buffer to a new value.
321+
for i := range buf[:] {
322+
buf[i] = n
323+
}
324+
err := enc.EncodeBuffer(buf[:])
325+
if err != nil {
326+
t.Fatal(err)
327+
}
328+
// We can write it again since we aren't changing it.
329+
err = enc.EncodeBuffer(buf[:])
330+
if err != nil {
331+
t.Fatal(err)
332+
}
333+
err = enc.Flush()
334+
if err != nil {
335+
t.Fatal(err)
336+
}
337+
}
338+
err := enc.Close()
339+
if err != nil {
340+
t.Fatal(err)
341+
}
342+
343+
dec := NewReader(dst)
344+
n, err := io.Copy(ioutil.Discard, dec)
345+
if err != nil {
346+
t.Fatal(err)
347+
}
348+
t.Log(n)
349+
}
350+
351+
func TestBigEncodeBufferSync(t *testing.T) {
352+
const blockSize = 1 << 20
353+
var buf [blockSize * 2]byte
354+
dst := bytes.NewBuffer(nil)
355+
enc := NewWriter(dst, WriterBlockSize(blockSize), WriterConcurrency(1), WriterBestCompression())
356+
max := uint8(10)
357+
if testing.Short() {
358+
max = 2
359+
}
360+
for n := uint8(0); n < max; n++ {
361+
// Change the buffer to a new value.
362+
for i := range buf[:] {
363+
buf[i] = n
364+
}
365+
// When WriterConcurrency == 1 we can encode and reuse the buffer.
366+
err := enc.EncodeBuffer(buf[:])
367+
if err != nil {
368+
t.Fatal(err)
369+
}
370+
}
371+
err := enc.Close()
372+
if err != nil {
373+
t.Fatal(err)
374+
}
375+
376+
dec := NewReader(dst)
377+
n, err := io.Copy(ioutil.Discard, dec)
378+
if err != nil {
379+
t.Fatal(err)
380+
}
381+
t.Log(n)
382+
}
383+
280384
func BenchmarkWriterRandom(b *testing.B) {
281385
rng := rand.New(rand.NewSource(1))
282386
// Make max window so we never get matches.

0 commit comments

Comments
 (0)