github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/libkbfs/config_local.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  	"flag"
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  	"sync"
    13  	"time"
    14  
    15  	"github.com/keybase/client/go/kbfs/cache"
    16  	"github.com/keybase/client/go/kbfs/data"
    17  	"github.com/keybase/client/go/kbfs/idutil"
    18  	"github.com/keybase/client/go/kbfs/ioutil"
    19  	"github.com/keybase/client/go/kbfs/kbfscodec"
    20  	"github.com/keybase/client/go/kbfs/kbfscrypto"
    21  	"github.com/keybase/client/go/kbfs/kbfsedits"
    22  	"github.com/keybase/client/go/kbfs/kbfsmd"
    23  	"github.com/keybase/client/go/kbfs/ldbutils"
    24  	"github.com/keybase/client/go/kbfs/libkey"
    25  	"github.com/keybase/client/go/kbfs/tlf"
    26  	"github.com/keybase/client/go/libkb"
    27  	"github.com/keybase/client/go/logger"
    28  	"github.com/keybase/client/go/protocol/keybase1"
    29  	"github.com/pkg/errors"
    30  	metrics "github.com/rcrowley/go-metrics"
    31  	"github.com/shirou/gopsutil/mem"
    32  	"github.com/syndtr/goleveldb/leveldb"
    33  	"github.com/syndtr/goleveldb/leveldb/storage"
    34  	"golang.org/x/net/context"
    35  	"golang.org/x/net/trace"
    36  )
    37  
    38  const (
    39  	// Default time after setting the rekey bit before prompting for a
    40  	// paper key.
    41  	rekeyWithPromptWaitTimeDefault = 10 * time.Minute
    42  	// see Config doc for the purpose of DelayedCancellationGracePeriod
    43  	delayedCancellationGracePeriodDefault = 2 * time.Second
    44  	// tlfValidDurationDefault is the default for tlf validity before redoing identify.
    45  	tlfValidDurationDefault = 6 * time.Hour
    46  	// bgFlushDirOpThresholdDefault is the default for how many
    47  	// directory operations should be batched together in a single
    48  	// background flush.
    49  	bgFlushDirOpBatchSizeDefault = 100
    50  	// bgFlushPeriodDefault is the default for how long to wait for a
    51  	// batch to fill up before syncing a set of changes to the servers.
    52  	bgFlushPeriodDefault         = 1 * time.Second
    53  	keyBundlesCacheCapacityBytes = 10 * cache.MB
    54  	// folder name for persisted config parameters.
    55  	syncedTlfConfigFolderName = "synced_tlf_config"
    56  
    57  	// By default, this will be the block type given to all blocks
    58  	// that aren't explicitly some other type.
    59  	defaultBlockTypeDefault = keybase1.BlockType_DATA
    60  
    61  	// By default, allow 10% of the free bytes on disk to be used in the disk block cache.
    62  	defaultDiskBlockCacheFraction = 0.10
    63  
    64  	// By default, allow 100% of the free bytes on disk to be used in the sync
    65  	// block cache.
    66  	defaultSyncBlockCacheFraction = 1.00
    67  
    68  	// By default, use v2 block encryption.
    69  	defaultBlockCryptVersion = kbfscrypto.EncryptionSecretboxWithKeyNonce
    70  
    71  	// How many times to retry loading the sync DB in the background
    72  	// if there's an error.
    73  	maxSyncDBLoadAttempts = 10
    74  	// How long to wait between load attempts.
    75  	syncDBLoadWaitPeriod = 10 * time.Second
    76  )
    77  
    78  // ConfigLocal implements the Config interface using purely local
    79  // server objects (no KBFS operations used RPCs).
    80  type ConfigLocal struct {
    81  	lock                 sync.RWMutex
    82  	kbfs                 KBFSOps
    83  	keyman               KeyManager
    84  	rep                  Reporter
    85  	kcache               KeyCache
    86  	kbcache              kbfsmd.KeyBundleCache
    87  	bcache               data.BlockCache
    88  	dirtyBcache          data.DirtyBlockCache
    89  	diskBlockCache       DiskBlockCache
    90  	diskMDCache          DiskMDCache
    91  	diskQuotaCache       DiskQuotaCache
    92  	blockMetadataStore   BlockMetadataStore
    93  	xattrStore           XattrStore
    94  	codec                kbfscodec.Codec
    95  	mdops                MDOps
    96  	kops                 libkey.KeyOps
    97  	crypto               Crypto
    98  	chat                 Chat
    99  	mdcache              MDCache
   100  	bops                 BlockOps
   101  	mdserv               MDServer
   102  	bserv                BlockServer
   103  	keyserv              libkey.KeyServer
   104  	service              KeybaseService
   105  	bsplit               data.BlockSplitter
   106  	notifier             Notifier
   107  	clock                Clock
   108  	kbpki                KBPKI
   109  	renamer              ConflictRenamer
   110  	userHistory          *kbfsedits.UserHistory
   111  	registry             metrics.Registry
   112  	loggerFn             func(prefix string) logger.Logger
   113  	noBGFlush            bool // logic opposite so the default value is the common setting
   114  	rwpWaitTime          time.Duration
   115  	diskLimiter          DiskLimiter
   116  	syncedTlfs           map[tlf.ID]FolderSyncConfig // if nil, couldn't load DB
   117  	syncedTlfPaths       map[string]bool
   118  	defaultBlockType     keybase1.BlockType
   119  	kbfsService          *KBFSService
   120  	kbCtx                Context
   121  	rootNodeWrappers     []func(Node) Node
   122  	tlfClearCancels      map[tlf.ID]context.CancelFunc
   123  	vdebugSetting        string
   124  	vlogs                []*libkb.VDebugLog
   125  	resetForLoginTargets []ResetForLoginer
   126  
   127  	maxNameBytes           uint32
   128  	rekeyQueue             RekeyQueue
   129  	storageRoot            string
   130  	diskCacheMode          DiskCacheMode
   131  	diskBlockCacheFraction float64
   132  	syncBlockCacheFraction float64
   133  
   134  	traceLock    sync.RWMutex
   135  	traceEnabled bool
   136  
   137  	delayedCancellationGracePeriod time.Duration
   138  
   139  	// allKnownConfigsForTesting is used for testing, and contains all created
   140  	// Config objects in this test.
   141  	allKnownConfigsForTesting *[]Config
   142  
   143  	// tlfValidDuration is the time TLFs are valid before redoing identification.
   144  	tlfValidDuration time.Duration
   145  
   146  	// bgFlushDirOpBatchSize indicates how many directory operations
   147  	// should be batched together in a single background flush.
   148  	bgFlushDirOpBatchSize int
   149  
   150  	// bgFlushPeriod indicates how long to wait for a batch to fill up
   151  	// before syncing a set of changes to the servers.
   152  	bgFlushPeriod time.Duration
   153  
   154  	// metadataVersion is the version to use when creating new metadata.
   155  	metadataVersion kbfsmd.MetadataVer
   156  
   157  	// blockCryptVersion is the version to use when encrypting blocks.
   158  	blockCryptVersion kbfscrypto.EncryptionVer
   159  
   160  	// conflictResolutionDB stores information about failed CRs
   161  	conflictResolutionDB *ldbutils.LevelDb
   162  
   163  	// settingsDB stores information about local KBFS settings
   164  	settingsDB *SettingsDB
   165  
   166  	mode InitMode
   167  
   168  	quotaUsage      map[keybase1.UserOrTeamID]*EventuallyConsistentQuotaUsage
   169  	rekeyFSMLimiter *OngoingWorkLimiter
   170  
   171  	subscriptionManagerManager *subscriptionManagerManager
   172  }
   173  
   174  // DiskCacheMode represents the mode of initialization for the disk cache.
   175  type DiskCacheMode int
   176  
   177  var _ flag.Value = (*DiskCacheMode)(nil)
   178  
   179  const (
   180  	// DiskCacheModeOff indicates to leave off the disk cache.
   181  	DiskCacheModeOff DiskCacheMode = iota
   182  	// DiskCacheModeLocal indicates to use a local disk cache.
   183  	DiskCacheModeLocal
   184  	// DiskCacheModeRemote indicates to use a remote disk cache.
   185  	DiskCacheModeRemote
   186  )
   187  
   188  // String outputs a human-readable description of this DiskBlockCacheMode.
   189  func (m DiskCacheMode) String() string {
   190  	switch m {
   191  	case DiskCacheModeOff:
   192  		return "off"
   193  	case DiskCacheModeLocal:
   194  		return "local"
   195  	case DiskCacheModeRemote:
   196  		return "remote"
   197  	}
   198  	return "unknown"
   199  }
   200  
   201  // Set parses a string representing a disk block cache initialization mode,
   202  // and outputs the mode value corresponding to that string. Defaults to
   203  // DiskCacheModeOff.
   204  func (m *DiskCacheMode) Set(s string) error {
   205  	*m = DiskCacheModeOff
   206  	switch strings.ToLower(strings.TrimSpace(s)) {
   207  	case "local":
   208  		*m = DiskCacheModeLocal
   209  	case "remote":
   210  		*m = DiskCacheModeRemote
   211  	}
   212  	return nil
   213  }
   214  
   215  var _ Config = (*ConfigLocal)(nil)
   216  
   217  // getDefaultCleanBlockCacheCapacity returns the default clean block
   218  // cache capacity. If we can get total RAM of the system, we cap at
   219  // the smaller of <1/8 of available memory> and
   220  // <MaxBlockSizeBytesDefault * DefaultBlocksInMemCache>; otherwise,
   221  // fallback to latter.
   222  func getDefaultCleanBlockCacheCapacity(mode InitMode) uint64 {
   223  	const minCapacity = 10 * uint64(data.MaxBlockSizeBytesDefault) // 5mb
   224  	capacity := uint64(data.MaxBlockSizeBytesDefault) * DefaultBlocksInMemCache
   225  	vmstat, err := mem.VirtualMemory()
   226  	if err == nil {
   227  		ramBased := vmstat.Total / 8
   228  		if ramBased < minCapacity {
   229  			ramBased = minCapacity
   230  		}
   231  		if ramBased < capacity {
   232  			capacity = ramBased
   233  		}
   234  	}
   235  	if capacity > mode.MaxCleanBlockCacheCapacity() {
   236  		capacity = mode.MaxCleanBlockCacheCapacity()
   237  	}
   238  	return capacity
   239  }
   240  
   241  type keyOpsConfigWrapper struct {
   242  	Config
   243  }
   244  
   245  func (k keyOpsConfigWrapper) KBPKI() idutil.KBPKI {
   246  	return k.Config.KBPKI()
   247  }
   248  
   249  // NewConfigLocal constructs a new ConfigLocal with some default
   250  // components that don't depend on a logger. The caller will have to
   251  // fill in the rest.
   252  //
   253  // TODO: Now that NewConfigLocal takes loggerFn, add more default
   254  // components.
   255  func NewConfigLocal(mode InitMode,
   256  	loggerFn func(module string) logger.Logger,
   257  	storageRoot string, diskCacheMode DiskCacheMode,
   258  	kbCtx Context) *ConfigLocal {
   259  	config := &ConfigLocal{
   260  		loggerFn:        loggerFn,
   261  		storageRoot:     storageRoot,
   262  		mode:            mode,
   263  		diskCacheMode:   diskCacheMode,
   264  		kbCtx:           kbCtx,
   265  		tlfClearCancels: make(map[tlf.ID]context.CancelFunc),
   266  	}
   267  	config.SetCodec(kbfscodec.NewMsgpack())
   268  	if diskCacheMode == DiskCacheModeLocal {
   269  		// Any error is logged in the function itself.
   270  		_ = config.loadSyncedTlfsLocked()
   271  	}
   272  	config.SetClock(data.WallClock{})
   273  	config.SetReporter(NewReporterSimple(config.Clock(), 10))
   274  	config.SetConflictRenamer(WriterDeviceDateConflictRenamer{config})
   275  	config.ResetCaches()
   276  	config.SetKeyOps(libkey.NewKeyOpsStandard(keyOpsConfigWrapper{config}))
   277  	config.SetRekeyQueue(NewRekeyQueueStandard(config))
   278  	uhLog := config.MakeLogger("HIS")
   279  	config.SetUserHistory(kbfsedits.NewUserHistory(
   280  		uhLog, config.MakeVLogger(uhLog)))
   281  
   282  	config.maxNameBytes = data.MaxNameBytesDefault
   283  	config.rwpWaitTime = rekeyWithPromptWaitTimeDefault
   284  
   285  	config.delayedCancellationGracePeriod = delayedCancellationGracePeriodDefault
   286  	// Don't bother creating the registry if UseNilMetrics is set, or
   287  	// if we're in minimal mode.
   288  	if !metrics.UseNilMetrics && config.Mode().MetricsEnabled() {
   289  		registry := metrics.NewRegistry()
   290  		config.SetMetricsRegistry(registry)
   291  	}
   292  
   293  	config.tlfValidDuration = tlfValidDurationDefault
   294  	config.bgFlushDirOpBatchSize = bgFlushDirOpBatchSizeDefault
   295  	config.bgFlushPeriod = bgFlushPeriodDefault
   296  	config.metadataVersion = defaultClientMetadataVer
   297  	config.defaultBlockType = defaultBlockTypeDefault
   298  	config.quotaUsage =
   299  		make(map[keybase1.UserOrTeamID]*EventuallyConsistentQuotaUsage)
   300  	config.rekeyFSMLimiter = NewOngoingWorkLimiter(config.Mode().RekeyWorkers())
   301  	config.diskBlockCacheFraction = defaultDiskBlockCacheFraction
   302  	config.syncBlockCacheFraction = defaultSyncBlockCacheFraction
   303  
   304  	config.blockCryptVersion = defaultBlockCryptVersion
   305  
   306  	config.conflictResolutionDB = openCRDB(config)
   307  	config.settingsDB = openSettingsDB(config)
   308  
   309  	config.subscriptionManagerManager = newSubscriptionManagerManager(config)
   310  
   311  	return config
   312  }
   313  
   314  // KBFSOps implements the Config interface for ConfigLocal.
   315  func (c *ConfigLocal) KBFSOps() KBFSOps {
   316  	c.lock.RLock()
   317  	defer c.lock.RUnlock()
   318  	return c.kbfs
   319  }
   320  
   321  // SetKBFSOps implements the Config interface for ConfigLocal.
   322  func (c *ConfigLocal) SetKBFSOps(k KBFSOps) {
   323  	c.lock.Lock()
   324  	defer c.lock.Unlock()
   325  	c.kbfs = k
   326  }
   327  
   328  // KBPKI implements the Config interface for ConfigLocal.
   329  func (c *ConfigLocal) KBPKI() KBPKI {
   330  	c.lock.RLock()
   331  	defer c.lock.RUnlock()
   332  	return c.kbpki
   333  }
   334  
   335  // CurrentSessionGetter implements the Config interface for ConfigLocal.
   336  func (c *ConfigLocal) CurrentSessionGetter() idutil.CurrentSessionGetter {
   337  	c.lock.RLock()
   338  	defer c.lock.RUnlock()
   339  	return c.kbpki
   340  }
   341  
   342  // SetKBPKI implements the Config interface for ConfigLocal.
   343  func (c *ConfigLocal) SetKBPKI(k KBPKI) {
   344  	c.lock.Lock()
   345  	defer c.lock.Unlock()
   346  	c.kbpki = k
   347  }
   348  
   349  // KeyManager implements the Config interface for ConfigLocal.
   350  func (c *ConfigLocal) KeyManager() KeyManager {
   351  	c.lock.RLock()
   352  	defer c.lock.RUnlock()
   353  	return c.keyman
   354  }
   355  
   356  // SetKeyManager implements the Config interface for ConfigLocal.
   357  func (c *ConfigLocal) SetKeyManager(k KeyManager) {
   358  	c.lock.Lock()
   359  	defer c.lock.Unlock()
   360  	c.keyman = k
   361  }
   362  
   363  // KeyGetter implements the Config interface for ConfigLocal.
   364  func (c *ConfigLocal) keyGetter() blockKeyGetter {
   365  	c.lock.RLock()
   366  	defer c.lock.RUnlock()
   367  	return c.keyman
   368  }
   369  
   370  // Reporter implements the Config interface for ConfigLocal.
   371  func (c *ConfigLocal) Reporter() Reporter {
   372  	c.lock.RLock()
   373  	defer c.lock.RUnlock()
   374  	return c.rep
   375  }
   376  
   377  // SetReporter implements the Config interface for ConfigLocal.
   378  func (c *ConfigLocal) SetReporter(r Reporter) {
   379  	c.lock.Lock()
   380  	defer c.lock.Unlock()
   381  	c.rep = r
   382  }
   383  
   384  // KeyCache implements the Config interface for ConfigLocal.
   385  func (c *ConfigLocal) KeyCache() KeyCache {
   386  	c.lock.RLock()
   387  	defer c.lock.RUnlock()
   388  	return c.kcache
   389  }
   390  
   391  // SetKeyCache implements the Config interface for ConfigLocal.
   392  func (c *ConfigLocal) SetKeyCache(k KeyCache) {
   393  	c.lock.Lock()
   394  	defer c.lock.Unlock()
   395  	c.kcache = k
   396  }
   397  
   398  // KeyBundleCache implements the Config interface for ConfigLocal.
   399  func (c *ConfigLocal) KeyBundleCache() kbfsmd.KeyBundleCache {
   400  	c.lock.RLock()
   401  	defer c.lock.RUnlock()
   402  	return c.kbcache
   403  }
   404  
   405  // SetKeyBundleCache implements the Config interface for ConfigLocal.
   406  func (c *ConfigLocal) SetKeyBundleCache(k kbfsmd.KeyBundleCache) {
   407  	c.lock.Lock()
   408  	defer c.lock.Unlock()
   409  	c.kbcache = k
   410  }
   411  
   412  // BlockCache implements the Config interface for ConfigLocal.
   413  func (c *ConfigLocal) BlockCache() data.BlockCache {
   414  	c.lock.RLock()
   415  	defer c.lock.RUnlock()
   416  	return c.bcache
   417  }
   418  
   419  // SetBlockCache implements the Config interface for ConfigLocal.
   420  func (c *ConfigLocal) SetBlockCache(b data.BlockCache) {
   421  	c.lock.Lock()
   422  	defer c.lock.Unlock()
   423  	c.bcache = b
   424  }
   425  
   426  // DirtyBlockCache implements the Config interface for ConfigLocal.
   427  func (c *ConfigLocal) DirtyBlockCache() data.DirtyBlockCache {
   428  	c.lock.RLock()
   429  	defer c.lock.RUnlock()
   430  	return c.dirtyBcache
   431  }
   432  
   433  // SetDirtyBlockCache implements the Config interface for ConfigLocal.
   434  func (c *ConfigLocal) SetDirtyBlockCache(d data.DirtyBlockCache) {
   435  	c.lock.Lock()
   436  	defer c.lock.Unlock()
   437  	c.dirtyBcache = d
   438  }
   439  
   440  // DiskBlockCache implements the Config interface for ConfigLocal.
   441  func (c *ConfigLocal) DiskBlockCache() DiskBlockCache {
   442  	c.lock.RLock()
   443  	defer c.lock.RUnlock()
   444  	return c.diskBlockCache
   445  }
   446  
   447  // SetDiskBlockCacheFraction implements the Config interface for ConfigLocal.
   448  func (c *ConfigLocal) SetDiskBlockCacheFraction(fraction float64) {
   449  	c.lock.Lock()
   450  	defer c.lock.Unlock()
   451  	c.diskBlockCacheFraction = fraction
   452  }
   453  
   454  // SetSyncBlockCacheFraction implements the Config interface for ConfigLocal.
   455  func (c *ConfigLocal) SetSyncBlockCacheFraction(fraction float64) {
   456  	c.lock.Lock()
   457  	defer c.lock.Unlock()
   458  	c.syncBlockCacheFraction = fraction
   459  }
   460  
   461  // DiskMDCache implements the Config interface for ConfigLocal.
   462  func (c *ConfigLocal) DiskMDCache() DiskMDCache {
   463  	c.lock.RLock()
   464  	defer c.lock.RUnlock()
   465  	return c.diskMDCache
   466  }
   467  
   468  // DiskQuotaCache implements the Config interface for ConfigLocal.
   469  func (c *ConfigLocal) DiskQuotaCache() DiskQuotaCache {
   470  	c.lock.RLock()
   471  	defer c.lock.RUnlock()
   472  	return c.diskQuotaCache
   473  }
   474  
   475  // XattrStore implements the Config interface for ConfigLocal.
   476  func (c *ConfigLocal) XattrStore() XattrStore {
   477  	c.lock.RLock()
   478  	defer c.lock.RUnlock()
   479  	return c.xattrStore
   480  }
   481  
   482  // DiskLimiter implements the Config interface for ConfigLocal.
   483  func (c *ConfigLocal) DiskLimiter() DiskLimiter {
   484  	c.lock.RLock()
   485  	defer c.lock.RUnlock()
   486  	return c.diskLimiter
   487  }
   488  
   489  // Crypto implements the Config interface for ConfigLocal.
   490  func (c *ConfigLocal) Crypto() Crypto {
   491  	c.lock.RLock()
   492  	defer c.lock.RUnlock()
   493  	return c.crypto
   494  }
   495  
   496  // Chat implements the Config interface for ConfigLocal.
   497  func (c *ConfigLocal) Chat() Chat {
   498  	c.lock.RLock()
   499  	defer c.lock.RUnlock()
   500  	return c.chat
   501  }
   502  
   503  // Signer implements the Config interface for ConfigLocal.
   504  func (c *ConfigLocal) Signer() kbfscrypto.Signer {
   505  	c.lock.RLock()
   506  	defer c.lock.RUnlock()
   507  	return c.crypto
   508  }
   509  
   510  // SetCrypto implements the Config interface for ConfigLocal.
   511  func (c *ConfigLocal) SetCrypto(cr Crypto) {
   512  	c.lock.Lock()
   513  	defer c.lock.Unlock()
   514  	c.crypto = cr
   515  }
   516  
   517  // SetChat implements the Config interface for ConfigLocal.
   518  func (c *ConfigLocal) SetChat(ch Chat) {
   519  	c.lock.Lock()
   520  	defer c.lock.Unlock()
   521  	c.chat = ch
   522  }
   523  
   524  // CryptoPure implements the Config interface for ConfigLocal.
   525  func (c *ConfigLocal) cryptoPure() cryptoPure {
   526  	c.lock.RLock()
   527  	defer c.lock.RUnlock()
   528  	return c.crypto
   529  }
   530  
   531  // Codec implements the Config interface for ConfigLocal.
   532  func (c *ConfigLocal) Codec() kbfscodec.Codec {
   533  	c.lock.RLock()
   534  	defer c.lock.RUnlock()
   535  	return c.codec
   536  }
   537  
   538  // SetCodec implements the Config interface for ConfigLocal.
   539  func (c *ConfigLocal) SetCodec(co kbfscodec.Codec) {
   540  	c.lock.Lock()
   541  	defer c.lock.Unlock()
   542  	c.codec = co
   543  	RegisterOps(c.codec)
   544  }
   545  
   546  // MDOps implements the Config interface for ConfigLocal.
   547  func (c *ConfigLocal) MDOps() MDOps {
   548  	c.lock.RLock()
   549  	defer c.lock.RUnlock()
   550  	return c.mdops
   551  }
   552  
   553  // SetMDOps implements the Config interface for ConfigLocal.
   554  func (c *ConfigLocal) SetMDOps(m MDOps) {
   555  	c.lock.Lock()
   556  	defer c.lock.Unlock()
   557  	c.mdops = m
   558  }
   559  
   560  // KeyOps implements the Config interface for ConfigLocal.
   561  func (c *ConfigLocal) KeyOps() libkey.KeyOps {
   562  	c.lock.RLock()
   563  	defer c.lock.RUnlock()
   564  	return c.kops
   565  }
   566  
   567  // SetKeyOps implements the Config interface for ConfigLocal.
   568  func (c *ConfigLocal) SetKeyOps(k libkey.KeyOps) {
   569  	c.lock.Lock()
   570  	defer c.lock.Unlock()
   571  	c.kops = k
   572  }
   573  
   574  // MDCache implements the Config interface for ConfigLocal.
   575  func (c *ConfigLocal) MDCache() MDCache {
   576  	c.lock.RLock()
   577  	defer c.lock.RUnlock()
   578  	return c.mdcache
   579  }
   580  
   581  // SetMDCache implements the Config interface for ConfigLocal.
   582  func (c *ConfigLocal) SetMDCache(m MDCache) {
   583  	c.lock.Lock()
   584  	defer c.lock.Unlock()
   585  	c.mdcache = m
   586  }
   587  
   588  // BlockOps implements the Config interface for ConfigLocal.
   589  func (c *ConfigLocal) BlockOps() BlockOps {
   590  	c.lock.RLock()
   591  	defer c.lock.RUnlock()
   592  	return c.bops
   593  }
   594  
   595  // SetBlockOps implements the Config interface for ConfigLocal.
   596  func (c *ConfigLocal) SetBlockOps(b BlockOps) {
   597  	c.lock.Lock()
   598  	defer c.lock.Unlock()
   599  	c.bops = b
   600  }
   601  
   602  // MDServer implements the Config interface for ConfigLocal.
   603  func (c *ConfigLocal) MDServer() MDServer {
   604  	c.lock.RLock()
   605  	defer c.lock.RUnlock()
   606  	return c.mdserv
   607  }
   608  
   609  // SetMDServer implements the Config interface for ConfigLocal.
   610  func (c *ConfigLocal) SetMDServer(m MDServer) {
   611  	c.lock.Lock()
   612  	defer c.lock.Unlock()
   613  	c.mdserv = m
   614  }
   615  
   616  // BlockServer implements the Config interface for ConfigLocal.
   617  func (c *ConfigLocal) BlockServer() BlockServer {
   618  	c.lock.RLock()
   619  	defer c.lock.RUnlock()
   620  	return c.bserv
   621  }
   622  
   623  // SetBlockServer implements the Config interface for ConfigLocal.
   624  func (c *ConfigLocal) SetBlockServer(b BlockServer) {
   625  	c.lock.Lock()
   626  	defer c.lock.Unlock()
   627  	c.bserv = b
   628  }
   629  
   630  // KeyServer implements the Config interface for ConfigLocal.
   631  func (c *ConfigLocal) KeyServer() libkey.KeyServer {
   632  	c.lock.RLock()
   633  	defer c.lock.RUnlock()
   634  	return c.keyserv
   635  }
   636  
   637  // SetKeyServer implements the Config interface for ConfigLocal.
   638  func (c *ConfigLocal) SetKeyServer(k libkey.KeyServer) {
   639  	c.lock.Lock()
   640  	defer c.lock.Unlock()
   641  	c.keyserv = k
   642  }
   643  
   644  // KeybaseService implements the Config interface for ConfigLocal.
   645  func (c *ConfigLocal) KeybaseService() KeybaseService {
   646  	c.lock.RLock()
   647  	defer c.lock.RUnlock()
   648  	return c.service
   649  }
   650  
   651  // SetKeybaseService implements the Config interface for ConfigLocal.
   652  func (c *ConfigLocal) SetKeybaseService(k KeybaseService) {
   653  	c.lock.Lock()
   654  	defer c.lock.Unlock()
   655  	c.service = k
   656  }
   657  
   658  // BlockSplitter implements the Config interface for ConfigLocal.
   659  func (c *ConfigLocal) BlockSplitter() data.BlockSplitter {
   660  	c.lock.RLock()
   661  	defer c.lock.RUnlock()
   662  	return c.bsplit
   663  }
   664  
   665  // SetBlockSplitter implements the Config interface for ConfigLocal.
   666  func (c *ConfigLocal) SetBlockSplitter(b data.BlockSplitter) {
   667  	c.lock.Lock()
   668  	defer c.lock.Unlock()
   669  	c.bsplit = b
   670  }
   671  
   672  // Notifier implements the Config interface for ConfigLocal.
   673  func (c *ConfigLocal) Notifier() Notifier {
   674  	c.lock.RLock()
   675  	defer c.lock.RUnlock()
   676  	return c.notifier
   677  }
   678  
   679  // SetNotifier implements the Config interface for ConfigLocal.
   680  func (c *ConfigLocal) SetNotifier(n Notifier) {
   681  	c.lock.Lock()
   682  	defer c.lock.Unlock()
   683  	c.notifier = n
   684  }
   685  
   686  // Clock implements the Config interface for ConfigLocal.
   687  func (c *ConfigLocal) Clock() Clock {
   688  	c.lock.RLock()
   689  	defer c.lock.RUnlock()
   690  	return c.clock
   691  }
   692  
   693  // SetClock implements the Config interface for ConfigLocal.
   694  func (c *ConfigLocal) SetClock(cl Clock) {
   695  	c.lock.Lock()
   696  	defer c.lock.Unlock()
   697  	c.clock = cl
   698  }
   699  
   700  // ConflictRenamer implements the Config interface for ConfigLocal.
   701  func (c *ConfigLocal) ConflictRenamer() ConflictRenamer {
   702  	c.lock.RLock()
   703  	defer c.lock.RUnlock()
   704  	return c.renamer
   705  }
   706  
   707  // SetConflictRenamer implements the Config interface for ConfigLocal.
   708  func (c *ConfigLocal) SetConflictRenamer(cr ConflictRenamer) {
   709  	c.lock.Lock()
   710  	defer c.lock.Unlock()
   711  	c.renamer = cr
   712  }
   713  
   714  // UserHistory implements the Config interface for ConfigLocal.
   715  func (c *ConfigLocal) UserHistory() *kbfsedits.UserHistory {
   716  	c.lock.RLock()
   717  	defer c.lock.RUnlock()
   718  	return c.userHistory
   719  }
   720  
   721  // SetUserHistory implements the Config interface for ConfigLocal.
   722  func (c *ConfigLocal) SetUserHistory(uh *kbfsedits.UserHistory) {
   723  	c.lock.Lock()
   724  	defer c.lock.Unlock()
   725  	c.userHistory = uh
   726  }
   727  
   728  // MetadataVersion implements the Config interface for ConfigLocal.
   729  func (c *ConfigLocal) MetadataVersion() kbfsmd.MetadataVer {
   730  	c.lock.RLock()
   731  	defer c.lock.RUnlock()
   732  	return c.metadataVersion
   733  }
   734  
   735  // SetMetadataVersion implements the Config interface for ConfigLocal.
   736  func (c *ConfigLocal) SetMetadataVersion(mdVer kbfsmd.MetadataVer) {
   737  	c.lock.Lock()
   738  	defer c.lock.Unlock()
   739  	c.metadataVersion = mdVer
   740  }
   741  
   742  // DataVersion implements the Config interface for ConfigLocal.
   743  func (c *ConfigLocal) DataVersion() data.Ver {
   744  	return data.IndirectDirsVer
   745  }
   746  
   747  // BlockCryptVersion implements the Config interface for ConfigLocal.
   748  func (c *ConfigLocal) BlockCryptVersion() kbfscrypto.EncryptionVer {
   749  	c.lock.RLock()
   750  	defer c.lock.RUnlock()
   751  	return c.blockCryptVersion
   752  }
   753  
   754  // SetBlockCryptVersion implements the Config interface for ConfigLocal.
   755  func (c *ConfigLocal) SetBlockCryptVersion(ver kbfscrypto.EncryptionVer) {
   756  	c.lock.Lock()
   757  	defer c.lock.Unlock()
   758  	c.blockCryptVersion = ver
   759  }
   760  
   761  // DefaultBlockType implements the Config interface for ConfigLocal.
   762  func (c *ConfigLocal) DefaultBlockType() keybase1.BlockType {
   763  	c.lock.RLock()
   764  	defer c.lock.RUnlock()
   765  	return c.defaultBlockType
   766  }
   767  
   768  // SetDefaultBlockType implements the Config interface for ConfigLocal.
   769  func (c *ConfigLocal) SetDefaultBlockType(blockType keybase1.BlockType) {
   770  	c.lock.Lock()
   771  	defer c.lock.Unlock()
   772  	c.defaultBlockType = blockType
   773  }
   774  
   775  // DoBackgroundFlushes implements the Config interface for ConfigLocal.
   776  func (c *ConfigLocal) DoBackgroundFlushes() bool {
   777  	if !c.Mode().BackgroundFlushesEnabled() {
   778  		return false
   779  	}
   780  
   781  	c.lock.RLock()
   782  	defer c.lock.RUnlock()
   783  	return !c.noBGFlush
   784  }
   785  
   786  // SetDoBackgroundFlushes implements the Config interface for ConfigLocal.
   787  func (c *ConfigLocal) SetDoBackgroundFlushes(doBGFlush bool) {
   788  	c.lock.Lock()
   789  	defer c.lock.Unlock()
   790  	c.noBGFlush = !doBGFlush
   791  }
   792  
   793  // RekeyWithPromptWaitTime implements the Config interface for
   794  // ConfigLocal.
   795  func (c *ConfigLocal) RekeyWithPromptWaitTime() time.Duration {
   796  	c.lock.Lock()
   797  	defer c.lock.Unlock()
   798  	return c.rwpWaitTime
   799  }
   800  
   801  // SetRekeyWithPromptWaitTime implements the Config interface for
   802  // ConfigLocal.
   803  func (c *ConfigLocal) SetRekeyWithPromptWaitTime(d time.Duration) {
   804  	c.lock.RLock()
   805  	defer c.lock.RUnlock()
   806  	c.rwpWaitTime = d
   807  }
   808  
   809  // Mode implements the Config interface for ConfigLocal.
   810  func (c *ConfigLocal) Mode() InitMode {
   811  	c.lock.RLock()
   812  	defer c.lock.RUnlock()
   813  	return c.mode
   814  }
   815  
   816  // SetMode implements the Config interface for ConfigLocal.
   817  func (c *ConfigLocal) SetMode(mode InitMode) {
   818  	c.lock.Lock()
   819  	defer c.lock.Unlock()
   820  	c.mode = mode
   821  }
   822  
   823  // IsTestMode implements the Config interface for ConfigLocal.
   824  func (c *ConfigLocal) IsTestMode() bool {
   825  	c.lock.RLock()
   826  	defer c.lock.RUnlock()
   827  	return c.mode.IsTestMode()
   828  }
   829  
   830  // DelayedCancellationGracePeriod implements the Config interface for ConfigLocal.
   831  func (c *ConfigLocal) DelayedCancellationGracePeriod() time.Duration {
   832  	return c.delayedCancellationGracePeriod
   833  }
   834  
   835  // SetDelayedCancellationGracePeriod implements the Config interface for ConfigLocal.
   836  func (c *ConfigLocal) SetDelayedCancellationGracePeriod(d time.Duration) {
   837  	c.delayedCancellationGracePeriod = d
   838  }
   839  
   840  // ReqsBufSize implements the Config interface for ConfigLocal.
   841  func (c *ConfigLocal) ReqsBufSize() int {
   842  	return 20
   843  }
   844  
   845  // MaxNameBytes implements the Config interface for ConfigLocal.
   846  func (c *ConfigLocal) MaxNameBytes() uint32 {
   847  	return c.maxNameBytes
   848  }
   849  
   850  // SetStorageRoot sets the storage root directory for this config.
   851  func (c *ConfigLocal) SetStorageRoot(storageRoot string) {
   852  	c.lock.Lock()
   853  	defer c.lock.Unlock()
   854  	c.storageRoot = storageRoot
   855  }
   856  
   857  // StorageRoot implements the Config interface for ConfigLocal.
   858  func (c *ConfigLocal) StorageRoot() string {
   859  	c.lock.RLock()
   860  	defer c.lock.RUnlock()
   861  	return c.storageRoot
   862  }
   863  
   864  func (c *ConfigLocal) resetCachesWithoutShutdown() data.DirtyBlockCache {
   865  	c.lock.Lock()
   866  	defer c.lock.Unlock()
   867  	c.mdcache = NewMDCacheStandard(defaultMDCacheCapacity)
   868  	c.kcache = NewKeyCacheStandard(defaultMDCacheCapacity)
   869  	c.kbcache = kbfsmd.NewKeyBundleCacheLRU(keyBundlesCacheCapacityBytes)
   870  
   871  	log := c.MakeLogger("")
   872  	var capacity uint64
   873  	if c.bcache == nil {
   874  		capacity = getDefaultCleanBlockCacheCapacity(c.mode)
   875  		log.Debug("setting default clean block cache capacity to %d",
   876  			capacity)
   877  	} else {
   878  		capacity = c.bcache.GetCleanBytesCapacity()
   879  		log.Debug("setting clean block cache capacity based on existing value %d",
   880  			capacity)
   881  	}
   882  	c.bcache = data.NewBlockCacheStandard(10000, capacity)
   883  
   884  	if !c.mode.DirtyBlockCacheEnabled() {
   885  		return nil
   886  	}
   887  
   888  	oldDirtyBcache := c.dirtyBcache
   889  
   890  	// TODO: we should probably fail or re-schedule this reset if
   891  	// there is anything dirty in the dirty block cache.
   892  
   893  	// The minimum number of bytes we'll try to sync in parallel.
   894  	// This should be roughly the minimum amount of bytes we expect
   895  	// our worst supported connection to send within the timeout
   896  	// forced on us by the upper layer (19 seconds on OS X).  With the
   897  	// current default of a single block, this minimum works out to
   898  	// ~1MB, so we can support a connection speed as low as ~54 KB/s.
   899  	minSyncBufferSize := int64(data.MaxBlockSizeBytesDefault)
   900  
   901  	// The maximum number of bytes we can try to sync at once (also limits the
   902  	// amount of memory used by dirty blocks). We use the same value from clean
   903  	// block cache capacity here.
   904  	maxSyncBufferSize := int64(capacity)
   905  
   906  	// Start off conservatively to avoid getting immediate timeouts on
   907  	// slow connections.
   908  	startSyncBufferSize := minSyncBufferSize
   909  
   910  	dbcLog := c.MakeLogger("DBC")
   911  	c.dirtyBcache = data.NewDirtyBlockCacheStandard(
   912  		c.clock, dbcLog, c.makeVLoggerLocked(dbcLog),
   913  		minSyncBufferSize, maxSyncBufferSize, startSyncBufferSize)
   914  	return oldDirtyBcache
   915  }
   916  
   917  // ResetCaches implements the Config interface for ConfigLocal.
   918  func (c *ConfigLocal) ResetCaches() {
   919  	oldDirtyBcache := c.resetCachesWithoutShutdown()
   920  	jManager, err := GetJournalManager(c)
   921  	if err == nil {
   922  		if err := c.journalizeBcaches(jManager); err != nil {
   923  			if log := c.MakeLogger(""); log != nil {
   924  				log.CWarningf(
   925  					context.TODO(),
   926  					"Error journalizing dirty block cache: %+v", err)
   927  			}
   928  		}
   929  	}
   930  	if oldDirtyBcache != nil {
   931  		// Shutdown outside of the lock so it doesn't block other
   932  		// access to this config.
   933  		if err := oldDirtyBcache.Shutdown(); err != nil {
   934  			if log := c.MakeLogger(""); log != nil {
   935  				log.CWarningf(
   936  					context.TODO(),
   937  					"Error shutting down old dirty block cache: %+v", err)
   938  			}
   939  		}
   940  	}
   941  }
   942  
   943  // MakeLogger implements the logMaker interface for ConfigLocal.
   944  func (c *ConfigLocal) MakeLogger(module string) logger.Logger {
   945  	// No need to lock since c.loggerFn is initialized once at
   946  	// construction. Also resetCachesWithoutShutdown would deadlock.
   947  	return c.loggerFn(module)
   948  }
   949  
   950  func (c *ConfigLocal) makeVLoggerLocked(log logger.Logger) *libkb.VDebugLog {
   951  	vlog := libkb.NewVDebugLog(log)
   952  	vlog.Configure(c.vdebugSetting)
   953  	c.vlogs = append(c.vlogs, vlog)
   954  	return vlog
   955  }
   956  
   957  // MakeVLogger implements the logMaker interface for ConfigLocal.
   958  func (c *ConfigLocal) MakeVLogger(log logger.Logger) *libkb.VDebugLog {
   959  	c.lock.Lock()
   960  	defer c.lock.Unlock()
   961  	return c.makeVLoggerLocked(log)
   962  }
   963  
   964  // MetricsRegistry implements the Config interface for ConfigLocal.
   965  func (c *ConfigLocal) MetricsRegistry() metrics.Registry {
   966  	return c.registry
   967  }
   968  
   969  // SetRekeyQueue implements the Config interface for ConfigLocal.
   970  func (c *ConfigLocal) SetRekeyQueue(r RekeyQueue) {
   971  	c.rekeyQueue = r
   972  }
   973  
   974  // RekeyQueue implements the Config interface for ConfigLocal.
   975  func (c *ConfigLocal) RekeyQueue() RekeyQueue {
   976  	return c.rekeyQueue
   977  }
   978  
   979  // SetMetricsRegistry implements the Config interface for ConfigLocal.
   980  func (c *ConfigLocal) SetMetricsRegistry(r metrics.Registry) {
   981  	c.registry = r
   982  }
   983  
   984  // SetTraceOptions implements the Config interface for ConfigLocal.
   985  func (c *ConfigLocal) SetTraceOptions(enabled bool) {
   986  	c.traceLock.Lock()
   987  	defer c.traceLock.Unlock()
   988  	c.traceEnabled = enabled
   989  }
   990  
   991  // MaybeStartTrace implements the Config interface for ConfigLocal.
   992  func (c *ConfigLocal) MaybeStartTrace(
   993  	ctx context.Context, family, title string) context.Context {
   994  	traceEnabled := func() bool {
   995  		c.traceLock.RLock()
   996  		defer c.traceLock.RUnlock()
   997  		return c.traceEnabled
   998  	}()
   999  	if !traceEnabled {
  1000  		return ctx
  1001  	}
  1002  
  1003  	tr := trace.New(family, title)
  1004  	tr.SetMaxEvents(25)
  1005  	ctx = trace.NewContext(ctx, tr)
  1006  	return ctx
  1007  }
  1008  
  1009  // MaybeFinishTrace implements the Config interface for ConfigLocal.
  1010  func (c *ConfigLocal) MaybeFinishTrace(ctx context.Context, err error) {
  1011  	if tr, ok := trace.FromContext(ctx); ok {
  1012  		if err != nil {
  1013  			tr.LazyPrintf("err=%+v", err)
  1014  			tr.SetError()
  1015  		}
  1016  		tr.Finish()
  1017  	}
  1018  }
  1019  
  1020  // SetTLFValidDuration implements the Config interface for ConfigLocal.
  1021  func (c *ConfigLocal) SetTLFValidDuration(r time.Duration) {
  1022  	c.tlfValidDuration = r
  1023  }
  1024  
  1025  // TLFValidDuration implements the Config interface for ConfigLocal.
  1026  func (c *ConfigLocal) TLFValidDuration() time.Duration {
  1027  	return c.tlfValidDuration
  1028  }
  1029  
  1030  // SetBGFlushDirOpBatchSize implements the Config interface for ConfigLocal.
  1031  func (c *ConfigLocal) SetBGFlushDirOpBatchSize(s int) {
  1032  	c.lock.Lock()
  1033  	defer c.lock.Unlock()
  1034  	c.bgFlushDirOpBatchSize = s
  1035  }
  1036  
  1037  // BGFlushDirOpBatchSize implements the Config interface for ConfigLocal.
  1038  func (c *ConfigLocal) BGFlushDirOpBatchSize() int {
  1039  	c.lock.RLock()
  1040  	defer c.lock.RUnlock()
  1041  	return c.bgFlushDirOpBatchSize
  1042  }
  1043  
  1044  // SetBGFlushPeriod implements the Config interface for ConfigLocal.
  1045  func (c *ConfigLocal) SetBGFlushPeriod(p time.Duration) {
  1046  	c.lock.Lock()
  1047  	defer c.lock.Unlock()
  1048  	c.bgFlushPeriod = p
  1049  }
  1050  
  1051  // BGFlushPeriod implements the Config interface for ConfigLocal.
  1052  func (c *ConfigLocal) BGFlushPeriod() time.Duration {
  1053  	c.lock.RLock()
  1054  	defer c.lock.RUnlock()
  1055  	return c.bgFlushPeriod
  1056  }
  1057  
  1058  // Shutdown implements the Config interface for ConfigLocal.
  1059  func (c *ConfigLocal) Shutdown(ctx context.Context) error {
  1060  	c.RekeyQueue().Shutdown()
  1061  	if c.CheckStateOnShutdown() && c.allKnownConfigsForTesting != nil {
  1062  		// Before we do anything, wait for all archiving and
  1063  		// journaling to finish.
  1064  		for _, config := range *c.allKnownConfigsForTesting {
  1065  			kbfsOps, ok := config.KBFSOps().(*KBFSOpsStandard)
  1066  			if !ok {
  1067  				continue
  1068  			}
  1069  			if err := kbfsOps.shutdownEdits(ctx); err != nil {
  1070  				return err
  1071  			}
  1072  			for _, fbo := range kbfsOps.ops {
  1073  				if err := fbo.fbm.waitForArchives(ctx); err != nil {
  1074  					return err
  1075  				}
  1076  				if err := fbo.fbm.waitForDeletingBlocks(ctx); err != nil {
  1077  					return err
  1078  				}
  1079  				log := config.MakeLogger("")
  1080  				if err := WaitForTLFJournal(ctx, config, fbo.id(),
  1081  					log); err != nil {
  1082  					return err
  1083  				}
  1084  				// The above wait could have resulted in some MD
  1085  				// flushes, so now we have to wait on any archives as
  1086  				// well.  We only need one more check for this, since
  1087  				// archives don't produce MDs.
  1088  				if err := fbo.mdFlushes.Wait(ctx); err != nil {
  1089  					return err
  1090  				}
  1091  				if err := fbo.fbm.waitForArchives(ctx); err != nil {
  1092  					return err
  1093  				}
  1094  				if err := WaitForTLFJournal(ctx, config, fbo.id(),
  1095  					log); err != nil {
  1096  					return err
  1097  				}
  1098  			}
  1099  		}
  1100  	}
  1101  
  1102  	var errorList []error
  1103  	err := c.KBFSOps().Shutdown(ctx)
  1104  	if err != nil {
  1105  		errorList = append(errorList, err)
  1106  		// Continue with shutdown regardless of err.
  1107  	}
  1108  	err = c.BlockOps().Shutdown(ctx)
  1109  	if err != nil {
  1110  		errorList = append(errorList, err)
  1111  	}
  1112  	c.MDServer().Shutdown()
  1113  	c.KeyServer().Shutdown()
  1114  	c.KeybaseService().Shutdown()
  1115  	c.BlockServer().Shutdown(ctx)
  1116  	c.Crypto().Shutdown()
  1117  	c.Reporter().Shutdown()
  1118  	dirtyBcache := c.DirtyBlockCache()
  1119  	if dirtyBcache != nil {
  1120  		err = dirtyBcache.Shutdown()
  1121  	}
  1122  	if err != nil {
  1123  		errorList = append(errorList, err)
  1124  	}
  1125  	dbc := c.DiskBlockCache()
  1126  	if dbc != nil {
  1127  		dbc.Shutdown(ctx)
  1128  	}
  1129  	dmc := c.DiskMDCache()
  1130  	if dmc != nil {
  1131  		dmc.Shutdown(ctx)
  1132  	}
  1133  	dqc := c.DiskQuotaCache()
  1134  	if dqc != nil {
  1135  		dqc.Shutdown(ctx)
  1136  	}
  1137  	bms := c.blockMetadataStore
  1138  	if bms != nil {
  1139  		bms.Shutdown()
  1140  	}
  1141  	if c.conflictResolutionDB != nil {
  1142  		if err := c.conflictResolutionDB.Close(); err != nil {
  1143  			errorList = append(errorList, err)
  1144  		}
  1145  	}
  1146  	if c.settingsDB != nil {
  1147  		if err := c.settingsDB.Close(); err != nil {
  1148  			errorList = append(errorList, err)
  1149  		}
  1150  	}
  1151  	kbfsServ := c.kbfsService
  1152  	if kbfsServ != nil {
  1153  		kbfsServ.Shutdown()
  1154  	}
  1155  
  1156  	c.subscriptionManagerManager.Shutdown(ctx)
  1157  
  1158  	if len(errorList) == 1 {
  1159  		return errorList[0]
  1160  	} else if len(errorList) > 1 {
  1161  		// Aggregate errors
  1162  		return errors.Errorf("Multiple errors on shutdown: %+v", errorList)
  1163  	}
  1164  
  1165  	c.lock.Lock()
  1166  	defer c.lock.Unlock()
  1167  	for _, cancel := range c.tlfClearCancels {
  1168  		cancel()
  1169  	}
  1170  
  1171  	return nil
  1172  }
  1173  
  1174  // CheckStateOnShutdown implements the Config interface for ConfigLocal.
  1175  func (c *ConfigLocal) CheckStateOnShutdown() bool {
  1176  	if !c.IsTestMode() {
  1177  		return false
  1178  	}
  1179  	if md, ok := c.MDServer().(mdServerLocal); ok {
  1180  		return !md.isShutdown()
  1181  	}
  1182  	return false
  1183  }
  1184  
  1185  func (c *ConfigLocal) journalizeBcaches(jManager *JournalManager) error {
  1186  	syncCache, ok := c.DirtyBlockCache().(*data.DirtyBlockCacheStandard)
  1187  	if !ok {
  1188  		return errors.Errorf("Dirty bcache unexpectedly type %T", syncCache)
  1189  	}
  1190  	jManager.delegateDirtyBlockCache = syncCache
  1191  
  1192  	// Make a dirty block cache specifically for the journal
  1193  	// server.  Since this doesn't rely directly on the network,
  1194  	// there's no need for an adaptive sync buffer size, so we
  1195  	// always set the min and max to the same thing.
  1196  	maxSyncBufferSize := int64(ForcedBranchSquashBytesThresholdDefault)
  1197  	log := c.MakeLogger("DBCJ")
  1198  	journalCache := data.NewDirtyBlockCacheStandard(
  1199  		c.clock, log, c.MakeVLogger(log),
  1200  		maxSyncBufferSize, maxSyncBufferSize, maxSyncBufferSize)
  1201  	c.SetDirtyBlockCache(jManager.dirtyBlockCache(journalCache))
  1202  
  1203  	jManager.delegateBlockCache = c.BlockCache()
  1204  	c.SetBlockCache(jManager.blockCache())
  1205  	return nil
  1206  }
  1207  
  1208  // GetQuotaUsage implements the Config interface for ConfigLocal.
  1209  func (c *ConfigLocal) GetQuotaUsage(
  1210  	chargedTo keybase1.UserOrTeamID) *EventuallyConsistentQuotaUsage {
  1211  	c.lock.RLock()
  1212  	quota, ok := c.quotaUsage[chargedTo]
  1213  	if ok {
  1214  		c.lock.RUnlock()
  1215  		return quota
  1216  	}
  1217  	c.lock.RUnlock()
  1218  
  1219  	c.lock.Lock()
  1220  	defer c.lock.Unlock()
  1221  	quota, ok = c.quotaUsage[chargedTo]
  1222  	log := c.MakeLogger(QuotaUsageLogModule("BDL"))
  1223  	vlog := c.makeVLoggerLocked(log)
  1224  	if !ok {
  1225  		if chargedTo.IsTeamOrSubteam() {
  1226  			quota = NewEventuallyConsistentTeamQuotaUsage(
  1227  				c, chargedTo.AsTeamOrBust(), log, vlog)
  1228  		} else {
  1229  			quota = NewEventuallyConsistentQuotaUsage(c, log, vlog)
  1230  		}
  1231  		c.quotaUsage[chargedTo] = quota
  1232  	}
  1233  	return quota
  1234  }
  1235  
  1236  // GetPerfLog returns the performance logger for KBFS.
  1237  func (c *ConfigLocal) GetPerfLog() logger.Logger {
  1238  	perfLog := c.kbCtx.GetPerfLog()
  1239  	if perfLog != nil {
  1240  		return perfLog
  1241  	}
  1242  	return c.MakeLogger("")
  1243  }
  1244  
  1245  // EnableDiskLimiter fills in c.diskLimiter for use in journaling and
  1246  // disk caching. It returns the EventuallyConsistentQuotaUsage object
  1247  // used by the disk limiter.
  1248  func (c *ConfigLocal) EnableDiskLimiter(configRoot string) error {
  1249  	if c.diskLimiter != nil {
  1250  		return errors.New("c.diskLimiter is already non-nil")
  1251  	}
  1252  
  1253  	params := makeDefaultBackpressureDiskLimiterParams(
  1254  		configRoot, c.GetQuotaUsage, c.diskBlockCacheFraction, c.syncBlockCacheFraction)
  1255  	log := c.MakeLogger("")
  1256  	log.Debug("Setting disk storage byte limit to %d and file limit to %d",
  1257  		params.byteLimit, params.fileLimit)
  1258  	err := os.MkdirAll(configRoot, 0700)
  1259  	if err != nil {
  1260  		return err
  1261  	}
  1262  
  1263  	diskLimiter, err := newBackpressureDiskLimiter(log, params)
  1264  	if err != nil {
  1265  		return err
  1266  	}
  1267  	c.diskLimiter = diskLimiter
  1268  	return nil
  1269  }
  1270  
  1271  // EnableJournaling creates a JournalManager and attaches it to
  1272  // this config. journalRoot must be non-empty. Errors returned are
  1273  // non-fatal.
  1274  func (c *ConfigLocal) EnableJournaling(
  1275  	ctx context.Context, journalRoot string,
  1276  	bws TLFJournalBackgroundWorkStatus) error {
  1277  	jManager, err := GetJournalManager(c)
  1278  	if err == nil {
  1279  		// Journaling shouldn't be enabled twice for the same
  1280  		// config.
  1281  		return errors.New("trying to enable journaling twice")
  1282  	}
  1283  
  1284  	if c.diskLimiter == nil {
  1285  		return errors.New("disk limiter must be enabled to enable journaling")
  1286  	}
  1287  
  1288  	// TODO: Sanity-check the root directory, e.g. create
  1289  	// it if it doesn't exist, make sure that it doesn't
  1290  	// point to /keybase itself, etc.
  1291  	log := c.MakeLogger("")
  1292  	branchListener := c.KBFSOps().(branchChangeListener)
  1293  	flushListener := c.KBFSOps().(mdFlushListener)
  1294  
  1295  	// Make sure the journal root exists.
  1296  	err = ioutil.MkdirAll(journalRoot, 0700)
  1297  	if err != nil {
  1298  		return err
  1299  	}
  1300  
  1301  	jManager = makeJournalManager(c, log, journalRoot, c.BlockCache(),
  1302  		c.DirtyBlockCache(), c.BlockServer(), c.MDOps(), branchListener,
  1303  		flushListener, bws)
  1304  
  1305  	c.SetBlockServer(jManager.blockServer())
  1306  	c.SetMDOps(jManager.mdOps())
  1307  
  1308  	bcacheErr := c.journalizeBcaches(jManager)
  1309  	enableErr := func() error {
  1310  		// If this fails, then existing journals will be
  1311  		// enabled when we receive the login notification.
  1312  		session, err := c.KBPKI().GetCurrentSession(ctx)
  1313  		if err != nil {
  1314  			return err
  1315  		}
  1316  
  1317  		err = jManager.EnableExistingJournals(
  1318  			ctx, session.UID, session.VerifyingKey, bws)
  1319  		if err != nil {
  1320  			return err
  1321  		}
  1322  
  1323  		wg := jManager.MakeFBOsForExistingJournals(ctx)
  1324  		wg.Wait()
  1325  		return nil
  1326  	}()
  1327  	switch {
  1328  	case bcacheErr != nil && enableErr != nil:
  1329  		return errors.Errorf(
  1330  			"Got errors %+v and %+v", bcacheErr, enableErr)
  1331  	case bcacheErr != nil:
  1332  		return bcacheErr
  1333  	case enableErr != nil:
  1334  		return enableErr
  1335  	}
  1336  
  1337  	return nil
  1338  }
  1339  
  1340  func (c *ConfigLocal) cleanSyncBlockCacheForTlfInBackgroundLocked(
  1341  	tlfID tlf.ID, ch chan<- error) {
  1342  	// Start a background goroutine deleting all the blocks from this
  1343  	// TLF.
  1344  	ctx, cancel := context.WithCancel(context.Background())
  1345  	if oldCancel, ok := c.tlfClearCancels[tlfID]; ok {
  1346  		oldCancel()
  1347  	}
  1348  	c.tlfClearCancels[tlfID] = cancel
  1349  	diskBlockCache := c.diskBlockCache
  1350  	go func() {
  1351  		defer cancel()
  1352  		ch <- diskBlockCache.ClearAllTlfBlocks(
  1353  			ctx, tlfID, DiskBlockSyncCache)
  1354  	}()
  1355  }
  1356  
  1357  func (c *ConfigLocal) cleanSyncBlockCache() {
  1358  	ctx := context.Background()
  1359  	dbc := c.DiskBlockCache()
  1360  	log := c.MakeLogger("")
  1361  	if dbc == nil {
  1362  		// This could happen if there's a race with the caches being
  1363  		// reset multiple times in a row.  Hopefully the next reset
  1364  		// will clean the caches properly.
  1365  		log.CDebugf(ctx, "No cache set; skipping sync cleaning")
  1366  		return
  1367  	}
  1368  	err := dbc.WaitUntilStarted(DiskBlockSyncCache)
  1369  	if err != nil {
  1370  		log.CDebugf(
  1371  			ctx, "Disk block cache failed to start; can't clean: %+v", err)
  1372  		return
  1373  	}
  1374  
  1375  	c.lock.Lock()
  1376  	defer c.lock.Unlock()
  1377  
  1378  	for i := 0; c.syncedTlfs == nil && i < maxSyncDBLoadAttempts; i++ {
  1379  		// Sometimes transient iOS storage permission errors prevent
  1380  		// us from reading the sync config DB on startup.  In that
  1381  		// case, the `syncedTlfs` map will be nil, but we don't want
  1382  		// to delete all the synced blocks.
  1383  		log.CDebugf(
  1384  			ctx, "Re-loading synced TLF list for cleaning")
  1385  
  1386  		err := c.loadSyncedTlfsLocked()
  1387  		if err == nil {
  1388  			break
  1389  		}
  1390  		c.lock.Unlock()
  1391  		time.Sleep(syncDBLoadWaitPeriod)
  1392  		c.lock.Lock()
  1393  	}
  1394  	if c.syncedTlfs == nil {
  1395  		log.CDebugf(
  1396  			ctx, "Couldn't load synced TLF list for cleaning; giving up")
  1397  		return
  1398  	}
  1399  
  1400  	cacheTlfIDs, err := c.diskBlockCache.GetTlfIDs(ctx, DiskBlockSyncCache)
  1401  	if err != nil {
  1402  		log.CDebugf(
  1403  			ctx, "Disk block cache can't get TLF IDs; can't clean: %+v", err)
  1404  		return
  1405  	}
  1406  
  1407  	for _, id := range cacheTlfIDs {
  1408  		if _, ok := c.syncedTlfs[id]; ok {
  1409  			continue
  1410  		}
  1411  
  1412  		c.GetPerfLog().CDebugf(ctx, "Clearing KBFS sync blocks for TLF %s", id)
  1413  		c.cleanSyncBlockCacheForTlfInBackgroundLocked(id, make(chan error, 1))
  1414  	}
  1415  }
  1416  
  1417  func (c *ConfigLocal) resetDiskBlockCacheLocked() error {
  1418  	dbc, err := newDiskBlockCacheWrapped(c, c.storageRoot, c.mode)
  1419  	if err != nil {
  1420  		return err
  1421  	}
  1422  	c.diskBlockCache = dbc
  1423  	if !c.mode.IsTestMode() {
  1424  		go c.cleanSyncBlockCache()
  1425  	}
  1426  	return nil
  1427  }
  1428  
  1429  // MakeDiskBlockCacheIfNotExists implements the Config interface for
  1430  // ConfigLocal.
  1431  func (c *ConfigLocal) MakeDiskBlockCacheIfNotExists() error {
  1432  	c.lock.Lock()
  1433  	defer c.lock.Unlock()
  1434  	if c.diskBlockCache != nil {
  1435  		return nil
  1436  	}
  1437  	switch c.diskCacheMode {
  1438  	case DiskCacheModeOff:
  1439  		return nil
  1440  	case DiskCacheModeLocal:
  1441  		return c.resetDiskBlockCacheLocked()
  1442  	case DiskCacheModeRemote:
  1443  		dbc, err := NewDiskBlockCacheRemote(c.kbCtx, c)
  1444  		if err != nil {
  1445  			return err
  1446  		}
  1447  		c.diskBlockCache = dbc
  1448  		return nil
  1449  	}
  1450  	return nil
  1451  }
  1452  
  1453  func (c *ConfigLocal) resetDiskMDCacheLocked() error {
  1454  	dmc, err := newDiskMDCacheLocal(c, c.storageRoot, c.mode)
  1455  	if err != nil {
  1456  		return err
  1457  	}
  1458  	if c.diskMDCache != nil {
  1459  		c.diskMDCache.Shutdown(context.TODO())
  1460  	}
  1461  	c.diskMDCache = dmc
  1462  	return nil
  1463  }
  1464  
  1465  // MakeDiskMDCacheIfNotExists implements the Config interface for
  1466  // ConfigLocal.
  1467  func (c *ConfigLocal) MakeDiskMDCacheIfNotExists() error {
  1468  	c.lock.Lock()
  1469  	defer c.lock.Unlock()
  1470  	if c.diskMDCache != nil {
  1471  		return nil
  1472  	}
  1473  	return c.resetDiskMDCacheLocked()
  1474  }
  1475  
  1476  func (c *ConfigLocal) resetDiskQuotaCacheLocked() error {
  1477  	dqc, err := newDiskQuotaCacheLocal(c, c.storageRoot, c.mode)
  1478  	if err != nil {
  1479  		return err
  1480  	}
  1481  	if c.diskQuotaCache != nil {
  1482  		c.diskQuotaCache.Shutdown(context.TODO())
  1483  	}
  1484  	c.diskQuotaCache = dqc
  1485  	return nil
  1486  }
  1487  
  1488  // MakeDiskQuotaCacheIfNotExists implements the Config interface for
  1489  // ConfigLocal.
  1490  func (c *ConfigLocal) MakeDiskQuotaCacheIfNotExists() error {
  1491  	c.lock.Lock()
  1492  	defer c.lock.Unlock()
  1493  	if c.diskQuotaCache != nil {
  1494  		return nil
  1495  	}
  1496  	return c.resetDiskQuotaCacheLocked()
  1497  }
  1498  
  1499  // MakeBlockMetadataStoreIfNotExists implements the Config interface for
  1500  // ConfigLocal. If error happens, a Noop one is populated.
  1501  func (c *ConfigLocal) MakeBlockMetadataStoreIfNotExists() (err error) {
  1502  	c.lock.Lock()
  1503  	defer c.lock.Unlock()
  1504  	defer func() {
  1505  		c.xattrStore = NewXattrStoreFromBlockMetadataStore(c.blockMetadataStore)
  1506  	}()
  1507  	if c.blockMetadataStore != nil {
  1508  		return nil
  1509  	}
  1510  	c.blockMetadataStore, err = newDiskBlockMetadataStore(
  1511  		c, c.mode, c.storageRoot)
  1512  	if err != nil {
  1513  		// TODO (KBFS-3659): when we can open levelDB read-only,
  1514  		//  do that instead of returning a Noop version.
  1515  		c.blockMetadataStore = &NoopBlockMetadataStore{}
  1516  		return err
  1517  	}
  1518  	return nil
  1519  }
  1520  
  1521  func (c *ConfigLocal) openConfigLevelDB(configName string) (
  1522  	*ldbutils.LevelDb, error) {
  1523  	dbPath := filepath.Join(c.storageRoot, configName)
  1524  	stor, err := storage.OpenFile(dbPath, false)
  1525  	if err != nil {
  1526  		return nil, err
  1527  	}
  1528  	return ldbutils.OpenLevelDb(stor, c.mode)
  1529  }
  1530  
  1531  func (c *ConfigLocal) loadSyncedTlfsLocked() (err error) {
  1532  	defer func() {
  1533  		ctx := context.TODO()
  1534  		c.MakeLogger("").CDebugf(ctx, "Loaded synced TLFs: %+v", err)
  1535  		if err != nil {
  1536  			// Should already be nil, but make it explicit just in
  1537  			// case, since the cleaning behavior depends on it being
  1538  			// nil if there has been an error.
  1539  			c.syncedTlfs = nil
  1540  			c.GetPerfLog().CDebugf(
  1541  				ctx, "KBFS failed to open synced TLFs database: %v", err)
  1542  		} else {
  1543  			c.GetPerfLog().CDebugf(
  1544  				ctx, "KBFS loaded %d synced TLFs", len(c.syncedTlfs))
  1545  		}
  1546  	}()
  1547  	syncedTlfs := make(map[tlf.ID]FolderSyncConfig)
  1548  	syncedTlfPaths := make(map[string]bool)
  1549  	if c.mode.IsTestMode() {
  1550  		c.syncedTlfs = syncedTlfs
  1551  		c.syncedTlfPaths = syncedTlfPaths
  1552  		return nil
  1553  	}
  1554  	if c.storageRoot == "" {
  1555  		return errors.New("empty storageRoot specified for non-test run")
  1556  	}
  1557  	ldb, err := c.openConfigLevelDB(syncedTlfConfigFolderName)
  1558  	if err != nil {
  1559  		return err
  1560  	}
  1561  	defer ldb.Close()
  1562  	iter := ldb.NewIterator(nil, nil)
  1563  	defer iter.Release()
  1564  
  1565  	log := c.MakeLogger("")
  1566  	// If there are any un-parseable IDs, delete them.
  1567  	deleteBatch := new(leveldb.Batch)
  1568  	for iter.Next() {
  1569  		key := string(iter.Key())
  1570  		tlfID, err := tlf.ParseID(key)
  1571  		if err != nil {
  1572  			log.Debug("deleting TLF %s from synced TLF list", key)
  1573  			deleteBatch.Delete(iter.Key())
  1574  			continue
  1575  		}
  1576  		var config FolderSyncConfig
  1577  		val := iter.Value()
  1578  		if val != nil {
  1579  			err = c.codec.Decode(val, &config)
  1580  			if err != nil {
  1581  				return err
  1582  			}
  1583  		} else {
  1584  			// For backwards-compatibility, consider a nil value to
  1585  			// mean "enabled".
  1586  			config.Mode = keybase1.FolderSyncMode_ENABLED
  1587  		}
  1588  		syncedTlfs[tlfID] = config
  1589  		if config.TlfPath != "" {
  1590  			syncedTlfPaths[config.TlfPath] = true
  1591  		}
  1592  	}
  1593  	c.syncedTlfs = syncedTlfs
  1594  	c.syncedTlfPaths = syncedTlfPaths
  1595  	return ldb.Write(deleteBatch, nil)
  1596  }
  1597  
  1598  // GetTlfSyncState implements the syncedTlfGetterSetter interface for
  1599  // ConfigLocal.
  1600  func (c *ConfigLocal) GetTlfSyncState(tlfID tlf.ID) FolderSyncConfig {
  1601  	c.lock.RLock()
  1602  	defer c.lock.RUnlock()
  1603  	return c.syncedTlfs[tlfID]
  1604  }
  1605  
  1606  // IsSyncedTlf implements the syncedTlfGetterSetter interface for
  1607  // ConfigLocal.
  1608  func (c *ConfigLocal) IsSyncedTlf(tlfID tlf.ID) bool {
  1609  	return c.GetTlfSyncState(tlfID).Mode == keybase1.FolderSyncMode_ENABLED
  1610  }
  1611  
  1612  // IsSyncedTlfPath implements the syncedTlfGetterSetter interface for
  1613  // ConfigLocal.
  1614  func (c *ConfigLocal) IsSyncedTlfPath(tlfPath string) bool {
  1615  	c.lock.RLock()
  1616  	defer c.lock.RUnlock()
  1617  	return c.syncedTlfPaths[tlfPath]
  1618  }
  1619  
  1620  // OfflineAvailabilityForPath implements the offlineStatusGetter
  1621  // interface for ConfigLocal.
  1622  func (c *ConfigLocal) OfflineAvailabilityForPath(
  1623  	tlfPath string) keybase1.OfflineAvailability {
  1624  	if c.IsSyncedTlfPath(tlfPath) {
  1625  		return keybase1.OfflineAvailability_BEST_EFFORT
  1626  	}
  1627  	return keybase1.OfflineAvailability_NONE
  1628  }
  1629  
  1630  // OfflineAvailabilityForID implements the offlineStatusGetter
  1631  // interface for ConfigLocal.
  1632  func (c *ConfigLocal) OfflineAvailabilityForID(
  1633  	tlfID tlf.ID) keybase1.OfflineAvailability {
  1634  	if c.GetTlfSyncState(tlfID).Mode != keybase1.FolderSyncMode_DISABLED {
  1635  		return keybase1.OfflineAvailability_BEST_EFFORT
  1636  	}
  1637  	return keybase1.OfflineAvailability_NONE
  1638  }
  1639  
  1640  func (c *ConfigLocal) setTlfSyncState(
  1641  	ctx context.Context, tlfID tlf.ID, config FolderSyncConfig) (
  1642  	<-chan error, error) {
  1643  	c.lock.Lock()
  1644  	defer c.lock.Unlock()
  1645  	diskCacheWrapped, ok := c.diskBlockCache.(*diskBlockCacheWrapped)
  1646  	if !ok {
  1647  		return nil, errors.Errorf(
  1648  			"invalid disk cache type to set TLF sync state: %T",
  1649  			c.diskBlockCache)
  1650  	}
  1651  	if !diskCacheWrapped.IsSyncCacheEnabled() {
  1652  		return nil, errors.New("sync block cache is not enabled")
  1653  	}
  1654  
  1655  	if !c.mode.IsTestMode() {
  1656  		if c.storageRoot == "" {
  1657  			return nil, errors.New(
  1658  				"empty storageRoot specified for non-test run")
  1659  		}
  1660  		ldb, err := c.openConfigLevelDB(syncedTlfConfigFolderName)
  1661  		if err != nil {
  1662  			return nil, err
  1663  		}
  1664  		defer ldb.Close()
  1665  		tlfBytes, err := tlfID.MarshalText()
  1666  		if err != nil {
  1667  			return nil, err
  1668  		}
  1669  		if config.Mode == keybase1.FolderSyncMode_DISABLED {
  1670  			err = ldb.Delete(tlfBytes, nil)
  1671  		} else {
  1672  			if cancel, ok := c.tlfClearCancels[tlfID]; ok {
  1673  				cancel()
  1674  			}
  1675  			var buf []byte
  1676  			buf, err = c.codec.Encode(&config)
  1677  			if err != nil {
  1678  				return nil, err
  1679  			}
  1680  			err = ldb.Put(tlfBytes, buf, nil)
  1681  		}
  1682  		if err != nil {
  1683  			return nil, err
  1684  		}
  1685  	}
  1686  
  1687  	ch := make(chan error, 1)
  1688  	if config.Mode == keybase1.FolderSyncMode_DISABLED {
  1689  		c.GetPerfLog().CDebugf(
  1690  			ctx, "Clearing KBFS sync blocks for disabled TLF %s", tlfID)
  1691  		c.cleanSyncBlockCacheForTlfInBackgroundLocked(tlfID, ch)
  1692  	} else {
  1693  		ch <- nil
  1694  	}
  1695  
  1696  	oldConfig := c.syncedTlfs[tlfID]
  1697  	if config.TlfPath != oldConfig.TlfPath {
  1698  		delete(c.syncedTlfPaths, oldConfig.TlfPath)
  1699  	}
  1700  
  1701  	c.syncedTlfs[tlfID] = config
  1702  	if config.TlfPath != "" {
  1703  		c.syncedTlfPaths[config.TlfPath] = true
  1704  	}
  1705  	return ch, nil
  1706  }
  1707  
  1708  // SetTlfSyncState implements the syncedTlfGetterSetter interface for
  1709  // ConfigLocal.
  1710  func (c *ConfigLocal) SetTlfSyncState(
  1711  	ctx context.Context, tlfID tlf.ID, config FolderSyncConfig) (
  1712  	<-chan error, error) {
  1713  	if !c.IsTestMode() && config.Mode != keybase1.FolderSyncMode_ENABLED {
  1714  		// If we're disabling, or just changing the partial sync
  1715  		// config (which may be removing paths), we should cancel all
  1716  		// the previous prefetches for this TLF.  For partial syncs, a
  1717  		// new sync will be started.
  1718  		err := c.BlockOps().Prefetcher().CancelTlfPrefetches(ctx, tlfID)
  1719  		if err != nil {
  1720  			return nil, err
  1721  		}
  1722  	}
  1723  	return c.setTlfSyncState(ctx, tlfID, config)
  1724  }
  1725  
  1726  // GetAllSyncedTlfs implements the syncedTlfGetterSetter interface for
  1727  // ConfigLocal.
  1728  func (c *ConfigLocal) GetAllSyncedTlfs() []tlf.ID {
  1729  	c.lock.RLock()
  1730  	defer c.lock.RUnlock()
  1731  	tlfs := make([]tlf.ID, 0, len(c.syncedTlfs))
  1732  	for tlf, config := range c.syncedTlfs {
  1733  		if config.Mode != keybase1.FolderSyncMode_DISABLED {
  1734  			tlfs = append(tlfs, tlf)
  1735  		}
  1736  	}
  1737  	return tlfs
  1738  }
  1739  
  1740  // PrefetchStatus implements the Config interface for ConfigLocal.
  1741  func (c *ConfigLocal) PrefetchStatus(ctx context.Context, tlfID tlf.ID,
  1742  	ptr data.BlockPointer) PrefetchStatus {
  1743  	dbc := c.DiskBlockCache()
  1744  	if dbc == nil {
  1745  		// We must be in testing mode, so check the block retrieval queue.
  1746  		bops, ok := c.BlockOps().(*BlockOpsStandard)
  1747  		if !ok {
  1748  			return NoPrefetch
  1749  		}
  1750  		status, err := bops.queue.getPrefetchStatus(ptr.ID)
  1751  		if err != nil {
  1752  			c.MakeLogger("").CDebugf(ctx,
  1753  				"Error getting prefetch status: %+v", err)
  1754  			return NoPrefetch
  1755  		}
  1756  		return status
  1757  	}
  1758  
  1759  	prefetchStatus, err := dbc.GetPrefetchStatus(
  1760  		ctx, tlfID, ptr.ID, DiskBlockAnyCache)
  1761  	if err != nil {
  1762  		return NoPrefetch
  1763  	}
  1764  	return prefetchStatus
  1765  }
  1766  
  1767  // GetRekeyFSMLimiter implements the Config interface for ConfigLocal.
  1768  func (c *ConfigLocal) GetRekeyFSMLimiter() *OngoingWorkLimiter {
  1769  	return c.rekeyFSMLimiter
  1770  }
  1771  
  1772  // GetConflictResolutionDB implements the Config interface for ConfigLocal.
  1773  func (c *ConfigLocal) GetConflictResolutionDB() (db *ldbutils.LevelDb) {
  1774  	return c.conflictResolutionDB
  1775  }
  1776  
  1777  // GetSettingsDB implements the Config interface for ConfigLocal.
  1778  func (c *ConfigLocal) GetSettingsDB() (db *SettingsDB) {
  1779  	return c.settingsDB
  1780  }
  1781  
  1782  // SetKBFSService sets the KBFSService for this ConfigLocal.
  1783  func (c *ConfigLocal) SetKBFSService(k *KBFSService) {
  1784  	c.lock.Lock()
  1785  	defer c.lock.Unlock()
  1786  	if c.kbfsService != nil {
  1787  		c.kbfsService.Shutdown()
  1788  	}
  1789  	c.kbfsService = k
  1790  }
  1791  
  1792  // RootNodeWrappers implements the Config interface for ConfigLocal.
  1793  func (c *ConfigLocal) RootNodeWrappers() []func(Node) Node {
  1794  	c.lock.RLock()
  1795  	defer c.lock.RUnlock()
  1796  	return c.rootNodeWrappers
  1797  }
  1798  
  1799  // AddRootNodeWrapper implements the Config interface for ConfigLocal.
  1800  func (c *ConfigLocal) AddRootNodeWrapper(f func(Node) Node) {
  1801  	c.lock.Lock()
  1802  	defer c.lock.Unlock()
  1803  	c.rootNodeWrappers = append(c.rootNodeWrappers, f)
  1804  	if c.kbfs != nil {
  1805  		c.kbfs.AddRootNodeWrapper(f)
  1806  	}
  1807  }
  1808  
  1809  // SetVLogLevel implements the Config interface for ConfigLocal.
  1810  func (c *ConfigLocal) SetVLogLevel(levelString string) {
  1811  	c.lock.Lock()
  1812  	defer c.lock.Unlock()
  1813  	c.vdebugSetting = levelString
  1814  	for _, vlog := range c.vlogs {
  1815  		vlog.Configure(levelString)
  1816  	}
  1817  }
  1818  
  1819  // VLogLevel implements the Config interface for ConfigLocal.
  1820  func (c *ConfigLocal) VLogLevel() string {
  1821  	c.lock.RLock()
  1822  	defer c.lock.RUnlock()
  1823  	return c.vdebugSetting
  1824  }
  1825  
  1826  // SetDiskCacheMode sets the disk cache mode for this config, after
  1827  // construction.  Mostly useful for tests.
  1828  func (c *ConfigLocal) SetDiskCacheMode(m DiskCacheMode) {
  1829  	c.lock.Lock()
  1830  	defer c.lock.Unlock()
  1831  	c.diskCacheMode = m
  1832  	if c.diskCacheMode == DiskCacheModeLocal {
  1833  		// Any error is logged in the function itself.
  1834  		_ = c.loadSyncedTlfsLocked()
  1835  	}
  1836  }
  1837  
  1838  // SubscriptionManager implements the Config interface.
  1839  func (c *ConfigLocal) SubscriptionManager(
  1840  	clientID SubscriptionManagerClientID, purgeable bool,
  1841  	notifier SubscriptionNotifier) SubscriptionManager {
  1842  	return c.subscriptionManagerManager.get(clientID, purgeable, notifier)
  1843  }
  1844  
  1845  // SubscriptionManagerPublisher implements the Config interface.
  1846  func (c *ConfigLocal) SubscriptionManagerPublisher() SubscriptionManagerPublisher {
  1847  	return c.subscriptionManagerManager
  1848  }
  1849  
  1850  // KbEnv implements the Config interface.
  1851  func (c *ConfigLocal) KbEnv() *libkb.Env {
  1852  	c.lock.RLock()
  1853  	defer c.lock.RUnlock()
  1854  	return c.kbCtx.GetEnv()
  1855  }
  1856  
  1857  // KbContext implements the Config interface.
  1858  func (c *ConfigLocal) KbContext() Context {
  1859  	c.lock.RLock()
  1860  	defer c.lock.RUnlock()
  1861  	return c.kbCtx
  1862  }
  1863  
  1864  // AddResetForLoginTarget implements the Config interface.
  1865  func (c *ConfigLocal) AddResetForLoginTarget(t ResetForLoginer) {
  1866  	c.lock.Lock()
  1867  	defer c.lock.Unlock()
  1868  	c.resetForLoginTargets = append(c.resetForLoginTargets, t)
  1869  }
  1870  
  1871  // ResetForLogin implements the Config interface.
  1872  func (c *ConfigLocal) ResetForLogin(ctx context.Context, username libkb.NormalizedUsername) {
  1873  	targets := func() []ResetForLoginer {
  1874  		ret := make([]ResetForLoginer, len(c.resetForLoginTargets))
  1875  		c.lock.Lock()
  1876  		defer c.lock.Unlock()
  1877  		copy(ret, c.resetForLoginTargets)
  1878  		return ret
  1879  	}()
  1880  	log := c.MakeLogger("")
  1881  	for _, target := range targets {
  1882  		err := target.ResetForLogin(ctx, username)
  1883  		if err != nil {
  1884  			log.Warning("target.ResetForLogin error: %v", err)
  1885  		}
  1886  	}
  1887  }