cubefs

Форк
0
/
extent_test.go 
302 строки · 9.6 Кб
1
// Copyright 2023 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 storage_test
16

17
import (
18
	"bytes"
19
	"fmt"
20
	"os"
21
	"syscall"
22
	"testing"
23

24
	"github.com/cubefs/cubefs/blobstore/blobnode/sys"
25
	"github.com/cubefs/cubefs/storage"
26
	"github.com/cubefs/cubefs/util"
27
	"github.com/stretchr/testify/require"
28
)
29

30
const (
31
	testTinyExtentID   = 1
32
	testNormalExtentID = 65
33

34
	dataStr  = "hello world"
35
	dataSize = int64(len(dataStr))
36
)
37

38
func getTestPathExtentName(id uint64) (string, func(), error) {
39
	dir, err := os.MkdirTemp(os.TempDir(), "cfs_storage_extent_")
40
	if err != nil {
41
		return "", nil, err
42
	}
43
	return fmt.Sprintf("%s/%d", dir, id), func() { os.RemoveAll(dir) }, nil
44
}
45

46
func mockCrcPersist(t *testing.T, e *storage.Extent, blockNo int, blockCrc uint32) (err error) {
47
	t.Logf("persist crc extent blockNo: %v blockCrc:%v", blockNo, blockCrc)
48
	return
49
}
50

51
func getMockCrcPersist(t *testing.T) storage.UpdateCrcFunc {
52
	return func(e *storage.Extent, blockNo int, crc uint32) (err error) {
53
		return mockCrcPersist(t, e, blockNo, crc)
54
	}
55
}
56

57
func normalExtentRwTest(t *testing.T, e *storage.Extent) {
58
	data := []byte(dataStr)
59
	_, err := e.Write(data, 0, 0, 0, storage.AppendWriteType, true, getMockCrcPersist(t), nil)
60
	require.Error(t, err)
61
	// append write
62
	_, err = e.Write(data, 0, int64(len(data)), 0, storage.AppendWriteType, true, getMockCrcPersist(t), nil)
63
	require.NoError(t, err)
64
	require.EqualValues(t, e.Size(), len(data))
65
	_, err = e.Read(data, 0, int64(len(data)), false)
66
	require.NoError(t, err)
67
	require.Equal(t, string(data), dataStr)
68
	// failed append write
69
	_, err = e.Write(data, 0, int64(len(data)), 0, storage.AppendWriteType, true, getMockCrcPersist(t), nil)
70
	require.Error(t, err)
71
	// random append write
72
	oldSize := e.Size()
73
	_, err = e.Write(data, 0, int64(len(data)), 0, storage.RandomWriteType, true, getMockCrcPersist(t), nil)
74
	require.NoError(t, err)
75
	require.Equal(t, e.Size(), oldSize)
76
	_, err = e.Read(data, 0, int64(len(data)), false)
77
	require.NoError(t, err)
78
	require.Equal(t, string(data), dataStr)
79
	_, err = e.Write(data, util.BlockSize, dataSize, 0, storage.RandomWriteType, true, getMockCrcPersist(t), nil)
80
	require.NoError(t, err)
81
	_, err = e.Write(data, util.ExtentSize, dataSize, 0, storage.RandomWriteType, true, getMockCrcPersist(t), nil)
82
	require.NoError(t, err)
83
	// TODO: append random write test
84
}
85

86
func tinyExtentRwTest(t *testing.T, e *storage.Extent) {
87
	data := []byte(dataStr)
88
	// write oversize
89
	_, err := e.Write(data, storage.ExtentMaxSize, dataSize, 0, storage.RandomWriteType, true, getMockCrcPersist(t), nil)
90
	require.ErrorIs(t, err, storage.ExtentIsFullError)
91
	// append write
92
	_, err = e.Write(data, 0, int64(len(data)), 0, storage.AppendWriteType, true, getMockCrcPersist(t), nil)
93
	require.NoError(t, err)
94
	require.EqualValues(t, e.Size()%util.PageSize, 0)
95
	_, err = e.Read(data, 0, int64(len(data)), false)
96
	require.NoError(t, err)
97
	require.Equal(t, string(data), dataStr)
98
	// failed append write
99
	_, err = e.Write(data, 0, int64(len(data)), 0, storage.AppendWriteType, true, getMockCrcPersist(t), nil)
100
	require.Error(t, err)
101
	// random write
102
	oldSize := e.Size()
103
	_, err = e.Write(data, int64(len(data)), int64(len(data)), 0, storage.RandomWriteType, true, getMockCrcPersist(t), nil)
104
	require.NoError(t, err)
105
	require.Equal(t, e.Size(), oldSize)
106
	_, err = e.Read(data, int64(len(data)), int64(len(data)), false)
107
	require.NoError(t, err)
108
	require.Equal(t, string(data), dataStr)
109
}
110

111
func normalExtentCreateTest(t *testing.T, name string) {
112
	e := storage.NewExtentInCore(name, testNormalExtentID)
113
	t.Log("normal-extent:", e)
114
	require.False(t, e.Exist())
115
	err := e.InitToFS()
116
	require.NoError(t, err)
117
	defer e.Close()
118
	normalExtentRwTest(t, e)
119
}
120

121
func normalExtentRecoveryTest(t *testing.T, name string) {
122
	e := storage.NewExtentInCore(name, testNormalExtentID)
123
	require.Equal(t, e.Exist(), true)
124
	t.Log("normal-extent:", e.String())
125
	err := e.RestoreFromFS()
126
	require.NoError(t, err)
127
	defer e.Close()
128
	for _, offset := range []int64{0, util.BlockSize, util.ExtentSize} {
129
		data := make([]byte, dataSize)
130
		_, err = e.Read(data, offset, dataSize, false)
131
		require.NoError(t, err)
132
		require.Equal(t, string(data), dataStr)
133
	}
134
}
135

136
func tinyExtentCreateTest(t *testing.T, name string) {
137
	e := storage.NewExtentInCore(name, testTinyExtentID)
138
	t.Log("tiny-extent:", e)
139
	require.False(t, e.Exist())
140
	require.ErrorIs(t, e.RestoreFromFS(), storage.ExtentNotFoundError)
141
	require.NoError(t, e.InitToFS())
142
	defer e.Close()
143
	tinyExtentRwTest(t, e)
144
}
145

146
func tinyExtentRecoveryTest(t *testing.T, name string) {
147
	e := storage.NewExtentInCore(name, testTinyExtentID)
148
	require.Equal(t, e.Exist(), true)
149
	err := e.RestoreFromFS()
150
	require.NoError(t, err)
151
	defer e.Close()
152
	data := make([]byte, dataSize)
153
	_, err = e.ReadTiny(data, 0, int64(len(data)), false)
154
	require.NoError(t, err)
155
	require.Equal(t, string(data), dataStr)
156
	_, err = e.Read(data, int64(len(data)), int64(len(data)), false)
157
	require.NoError(t, err)
158
	require.Equal(t, string(data), dataStr)
159
}
160

161
func tinyExtentRepairTest(t *testing.T, name string) {
162
	e := storage.NewExtentInCore(name, testTinyExtentID)
163
	require.Equal(t, e.Exist(), true)
164
	err := e.RestoreFromFS()
165
	require.NoError(t, err)
166
	defer e.Close()
167
	data := []byte(dataStr)
168
	size := e.Size()
169
	err = e.TinyExtentRecover(nil, size, int64(len(data)), 0, true)
170
	require.NoError(t, err)
171
	t.Logf("extent data size is %v", e.Size())
172
	_, err = e.Read(data, size, int64(len(data)), true)
173
	require.NoError(t, err)
174
	for _, v := range data {
175
		require.EqualValues(t, v, 0)
176
	}
177
	size = e.Size()
178
	data = []byte(dataStr)
179
	err = e.TinyExtentRecover(data, size, int64(len(data)), 0, false)
180
	require.NoError(t, err)
181
	_, err = e.Read(data, size, int64(len(data)), false)
182
	require.NoError(t, err)
183
	require.Equal(t, string(data), dataStr)
184
}
185

186
func TestTinyExtent(t *testing.T) {
187
	name, clean, err := getTestPathExtentName(testTinyExtentID)
188
	require.NoError(t, err)
189
	defer clean()
190
	tinyExtentCreateTest(t, name)
191
	tinyExtentRecoveryTest(t, name)
192
	tinyExtentRepairTest(t, name)
193
}
194

195
func TestNormalExtent(t *testing.T) {
196
	name, clean, err := getTestPathExtentName(testNormalExtentID)
197
	require.NoError(t, err)
198
	defer clean()
199
	normalExtentCreateTest(t, name)
200
	normalExtentRecoveryTest(t, name)
201
}
202

203
func TestSeekHole(t *testing.T) {
204
	var (
205
		info     os.FileInfo
206
		filePath = "./filename"
207
		err      error
208
		size     int64
209
	)
210
	os.Remove(filePath)
211
	defer os.Remove(filePath)
212
	e := storage.NewExtentInCore(filePath, 0)
213
	err = e.InitToFS()
214
	require.NoError(t, err)
215

216
	file := e.GetFile()
217
	info, err = file.Stat()
218
	require.NoError(t, err)
219

220
	size = e.GetDataSize(info.Size())
221
	t.Logf("data size %v, file stat size %v", size, info.Size())
222
	blockSize := info.Sys().(*syscall.Stat_t).Blksize
223
	t.Logf("blockSize %v", blockSize)
224
	headSize := 10 * 1024 * 1024
225
	file.Truncate(util.ExtentSize) // this necessary or else hole position not stable
226

227
	var size_ int
228
	data := bytes.Repeat([]byte("s"), headSize)
229

230
	// write at begin
231
	size_, err = file.Write(data)
232
	require.NoError(t, err)
233
	info, err = file.Stat()
234
	require.NoError(t, err)
235
	t.Logf("err %v,size %v, file stat size %v", err, size_, info.Size())
236

237
	// puch hole at the begin
238
	err = sys.Fallocate(file.Fd(), util.FallocFLPunchHole|util.FallocFLKeepSize, 4*1024, blockSize)
239
	require.NoError(t, err)
240

241
	midDataOffset := int64(util.ExtentSize / 4)
242
	_, err = file.WriteAt(data[:1024], midDataOffset)
243
	require.NoError(t, err)
244

245
	// write at middle
246
	midDataOffset = int64(util.ExtentSize / 2)
247
	size_, err = file.WriteAt(data[:1024], midDataOffset)
248
	require.NoError(t, err)
249
	info, err = file.Stat()
250
	t.Logf("err %v,size %v, file stat size %v", err, size_, info.Size())
251

252
	// calc last hole in 128M
253
	lastHole := midDataOffset + 1024
254
	alignlastHole := lastHole + (blockSize - lastHole%blockSize)
255
	t.Logf("write at %v size %v last hole off %v ,aligned off %v", midDataOffset, size_, lastHole, alignlastHole)
256

257
	// write after 128M
258
	_, err = file.WriteAt(data[:1024], int64(util.ExtentSize))
259
	require.NoError(t, err)
260

261
	// seek last hole in 128M
262
	info, err = file.Stat()
263
	size = e.GetDataSize(info.Size())
264
	t.Logf("datasize %v alignLastOff %v lastHoleOfData %v size %v", size, alignlastHole, lastHole, info.Size())
265
	require.NoError(t, err)
266

267
	file.Close()
268

269
	err = e.RestoreFromFS()
270
	require.NoError(t, err)
271

272
	dataSize, snapSize := e.GetSize()
273
	t.Logf("dataSize %v, snapSize %v", dataSize, snapSize)
274
	require.True(t, dataSize == alignlastHole)
275
}
276

277
func TestExtentRecovery(t *testing.T) {
278
	filePath := "./1025"
279
	os.Remove(filePath)
280
	defer os.Remove(filePath)
281
	e := storage.NewExtentInCore(filePath, 1025)
282
	err := e.InitToFS()
283
	require.NoError(t, err)
284

285
	headSize := 128 * 1024
286

287
	data := bytes.Repeat([]byte("s"), headSize)
288
	for i := 0; i < 10; i++ {
289
		_, err := e.Write(data, int64(i)*util.BlockSize, int64(headSize), 0, storage.AppendWriteType, true, getMockCrcPersist(t), nil)
290
		require.NoError(t, err)
291
	}
292
	for i := 0; i < 10; i++ {
293
		_, err := e.Write(data, int64(i)*util.BlockSize+util.ExtentSize, int64(headSize), 0, storage.AppendRandomWriteType, true, getMockCrcPersist(t), nil)
294
		require.NoError(t, err)
295
	}
296
	e.GetFile().Close()
297
	err = e.RestoreFromFS()
298
	require.NoError(t, err)
299
	dataSize, snapSize := e.GetSize()
300
	t.Logf("dataSize %v, snapSize %v", dataSize, snapSize)
301
	require.True(t, util.BlockSize*10 == dataSize)
302
}
303

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

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

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

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