cubefs

Форк
0
/
reader_test.go 
547 строк · 16.8 Кб
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 blobstore
16

17
import (
18
	"context"
19
	"fmt"
20
	"io"
21
	"math/rand"
22
	"os"
23
	"strings"
24
	"syscall"
25
	"testing"
26

27
	"github.com/brahma-adshonor/gohook"
28
	"github.com/stretchr/testify/assert"
29

30
	"github.com/cubefs/cubefs/blockcache/bcache"
31
	"github.com/cubefs/cubefs/proto"
32
	"github.com/cubefs/cubefs/sdk/data/manager"
33
	"github.com/cubefs/cubefs/sdk/data/stream"
34
	"github.com/cubefs/cubefs/sdk/meta"
35
	"github.com/cubefs/cubefs/util/errors"
36
)
37

38
func TestNewReader(t *testing.T) {
39
	mockConfig := ClientConfig{
40
		VolName:         "cfs",
41
		VolType:         0,
42
		BlockSize:       0,
43
		Ino:             2,
44
		Bc:              nil,
45
		Mw:              nil,
46
		Ec:              nil,
47
		Ebsc:            nil,
48
		EnableBcache:    false,
49
		WConcurrency:    0,
50
		ReadConcurrency: 0,
51
		CacheAction:     0,
52
		FileCache:       false,
53
		FileSize:        0,
54
		CacheThreshold:  0,
55
	}
56
	ec := &stream.ExtentClient{}
57
	err := gohook.HookMethod(ec, "Write", MockWriteTrue, nil)
58
	if err != nil {
59
		panic(fmt.Sprintf("Hook advance instance method failed:%s", err.Error()))
60
	}
61
	mockConfig.Ec = ec
62

63
	reader := NewReader(mockConfig)
64
	assert.NotEmpty(t, reader, nil)
65
}
66

67
func TestBuildExtentKey(t *testing.T) {
68
	testCase := []struct {
69
		eks      []proto.ExtentKey
70
		expectEk proto.ExtentKey
71
	}{
72
		{nil, proto.ExtentKey{}},
73
		{[]proto.ExtentKey{
74
			{FileOffset: uint64(0), Size: uint32(100)},
75
			{FileOffset: uint64(100), Size: uint32(100)},
76
			{FileOffset: uint64(200), Size: uint32(100)},
77
			{FileOffset: uint64(300), Size: uint32(100)},
78
		}, proto.ExtentKey{FileOffset: uint64(100), Size: uint32(100)}},
79
		{[]proto.ExtentKey{
80
			{FileOffset: uint64(0), Size: uint32(1)},
81
			{FileOffset: uint64(1), Size: uint32(1)},
82
			{FileOffset: uint64(2), Size: uint32(1)},
83
			{FileOffset: uint64(3), Size: uint32(1)},
84
		}, proto.ExtentKey{}},
85
	}
86

87
	rs := &rwSlice{}
88
	rs.objExtentKey = proto.ObjExtentKey{FileOffset: 100, Size: 100}
89
	for _, tc := range testCase {
90
		reader := Reader{}
91
		reader.limitManager = manager.NewLimitManager(nil)
92
		reader.extentKeys = tc.eks
93
		reader.buildExtentKey(rs)
94
		assert.Equal(t, tc.expectEk, rs.extentKey)
95
	}
96
}
97

98
func TestFileSize(t *testing.T) {
99
	testCase := []struct {
100
		valid      bool
101
		objEks     []proto.ObjExtentKey
102
		expectSize uint64
103
		expectOk   bool
104
	}{
105
		{false, nil, 0, false},
106
		{true, nil, 0, true},
107
		{true, []proto.ObjExtentKey{{Size: uint64(100), FileOffset: uint64(100)}}, 200, true},
108
	}
109

110
	for _, tc := range testCase {
111
		reader := Reader{}
112
		reader.limitManager = manager.NewLimitManager(nil)
113
		reader.valid = tc.valid
114
		reader.objExtentKeys = tc.objEks
115
		gotSize, gotOk := reader.fileSize()
116
		assert.Equal(t, tc.expectSize, gotSize)
117
		assert.Equal(t, tc.expectOk, gotOk)
118
	}
119

120
	//// mock objExtentKey
121
	//objEks := make([]proto.ObjExtentKey, 0)
122
	//objEkLen := rand.Intn(20)
123
	//expectedFileSize := 0
124
	//for i := 0; i < objEkLen; i++ {
125
	//	size := rand.Intn(1000)
126
	//	objEks = append(objEks, proto.ObjExtentKey{Size: uint64(size), FileOffset: uint64(expectedFileSize)})
127
	//	expectedFileSize += size
128
	//}
129
	//
130
	//// mock reader
131
	//mockConfig := ClientConfig{
132
	//	VolName:         "cfs",
133
	//	VolType:         0,
134
	//	BlockSize:       0,
135
	//	Ino:             2,
136
	//	Bc:              nil,
137
	//	Mw:              nil,
138
	//	Ec:              nil,
139
	//	Bsc:            nil,
140
	//	EnableBcache:    false,
141
	//	WConcurrency:    0,
142
	//	ReadConcurrency: 0,
143
	//	CacheAction:     0,
144
	//	FileCache:       false,
145
	//	FileSize:        0,
146
	//	CacheThreshold:  0,
147
	//}
148
	//reader := NewReader(mockConfig)
149
	//reader.valid = true
150
	//reader.objExtentKeys = objEks
151
	//
152
	//got, ok := reader.fileSize()
153
	//assert.True(t, true, ok)
154
	//assert.Equal(t, expectedFileSize, int(got))
155
	//
156
	//ctx := context.Background()
157
	//reader.Close(ctx)
158
}
159

160
func TestRefreshEbsExtents(t *testing.T) {
161
	testCase := []struct {
162
		getObjFunc  func(*meta.MetaWrapper, uint64) (uint64, uint64, []proto.ExtentKey, []proto.ObjExtentKey, error)
163
		expectValid bool
164
	}{
165
		{MockGetObjExtentsTrue, true},
166
		{MockGetObjExtentsFalse, false},
167
	}
168

169
	for _, tc := range testCase {
170
		reader := Reader{}
171
		reader.limitManager = manager.NewLimitManager(nil)
172
		mw := &meta.MetaWrapper{}
173
		err := gohook.HookMethod(mw, "GetObjExtents", tc.getObjFunc, nil)
174
		if err != nil {
175
			panic(fmt.Sprintf("Hook advance instance method failed:%s", err.Error()))
176
		}
177
		reader.mw = mw
178
		reader.refreshEbsExtents()
179
		assert.Equal(t, reader.valid, tc.expectValid)
180
	}
181
}
182

183
func TestPrepareEbsSlice(t *testing.T) {
184
	testCase := []struct {
185
		getObjFunc  func(*meta.MetaWrapper, uint64) (uint64, uint64, []proto.ExtentKey, []proto.ObjExtentKey, error)
186
		offset      int
187
		size        uint32
188
		expectError error
189
	}{
190
		{nil, -1, 100, syscall.EIO},
191
		{MockGetObjExtentsTrue, 0, 100, nil},
192
		{MockGetObjExtentsTrue, 501, 100, io.EOF},
193
		{MockGetObjExtentsTrue, 400, 101, nil},
194
		{MockGetObjExtentsFalse, 0, 100, syscall.EIO},
195
		{MockGetObjExtentsFalse, 501, 100, syscall.EIO},
196
		{MockGetObjExtentsFalse, 400, 101, syscall.EIO},
197
	}
198

199
	for _, tc := range testCase {
200
		mw := &meta.MetaWrapper{}
201
		err := gohook.HookMethod(mw, "GetObjExtents", tc.getObjFunc, nil)
202
		if err != nil {
203
			panic(fmt.Sprintf("Hook advance instance method failed:%s", err.Error()))
204
		}
205
		reader := Reader{}
206
		reader.limitManager = manager.NewLimitManager(nil)
207
		reader.mw = mw
208
		_, got := reader.prepareEbsSlice(tc.offset, tc.size)
209
		assert.Equal(t, tc.expectError, got)
210
	}
211
}
212

213
func TestRead(t *testing.T) {
214
	testCase := []struct {
215
		close            bool
216
		readConcurrency  int
217
		getObjFunc       func(*meta.MetaWrapper, uint64) (uint64, uint64, []proto.ExtentKey, []proto.ObjExtentKey, error)
218
		bcacheGetFunc    func(*bcache.BcacheClient, string, []byte, uint64, uint32) (int, error)
219
		checkDpExistFunc func(*stream.ExtentClient, uint64) error
220
		readExtentFunc   func(*stream.ExtentClient, uint64, *proto.ExtentKey, []byte, int, int) (int, error, bool)
221
		ebsReadFunc      func(*BlobStoreClient, context.Context, string, []byte, uint64, uint64, proto.ObjExtentKey) (int, error)
222
		expectError      error
223
	}{
224
		{true, 2, MockGetObjExtentsTrue, MockGetTrue, MockCheckDataPartitionExistTrue, MockReadExtentTrue, MockEbscReadTrue, os.ErrInvalid},
225
		{false, 2, MockGetObjExtentsFalse, MockGetTrue, MockCheckDataPartitionExistTrue, MockReadExtentTrue, MockEbscReadTrue, syscall.EIO},
226
		{false, 2, MockGetObjExtentsTrue, MockGetTrue, MockCheckDataPartitionExistTrue, MockReadExtentTrue, MockEbscReadFalse, syscall.EIO},
227
		{false, 2, MockGetObjExtentsTrue, MockGetTrue, MockCheckDataPartitionExistTrue, MockReadExtentTrue, MockEbscReadTrue, nil},
228
	}
229

230
	for _, tc := range testCase {
231
		reader := &Reader{}
232
		reader.limitManager = manager.NewLimitManager(nil)
233
		reader.close = tc.close
234
		reader.readConcurrency = tc.readConcurrency
235

236
		mw := &meta.MetaWrapper{}
237
		ebsc := &BlobStoreClient{}
238
		bc := &bcache.BcacheClient{}
239
		ec := &stream.ExtentClient{}
240
		err := gohook.HookMethod(mw, "GetObjExtents", tc.getObjFunc, nil)
241
		if err != nil {
242
			panic(fmt.Sprintf("Hook advance instance method failed:%s", err.Error()))
243
		}
244
		err = gohook.HookMethod(ec, "CheckDataPartitionExsit", tc.checkDpExistFunc, nil)
245
		if err != nil {
246
			panic(fmt.Sprintf("Hook advance instance method failed:%s", err.Error()))
247
		}
248
		err = gohook.HookMethod(ec, "ReadExtent", tc.readExtentFunc, nil)
249
		if err != nil {
250
			panic(fmt.Sprintf("Hook advance instance method failed:%s", err.Error()))
251
		}
252
		err = gohook.HookMethod(ebsc, "Read", tc.ebsReadFunc, nil)
253
		if err != nil {
254
			panic(fmt.Sprintf("Hook advance instance method failed:%s", err.Error()))
255
		}
256
		err = gohook.HookMethod(bc, "Get", tc.bcacheGetFunc, nil)
257
		if err != nil {
258
			panic(fmt.Sprintf("Hook advance instance method failed:%s", err.Error()))
259
		}
260
		reader.mw = mw
261
		reader.ebs = ebsc
262
		reader.bc = bc
263
		reader.ec = ec
264

265
		ctx := context.Background()
266
		buf := make([]byte, 500)
267
		_, gotError := reader.Read(ctx, buf, 0, 100)
268
		assert.Equal(t, tc.expectError, gotError)
269
	}
270
}
271

272
func TestAsyncCache(t *testing.T) {
273
	ebsc := &BlobStoreClient{}
274
	ec := &stream.ExtentClient{}
275
	bc := &bcache.BcacheClient{}
276
	err := gohook.HookMethod(ec, "Write", MockWriteTrue, nil)
277
	if err != nil {
278
		panic(fmt.Sprintf("Hook advance instance method failed:%s", err.Error()))
279
	}
280
	err = gohook.HookMethod(bc, "Put", MockPutTrue, nil)
281
	if err != nil {
282
		panic(fmt.Sprintf("Hook advance instance method failed:%s", err.Error()))
283
	}
284

285
	testCase := []struct {
286
		ebsReadFunc  func(*BlobStoreClient, context.Context, string, []byte, uint64, uint64, proto.ObjExtentKey) (int, error)
287
		cacheAction  int
288
		enableBcache bool
289
		fileSize     uint64
290
	}{
291
		{MockEbscReadTrue, proto.NoCache, true, rand.Uint64() % 1000},
292
		{MockEbscReadTrue, proto.RCache, true, rand.Uint64() % 1000},
293
		{MockEbscReadTrue, proto.RWCache, true, rand.Uint64() % 1000},
294
		{MockEbscReadTrue, proto.NoCache, false, rand.Uint64() % 1000},
295
		{MockEbscReadTrue, proto.RCache, false, rand.Uint64() % 1000},
296
		{MockEbscReadTrue, proto.RWCache, false, rand.Uint64() % 1000},
297
		{MockEbscReadFalse, proto.NoCache, true, rand.Uint64() % 1000},
298
		{MockEbscReadFalse, proto.RCache, true, rand.Uint64() % 1000},
299
		{MockEbscReadFalse, proto.RWCache, true, rand.Uint64() % 1000},
300
		{MockEbscReadFalse, proto.NoCache, false, rand.Uint64() % 1000},
301
		{MockEbscReadFalse, proto.RCache, false, rand.Uint64() % 1000},
302
		{MockEbscReadFalse, proto.RWCache, false, rand.Uint64() % 1000},
303
	}
304

305
	size := rand.Intn(1000)
306
	objEk := proto.ObjExtentKey{
307
		Cid:        0,
308
		CodeMode:   0,
309
		BlobSize:   0,
310
		BlobsLen:   0,
311
		Size:       uint64(size),
312
		Blobs:      nil,
313
		FileOffset: 0,
314
		Crc:        0,
315
	}
316

317
	for _, tc := range testCase {
318
		reader := Reader{}
319
		reader.limitManager = manager.NewLimitManager(nil)
320
		reader.cacheThreshold = 1000
321
		ctx := context.Background()
322
		err := gohook.HookMethod(ebsc, "Read", tc.ebsReadFunc, nil)
323
		if err != nil {
324
			t.Fatal(fmt.Sprintf("Hook advance instance method failed:%s", err.Error()))
325
		}
326
		reader.fileLength = tc.fileSize
327
		reader.cacheAction = tc.cacheAction
328
		reader.asyncCache(ctx, "cacheKey", objEk)
329
	}
330
}
331

332
func TestNeedCacheL2(t *testing.T) {
333
	testCase := []struct {
334
		cacheAction    int
335
		fileLength     uint64
336
		cacheThreshold int
337
		fileCache      bool
338
		expectCache    bool
339
	}{
340
		{proto.NoCache, 10, 100, false, false},
341
		{proto.NoCache, 10, 100, true, true},
342
		{proto.NoCache, 101, 100, true, true},
343
		{proto.NoCache, 101, 100, false, false},
344
		{proto.RCache, 10, 100, false, true},
345
		{proto.RCache, 10, 100, true, true},
346
		{proto.RCache, 101, 100, false, false},
347
		{proto.RCache, 101, 100, true, true},
348
		{proto.RWCache, 10, 100, false, true},
349
		{proto.RWCache, 10, 100, true, true},
350
		{proto.RWCache, 101, 100, false, false},
351
		{proto.RWCache, 101, 100, true, true},
352
	}
353

354
	for _, tc := range testCase {
355
		reader := Reader{}
356
		reader.limitManager = manager.NewLimitManager(nil)
357
		reader.cacheAction = tc.cacheAction
358
		reader.fileLength = tc.fileLength
359
		reader.cacheThreshold = tc.cacheThreshold
360
		reader.fileCache = tc.fileCache
361
		got := reader.needCacheL2()
362
		assert.Equal(t, tc.expectCache, got)
363
	}
364
}
365

366
func TestNeedCacheL1(t *testing.T) {
367
	testCase := []struct {
368
		enableCache bool
369
		expectCache bool
370
	}{
371
		{true, true},
372
		{false, false},
373
	}
374

375
	for _, tc := range testCase {
376
		reader := Reader{}
377
		reader.limitManager = manager.NewLimitManager(nil)
378
		reader.enableBcache = tc.enableCache
379
		got := reader.needCacheL1()
380
		assert.Equal(t, tc.expectCache, got)
381
	}
382
}
383

384
func TestReadSliceRange(t *testing.T) {
385
	testCase := []struct {
386
		enableBcache     bool
387
		extentKey        proto.ExtentKey
388
		bcacheGetFunc    func(*bcache.BcacheClient, string, []byte, uint64, uint32) (int, error)
389
		checkDpExistFunc func(*stream.ExtentClient, uint64) error
390
		readExtentFunc   func(*stream.ExtentClient, uint64, *proto.ExtentKey, []byte, int, int) (int, error, bool)
391
		ebsReadFunc      func(*BlobStoreClient, context.Context, string, []byte, uint64, uint64, proto.ObjExtentKey) (int, error)
392
		expectError      error
393
	}{
394
		{
395
			false,
396
			proto.ExtentKey{},
397
			MockGetTrue, MockCheckDataPartitionExistTrue,
398
			MockReadExtentTrue, MockEbscReadTrue, nil,
399
		},
400
		{
401
			false,
402
			proto.ExtentKey{},
403
			MockGetTrue, MockCheckDataPartitionExistTrue,
404
			MockReadExtentTrue, MockEbscReadFalse, syscall.EIO,
405
		},
406
		{
407
			true,
408
			proto.ExtentKey{},
409
			MockGetTrue, MockCheckDataPartitionExistTrue,
410
			MockReadExtentTrue, MockEbscReadFalse, nil,
411
		},
412
		{
413
			true,
414
			proto.ExtentKey{},
415
			MockGetFalse, MockCheckDataPartitionExistTrue,
416
			MockReadExtentTrue, MockEbscReadFalse, syscall.EIO,
417
		},
418
		{
419
			true,
420
			proto.ExtentKey{},
421
			MockGetFalse, MockCheckDataPartitionExistTrue,
422
			MockReadExtentTrue, MockEbscReadTrue, nil,
423
		},
424
	}
425

426
	for _, tc := range testCase {
427
		reader := &Reader{}
428
		reader.limitManager = manager.NewLimitManager(nil)
429
		ebsc := &BlobStoreClient{}
430
		bc := &bcache.BcacheClient{}
431
		ec := &stream.ExtentClient{}
432
		reader.volName = "cfs"
433
		reader.ino = 12407
434
		reader.fileLength = 10
435
		reader.cacheThreshold = 100
436
		reader.err = make(chan error)
437
		rs := &rwSlice{}
438
		rs.rSize = uint32(len("Hello world"))
439
		rs.Data = make([]byte, len("Hello world"))
440
		rs.extentKey = tc.extentKey
441

442
		reader.enableBcache = tc.enableBcache
443
		err := gohook.HookMethod(ebsc, "Read", tc.ebsReadFunc, nil)
444
		if err != nil {
445
			panic(fmt.Sprintf("Hook advance instance method failed:%s", err.Error()))
446
		}
447
		err = gohook.HookMethod(bc, "Get", tc.bcacheGetFunc, nil)
448
		if err != nil {
449
			panic(fmt.Sprintf("Hook advance instance method failed:%s", err.Error()))
450
		}
451
		err = gohook.HookMethod(ec, "CheckDataPartitionExsit", tc.checkDpExistFunc, nil)
452
		if err != nil {
453
			panic(fmt.Sprintf("Hook advance instance method failed:%s", err.Error()))
454
		}
455
		err = gohook.HookMethod(ec, "ReadExtent", tc.readExtentFunc, nil)
456
		if err != nil {
457
			panic(fmt.Sprintf("Hook advance instance method failed:%s", err.Error()))
458
		}
459
		reader.ebs = ebsc
460
		reader.ec = ec
461
		reader.bc = bc
462

463
		ctx := context.Background()
464
		reader.wg.Add(1)
465
		go func() {
466
			<-reader.err
467
		}()
468
		gotError := reader.readSliceRange(ctx, rs)
469
		assert.Equal(t, tc.expectError, gotError)
470
	}
471
}
472

473
func MockGetObjExtentsTrue(m *meta.MetaWrapper, inode uint64) (gen uint64, size uint64,
474
	extents []proto.ExtentKey, objExtents []proto.ObjExtentKey, err error) {
475
	objEks := make([]proto.ObjExtentKey, 0)
476
	objEkLen := 5
477
	expectedFileSize := 0
478
	for i := 0; i < objEkLen; i++ {
479
		size := 100
480
		objEks = append(objEks, proto.ObjExtentKey{Size: uint64(100), FileOffset: uint64(expectedFileSize)})
481
		expectedFileSize += size
482
	}
483
	return 1, 1, nil, objEks, nil
484
}
485

486
func MockGetObjExtentsFalse(m *meta.MetaWrapper, inode uint64) (gen uint64, size uint64,
487
	extents []proto.ExtentKey, objExtents []proto.ObjExtentKey, err error) {
488
	return 1, 1, nil, nil, errors.New("Get objEks failed")
489
}
490

491
func MockEbscReadTrue(ebsc *BlobStoreClient, ctx context.Context, volName string,
492
	buf []byte, offset uint64, size uint64,
493
	oek proto.ObjExtentKey) (readN int, err error) {
494
	reader := strings.NewReader("Hello world.")
495
	readN, err = io.ReadFull(reader, buf)
496
	return readN, nil
497
}
498

499
func MockEbscReadFalse(ebsc *BlobStoreClient, ctx context.Context, volName string,
500
	buf []byte, offset uint64, size uint64,
501
	oek proto.ObjExtentKey) (readN int, err error) {
502
	return 0, syscall.EIO
503
}
504

505
func MockReadExtentTrue(client *stream.ExtentClient, inode uint64, ek *proto.ExtentKey,
506
	data []byte, offset int, size int) (read int, err error, b bool) {
507
	return len("Hello world"), nil, true
508
}
509

510
func MockReadExtentFalse(client *stream.ExtentClient, inode uint64, ek *proto.ExtentKey,
511
	data []byte, offset int, size int) (read int, err error) {
512
	return 0, errors.New("Read extent failed")
513
}
514

515
func MockCheckDataPartitionExistTrue(client *stream.ExtentClient, partitionID uint64) error {
516
	return nil
517
}
518

519
func MockCheckDataPartitionExistFalse(client *stream.ExtentClient, partitionID uint64) error {
520
	return errors.New("CheckDataPartitionExist failed")
521
}
522

523
func MockWriteTrue(client *stream.ExtentClient, inode uint64, offset int, data []byte,
524
	flags int, checkFunc func() error) (write int, err error) {
525
	return len(data), nil
526
}
527

528
func MockWriteFalse(client *stream.ExtentClient, inode uint64, offset int, data []byte,
529
	flags int) (write int, err error) {
530
	return 0, errors.New("Write failed")
531
}
532

533
func MockPutTrue(bc *bcache.BcacheClient, key string, buf []byte) error {
534
	return nil
535
}
536

537
func MockPutFalse(bc *bcache.BcacheClient, key string, buf []byte) error {
538
	return errors.New("Bcache put failed")
539
}
540

541
func MockGetTrue(bc *bcache.BcacheClient, key string, buf []byte, offset uint64, size uint32) (int, error) {
542
	return int(size), nil
543
}
544

545
func MockGetFalse(bc *bcache.BcacheClient, key string, buf []byte, offset uint64, size uint32) (int, error) {
546
	return 0, errors.New("Bcache get failed")
547
}
548

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

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

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

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