From 4a462a143731cef20d1eda8f6e3a7135736946e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Tue, 25 Feb 2025 19:35:43 +0900 Subject: [PATCH] optimize: change Destroy -> ManualDestroy --- item.go | 7 +++++-- pbuf/buffer_test.go | 4 ++-- pbuf/bytes.go | 5 ----- pbuf/bytes_test.go | 19 +++++++++++++------ pool.go | 25 ++++++++++++++++++------- pool_test.go | 6 +++--- 6 files changed, 41 insertions(+), 25 deletions(-) diff --git a/item.go b/item.go index 7eacb89..ce08c54 100644 --- a/item.go +++ b/item.go @@ -104,8 +104,11 @@ func (b *Item[T]) destroybystat(stat status) { b.pool.put(b) } -// Destroy item and put it back to pool. -func (b *Item[T]) Destroy() { +// ManualDestroy item and put it back to pool. +// +// Calling this method without setting pool.SetManualDestroy(true) +// can probably cause panic. +func (b *Item[T]) ManualDestroy() { b.destroybystat(status(atomic.SwapUintptr( (*uintptr)(&b.stat), uintptr(destroyedstatus), ))) diff --git a/pbuf/buffer_test.go b/pbuf/buffer_test.go index fe81f90..ea1ad1a 100644 --- a/pbuf/buffer_test.go +++ b/pbuf/buffer_test.go @@ -42,7 +42,7 @@ func testBuffer(buf *orbyte.Item[bytes.Buffer], t *testing.T) { if !bytes.Equal(bufr.Pointer().Bytes(), buf.Pointer().Bytes()) { t.Fatal("unexpected") } - bufr.Destroy() + bufr.ManualDestroy() bufcp = bufcp.Trans() if bufcp.Pointer().Len() != 4096 { @@ -51,7 +51,7 @@ func testBuffer(buf *orbyte.Item[bytes.Buffer], t *testing.T) { if !bytes.Equal(bufcp.Pointer().Bytes(), buf.Pointer().Bytes()) { t.Fatal("unexpected") } - bufcp.Destroy() + bufcp.ManualDestroy() runtime.GC() runtime.Gosched() diff --git a/pbuf/bytes.go b/pbuf/bytes.go index 05267f1..cecc3b9 100644 --- a/pbuf/bytes.go +++ b/pbuf/bytes.go @@ -117,8 +117,3 @@ func (b Bytes) Slice(from, to int) Bytes { nb.dat = b.dat[from:to] return nb } - -// Destroy please refer to Item.Destroy(). -func (b Bytes) Destroy() { - b.buf.Destroy() -} diff --git a/pbuf/bytes_test.go b/pbuf/bytes_test.go index 21d44a6..d74c763 100644 --- a/pbuf/bytes_test.go +++ b/pbuf/bytes_test.go @@ -11,6 +11,13 @@ import ( "time" ) +// manualDestroy please refer to Item.manualDestroy(). +// +// Only for test purposes. +func (b Bytes) manualDestroy() { + b.buf.ManualDestroy() +} + // TestBytesSlice sometimes fails at first run because // GC not collecting all unused items. func TestBytesSlice(t *testing.T) { @@ -29,7 +36,7 @@ func TestBytesSlice(t *testing.T) { t.Log("got:", hex.EncodeToString(x.Bytes())) t.Fatal("index", i, "unexpected") } - x.Destroy() + x.manualDestroy() // test trans slice b = b.Trans().SliceFrom(5).SliceTo(i - 5 - 5) if !bytes.Equal(buf[5:i-5], b.Bytes()) { @@ -37,7 +44,7 @@ func TestBytesSlice(t *testing.T) { t.Log("got:", hex.EncodeToString(b.Bytes())) t.Fatal("index", i, "unexpected") } - b.Destroy() + b.manualDestroy() } runtime.GC() runtime.Gosched() @@ -61,7 +68,7 @@ func TestBytesInvolve(t *testing.T) { if !bytes.Equal(b.Bytes(), buf[:i]) { t.Fatal("index", i, "unexpected") } - b.Destroy() + b.manualDestroy() } runtime.GC() out, in := bufferPool.p.CountItems() @@ -82,7 +89,7 @@ func TestBytesParse(t *testing.T) { if !bytes.Equal(b.Bytes(), buf[:i]) { t.Fatal("index", i, "unexpected") } - b.Destroy() + b.manualDestroy() } runtime.GC() out, in := bufferPool.p.CountItems() @@ -106,7 +113,7 @@ func TestBytesCopy(t *testing.T) { if bytes.Equal(b.Bytes(), buf[:i]) { t.Fatal("index", i, "unexpected") } - b.Destroy() + b.manualDestroy() } runtime.GC() out, in := bufferPool.p.CountItems() @@ -134,7 +141,7 @@ func TestBytesTransMultithread(t *testing.T) { if !bytes.Equal(refer, buf.Bytes()) { panic("unexpected") } - buf.Destroy() + buf.manualDestroy() }(buf.Trans()) }() } diff --git a/pool.go b/pool.go index 19c66da..a98ccf0 100644 --- a/pool.go +++ b/pool.go @@ -13,7 +13,8 @@ type Pool[T any] struct { pool sync.Pool countin int32 countout int32 - isstrict bool + noputbak bool + manudstr bool } // NewPool make a new pool from custom pooler. @@ -26,11 +27,17 @@ func NewPool[T any](pooler Pooler[T]) *Pool[T] { return p } -// SetStrictMode panic on every misuse. +// SetNoPutBack make it panic on every use-after-destroy. // // Enable this to detect coding errors. -func (pool *Pool[T]) SetStrictMode(on bool) { - pool.isstrict = on +func (pool *Pool[T]) SetNoPutBack(on bool) { + pool.noputbak = on +} + +// SetManualDestroy mark that user must manually +// run Item.Destroy(). +func (pool *Pool[T]) SetManualDestroy(on bool) { + pool.manudstr = on } func (pool *Pool[T]) incin() { @@ -56,17 +63,21 @@ func (pool *Pool[T]) newempty() *Item[T] { } item.stat = status(0) pool.incout() - item.setautodestroy() + if !pool.manudstr { + item.setautodestroy() + } return item } func (pool *Pool[T]) put(item *Item[T]) { - runtime.SetFinalizer(item, nil) + if !pool.manudstr { + runtime.SetFinalizer(item, nil) + } item.stat.setdestroyed(true) item.cfg = nil - if pool.isstrict { + if pool.noputbak { return } pool.pool.Put(item) diff --git a/pool_test.go b/pool_test.go index e2d0940..3e00c3e 100644 --- a/pool_test.go +++ b/pool_test.go @@ -10,7 +10,7 @@ import ( func TestPool(t *testing.T) { p := NewPool[[]byte](simplepooler{}) x := p.New(200) - x.Destroy() + x.ManualDestroy() out, in := p.CountItems() t.Log("out", out, "in", in) if out != 0 || in != 1 { @@ -22,7 +22,7 @@ func TestPool(t *testing.T) { if out != 1 || in != 0 { t.Fatal("unexpected behavior") } - item.Destroy() + item.ManualDestroy() } out, in = p.CountItems() t.Log("out", out, "in", in) @@ -53,7 +53,7 @@ func TestPool(t *testing.T) { func user(item *Item[[]byte], wg *sync.WaitGroup) { defer wg.Done() rand.Read(item.Unwrap()) - item.Destroy() + item.ManualDestroy() } func usernodestroy(item *Item[[]byte], wg *sync.WaitGroup) {