cubefs

Форк
0
208 строк · 5.2 Кб
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

15
package ec
16

17
import (
18
	"github.com/cubefs/cubefs/blobstore/common/codemode"
19
	"github.com/cubefs/cubefs/blobstore/common/resourcepool"
20
	"github.com/cubefs/cubefs/blobstore/util/log"
21
)
22

23
// Buffer one ec blob's reused buffer
24
// Manually manage the DataBuf in Ranged mode, do not Split it
25
//  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
26
//  |   data      |    align bytes    |       partiy        | local |
27
//  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
28
//  |   DataBuf   |
29
//  |<--DataSize->|
30
//  - - - - - - - - - - - - - - - - - -
31
//  |            ECDataBuf            |
32
//  |<--         ECDataSize        -->|
33
//  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
34
//  |                           ECBuf                               |
35
//  |<---                       ECSize                          --->|
36
type Buffer struct {
37
	tactic codemode.Tactic
38
	pool   *resourcepool.MemPool
39

40
	// DataBuf real data buffer
41
	DataBuf []byte
42
	// ECDataBuf ec data buffer to Split,
43
	// is nil if Buffer is Ranged mode
44
	ECDataBuf []byte
45
	// BufferSizes all sizes
46
	BufferSizes
47
}
48

49
// BufferSizes all sizes
50
// ECSize is sum of all ec shards size,
51
// not equal the capacity of DataBuf in Ranged mode
52
type BufferSizes struct {
53
	ShardSize  int // per shard size
54
	DataSize   int // real data size
55
	ECDataSize int // ec data size only with data
56
	ECSize     int // ec buffer size with partiy and local shards
57
	From       int // ranged from
58
	To         int // ranged to
59
}
60

61
func isOutOfRange(dataSize, from, to int) bool {
62
	return dataSize <= 0 || to < from ||
63
		from < 0 || from > dataSize ||
64
		to < 0 || to > dataSize
65
}
66

67
func newBuffer(dataSize, from, to int, tactic codemode.Tactic, pool *resourcepool.MemPool, hasParity bool) (*Buffer, error) {
68
	if isOutOfRange(dataSize, from, to) {
69
		return nil, ErrShortData
70
	}
71

72
	shardN := tactic.N
73
	if shardN <= 0 {
74
		return nil, ErrInvalidCodeMode
75
	}
76

77
	shardSize := (dataSize + shardN - 1) / shardN
78
	// align per shard with tactic MinShardSize
79
	if shardSize < tactic.MinShardSize {
80
		shardSize = tactic.MinShardSize
81
	}
82

83
	ecDataSize := shardSize * tactic.N
84
	ecSize := shardSize * (tactic.N + tactic.M + tactic.L)
85

86
	var (
87
		err error
88

89
		buf       []byte
90
		dataBuf   []byte
91
		ecDataBuf []byte
92
	)
93
	if pool != nil {
94
		size := ecSize
95
		if !hasParity {
96
			size = to - from
97
		}
98

99
		buf, err = pool.Get(size)
100
		if err == resourcepool.ErrNoSuitableSizeClass {
101
			log.Warn(err, "for", size, "try to alloc bytes")
102
			buf, err = pool.Alloc(size)
103
		}
104
		if err != nil {
105
			return nil, err
106
		}
107

108
		if !hasParity {
109
			dataBuf = buf[:size]
110
			ecDataBuf = nil
111
		} else {
112
			// zero the padding bytes of data section
113
			pool.Zero(buf[dataSize:ecDataSize])
114
			dataBuf = buf[:dataSize]
115
			ecDataBuf = buf[:ecDataSize]
116
		}
117
	}
118

119
	return &Buffer{
120
		tactic:    tactic,
121
		pool:      pool,
122
		DataBuf:   dataBuf,
123
		ECDataBuf: ecDataBuf,
124
		BufferSizes: BufferSizes{
125
			ShardSize:  shardSize,
126
			DataSize:   dataSize,
127
			ECDataSize: ecDataSize,
128
			ECSize:     ecSize,
129
			From:       from,
130
			To:         to,
131
		},
132
	}, nil
133
}
134

135
// NewBuffer new ec buffer with data size and ec mode
136
func NewBuffer(dataSize int, tactic codemode.Tactic, pool *resourcepool.MemPool) (*Buffer, error) {
137
	return newBuffer(dataSize, 0, dataSize, tactic, pool, true)
138
}
139

140
// NewRangeBuffer ranged buffer with least data size
141
func NewRangeBuffer(dataSize, from, to int, tactic codemode.Tactic, pool *resourcepool.MemPool) (*Buffer, error) {
142
	return newBuffer(dataSize, from, to, tactic, pool, false)
143
}
144

145
// GetBufferSizes calculate ec buffer sizes
146
func GetBufferSizes(dataSize int, tactic codemode.Tactic) (BufferSizes, error) {
147
	buf, err := NewBuffer(dataSize, tactic, nil)
148
	if err != nil {
149
		return BufferSizes{}, err
150
	}
151
	return buf.BufferSizes, nil
152
}
153

154
// Resize re-calculate ec buffer, alloc a new buffer if oversize
155
func (b *Buffer) Resize(dataSize int) error {
156
	if dataSize == b.BufferSizes.DataSize {
157
		return nil
158
	}
159

160
	sizes, err := GetBufferSizes(dataSize, b.tactic)
161
	if err != nil {
162
		return err
163
	}
164

165
	// buffer is enough
166
	if sizes.ECSize <= cap(b.DataBuf) {
167
		buf := b.DataBuf[:cap(b.DataBuf)]
168
		// zero the padding bytes of data section
169
		b.pool.Zero(buf[sizes.DataSize:sizes.ECDataSize])
170

171
		b.DataBuf = buf[:sizes.DataSize]
172
		b.ECDataBuf = buf[:sizes.ECDataSize]
173
		b.BufferSizes = sizes
174
		return nil
175
	}
176

177
	newb, err := NewBuffer(dataSize, b.tactic, b.pool)
178
	if err != nil {
179
		return err
180
	}
181

182
	b.Release()
183
	*b = *newb
184
	return nil
185
}
186

187
// Release recycles the buffer into pool
188
func (b *Buffer) Release() error {
189
	if b == nil {
190
		return nil
191
	}
192
	if b.DataBuf == nil {
193
		b.pool = nil
194
		return nil
195
	}
196

197
	buf := b.DataBuf
198
	b.DataBuf = nil
199
	b.ECDataBuf = nil
200

201
	pool := b.pool
202
	b.pool = nil
203
	if pool != nil {
204
		return pool.Put(buf)
205
	}
206

207
	return nil
208
}
209

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.