• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tarantool / go-tarantool / 24095941689

07 Apr 2026 05:47PM UTC coverage: 74.565% (+0.4%) from 74.198%
24095941689

push

github

oleg-jukovec
api: add Allocator interface for response buffers

Previously, response buffer allocation was hardcoded with an internal
pooler implementation. Users had no control over memory management
for responses, which could be problematic for applications with
specific memory requirements or custom allocation strategies.

The new Allocator interface allows users to implement custom buffer
allocation and reuse strategies:

```
// Allocator is an interface for allocating and deallocating byte
// slices.
type Allocator interface {
    // Get returns a pointer to a byte slice of at least the given
    // length.
    // The caller should not assume anything about the slice's
    // capacity.
    //
    // If the allocator cannot allocate a buffer (e.g., invalid
    // length), it returns nil. The caller must handle this case
    // appropriately.
    Get(length int) *[]byte
    // Put returns a byte slice to the allocator for reuse.
    // After calling Put, the caller must not use the slice.
    //
    // The caller must ensure that the slice length remains unchanged
    // between Get and Put calls. Modifying the slice length before
    // calling Put may prevent the allocator from properly reusing the
    // buffer.
    Put(buf *[]byte)
}
```

The PoolAllocator type provides a ready-to-use implementation based
on sync.Pool for power-of-two sized byte slices.

The Opts.Allocator option enables configuring a custom allocator
for a connection. This is useful for applications that need to
optimize memory usage or integrate with custom memory management
systems.

Closes #493

80 of 90 new or added lines in 4 files covered. (88.89%)

232 existing lines in 4 files now uncovered.

3087 of 4140 relevant lines covered (74.57%)

10177.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.98
/poolalloc.go
1
package tarantool
2

3
import (
4
        "errors"
5
        "math/bits"
6
        "slices"
7
        "sync"
8
)
9

10
// PoolAllocator implements the Allocator interface using a set of sync.Pool
11
// instances for different power-of-two sized byte slices.
12
//
13
// The exponents parameter in NewPoolAllocator specifies the powers of two for
14
// the pool sizes. For example, []int{8, 10, 12} creates pools for 256, 1024,
15
// and 4096 byte slices.
16
type PoolAllocator struct {
17
        pool []*sync.Pool
18
        size []int
19
        help []int
20
}
21

22
var _ Allocator = (*PoolAllocator)(nil)
23

24
// NewPoolAllocator creates a new PoolAllocator with the given exponents.
25
// Each exponent represents a power of two pool size. For example, exponent 10
26
// creates a pool for 1024-byte slices.
27
//
28
// Exponents must be sorted in ascending order and each exponent must be
29
// in range [0, 31].
30
func NewPoolAllocator(exponents []int) (*PoolAllocator, error) {
29✔
31
        hSize := 32
29✔
32

29✔
33
        for i, s := range exponents {
95✔
34
                if s < 0 || s >= hSize {
68✔
35
                        return nil, errors.New("exponent must be in range [0, 31]")
2✔
36
                }
2✔
37

38
                if i > 0 && exponents[i-1] >= s {
66✔
39
                        return nil, errors.New("exponents must be sorted in ascending order")
2✔
40
                }
2✔
41
        }
42

43
        var p = PoolAllocator{
25✔
44
                size: make([]int, len(exponents)),
25✔
45
                pool: make([]*sync.Pool, len(exponents)),
25✔
46
                help: slices.Repeat([]int{-1}, hSize),
25✔
47
        }
25✔
48

25✔
49
        for i, s := range exponents {
83✔
50
                p.size[i] = 1 << s
58✔
51
                p.help[s] = i
58✔
52
                p.pool[i] = &sync.Pool{
58✔
53
                        New: func() interface{} {
81✔
54
                                buf := make([]byte, p.size[i])
23✔
55
                                return &buf
23✔
56
                        },
23✔
57
                }
58
        }
59

60
        for i := hSize - 2; i >= 0; i-- {
800✔
61
                if p.help[i] != -1 {
832✔
62
                        continue
57✔
63
                }
64

65
                p.help[i] = p.help[i+1]
718✔
66
        }
67

68
        return &p, nil
25✔
69
}
70

71
func (p *PoolAllocator) getInd(size int) int {
2,840✔
72
        if size <= 0 {
2,840✔
NEW
73
                return -1
×
NEW
74
        }
×
75

76
        idx := bits.Len(uint(size - 1))
2,840✔
77
        if idx >= len(p.help) {
2,840✔
NEW
78
                return -1
×
NEW
79
        }
×
80

81
        return p.help[idx]
2,840✔
82
}
83

84
// Get returns a pointer to a byte slice of at least the given length.
85
// If the requested size fits within one of the pool sizes, it returns a
86
// slice from the appropriate pool.
87
//
88
// It returns nil if:
89
//   - length is less than or equal to zero
90
//   - length exceeds the maximum pool size
91
func (p *PoolAllocator) Get(length int) *[]byte {
1,426✔
92
        if length <= 0 {
1,428✔
93
                return nil
2✔
94
        }
2✔
95

96
        ind := p.getInd(length)
1,424✔
97
        if ind == -1 {
1,429✔
98
                return nil
5✔
99
        }
5✔
100

101
        bs := p.pool[ind].Get().(*[]byte)
1,419✔
102
        *bs = (*bs)[:length]
1,419✔
103
        return bs
1,419✔
104
}
105

106
// Put returns a byte slice to the appropriate pool for reuse.
107
// The slice is cleared before being returned to the pool.
108
// If the slice size doesn't match any pool, it is discarded.
109
// If buf is nil, the method does nothing.
110
func (p *PoolAllocator) Put(buf *[]byte) {
1,417✔
111
        if buf == nil {
1,418✔
112
                return
1✔
113
        }
1✔
114

115
        if ind := p.getInd(len(*buf)); ind != -1 {
2,831✔
116
                clear((*buf)[:len(*buf)])
1,415✔
117
                p.pool[ind].Put(buf)
1,415✔
118
        }
1,415✔
119
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc