github.com/matrixorigin/matrixone@v1.2.0/pkg/objectio/cache.go (about)

     1  // Copyright 2021 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 objectio
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"fmt"
    21  	"sync"
    22  
    23  	"github.com/cespare/xxhash/v2"
    24  	"github.com/shirou/gopsutil/v3/mem"
    25  
    26  	"github.com/matrixorigin/matrixone/pkg/common/mpool"
    27  	"github.com/matrixorigin/matrixone/pkg/container/types"
    28  	"github.com/matrixorigin/matrixone/pkg/fileservice"
    29  	"github.com/matrixorigin/matrixone/pkg/fileservice/fifocache"
    30  	"github.com/matrixorigin/matrixone/pkg/perfcounter"
    31  	"github.com/matrixorigin/matrixone/pkg/util/toml"
    32  )
    33  
    34  const (
    35  	cacheKeyTypeLen = 2
    36  	cacheKeyLen     = ObjectNameShortLen + cacheKeyTypeLen
    37  )
    38  
    39  const (
    40  	cacheKeyTypeMeta uint16 = iota
    41  	cacheKeyTypeBloomFilter
    42  )
    43  
    44  type CacheConfig struct {
    45  	MemoryCapacity toml.ByteSize `toml:"memory-capacity"`
    46  }
    47  
    48  // BlockReadStats collect blk read related cache statistics,
    49  // include mem and disk
    50  type BlockReadStats struct {
    51  	// using this we can collect the number of blks have read and hit among them
    52  	BlkCacheHitStats hitStats
    53  	// using this we can collect the number of entries have read and hit among them
    54  	EntryCacheHitStats hitStats
    55  	// using this we can collect the number of blks each reader will read
    56  	BlksByReaderStats hitStats
    57  	CounterSet        *perfcounter.CounterSet
    58  }
    59  
    60  func newBlockReadStats() *BlockReadStats {
    61  	s := BlockReadStats{
    62  		CounterSet: new(perfcounter.CounterSet),
    63  	}
    64  	return &s
    65  }
    66  
    67  var BlkReadStats = newBlockReadStats()
    68  
    69  type mataCacheKey [cacheKeyLen]byte
    70  
    71  var metaCache *fifocache.Cache[mataCacheKey, []byte]
    72  var onceInit sync.Once
    73  var metaCacheStats hitStats
    74  var metaCacheHitStats hitStats
    75  
    76  func metaCacheSize() int64 {
    77  	v, err := mem.VirtualMemory()
    78  	if err != nil {
    79  		panic(err)
    80  	}
    81  
    82  	total := v.Total
    83  	if total < 2*mpool.GB {
    84  		return int64(total / 4)
    85  	}
    86  	if total < 16*mpool.GB {
    87  		return 512 * mpool.MB
    88  	}
    89  	if total < 32*mpool.GB {
    90  		return 1 * mpool.GB
    91  	}
    92  	return 2 * mpool.GB
    93  }
    94  
    95  func shardMetaCacheKey(key mataCacheKey) uint8 {
    96  	return uint8(xxhash.Sum64(key[:]))
    97  }
    98  
    99  func init() {
   100  	metaCache = fifocache.New[mataCacheKey, []byte](int(metaCacheSize()), nil, shardMetaCacheKey)
   101  }
   102  
   103  func InitMetaCache(size int64) {
   104  	onceInit.Do(func() {
   105  		metaCache = fifocache.New[mataCacheKey, []byte](int(size), nil, shardMetaCacheKey)
   106  	})
   107  }
   108  
   109  func encodeCacheKey(name ObjectNameShort, cacheKeyType uint16) mataCacheKey {
   110  	var key mataCacheKey
   111  	copy(key[:], name[:])
   112  	copy(key[ObjectNameShortLen:], types.EncodeUint16(&cacheKeyType))
   113  	return key
   114  }
   115  
   116  func ExportCacheStats() string {
   117  	var buf bytes.Buffer
   118  	hw, hwt := metaCacheHitStats.ExportW()
   119  	ht, htt := metaCacheHitStats.Export()
   120  	w, wt := metaCacheStats.ExportW()
   121  	t, tt := metaCacheStats.Export()
   122  
   123  	fmt.Fprintf(
   124  		&buf,
   125  		"MetaCacheWindow: %d/%d | %d/%d, MetaCacheTotal: %d/%d | %d/%d", hw, hwt, w, wt, ht, htt, t, tt,
   126  	)
   127  
   128  	return buf.String()
   129  }
   130  
   131  func LoadObjectMetaByExtent(
   132  	ctx context.Context,
   133  	name *ObjectName,
   134  	extent *Extent,
   135  	prefetch bool,
   136  	policy fileservice.Policy,
   137  	fs fileservice.FileService,
   138  ) (meta ObjectMeta, err error) {
   139  	key := encodeCacheKey(*name.Short(), cacheKeyTypeMeta)
   140  	v, ok := metaCache.Get(key)
   141  	if ok {
   142  		var obj any
   143  		obj, err = Decode(v)
   144  		if err != nil {
   145  			return
   146  		}
   147  		meta = obj.(ObjectMeta)
   148  		// metaCacheStats.Record(1, 1)
   149  		// if !prefetch {
   150  		// 	metaCacheHitStats.Record(1, 1)
   151  		// }
   152  		return
   153  	}
   154  	if v, err = ReadExtent(ctx, name.String(), extent, policy, fs, constructorFactory); err != nil {
   155  		return
   156  	}
   157  	var obj any
   158  	obj, err = Decode(v)
   159  	if err != nil {
   160  		return
   161  	}
   162  	meta = obj.(ObjectMeta)
   163  	metaCache.Set(key, v[:], len(v))
   164  	// metaCacheStats.Record(0, 1)
   165  	// if !prefetch {
   166  	// 	metaCacheHitStats.Record(0, 1)
   167  	// }
   168  	return
   169  }
   170  
   171  func FastLoadBF(
   172  	ctx context.Context,
   173  	location Location,
   174  	isPrefetch bool,
   175  	fs fileservice.FileService,
   176  ) (BloomFilter, error) {
   177  	key := encodeCacheKey(*location.ShortName(), cacheKeyTypeBloomFilter)
   178  	v, ok := metaCache.Get(key)
   179  	if ok {
   180  		// metaCacheStats.Record(1, 1)
   181  		return v, nil
   182  	}
   183  	meta, err := FastLoadObjectMeta(ctx, &location, isPrefetch, fs)
   184  	if err != nil {
   185  		return nil, err
   186  	}
   187  	return LoadBFWithMeta(ctx, meta.MustDataMeta(), location, fs)
   188  }
   189  
   190  func LoadBFWithMeta(
   191  	ctx context.Context,
   192  	meta ObjectDataMeta,
   193  	location Location,
   194  	fs fileservice.FileService,
   195  ) (BloomFilter, error) {
   196  	key := encodeCacheKey(*location.ShortName(), cacheKeyTypeBloomFilter)
   197  	v, ok := metaCache.Get(key)
   198  	if ok {
   199  		// metaCacheStats.Record(1, 1)
   200  		return v, nil
   201  	}
   202  	extent := meta.BlockHeader().BFExtent()
   203  	bf, err := ReadBloomFilter(ctx, location.Name().String(), &extent, fileservice.SkipMemoryCache|fileservice.SkipFullFilePreloads, fs)
   204  	if err != nil {
   205  		return nil, err
   206  	}
   207  	metaCache.Set(key, bf, len(bf))
   208  	// metaCacheStats.Record(0, 1)
   209  	return bf, nil
   210  }
   211  
   212  func FastLoadObjectMeta(
   213  	ctx context.Context,
   214  	location *Location,
   215  	prefetch bool,
   216  	fs fileservice.FileService,
   217  ) (ObjectMeta, error) {
   218  	extent := location.Extent()
   219  	name := location.Name()
   220  	var metaReadPolicy fileservice.Policy
   221  	metaReadPolicy = fileservice.SkipMemoryCache
   222  	metaReadPolicy |= fileservice.SkipFullFilePreloads
   223  	return LoadObjectMetaByExtent(ctx, &name, &extent, prefetch, metaReadPolicy, fs)
   224  }