cubefs
147 строк · 3.5 Кб
1// Copyright 2022 The CubeFS Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12// implied. See the License for the specific language governing
13// permissions and limitations under the License.
14
15package resourcepool16
17import (18"errors"19"sort"20)
21
22// ErrNoSuitableSizeClass no suitable pool of size
23var ErrNoSuitableSizeClass = errors.New("no suitable size class")24
25// zero bytes, high performance at the 16KB, see more in the benchmark:
26// BenchmarkZero/4MB-16KB-4 13338 88378 ns/op
27// BenchmarkZero/8MB-16KB-4 6670 183987 ns/op
28// BenchmarkZero/16MB-16KB-4 1926 590422 ns/op
29const zeroLen = 1 << 1430
31var zero = make([]byte, zeroLen)32
33// MemPool reused buffer pool
34type MemPool struct {35pool []Pool36poolSize []int37}
38
39// Status memory pools status
40type Status []PoolStatus41
42// PoolStatus status of the pool
43type PoolStatus struct {44Size int `json:"size"`45Capacity int `json:"capacity"`46Running int `json:"running"`47Idle int `json:"idle"`48}
49
50// NewMemPool returns a MemPool within chan pool
51func NewMemPool(sizeClasses map[int]int) *MemPool {52return NewMemPoolWith(sizeClasses, func(size, capacity int) Pool {53return NewChanPool(func() []byte {54return make([]byte, size)55}, capacity)56})57}
58
59// NewMemPoolWith new MemPool with size-class and self-defined pool
60func NewMemPoolWith(sizeClasses map[int]int, newPool func(size, capacity int) Pool) *MemPool {61pool := make([]Pool, 0, len(sizeClasses))62poolSize := make([]int, 0, len(sizeClasses))63for sizeClass := range sizeClasses {64if sizeClass > 0 {65poolSize = append(poolSize, sizeClass)66}67}68
69sort.Ints(poolSize)70for _, sizeClass := range poolSize {71pool = append(pool, newPool(sizeClass, sizeClasses[sizeClass]))72}73
74return &MemPool{75pool: pool,76poolSize: poolSize,77}78}
79
80// Get return a suitable buffer
81func (p *MemPool) Get(size int) ([]byte, error) {82for idx, ps := range p.poolSize {83if size <= ps {84buf, err := p.pool[idx].Get()85if err != nil {86return nil, err87}88buff := buf.([]byte)89return buff[:size], nil90}91}92
93return nil, ErrNoSuitableSizeClass94}
95
96// Alloc return a buffer, make a new if oversize
97func (p *MemPool) Alloc(size int) ([]byte, error) {98buf, err := p.Get(size)99if err == ErrNoSuitableSizeClass {100return make([]byte, size), nil101}102
103return buf, err104}
105
106// Put adds x to the pool, appropriately resize
107func (p *MemPool) Put(b []byte) error {108sizeClass := cap(b)109b = b[0:sizeClass]110for ii := len(p.poolSize) - 1; ii >= 0; ii-- {111if sizeClass >= p.poolSize[ii] {112b = b[0:p.poolSize[ii]]113p.pool[ii].Put(b)114return nil115}116}117
118return ErrNoSuitableSizeClass119}
120
121// Zero clean up the buffer b to zero bytes
122func (p *MemPool) Zero(b []byte) {123Zero(b)124}
125
126// Status returns status of memory pool
127func (p *MemPool) Status() Status {128st := make(Status, len(p.poolSize))129for idx, size := range p.poolSize {130pool := p.pool[idx]131st[idx] = PoolStatus{132Size: size,133Capacity: pool.Cap(),134Running: pool.Len(),135Idle: pool.Idle(),136}137}138return st139}
140
141// Zero clean up the buffer b to zero bytes
142func Zero(b []byte) {143for len(b) > 0 {144n := copy(b, zero)145b = b[n:]146}147}
148