github.com/matrixorigin/matrixone@v1.2.0/pkg/fileservice/local_fs_test.go (about)

     1  // Copyright 2022 Matrix Origin
     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 implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package fileservice
    16  
    17  import (
    18  	"context"
    19  	"crypto/rand"
    20  	"fmt"
    21  	"io"
    22  	"testing"
    23  
    24  	"github.com/matrixorigin/matrixone/pkg/fileservice/memorycache"
    25  	"github.com/matrixorigin/matrixone/pkg/perfcounter"
    26  	"github.com/matrixorigin/matrixone/pkg/util/toml"
    27  	"github.com/stretchr/testify/assert"
    28  )
    29  
    30  func TestLocalFS(t *testing.T) {
    31  
    32  	t.Run("file service", func(t *testing.T) {
    33  		testFileService(t, 0, func(name string) FileService {
    34  			ctx := context.Background()
    35  			dir := t.TempDir()
    36  			fs, err := NewLocalFS(ctx, name, dir, DisabledCacheConfig, nil)
    37  			assert.Nil(t, err)
    38  			return fs
    39  		})
    40  	})
    41  
    42  	t.Run("with memory cache", func(t *testing.T) {
    43  		testFileService(t, 0, func(name string) FileService {
    44  			ctx := context.Background()
    45  			dir := t.TempDir()
    46  			fs, err := NewLocalFS(ctx, name, dir, CacheConfig{
    47  				MemoryCapacity: ptrTo[toml.ByteSize](128 * 1024),
    48  			}, nil)
    49  			assert.Nil(t, err)
    50  			return fs
    51  		})
    52  	})
    53  
    54  	t.Run("mutable file service", func(t *testing.T) {
    55  		testMutableFileService(t, func() MutableFileService {
    56  			ctx := context.Background()
    57  			dir := t.TempDir()
    58  			fs, err := NewLocalFS(ctx, "local", dir, DisabledCacheConfig, nil)
    59  			assert.Nil(t, err)
    60  			return fs
    61  		})
    62  	})
    63  
    64  	t.Run("replaceable file service", func(t *testing.T) {
    65  		testReplaceableFileService(t, func() ReplaceableFileService {
    66  			ctx := context.Background()
    67  			dir := t.TempDir()
    68  			fs, err := NewLocalFS(ctx, "local", dir, DisabledCacheConfig, nil)
    69  			assert.Nil(t, err)
    70  			return fs
    71  		})
    72  	})
    73  
    74  	t.Run("caching file service", func(t *testing.T) {
    75  		testCachingFileService(t, func() CachingFileService {
    76  			ctx := context.Background()
    77  			dir := t.TempDir()
    78  			fs, err := NewLocalFS(ctx, "local", dir, CacheConfig{
    79  				MemoryCapacity: ptrTo[toml.ByteSize](128 * 1024),
    80  			}, nil)
    81  			assert.Nil(t, err)
    82  			return fs
    83  		})
    84  	})
    85  
    86  }
    87  
    88  func BenchmarkLocalFS(b *testing.B) {
    89  	ctx := context.Background()
    90  	benchmarkFileService(ctx, b, func() FileService {
    91  		dir := b.TempDir()
    92  		fs, err := NewLocalFS(ctx, "local", dir, DisabledCacheConfig, nil)
    93  		assert.Nil(b, err)
    94  		return fs
    95  	})
    96  }
    97  
    98  func TestLocalFSWithDiskCache(t *testing.T) {
    99  	ctx := context.Background()
   100  	var counter perfcounter.CounterSet
   101  	ctx = perfcounter.WithCounterSet(ctx, &counter)
   102  	const (
   103  		n       = 128
   104  		dataLen = 128
   105  	)
   106  
   107  	// new fs
   108  	fs, err := NewLocalFS(
   109  		ctx,
   110  		"foo",
   111  		t.TempDir(),
   112  		CacheConfig{
   113  			DiskPath:                  ptrTo(t.TempDir()),
   114  			DiskCapacity:              ptrTo[toml.ByteSize](dataLen * n / 32),
   115  			enableDiskCacheForLocalFS: true,
   116  		},
   117  		nil,
   118  	)
   119  	assert.Nil(t, err)
   120  
   121  	// prepare data
   122  	datas := make([][]byte, 0, n)
   123  	for i := 0; i < n; i++ {
   124  		data := make([]byte, dataLen)
   125  		_, err := rand.Read(data)
   126  		assert.Nil(t, err)
   127  		datas = append(datas, data)
   128  	}
   129  
   130  	// write
   131  	for i := 0; i < n; i++ {
   132  		data := datas[i]
   133  		vec := IOVector{
   134  			FilePath: fmt.Sprintf("%d", i),
   135  			Entries: []IOEntry{
   136  				{
   137  					Data: data,
   138  					Size: int64(len(data)),
   139  				},
   140  			},
   141  		}
   142  		err := fs.Write(ctx, vec)
   143  		assert.Nil(t, err)
   144  	}
   145  
   146  	// read
   147  	for i := 0; i < n*10; i++ {
   148  		idx := i % n
   149  		expected := datas[idx]
   150  		length := 8
   151  		for j := 0; j < dataLen/length; j++ {
   152  			offset := j * length
   153  			vec := IOVector{
   154  				FilePath: fmt.Sprintf("%d", idx),
   155  				Entries: []IOEntry{
   156  					{
   157  						Offset: int64(offset),
   158  						Size:   int64(length),
   159  					},
   160  				},
   161  			}
   162  			err := fs.Read(ctx, &vec)
   163  			assert.Nil(t, err)
   164  			assert.Equal(t, expected[offset:offset+length], vec.Entries[0].Data)
   165  		}
   166  	}
   167  
   168  }
   169  
   170  // default allocator must use with no memcache
   171  // only memory obtained through memcache.Alloc can be set to memcache
   172  func TestLocalFSWithIOVectorCache(t *testing.T) {
   173  	memCache1 := NewMemCache(
   174  		NewMemoryCache(1<<20, false, nil),
   175  		nil,
   176  	)
   177  	memCache2 := NewMemCache(
   178  		NewMemoryCache(1<<20, false, nil),
   179  		nil,
   180  	)
   181  	caches := []IOVectorCache{memCache1, memCache2}
   182  
   183  	ctx := context.Background()
   184  	dir := t.TempDir()
   185  	fs, err := NewLocalFS(ctx, "test", dir, CacheConfig{
   186  		MemoryCapacity: ptrTo[toml.ByteSize](128 * 1024),
   187  	}, nil)
   188  	assert.Nil(t, err)
   189  
   190  	err = fs.Write(ctx, IOVector{
   191  		Caches:   caches,
   192  		FilePath: "foo",
   193  		Entries: []IOEntry{
   194  			{
   195  				Size: 8,
   196  				Data: []byte("12345678"),
   197  			},
   198  		},
   199  	})
   200  	assert.Nil(t, err)
   201  
   202  	vec := IOVector{
   203  		Caches:   caches,
   204  		FilePath: "foo",
   205  		Entries: []IOEntry{
   206  			{
   207  				Size: 8,
   208  				ToCacheData: func(r io.Reader, _ []byte, allocator CacheDataAllocator) (memorycache.CacheData, error) {
   209  					cacheData := allocator.Alloc(8)
   210  					_, err := io.ReadFull(r, cacheData.Bytes())
   211  					if err != nil {
   212  						return nil, err
   213  					}
   214  					return cacheData, nil
   215  				},
   216  			},
   217  		},
   218  	}
   219  	err = fs.Read(ctx, &vec)
   220  	assert.Nil(t, err)
   221  	vec.Release()
   222  
   223  	assert.Equal(t, int64(8), memCache1.cache.Used())
   224  	assert.Equal(t, int64(8), memCache2.cache.Used())
   225  	memCache1.cache.Flush()
   226  	memCache2.cache.Flush()
   227  	fs.FlushCache()
   228  }
   229  
   230  func TestLocalFSEmptyRootPath(t *testing.T) {
   231  	fs, err := NewLocalFS(
   232  		context.Background(),
   233  		"test",
   234  		"",
   235  		CacheConfig{},
   236  		nil,
   237  	)
   238  	assert.Nil(t, err)
   239  	assert.NotNil(t, fs)
   240  }