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 package service
import ( import (
"context"
"fmt" "fmt"
"sync/atomic" "sync/atomic"
"time"
"github.com/lionsoul2014/ip2region/binding/golang/xdb" "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 // Stat return the stat {loanCount, leftCount} info of the pool
func (sp *SearcherPool) Stat() (int, int) { func (sp *SearcherPool) Stat() (int, int) {
loanCount := int(atomic.LoadInt32(&sp.loanCount)) 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 { func (sp *SearcherPool) BorrowSearcher() *xdb.Searcher {
select { // @Note: still accept searcher borrow while closing
case <-sp.closing: s := <-sp.pool
// stop searcher borrow while closing atomic.AddInt32(&sp.loanCount, 1)
return nil return s
case s := <-sp.pool:
atomic.AddInt32(&sp.loanCount, 1)
return s
}
} }
func (sp *SearcherPool) ReturnSearcher(searcher *xdb.Searcher) { func (sp *SearcherPool) ReturnSearcher(searcher *xdb.Searcher) {
@ -80,6 +81,9 @@ func (sp *SearcherPool) ReturnSearcher(searcher *xdb.Searcher) {
case <-sp.closing: case <-sp.closing:
// manually close the searcher // manually close the searcher
searcher.Close() searcher.Close()
// decrease the loan count
atomic.AddInt32(&sp.loanCount, -1)
default: default:
// return the searcher // return the searcher
sp.pool <- 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) close(sp.closing)
for s := range sp.pool { for {
s.Close() 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()
}