github.com/matrixorigin/matrixone@v1.2.0/pkg/fileservice/remote_cache.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  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    20  	"sync"
    21  	"time"
    22  
    23  	"github.com/matrixorigin/matrixone/pkg/pb/query"
    24  	"github.com/matrixorigin/matrixone/pkg/perfcounter"
    25  	"github.com/matrixorigin/matrixone/pkg/queryservice/client"
    26  	metric "github.com/matrixorigin/matrixone/pkg/util/metric/v2"
    27  )
    28  
    29  type TargetCacheKeys map[string][]*query.RequestCacheKey
    30  
    31  type KeyRouterFactory[T comparable] func() client.KeyRouter[T]
    32  
    33  // RemoteCache is the cache for remote read.
    34  type RemoteCache struct {
    35  	// client sends the cache request to query server.
    36  	client client.QueryClient
    37  	// keyRouterFactory is used to set the keyRouter async.
    38  	keyRouterFactory KeyRouterFactory[query.CacheKey]
    39  	// keyRouter is used to find out which node we should send
    40  	// cache request to.
    41  	keyRouter client.KeyRouter[query.CacheKey]
    42  	// We only init the key router for the first time.
    43  	init sync.Once
    44  }
    45  
    46  var _ IOVectorCache = new(RemoteCache)
    47  
    48  func NewRemoteCache(client client.QueryClient, factory KeyRouterFactory[query.CacheKey]) *RemoteCache {
    49  	return &RemoteCache{
    50  		client:           client,
    51  		keyRouterFactory: factory,
    52  	}
    53  }
    54  
    55  func (r *RemoteCache) Read(ctx context.Context, vector *IOVector) error {
    56  	if r.keyRouterFactory == nil {
    57  		return nil
    58  	}
    59  	r.init.Do(func() {
    60  		r.keyRouter = r.keyRouterFactory()
    61  	})
    62  	if r.keyRouter == nil {
    63  		return nil
    64  	}
    65  
    66  	path, err := ParsePath(vector.FilePath)
    67  	if err != nil {
    68  		return err
    69  	}
    70  
    71  	var numHit, numRead int64
    72  	defer func() {
    73  		metric.FSReadHitRemoteCounter.Add(float64(numHit))
    74  		perfcounter.Update(ctx, func(c *perfcounter.CounterSet) {
    75  			c.FileService.Cache.Read.Add(numRead)
    76  			c.FileService.Cache.Hit.Add(numHit)
    77  			c.FileService.Cache.Remote.Read.Add(numRead)
    78  			c.FileService.Cache.Remote.Hit.Add(numHit)
    79  		})
    80  	}()
    81  
    82  	targetCacheKeys := make(TargetCacheKeys, len(vector.Entries))
    83  	for i, entry := range vector.Entries {
    84  		if entry.done {
    85  			continue
    86  		}
    87  		if entry.Size < 0 {
    88  			continue
    89  		}
    90  
    91  		cacheKey := CacheKey{
    92  			Path:   path.File,
    93  			Offset: entry.Offset,
    94  			Sz:     entry.Size,
    95  		}
    96  		target := r.keyRouter.Target(cacheKey)
    97  		if len(target) == 0 {
    98  			continue
    99  		}
   100  
   101  		if _, ok := targetCacheKeys[target]; !ok {
   102  			targetCacheKeys[target] = make([]*query.RequestCacheKey, 0)
   103  		}
   104  		targetCacheKeys[target] = append(targetCacheKeys[target], &query.RequestCacheKey{
   105  			Index:    int32(i),
   106  			CacheKey: &cacheKey,
   107  		})
   108  	}
   109  
   110  	for target, key := range targetCacheKeys {
   111  		req := r.client.NewRequest(query.CmdMethod_GetCacheData)
   112  		req.GetCacheDataRequest = &query.GetCacheDataRequest{
   113  			RequestCacheKey: key,
   114  		}
   115  
   116  		func(ctx context.Context) {
   117  			ctx, cancel := context.WithTimeout(ctx, time.Second*2)
   118  			defer cancel()
   119  			resp, err := r.client.SendMessage(ctx, target, req)
   120  			if err != nil {
   121  				// Do not return error here to read data from local storage.
   122  				return
   123  			}
   124  			defer r.client.Release(resp)
   125  			if resp.GetCacheDataResponse != nil {
   126  				for _, cacheData := range resp.GetCacheDataResponse.ResponseCacheData {
   127  					numRead++
   128  					idx := int(cacheData.Index)
   129  					if cacheData.Hit {
   130  						vector.Entries[idx].done = true
   131  						vector.Entries[idx].CachedData = Bytes(cacheData.Data)
   132  						vector.Entries[idx].fromCache = r
   133  						numHit++
   134  					}
   135  				}
   136  			}
   137  		}(ctx)
   138  	}
   139  	return nil
   140  }
   141  
   142  func (r *RemoteCache) Update(ctx context.Context, vector *IOVector, async bool) error {
   143  	return nil
   144  }
   145  
   146  func (r *RemoteCache) Flush() {}
   147  
   148  func (r *RemoteCache) DeletePaths(ctx context.Context, paths []string) error {
   149  	//TODO
   150  	return nil
   151  }
   152  
   153  func HandleRemoteRead(
   154  	ctx context.Context, fs FileService, req *query.Request, resp *query.WrappedResponse,
   155  ) error {
   156  	if req.GetCacheDataRequest == nil {
   157  		return moerr.NewInternalError(ctx, "bad request")
   158  	}
   159  	first := req.GetCacheDataRequest.RequestCacheKey[0].CacheKey
   160  	if first == nil { // We cannot get the first one.
   161  		return nil
   162  	}
   163  
   164  	ioVec := &IOVector{
   165  		FilePath: first.Path,
   166  	}
   167  	ioVec.Entries = make([]IOEntry, len(req.GetCacheDataRequest.RequestCacheKey))
   168  	for i, k := range req.GetCacheDataRequest.RequestCacheKey {
   169  		ioVec.Entries[i].Offset = k.CacheKey.Offset
   170  		ioVec.Entries[i].Size = k.CacheKey.Sz
   171  	}
   172  	if err := fs.ReadCache(ctx, ioVec); err != nil {
   173  		return err
   174  	}
   175  	respData := make([]*query.ResponseCacheData, len(req.GetCacheDataRequest.RequestCacheKey))
   176  	for i, k := range req.GetCacheDataRequest.RequestCacheKey {
   177  		var data []byte
   178  		if ioVec.Entries[i].CachedData != nil {
   179  			data = ioVec.Entries[i].CachedData.Bytes()
   180  		}
   181  		respData[i] = &query.ResponseCacheData{
   182  			Index: k.Index,
   183  			Hit:   ioVec.Entries[i].fromCache != nil,
   184  			Data:  data,
   185  		}
   186  	}
   187  
   188  	resp.GetCacheDataResponse = &query.GetCacheDataResponse{
   189  		ResponseCacheData: respData,
   190  	}
   191  	resp.ReleaseFunc = func() { ioVec.Release() }
   192  	return nil
   193  }