github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libkbfs/disk_block_cache_service.go (about)

     1  // Copyright 2017 Keybase Inc. All rights reserved.
     2  // Use of this source code is governed by a BSD
     3  // license that can be found in the LICENSE file.
     4  
     5  package libkbfs
     6  
     7  import (
     8  	"context"
     9  
    10  	"github.com/keybase/client/go/kbfs/kbfsblock"
    11  	"github.com/keybase/client/go/kbfs/kbfscrypto"
    12  	"github.com/keybase/client/go/kbfs/tlf"
    13  	kbgitkbfs "github.com/keybase/client/go/protocol/kbgitkbfs1"
    14  )
    15  
    16  type diskBlockCacheServiceConfig interface {
    17  	diskBlockCacheGetter
    18  	syncedTlfGetterSetter
    19  }
    20  
    21  // DiskBlockCacheService delegates requests for blocks to this KBFS
    22  // instance's disk cache.
    23  type DiskBlockCacheService struct {
    24  	config diskBlockCacheServiceConfig
    25  }
    26  
    27  var _ kbgitkbfs.DiskBlockCacheInterface = (*DiskBlockCacheService)(nil)
    28  
    29  // NewDiskBlockCacheService creates a new DiskBlockCacheService.
    30  func NewDiskBlockCacheService(config diskBlockCacheServiceConfig) *DiskBlockCacheService {
    31  	return &DiskBlockCacheService{
    32  		config: config,
    33  	}
    34  }
    35  
    36  // GetBlock implements the DiskBlockCacheInterface interface for
    37  // DiskBlockCacheService.
    38  func (cache *DiskBlockCacheService) GetBlock(ctx context.Context,
    39  	arg kbgitkbfs.GetBlockArg) (kbgitkbfs.GetBlockRes, error) {
    40  	// TODO: make sure this isn't remote.
    41  	dbc := cache.config.DiskBlockCache()
    42  	if dbc == nil {
    43  		return kbgitkbfs.GetBlockRes{},
    44  			DiskBlockCacheError{"Disk cache is nil"}
    45  	}
    46  	tlfID := tlf.ID{}
    47  	err := tlfID.UnmarshalBinary(arg.TlfID)
    48  	if err != nil {
    49  		return kbgitkbfs.GetBlockRes{}, newDiskBlockCacheError(err)
    50  	}
    51  	blockID := kbfsblock.ID{}
    52  	err = blockID.UnmarshalBinary(arg.BlockID)
    53  	if err != nil {
    54  		return kbgitkbfs.GetBlockRes{}, newDiskBlockCacheError(err)
    55  	}
    56  	buf, serverHalf, prefetchStatus, err := dbc.Get(
    57  		ctx, tlfID, blockID, DiskBlockAnyCache)
    58  	if err != nil {
    59  		return kbgitkbfs.GetBlockRes{}, newDiskBlockCacheError(err)
    60  	}
    61  	protocolPrefetchStatus := prefetchStatus.ToProtocol()
    62  
    63  	return kbgitkbfs.GetBlockRes{
    64  		Buf:            buf,
    65  		ServerHalf:     serverHalf.Bytes(),
    66  		PrefetchStatus: protocolPrefetchStatus,
    67  	}, nil
    68  }
    69  
    70  // GetPrefetchStatus implements the DiskBlockCacheInterface interface
    71  // for DiskBlockCacheService.
    72  func (cache *DiskBlockCacheService) GetPrefetchStatus(
    73  	ctx context.Context, arg kbgitkbfs.GetPrefetchStatusArg) (
    74  	prefetchStatus kbgitkbfs.PrefetchStatus, err error) {
    75  	dbc := cache.config.DiskBlockCache()
    76  	if dbc == nil {
    77  		return NoPrefetch.ToProtocol(), DiskBlockCacheError{"Disk cache is nil"}
    78  	}
    79  	tlfID := tlf.ID{}
    80  	err = tlfID.UnmarshalBinary(arg.TlfID)
    81  	if err != nil {
    82  		return NoPrefetch.ToProtocol(), newDiskBlockCacheError(err)
    83  	}
    84  	blockID := kbfsblock.ID{}
    85  	err = blockID.UnmarshalBinary(arg.BlockID)
    86  	if err != nil {
    87  		return NoPrefetch.ToProtocol(), newDiskBlockCacheError(err)
    88  	}
    89  
    90  	cacheType := DiskBlockAnyCache
    91  	if cache.config.IsSyncedTlf(tlfID) {
    92  		cacheType = DiskBlockSyncCache
    93  	}
    94  
    95  	dbStatus, err := dbc.GetPrefetchStatus(ctx, tlfID, blockID, cacheType)
    96  	if err != nil {
    97  		return NoPrefetch.ToProtocol(), newDiskBlockCacheError(err)
    98  	}
    99  	return dbStatus.ToProtocol(), nil
   100  }
   101  
   102  // PutBlock implements the DiskBlockCacheInterface interface for
   103  // DiskBlockCacheService.
   104  func (cache *DiskBlockCacheService) PutBlock(ctx context.Context,
   105  	arg kbgitkbfs.PutBlockArg) error {
   106  	dbc := cache.config.DiskBlockCache()
   107  	if dbc == nil {
   108  		return DiskBlockCacheError{"Disk cache is nil"}
   109  	}
   110  	tlfID := tlf.ID{}
   111  	err := tlfID.UnmarshalBinary(arg.TlfID)
   112  	if err != nil {
   113  		return newDiskBlockCacheError(err)
   114  	}
   115  	blockID := kbfsblock.ID{}
   116  	err = blockID.UnmarshalBinary(arg.BlockID)
   117  	if err != nil {
   118  		return newDiskBlockCacheError(err)
   119  	}
   120  	serverHalf := kbfscrypto.BlockCryptKeyServerHalf{}
   121  	err = serverHalf.UnmarshalBinary(arg.ServerHalf)
   122  	if err != nil {
   123  		return newDiskBlockCacheError(err)
   124  	}
   125  	cacheType := DiskBlockAnyCache
   126  	if cache.config.IsSyncedTlf(tlfID) {
   127  		cacheType = DiskBlockSyncCache
   128  	}
   129  	err = dbc.Put(ctx, tlfID, blockID, arg.Buf, serverHalf, cacheType)
   130  	if err != nil {
   131  		return newDiskBlockCacheError(err)
   132  	}
   133  	return nil
   134  }
   135  
   136  // DeleteBlocks implements the DiskBlockCacheInterface interface for
   137  // DiskBlockCacheService.
   138  func (cache *DiskBlockCacheService) DeleteBlocks(ctx context.Context,
   139  	blockIDs [][]byte) (kbgitkbfs.DeleteBlocksRes, error) {
   140  	dbc := cache.config.DiskBlockCache()
   141  	if dbc == nil {
   142  		return kbgitkbfs.DeleteBlocksRes{},
   143  			DiskBlockCacheError{"Disk cache is nil"}
   144  	}
   145  	blocks := make([]kbfsblock.ID, 0, len(blockIDs))
   146  	for _, b := range blockIDs {
   147  		blockID := kbfsblock.ID{}
   148  		err := blockID.UnmarshalBinary(b)
   149  		if err != nil {
   150  			return kbgitkbfs.DeleteBlocksRes{}, newDiskBlockCacheError(err)
   151  		}
   152  		blocks = append(blocks, blockID)
   153  	}
   154  	numRemoved, sizeRemoved, err := dbc.Delete(ctx, blocks, DiskBlockAnyCache)
   155  	if err != nil {
   156  		return kbgitkbfs.DeleteBlocksRes{}, newDiskBlockCacheError(err)
   157  	}
   158  	return kbgitkbfs.DeleteBlocksRes{
   159  		NumRemoved:  numRemoved,
   160  		SizeRemoved: sizeRemoved,
   161  	}, nil
   162  }
   163  
   164  // UpdateBlockMetadata implements the DiskBlockCacheInterface interface for
   165  // DiskBlockCacheService.
   166  func (cache *DiskBlockCacheService) UpdateBlockMetadata(ctx context.Context,
   167  	arg kbgitkbfs.UpdateBlockMetadataArg) error {
   168  	dbc := cache.config.DiskBlockCache()
   169  	if dbc == nil {
   170  		return DiskBlockCacheError{"Disk cache is nil"}
   171  	}
   172  	tlfID := tlf.ID{}
   173  	err := tlfID.UnmarshalBinary(arg.TlfID)
   174  	if err != nil {
   175  		return newDiskBlockCacheError(err)
   176  	}
   177  	blockID := kbfsblock.ID{}
   178  	err = blockID.UnmarshalBinary(arg.BlockID)
   179  	if err != nil {
   180  		return newDiskBlockCacheError(err)
   181  	}
   182  	err = dbc.UpdateMetadata(
   183  		ctx, tlfID, blockID, PrefetchStatus(arg.PrefetchStatus),
   184  		DiskBlockAnyCache)
   185  	if err != nil {
   186  		return newDiskBlockCacheError(err)
   187  	}
   188  	return nil
   189  }