From cb9be97eb765e975d868f32e868c3992dc68182f Mon Sep 17 00:00:00 2001 From: Andy Balholm Date: Tue, 5 May 2020 17:18:33 -0700 Subject: [PATCH] Reuse more memory when a Writer is Reset. --- brotli_test.go | 104 +++++++++++++++++++++++++++++++++---------------- encode.go | 10 ++--- ringbuffer.go | 3 -- 3 files changed, 73 insertions(+), 44 deletions(-) diff --git a/brotli_test.go b/brotli_test.go index 8e3329c..0a81541 100644 --- a/brotli_test.go +++ b/brotli_test.go @@ -67,23 +67,41 @@ func TestEncoderEmptyWrite(t *testing.T) { } func TestWriter(t *testing.T) { - // Test basic encoder usage. - input := []byte("

Hello world

") - out := bytes.Buffer{} - e := NewWriterOptions(&out, WriterOptions{Quality: 1}) - in := bytes.NewReader([]byte(input)) - n, err := io.Copy(e, in) - if err != nil { - t.Errorf("Copy Error: %v", err) - } - if int(n) != len(input) { - t.Errorf("Copy() n=%v, want %v", n, len(input)) - } - if err := e.Close(); err != nil { - t.Errorf("Close Error after copied %d bytes: %v", n, err) - } - if err := checkCompressedData(out.Bytes(), input); err != nil { - t.Error(err) + for level := BestSpeed; level <= BestCompression; level++ { + // Test basic encoder usage. + input := []byte("

Hello world

") + out := bytes.Buffer{} + e := NewWriterOptions(&out, WriterOptions{Quality: level}) + in := bytes.NewReader([]byte(input)) + n, err := io.Copy(e, in) + if err != nil { + t.Errorf("Copy Error: %v", err) + } + if int(n) != len(input) { + t.Errorf("Copy() n=%v, want %v", n, len(input)) + } + if err := e.Close(); err != nil { + t.Errorf("Close Error after copied %d bytes: %v", n, err) + } + if err := checkCompressedData(out.Bytes(), input); err != nil { + t.Error(err) + } + + out2 := bytes.Buffer{} + e.Reset(&out2) + n2, err := e.Write(input) + if err != nil { + t.Errorf("Write error after Reset: %v", err) + } + if n2 != len(input) { + t.Errorf("Write() after Reset n=%d, want %d", n2, len(input)) + } + if err := e.Close(); err != nil { + t.Errorf("Close error after Reset (copied %d) bytes: %v", n2, err) + } + if !bytes.Equal(out.Bytes(), out2.Bytes()) { + t.Error("Compressed data after Reset doesn't equal first time") + } } } @@ -119,24 +137,42 @@ func TestEncoderStreams(t *testing.T) { } func TestEncoderLargeInput(t *testing.T) { - input := make([]byte, 1000000) - rand.Read(input) - out := bytes.Buffer{} - e := NewWriterOptions(&out, WriterOptions{Quality: 5}) - in := bytes.NewReader(input) + for level := BestSpeed; level <= BestCompression; level++ { + input := make([]byte, 1000000) + rand.Read(input) + out := bytes.Buffer{} + e := NewWriterOptions(&out, WriterOptions{Quality: level}) + in := bytes.NewReader(input) - n, err := io.Copy(e, in) - if err != nil { - t.Errorf("Copy Error: %v", err) - } - if int(n) != len(input) { - t.Errorf("Copy() n=%v, want %v", n, len(input)) - } - if err := e.Close(); err != nil { - t.Errorf("Close Error after copied %d bytes: %v", n, err) - } - if err := checkCompressedData(out.Bytes(), input); err != nil { - t.Error(err) + n, err := io.Copy(e, in) + if err != nil { + t.Errorf("Copy Error: %v", err) + } + if int(n) != len(input) { + t.Errorf("Copy() n=%v, want %v", n, len(input)) + } + if err := e.Close(); err != nil { + t.Errorf("Close Error after copied %d bytes: %v", n, err) + } + if err := checkCompressedData(out.Bytes(), input); err != nil { + t.Error(err) + } + + out2 := bytes.Buffer{} + e.Reset(&out2) + n2, err := e.Write(input) + if err != nil { + t.Errorf("Write error after Reset: %v", err) + } + if n2 != len(input) { + t.Errorf("Write() after Reset n=%d, want %d", n2, len(input)) + } + if err := e.Close(); err != nil { + t.Errorf("Close error after Reset (copied %d) bytes: %v", n2, err) + } + if !bytes.Equal(out.Bytes(), out2.Bytes()) { + t.Error("Compressed data after Reset doesn't equal first time") + } } } diff --git a/encode.go b/encode.go index c01322b..c299606 100644 --- a/encode.go +++ b/encode.go @@ -1088,14 +1088,10 @@ func encoderInitState(s *Writer) { s.last_processed_pos_ = 0 s.prev_byte_ = 0 s.prev_byte2_ = 0 - s.storage_size_ = 0 - s.storage_ = nil - s.hasher_ = nil - s.large_table_ = nil - s.large_table_size_ = 0 + if s.hasher_ != nil { + s.hasher_.Common().is_prepared_ = false + } s.cmd_code_numbits_ = 0 - s.command_buf_ = nil - s.literal_buf_ = nil s.next_out_ = nil s.available_out_ = 0 s.total_out_ = 0 diff --git a/ringbuffer.go b/ringbuffer.go index 693a3f6..a304964 100644 --- a/ringbuffer.go +++ b/ringbuffer.go @@ -27,10 +27,7 @@ type ringBuffer struct { } func ringBufferInit(rb *ringBuffer) { - rb.cur_size_ = 0 rb.pos_ = 0 - rb.data_ = nil - rb.buffer_ = nil } func ringBufferSetup(params *encoderParams, rb *ringBuffer) {