Skip to content
This repository was archived by the owner on Mar 22, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions FUTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
* [x] 全新 vex 通信协议
* [x] 优化性能,全双工通信
* [x] 支持客户端连接池
* [ ] 支持拒绝策略,比如 ip 拒绝
* [ ] 支持 tls 安全传输
* [x] 单元测试覆盖率提高到 90%

### v0.4.x
Expand Down
6 changes: 6 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
## 🎡 历史版本的特性介绍

### v0.5.2

> 此版本发布于 2026-03-01

* 增加 Pool 代码和单元测试

### v0.5.1-alpha

> 此版本发布于 2026-02-27
Expand Down
4 changes: 2 additions & 2 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ goos: linux
goarch: amd64
cpu: Intel(R) Xeon(R) CPU E5-26xx v4

BenchmarkPacket-2 48885 25712 ns/op 4600 B/op 9 allocs/op
BenchmarkPacketPool-2 58665 21461 ns/op 4601 B/op 9 allocs/op
BenchmarkPacket-2 43992 26818 ns/op 4664 B/op 15 allocs/op
BenchmarkPacketPool-2 56511 20681 ns/op 4690 B/op 16 allocs/op
```

> Benchmark: [_examples/packet_test.go](./_examples/packet_test.go).
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ goos: linux
goarch: amd64
cpu: Intel(R) Xeon(R) CPU E5-26xx v4

BenchmarkPacket-2 48885 25712 ns/op 4600 B/op 9 allocs/op
BenchmarkPacketPool-2 58665 21461 ns/op 4601 B/op 9 allocs/op
BenchmarkPacket-2 43992 26818 ns/op 4664 B/op 15 allocs/op
BenchmarkPacketPool-2 56511 20681 ns/op 4690 B/op 16 allocs/op
```

> 测试文件:[_examples/packet_test.go](./_examples/packet_test.go)。
Expand Down
4 changes: 2 additions & 2 deletions _icons/coverage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,18 @@ package vex

import (
"context"
"errors"

"github.com/FishGoddess/rego"
)

var (
errPoolClosed = errors.New("vex: pool is closed")
)

// Status is the status information of pool.
type Status rego.Status

type poolClient struct {
pool *Pool

Expand Down Expand Up @@ -61,6 +69,10 @@ func NewPool(limit uint64, dial DialFunc, opts ...Option) *Pool {
}

pool.clients = rego.New(limit, acquire, release)
pool.clients.WithPoolClosedErrFunc(func(ctx context.Context) error {
return errPoolClosed
})

return pool
}

Expand All @@ -69,6 +81,12 @@ func (p *Pool) Get(ctx context.Context) (Client, error) {
return p.clients.Acquire(ctx)
}

// Status returns the status of pool.
func (p *Pool) Status() Status {
status := p.clients.Status()
return Status(status)
}

// Close closes the pool and releases all clients in it.
func (p *Pool) Close() error {
ctx := context.Background()
Expand Down
86 changes: 86 additions & 0 deletions pool_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2025 FishGoddess. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package vex

import (
"context"
"fmt"
"sync/atomic"
"testing"
)

// go test -v -cover -run=^TestNewPool$
func TestPool(t *testing.T) {
ctx := context.Background()

address, done, err := runTestServer()
if err != nil {
t.Fatal(err)
}

defer done()

var clientPtr atomic.Pointer[Client]
dial := func(ctx context.Context) (Client, error) {
client, err := NewClient(address)
if err != nil {
return nil, err
}

clientPtr.Store(&client)
return client, nil
}

pool := NewPool(4, dial)
defer pool.Close()

for range 100 {
func() {
client, err := pool.Get(ctx)
if err != nil {
t.Fatal(err)
}

defer client.Close()

poolClient, ok := client.(poolClient)
if !ok {
t.Fatalf("got %T is wrong", client)
}

loadClient := clientPtr.Load()
if loadClient == nil {
t.Fatalf("load client is nil")
}

got := fmt.Sprintf("%p", poolClient.client)
want := fmt.Sprintf("%p", *loadClient)
if got != want {
t.Fatalf("got %s != want %s", got, want)
}

status := pool.Status()
wantStatus := Status{Limit: 4, Using: 1, Idle: 0, Waiting: 0}
if status != wantStatus {
t.Fatalf("got %+v != want %+v", status, wantStatus)
}
}()
}

status := pool.Status()
wantStatus := Status{Limit: 4, Using: 0, Idle: 1, Waiting: 0}
if status != wantStatus {
t.Fatalf("got %+v != want %+v", status, wantStatus)
}

if err = pool.Close(); err != nil {
t.Fatal(err)
}

_, err = pool.Get(ctx)
if err != errPoolClosed {
t.Fatalf("got %+v != want %+v", err, errPoolClosed)
}
}
Loading