From e73321a86034cce6dd2c51a8a571ac6442f81dd9 Mon Sep 17 00:00:00 2001 From: lionsoul2014 Date: Fri, 5 Dec 2025 12:42:45 +0800 Subject: [PATCH] searcher pool is ready --- binding/golang/service/searcher_pool.go | 50 ++++++++++---- binding/golang/service/searcher_pool_test.go | 70 ++++++++++++++++++++ 2 files changed, 107 insertions(+), 13 deletions(-) create mode 100644 binding/golang/service/searcher_pool_test.go diff --git a/binding/golang/service/searcher_pool.go b/binding/golang/service/searcher_pool.go index 088eba8..31076e3 100644 --- a/binding/golang/service/searcher_pool.go +++ b/binding/golang/service/searcher_pool.go @@ -11,9 +11,9 @@ package service import ( - "context" "fmt" "sync/atomic" + "time" "github.com/lionsoul2014/ip2region/binding/golang/xdb" ) @@ -61,18 +61,19 @@ func NewSearcherPool(config *Config) (*SearcherPool, error) { // Stat return the stat {loanCount, leftCount} info of the pool func (sp *SearcherPool) Stat() (int, int) { loanCount := int(atomic.LoadInt32(&sp.loanCount)) - return loanCount, len(sp.pool) - loanCount + return loanCount, len(sp.pool) +} + +// get the loaned count +func (sp *SearcherPool) LoanCount() int { + return int(atomic.LoadInt32(&sp.loanCount)) } func (sp *SearcherPool) BorrowSearcher() *xdb.Searcher { - select { - case <-sp.closing: - // stop searcher borrow while closing - return nil - case s := <-sp.pool: - atomic.AddInt32(&sp.loanCount, 1) - return s - } + // @Note: still accept searcher borrow while closing + s := <-sp.pool + atomic.AddInt32(&sp.loanCount, 1) + return s } func (sp *SearcherPool) ReturnSearcher(searcher *xdb.Searcher) { @@ -80,6 +81,9 @@ func (sp *SearcherPool) ReturnSearcher(searcher *xdb.Searcher) { case <-sp.closing: // manually close the searcher searcher.Close() + + // decrease the loan count + atomic.AddInt32(&sp.loanCount, -1) default: // return the searcher sp.pool <- searcher @@ -87,9 +91,29 @@ func (sp *SearcherPool) ReturnSearcher(searcher *xdb.Searcher) { } } -func (sp *SearcherPool) Close(ctx context.Context) { +func (sp *SearcherPool) Close() { + sp.CloseTimeout(time.Second * 10) +} + +func (sp *SearcherPool) CloseTimeout(d time.Duration) { close(sp.closing) - for s := range sp.pool { - s.Close() + for { + timeout := false + select { + case s := <-sp.pool: + s.Close() + case <-time.After(d): + // check if all the loaned searchers was closed + timeout = true + } + + lc, left := sp.LoanCount(), len(sp.pool) + if left == 0 && lc == 0 { + break + } + + if timeout { + break + } } } diff --git a/binding/golang/service/searcher_pool_test.go b/binding/golang/service/searcher_pool_test.go new file mode 100644 index 0000000..af2503c --- /dev/null +++ b/binding/golang/service/searcher_pool_test.go @@ -0,0 +1,70 @@ +// Copyright 2022 The Ip2Region Authors. All rights reserved. +// Use of this source code is governed by a Apache2.0-style +// license that can be found in the LICENSE file. + +package service + +import ( + "fmt" + "testing" +) + +func TestV4SearcherPool(t *testing.T) { + v4Config, err := NewV4Config(VIndexCache, "../../../data/ip2region_v4.xdb", 5) + if err != nil { + t.Fatalf("failed to new v4 config: %s", err) + } + + searcherPool, err := NewSearcherPool(v4Config) + if err != nil { + t.Fatalf("failed to create searcher pool: %s", err) + } + + ipString := "219.133.110.197" + for i := 0; i < 20; i++ { + searcher := searcherPool.BorrowSearcher() + region, err := searcher.SearchByStr(ipString) + if err != nil { + t.Fatalf("failed to search(%s): %s", ipString, err) + } + + fmt.Printf("%2d->search(%s)=%s\n", i, ipString, region) + searcherPool.ReturnSearcher(searcher) + } + + // borrow one at last for Close timeout wait testing ONLY + // searcherPool.BorrowSearcher() + + // close the searcher pool + searcherPool.Close() +} + +func TestV6SearcherPool(t *testing.T) { + v6Config, err := NewV6Config(VIndexCache, "../../../data/ip2region_v6.xdb", 5) + if err != nil { + t.Fatalf("failed to new v6 config: %s", err) + } + + searcherPool, err := NewSearcherPool(v6Config) + if err != nil { + t.Fatalf("failed to create searcher pool: %s", err) + } + + ipString := "240e:3b7:3275:f090:d2a3:7d1a:dd90:c3b6" + for i := 0; i < 20; i++ { + searcher := searcherPool.BorrowSearcher() + region, err := searcher.SearchByStr(ipString) + if err != nil { + t.Fatalf("failed to search(%s): %s", ipString, err) + } + + fmt.Printf("%2d->search(%s)=%s\n", i, ipString, region) + searcherPool.ReturnSearcher(searcher) + } + + // borrow one at last for Close timeout wait testing ONLY + // searcherPool.BorrowSearcher() + + // close the searcher pool + searcherPool.Close() +}