From 14fd04a041994e35393a2abf5c039db4e9f29f60 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Sat, 23 Jan 2021 17:52:30 +0800 Subject: [PATCH] opt: shrink the ring-buffer for saving memory --- eventloop_unix.go | 2 +- ringbuffer/ring_buffer.go | 23 ++++++++++--------- ringbuffer/ring_buffer_test.go | 41 ++++++++++++++++++++++++++-------- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/eventloop_unix.go b/eventloop_unix.go index 1925c0fa5..81e5252ff 100644 --- a/eventloop_unix.go +++ b/eventloop_unix.go @@ -49,7 +49,7 @@ type internalEventloop struct { idx int // loop index in the server loops list svr *server // server in loop poller *netpoll.Poller // epoll or kqueue - packet []byte // read packet buffer + packet []byte // read packet buffer whose capacity is 64KB connCount int32 // number of active connections in event-loop connections map[int]*conn // loop connections fd -> conn eventHandler EventHandler // user eventHandler diff --git a/ringbuffer/ring_buffer.go b/ringbuffer/ring_buffer.go index d285f43c5..aaf1e29e6 100644 --- a/ringbuffer/ring_buffer.go +++ b/ringbuffer/ring_buffer.go @@ -118,9 +118,6 @@ func (r *RingBuffer) Shift(n int) { if n < r.Length() { r.r = (r.r + n) & r.mask - if r.r == r.w { - r.isEmpty = true - } } else { r.Reset() } @@ -154,7 +151,7 @@ func (r *RingBuffer) Read(p []byte) (n int, err error) { copy(p, r.buf[r.r:r.r+n]) r.r += n if r.r == r.w { - r.isEmpty = true + r.Reset() } return } @@ -174,7 +171,7 @@ func (r *RingBuffer) Read(p []byte) (n int, err error) { } r.r = (r.r + n) & r.mask if r.r == r.w { - r.isEmpty = true + r.Reset() } return n, err @@ -191,7 +188,7 @@ func (r *RingBuffer) ReadByte() (b byte, err error) { r.r = 0 } if r.r == r.w { - r.isEmpty = true + r.Reset() } return b, err @@ -370,14 +367,20 @@ func (r *RingBuffer) IsEmpty() bool { // Reset the read pointer and writer pointer to zero. func (r *RingBuffer) Reset() { - r.r = 0 - r.w = 0 r.isEmpty = true + r.r, r.w = 0, 0 + + // Shrink the internal buffer for saving memory. + newCap := r.size / 2 + newBuf := make([]byte, newCap) + r.buf = newBuf + r.size = newCap + r.mask = newCap - 1 } func (r *RingBuffer) malloc(cap int) { var newCap int - if r.size == 0 && initSize >= cap { + if r.size == 0 && cap < initSize { newCap = initSize } else { newCap = internal.CeilToPowerOfTwo(r.size + cap) @@ -385,9 +388,9 @@ func (r *RingBuffer) malloc(cap int) { newBuf := make([]byte, newCap) oldLen := r.Length() _, _ = r.Read(newBuf) + r.buf = newBuf r.r = 0 r.w = oldLen r.size = newCap r.mask = newCap - 1 - r.buf = newBuf } diff --git a/ringbuffer/ring_buffer_test.go b/ringbuffer/ring_buffer_test.go index 37cb6f069..ca8bf0088 100644 --- a/ringbuffer/ring_buffer_test.go +++ b/ringbuffer/ring_buffer_test.go @@ -144,6 +144,7 @@ func TestRingBuffer_Write(t *testing.T) { } rb.Reset() + size = rb.Cap() // write 4 * 2 = 8 bytes n, _ = rb.Write([]byte(strings.Repeat("abcd", 2))) if n != 8 { @@ -264,6 +265,7 @@ func TestRingBuffer_Read(t *testing.T) { // write 16 bytes to read _, _ = rb.Write([]byte(strings.Repeat("abcd", 4))) + // read all data from buffer, it will be shrunk from 64 to 32. n, err = rb.Read(buf) if err != nil { t.Fatalf("read failed: %v", err) @@ -274,15 +276,16 @@ func TestRingBuffer_Read(t *testing.T) { if rb.Length() != 0 { t.Fatalf("expect len 0 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r) } - if rb.Free() != 64 { + if rb.Free() != 32 { t.Fatalf("expect free 64 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r) } - if rb.r != 16 { - t.Fatalf("expect r.r=16 but got %d. r.w=%d", rb.r, rb.w) + if rb.r != 0 { + t.Fatalf("expect r.r=0 but got %d. r.w=%d", rb.r, rb.w) } - // write long slice to read, it will scale from 64 to 128 bytes. + // write long slice to read, it will scale from 32 to 128 bytes. _, _ = rb.Write([]byte(strings.Repeat("abcd", 20))) + // read all data from buffer, it will be shrunk from 128 to 64. n, err = rb.Read(buf) if err != nil { t.Fatalf("read failed: %v", err) @@ -293,11 +296,11 @@ func TestRingBuffer_Read(t *testing.T) { if rb.Length() != 0 { t.Fatalf("expect len 0 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r) } - if rb.Free() != 128 { + if rb.Free() != 64 { t.Fatalf("expect free 128 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r) } - if rb.r != 80 { - t.Fatalf("expect r.r=80 but got %d. r.w=%d", rb.r, rb.w) + if rb.r != 0 { + t.Fatalf("expect r.r=0 but got %d. r.w=%d", rb.r, rb.w) } rb.Reset() @@ -374,7 +377,7 @@ func TestRingBuffer_ByteInterface(t *testing.T) { t.Fatalf("expect IsFull is false but got true") } - // write to, isFull + // write two, isFull _ = rb.WriteByte('b') if rb.Length() != 2 { t.Fatalf("expect len 2 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r) @@ -461,7 +464,7 @@ func TestRingBuffer_ByteInterface(t *testing.T) { if rb.Length() != 0 { t.Fatalf("expect len 0 byte but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r) } - if rb.Free() != 4 { + if rb.Free() != 2 { t.Fatalf("expect free 4 byte but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r) } // check empty or full @@ -472,3 +475,23 @@ func TestRingBuffer_ByteInterface(t *testing.T) { t.Fatalf("expect IsFull is false but got true") } } + +func TestShrinkBuffer(t *testing.T) { + testStr := "Hello World!" + testCap := 1024 + + rb := New(testCap) + _, _ = rb.WriteString(testStr) + rb.LazyReadAll() + rb.Shift(len(testStr)) + if rb.Cap() != testCap/2 { + t.Fatalf("expect buffer capacity %d, but got %d", testCap/2, rb.Cap()) + } + + _, _ = rb.WriteString(testStr) + rb.LazyReadAll() + rb.Reset() + if rb.Cap() != testCap/4 { + t.Fatalf("expect buffer capacity %d, but got %d", testCap/4, rb.Cap()) + } +}