github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/libkbfs/journal_block_server.go (about)

     1  // Copyright 2016 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  	"github.com/keybase/client/go/kbfs/kbfsblock"
     9  	"github.com/keybase/client/go/kbfs/kbfscrypto"
    10  	"github.com/keybase/client/go/kbfs/tlf"
    11  	"github.com/pkg/errors"
    12  	"golang.org/x/net/context"
    13  )
    14  
    15  type journalBlockServer struct {
    16  	jManager *JournalManager
    17  	BlockServer
    18  	enableAddBlockReference bool
    19  }
    20  
    21  var _ BlockServer = journalBlockServer{}
    22  
    23  func (j journalBlockServer) getBlockFromJournal(
    24  	ctx context.Context, tlfID tlf.ID, id kbfsblock.ID) (
    25  	data []byte, serverHalf kbfscrypto.BlockCryptKeyServerHalf,
    26  	found bool, err error) {
    27  	tlfJournal, ok := j.jManager.getTLFJournal(tlfID, nil)
    28  	if !ok {
    29  		return nil, kbfscrypto.BlockCryptKeyServerHalf{}, false, nil
    30  	}
    31  
    32  	defer func() {
    33  		err = translateToBlockServerError(err)
    34  	}()
    35  	data, serverHalf, err = tlfJournal.getBlockData(ctx, id)
    36  	switch errors.Cause(err).(type) {
    37  	case nil:
    38  		return data, serverHalf, true, nil
    39  	case blockNonExistentError:
    40  		return nil, kbfscrypto.BlockCryptKeyServerHalf{}, false, nil
    41  	case errTLFJournalDisabled:
    42  		return nil, kbfscrypto.BlockCryptKeyServerHalf{}, false, nil
    43  	default:
    44  		return nil, kbfscrypto.BlockCryptKeyServerHalf{}, false, err
    45  	}
    46  }
    47  
    48  func (j journalBlockServer) getBlockSizeFromJournal(
    49  	ctx context.Context, tlfID tlf.ID, id kbfsblock.ID) (
    50  	size uint32, found bool, err error) {
    51  	tlfJournal, ok := j.jManager.getTLFJournal(tlfID, nil)
    52  	if !ok {
    53  		return 0, false, nil
    54  	}
    55  
    56  	defer func() {
    57  		err = translateToBlockServerError(err)
    58  	}()
    59  	size, err = tlfJournal.getBlockSize(ctx, id)
    60  	switch errors.Cause(err).(type) {
    61  	case nil:
    62  		return size, true, nil
    63  	case blockNonExistentError:
    64  		return 0, false, nil
    65  	case errTLFJournalDisabled:
    66  		return 0, false, nil
    67  	default:
    68  		return 0, false, err
    69  	}
    70  }
    71  
    72  func (j journalBlockServer) Get(
    73  	ctx context.Context, tlfID tlf.ID, id kbfsblock.ID,
    74  	context kbfsblock.Context, cacheType DiskBlockCacheType) (
    75  	data []byte, serverHalf kbfscrypto.BlockCryptKeyServerHalf, err error) {
    76  	j.jManager.log.LazyTrace(ctx, "jBServer: Get %s", id)
    77  	defer func() {
    78  		j.jManager.deferLog.LazyTrace(ctx, "jBServer: Get %s done (err=%v)", id, err)
    79  	}()
    80  
    81  	data, serverHalf, found, err := j.getBlockFromJournal(ctx, tlfID, id)
    82  	if err != nil {
    83  		return nil, kbfscrypto.BlockCryptKeyServerHalf{}, err
    84  	}
    85  	if found {
    86  		return data, serverHalf, nil
    87  	}
    88  
    89  	return j.BlockServer.Get(ctx, tlfID, id, context, cacheType)
    90  }
    91  
    92  func (j journalBlockServer) Put(
    93  	ctx context.Context, tlfID tlf.ID, id kbfsblock.ID,
    94  	context kbfsblock.Context, buf []byte,
    95  	serverHalf kbfscrypto.BlockCryptKeyServerHalf,
    96  	cacheType DiskBlockCacheType) (err error) {
    97  	// Don't trace this function, as it gets too verbose and is
    98  	// called in parallel anyway. Rely on caller (usually
    99  	// doBlockPuts) to do the tracing.
   100  
   101  	if tlfJournal, ok := j.jManager.getTLFJournal(tlfID, nil); ok {
   102  		defer func() {
   103  			err = translateToBlockServerError(err)
   104  		}()
   105  		err := tlfJournal.putBlockData(ctx, id, context, buf, serverHalf)
   106  		switch e := errors.Cause(err).(type) {
   107  		case nil:
   108  			usedQuotaBytes, quotaBytes := tlfJournal.getQuotaInfo()
   109  			return j.jManager.maybeReturnOverQuotaError(
   110  				usedQuotaBytes, quotaBytes)
   111  		case errTLFJournalDisabled:
   112  			break
   113  		case *ErrDiskLimitTimeout:
   114  			return j.jManager.maybeMakeDiskLimitErrorReportable(e)
   115  		default:
   116  			return err
   117  		}
   118  	}
   119  
   120  	return j.BlockServer.Put(
   121  		ctx, tlfID, id, context, buf, serverHalf, cacheType)
   122  }
   123  
   124  func (j journalBlockServer) AddBlockReference(
   125  	ctx context.Context, tlfID tlf.ID, id kbfsblock.ID,
   126  	context kbfsblock.Context) (err error) {
   127  	j.jManager.log.LazyTrace(ctx, "jBServer: AddRef %s", id)
   128  	defer func() {
   129  		j.jManager.deferLog.LazyTrace(ctx, "jBServer: AddRef %s done (err=%v)", id, err)
   130  	}()
   131  
   132  	if tlfJournal, ok := j.jManager.getTLFJournal(tlfID, nil); ok {
   133  		if !j.enableAddBlockReference {
   134  			// TODO: Temporarily return an error until KBFS-1149 is
   135  			// fixed. This is needed despite
   136  			// journalBlockCache.CheckForBlockPtr, since
   137  			// CheckForBlockPtr may be called before journaling is
   138  			// turned on for a TLF.
   139  			return kbfsblock.ServerErrorBlockNonExistent{}
   140  		}
   141  
   142  		defer func() {
   143  			err = translateToBlockServerError(err)
   144  		}()
   145  		err := tlfJournal.addBlockReference(ctx, id, context)
   146  		switch errors.Cause(err).(type) {
   147  		case nil:
   148  			return nil
   149  		case errTLFJournalDisabled:
   150  			break
   151  		default:
   152  			return err
   153  		}
   154  	}
   155  
   156  	return j.BlockServer.AddBlockReference(ctx, tlfID, id, context)
   157  }
   158  
   159  func (j journalBlockServer) RemoveBlockReferences(
   160  	ctx context.Context, tlfID tlf.ID,
   161  	contexts kbfsblock.ContextMap) (
   162  	liveCounts map[kbfsblock.ID]int, err error) {
   163  	j.jManager.log.LazyTrace(ctx, "jBServer: RemRef %v", contexts)
   164  	defer func() {
   165  		j.jManager.deferLog.LazyTrace(ctx, "jBServer: RemRef %v done (err=%v)", contexts, err)
   166  	}()
   167  
   168  	// Deletes always go straight to the server, since they slow down
   169  	// the journal and already only happen in the background anyway.
   170  	// Note that this means delete operations must be issued after the
   171  	// corresponding MD that unreferenced the block was flushed from
   172  	// the journal.
   173  	return j.BlockServer.RemoveBlockReferences(ctx, tlfID, contexts)
   174  }
   175  
   176  func (j journalBlockServer) ArchiveBlockReferences(
   177  	ctx context.Context, tlfID tlf.ID,
   178  	contexts kbfsblock.ContextMap) (err error) {
   179  	j.jManager.log.LazyTrace(ctx, "jBServer: ArchiveRef %v", contexts)
   180  	defer func() {
   181  		j.jManager.deferLog.LazyTrace(ctx, "jBServer: ArchiveRef %v done (err=%v)", contexts, err)
   182  	}()
   183  
   184  	// Archives always go straight to the server, since they slow down
   185  	// the journal and already only happen in the background anyway.
   186  	// Note that this means delete operations must be issued after the
   187  	// corresponding MD that unreferenced the block was flushed from
   188  	// the journal.
   189  	return j.BlockServer.ArchiveBlockReferences(ctx, tlfID, contexts)
   190  }
   191  
   192  func (j journalBlockServer) IsUnflushed(ctx context.Context, tlfID tlf.ID,
   193  	id kbfsblock.ID) (isLocal bool, err error) {
   194  	j.jManager.log.LazyTrace(ctx, "jBServer: IsUnflushed %s", id)
   195  	defer func() {
   196  		j.jManager.deferLog.LazyTrace(ctx, "jBServer: IsUnflushed %s done (err=%v)", id, err)
   197  	}()
   198  
   199  	if tlfJournal, ok := j.jManager.getTLFJournal(tlfID, nil); ok {
   200  		defer func() {
   201  			err = translateToBlockServerError(err)
   202  		}()
   203  		return tlfJournal.isBlockUnflushed(ctx, id)
   204  	}
   205  
   206  	return j.BlockServer.IsUnflushed(ctx, tlfID, id)
   207  }
   208  
   209  func (j journalBlockServer) Shutdown(ctx context.Context) {
   210  	j.jManager.shutdown(ctx)
   211  	j.BlockServer.Shutdown(ctx)
   212  }