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  }