github.com/matrixorigin/matrixone@v1.2.0/pkg/fileservice/remote_cache_test.go (about) 1 // Copyright 2021 - 2023 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 "fmt" 20 "os" 21 "testing" 22 "time" 23 24 "github.com/lni/goutils/leaktest" 25 "github.com/matrixorigin/matrixone/pkg/common/morpc" 26 "github.com/matrixorigin/matrixone/pkg/common/runtime" 27 "github.com/matrixorigin/matrixone/pkg/pb/gossip" 28 "github.com/matrixorigin/matrixone/pkg/pb/query" 29 "github.com/matrixorigin/matrixone/pkg/queryservice" 30 "github.com/matrixorigin/matrixone/pkg/queryservice/client" 31 "github.com/stretchr/testify/assert" 32 ) 33 34 type mockKeyRouter[K comparable] struct { 35 target string 36 } 37 38 func (r *mockKeyRouter[K]) Target(_ CacheKey) string { return r.target } 39 func (r *mockKeyRouter[K]) AddItem(_ gossip.CommonItem) {} 40 41 type cacheFs struct { 42 qs queryservice.QueryService 43 qt client.QueryClient 44 rc *RemoteCache 45 fs FileService 46 } 47 48 func TestRemoteCache(t *testing.T) { 49 runTestWithTwoFileServices(t, func(sf1 *cacheFs, sf2 *cacheFs) { 50 ctx := context.Background() 51 err := sf1.fs.Write(ctx, IOVector{ 52 FilePath: "foo", 53 Entries: []IOEntry{ 54 { 55 Offset: 0, 56 Size: 2, 57 Data: []byte{1, 2}, 58 }, 59 }, 60 }) 61 assert.NoError(t, err) 62 ioVec1 := &IOVector{ 63 FilePath: "foo", 64 Entries: []IOEntry{ 65 { 66 Offset: 0, 67 Size: 2, 68 ToCacheData: CacheOriginalData, 69 }, 70 }, 71 } 72 err = sf1.fs.Read(ctx, ioVec1) 73 assert.NoError(t, err) 74 assert.Equal(t, 1, len(ioVec1.Entries)) 75 assert.Equal(t, []byte{1, 2}, ioVec1.Entries[0].Data) 76 ioVec1.Release() 77 78 ioVec2 := &IOVector{ 79 FilePath: "foo", 80 Entries: []IOEntry{ 81 { 82 Offset: 0, 83 Size: 2, 84 }, 85 }, 86 } 87 err = sf2.rc.Read(ctx, ioVec2) 88 assert.NoError(t, err) 89 assert.Equal(t, 1, len(ioVec2.Entries)) 90 assert.Equal(t, Bytes{1, 2}, ioVec2.Entries[0].CachedData) 91 assert.Equal(t, true, ioVec2.Entries[0].done) 92 assert.NotNil(t, ioVec2.Entries[0].fromCache) 93 94 sf1.fs.Close() 95 }) 96 } 97 98 func runTestWithTwoFileServices(t *testing.T, fn func(sf1 *cacheFs, sf2 *cacheFs)) { 99 defer leaktest.AfterTest(t)() 100 runtime.SetupProcessLevelRuntime(runtime.DefaultRuntime()) 101 address1 := fmt.Sprintf("unix:///tmp/sock1-%d.sock", time.Now().Nanosecond()) 102 if err := os.RemoveAll(address1[7:]); err != nil { 103 panic(err) 104 } 105 address2 := fmt.Sprintf("unix:///tmp/sock2-%d.sock", time.Now().Nanosecond()) 106 if err := os.RemoveAll(address2[7:]); err != nil { 107 panic(err) 108 } 109 110 create := func(selfAddr, pairAddr string) *cacheFs { 111 dir := t.TempDir() 112 ctx := context.Background() 113 qt, err := client.NewQueryClient("", morpc.Config{}) 114 assert.NoError(t, err) 115 assert.NotNil(t, qt) 116 117 keyRouter := &mockKeyRouter[query.CacheKey]{target: pairAddr} 118 cacheCfg := CacheConfig{ 119 RemoteCacheEnabled: true, 120 KeyRouterFactory: func() client.KeyRouter[query.CacheKey] { 121 return keyRouter 122 }, 123 QueryClient: qt, 124 } 125 cacheCfg.setDefaults() 126 cacheCfg.SetRemoteCacheCallback() 127 fs, err := NewLocalFS(ctx, "local-"+selfAddr, dir, cacheCfg, nil) 128 assert.Nil(t, err) 129 assert.NotNil(t, fs) 130 qs, err := queryservice.NewQueryService("", selfAddr, morpc.Config{}) 131 assert.NoError(t, err) 132 qs.AddHandleFunc(query.CmdMethod_GetCacheData, 133 func(ctx context.Context, req *query.Request, resp *query.Response) error { 134 wr := &query.WrappedResponse{ 135 Response: resp, 136 } 137 err = HandleRemoteRead(ctx, fs, req, wr) 138 if err != nil { 139 return err 140 } 141 qs.SetReleaseFunc(resp, wr.ReleaseFunc) 142 return nil 143 }, 144 false, 145 ) 146 err = qs.Start() 147 assert.NoError(t, err) 148 149 rc := NewRemoteCache(qt, func() client.KeyRouter[query.CacheKey] { return keyRouter }) 150 assert.NotNil(t, rc) 151 return &cacheFs{qs: qs, rc: rc, fs: fs, qt: qt} 152 } 153 154 cf1 := create(address1, address2) 155 defer func() { 156 assert.NoError(t, cf1.qs.Close()) 157 assert.NoError(t, cf1.qt.Close()) 158 }() 159 cf2 := create(address2, address1) 160 defer func() { 161 assert.NoError(t, cf2.qs.Close()) 162 assert.NoError(t, cf2.qt.Close()) 163 }() 164 165 fn(cf1, cf2) 166 }