searcher pool is ready

This commit is contained in:
lionsoul2014 2025-12-05 12:42:45 +08:00
parent ab22a5e03c
commit e73321a860
2 changed files with 107 additions and 13 deletions

View File

@ -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
}
}
}

View File

@ -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()
}