github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/libkbfs/mdserver_disk.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  	"bytes"
     9  	"os"
    10  	"path/filepath"
    11  	"reflect"
    12  	"sync"
    13  	"time"
    14  
    15  	"github.com/keybase/client/go/kbfs/ioutil"
    16  	"github.com/keybase/client/go/kbfs/kbfsmd"
    17  	"github.com/keybase/client/go/kbfs/ldbutils"
    18  	"github.com/keybase/client/go/kbfs/tlf"
    19  	"github.com/keybase/client/go/logger"
    20  	"github.com/keybase/client/go/protocol/keybase1"
    21  	"github.com/pkg/errors"
    22  	"github.com/syndtr/goleveldb/leveldb"
    23  	"golang.org/x/net/context"
    24  )
    25  
    26  type mdServerDiskShared struct {
    27  	dirPath string
    28  
    29  	// Protects handleDb, branchDb, tlfStorage, and
    30  	// truncateLockManager. After Shutdown() is called, handleDb,
    31  	// branchDb, tlfStorage, and truncateLockManager are nil.
    32  	lock sync.RWMutex // nolint
    33  	// Bare TLF handle -> TLF ID
    34  	handleDb *leveldb.DB
    35  	// (TLF ID, device crypt public key) -> branch ID
    36  	branchDb   *leveldb.DB
    37  	tlfStorage map[tlf.ID]*mdServerTlfStorage
    38  	// Always use memory for the lock storage, so it gets wiped
    39  	// after a restart.
    40  	truncateLockManager  *mdServerLocalTruncateLockManager
    41  	implicitTeamsEnabled bool // nolint
    42  	// In-memory only, for now.
    43  	merkleRoots map[keybase1.MerkleTreeID]*kbfsmd.MerkleRoot
    44  
    45  	updateManager *mdServerLocalUpdateManager
    46  
    47  	shutdownFunc func(logger.Logger)
    48  }
    49  
    50  // MDServerDisk stores all info on disk, either in levelDBs, or disk
    51  // journals and flat files for the actual MDs.
    52  type MDServerDisk struct {
    53  	config mdServerLocalConfig
    54  	log    logger.Logger
    55  
    56  	*mdServerDiskShared
    57  }
    58  
    59  var _ mdServerLocal = (*MDServerDisk)(nil)
    60  
    61  func newMDServerDisk(config mdServerLocalConfig, dirPath string,
    62  	shutdownFunc func(logger.Logger)) (*MDServerDisk, error) {
    63  	handlePath := filepath.Join(dirPath, "handles")
    64  	handleDb, err := leveldb.OpenFile(handlePath, ldbutils.LeveldbOptions(nil))
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	branchPath := filepath.Join(dirPath, "branches")
    70  	branchDb, err := leveldb.OpenFile(branchPath, ldbutils.LeveldbOptions(nil))
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	log := config.MakeLogger("MDSD")
    75  	truncateLockManager := newMDServerLocalTruncatedLockManager()
    76  	shared := mdServerDiskShared{
    77  		dirPath:             dirPath,
    78  		handleDb:            handleDb,
    79  		branchDb:            branchDb,
    80  		tlfStorage:          make(map[tlf.ID]*mdServerTlfStorage),
    81  		truncateLockManager: &truncateLockManager,
    82  		updateManager:       newMDServerLocalUpdateManager(),
    83  		shutdownFunc:        shutdownFunc,
    84  		merkleRoots:         make(map[keybase1.MerkleTreeID]*kbfsmd.MerkleRoot),
    85  	}
    86  	mdserv := &MDServerDisk{config, log, &shared}
    87  	return mdserv, nil
    88  }
    89  
    90  // NewMDServerDir constructs a new MDServerDisk that stores its data
    91  // in the given directory.
    92  func NewMDServerDir(
    93  	config mdServerLocalConfig, dirPath string) (*MDServerDisk, error) {
    94  	return newMDServerDisk(config, dirPath, nil)
    95  }
    96  
    97  // NewMDServerTempDir constructs a new MDServerDisk that stores its
    98  // data in a temp directory which is cleaned up on shutdown.
    99  func NewMDServerTempDir(config mdServerLocalConfig) (*MDServerDisk, error) {
   100  	tempdir, err := ioutil.TempDir(os.TempDir(), "kbfs_mdserver_tmp")
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	return newMDServerDisk(config, tempdir, func(log logger.Logger) {
   105  		err := ioutil.RemoveAll(tempdir)
   106  		if err != nil {
   107  			log.Warning("error removing %s: %s", tempdir, err)
   108  		}
   109  	})
   110  }
   111  
   112  type errMDServerDiskShutdown struct{}
   113  
   114  func (e errMDServerDiskShutdown) Error() string {
   115  	return "MDServerDisk is shutdown"
   116  }
   117  
   118  func (md *MDServerDisk) checkShutdownLocked() error {
   119  	if md.tlfStorage == nil {
   120  		return errors.WithStack(errMDServerDiskShutdown{})
   121  	}
   122  	return nil
   123  }
   124  
   125  func (md *MDServerDisk) enableImplicitTeams() {
   126  	md.lock.Lock()
   127  	defer md.lock.Unlock()
   128  	md.implicitTeamsEnabled = true
   129  }
   130  
   131  func (md *MDServerDisk) setKbfsMerkleRoot(
   132  	treeID keybase1.MerkleTreeID, root *kbfsmd.MerkleRoot) {
   133  	md.lock.Lock()
   134  	defer md.lock.Unlock()
   135  	md.merkleRoots[treeID] = root
   136  }
   137  
   138  func (md *MDServerDisk) getStorage(tlfID tlf.ID) (*mdServerTlfStorage, error) {
   139  	storage, err := func() (*mdServerTlfStorage, error) {
   140  		md.lock.RLock()
   141  		defer md.lock.RUnlock()
   142  		err := md.checkShutdownLocked()
   143  		if err != nil {
   144  			return nil, err
   145  		}
   146  		return md.tlfStorage[tlfID], nil
   147  	}()
   148  
   149  	if err != nil {
   150  		return nil, err
   151  	}
   152  
   153  	if storage != nil {
   154  		return storage, nil
   155  	}
   156  
   157  	md.lock.Lock()
   158  	defer md.lock.Unlock()
   159  	if md.tlfStorage == nil {
   160  		return nil, errors.WithStack(errMDServerDiskShutdown{})
   161  	}
   162  
   163  	storage = md.tlfStorage[tlfID]
   164  	if storage != nil {
   165  		return storage, nil
   166  	}
   167  
   168  	path := filepath.Join(md.dirPath, tlfID.String())
   169  	storage = makeMDServerTlfStorage(
   170  		tlfID, md.config.Codec(),
   171  		md.config.Clock(), md.config.teamMembershipChecker(),
   172  		md.config.MetadataVersion(), path)
   173  
   174  	md.tlfStorage[tlfID] = storage
   175  	return storage, nil
   176  }
   177  
   178  func (md *MDServerDisk) getHandleID(ctx context.Context, handle tlf.Handle,
   179  	mStatus kbfsmd.MergeStatus) (tlfID tlf.ID, created bool, err error) {
   180  	handleBytes, err := md.config.Codec().Encode(handle)
   181  	if err != nil {
   182  		return tlf.NullID, false, kbfsmd.ServerError{Err: err}
   183  	}
   184  
   185  	md.lock.Lock()
   186  	defer md.lock.Unlock()
   187  	err = md.checkShutdownLocked()
   188  	if err != nil {
   189  		return tlf.NullID, false, err
   190  	}
   191  
   192  	buf, err := md.handleDb.Get(handleBytes, nil)
   193  	if err != nil && err != leveldb.ErrNotFound {
   194  		return tlf.NullID, false, kbfsmd.ServerError{Err: err}
   195  	}
   196  	if err == nil {
   197  		var id tlf.ID
   198  		err := id.UnmarshalBinary(buf)
   199  		if err != nil {
   200  			return tlf.NullID, false, kbfsmd.ServerError{Err: err}
   201  		}
   202  		return id, false, nil
   203  	}
   204  
   205  	// Non-readers shouldn't be able to create the dir.
   206  	session, err := md.config.currentSessionGetter().GetCurrentSession(ctx)
   207  	if err != nil {
   208  		return tlf.NullID, false, kbfsmd.ServerError{Err: err}
   209  	}
   210  	if handle.Type() == tlf.SingleTeam {
   211  		isReader, err := md.config.teamMembershipChecker().IsTeamReader(
   212  			ctx, handle.Writers[0].AsTeamOrBust(), session.UID,
   213  			keybase1.OfflineAvailability_NONE)
   214  		if err != nil {
   215  			return tlf.NullID, false, kbfsmd.ServerError{Err: err}
   216  		} else if !isReader {
   217  			return tlf.NullID, false, kbfsmd.ServerErrorUnauthorized{}
   218  		}
   219  	} else if !handle.IsReader(session.UID.AsUserOrTeam()) {
   220  		return tlf.NullID, false, kbfsmd.ServerErrorUnauthorized{}
   221  	}
   222  
   223  	if md.implicitTeamsEnabled {
   224  		return tlf.NullID, false, kbfsmd.ServerErrorClassicTLFDoesNotExist{}
   225  	}
   226  
   227  	// Allocate a new random ID.
   228  	id, err := md.config.cryptoPure().MakeRandomTlfID(handle.Type())
   229  	if err != nil {
   230  		return tlf.NullID, false, kbfsmd.ServerError{Err: err}
   231  	}
   232  
   233  	err = md.handleDb.Put(handleBytes, id.Bytes(), nil)
   234  	if err != nil {
   235  		return tlf.NullID, false, kbfsmd.ServerError{Err: err}
   236  	}
   237  	return id, true, nil
   238  }
   239  
   240  // GetForHandle implements the MDServer interface for MDServerDisk.
   241  func (md *MDServerDisk) GetForHandle(ctx context.Context, handle tlf.Handle,
   242  	mStatus kbfsmd.MergeStatus, _ *keybase1.LockID) (
   243  	tlf.ID, *RootMetadataSigned, error) {
   244  	if err := checkContext(ctx); err != nil {
   245  		return tlf.NullID, nil, err
   246  	}
   247  
   248  	id, created, err := md.getHandleID(ctx, handle, mStatus)
   249  	if err != nil {
   250  		return tlf.NullID, nil, err
   251  	}
   252  
   253  	if created {
   254  		return id, nil, nil
   255  	}
   256  
   257  	rmds, err := md.GetForTLF(ctx, id, kbfsmd.NullBranchID, mStatus, nil)
   258  	if err != nil {
   259  		return tlf.NullID, nil, err
   260  	}
   261  	return id, rmds, nil
   262  }
   263  
   264  func (md *MDServerDisk) getBranchKey(ctx context.Context, id tlf.ID) ([]byte, error) {
   265  	buf := &bytes.Buffer{}
   266  	// add folder id
   267  	_, err := buf.Write(id.Bytes())
   268  	if err != nil {
   269  		return nil, err
   270  	}
   271  	// add device key
   272  	session, err := md.config.currentSessionGetter().GetCurrentSession(ctx)
   273  	if err != nil {
   274  		return nil, err
   275  	}
   276  	_, err = buf.Write(session.CryptPublicKey.KID().ToBytes())
   277  	if err != nil {
   278  		return nil, err
   279  	}
   280  	return buf.Bytes(), nil
   281  }
   282  
   283  func (md *MDServerDisk) getBranchID(ctx context.Context, id tlf.ID) (kbfsmd.BranchID, error) {
   284  	branchKey, err := md.getBranchKey(ctx, id)
   285  	if err != nil {
   286  		return kbfsmd.NullBranchID, kbfsmd.ServerError{Err: err}
   287  	}
   288  
   289  	md.lock.RLock()
   290  	defer md.lock.RUnlock()
   291  	err = md.checkShutdownLocked()
   292  	if err != nil {
   293  		return kbfsmd.NullBranchID, err
   294  	}
   295  
   296  	buf, err := md.branchDb.Get(branchKey, nil)
   297  	if err == leveldb.ErrNotFound {
   298  		return kbfsmd.NullBranchID, nil
   299  	}
   300  	if err != nil {
   301  		return kbfsmd.NullBranchID, kbfsmd.ServerErrorBadRequest{Reason: "Invalid branch ID"}
   302  	}
   303  	var bid kbfsmd.BranchID
   304  	err = md.config.Codec().Decode(buf, &bid)
   305  	if err != nil {
   306  		return kbfsmd.NullBranchID, kbfsmd.ServerErrorBadRequest{Reason: "Invalid branch ID"}
   307  	}
   308  	return bid, nil
   309  }
   310  
   311  func (md *MDServerDisk) putBranchID(
   312  	ctx context.Context, id tlf.ID, bid kbfsmd.BranchID) error {
   313  	md.lock.Lock()
   314  	defer md.lock.Unlock()
   315  	err := md.checkShutdownLocked()
   316  	if err != nil {
   317  		return err
   318  	}
   319  
   320  	branchKey, err := md.getBranchKey(ctx, id)
   321  	if err != nil {
   322  		return kbfsmd.ServerError{Err: err}
   323  	}
   324  	buf, err := md.config.Codec().Encode(bid)
   325  	if err != nil {
   326  		return kbfsmd.ServerError{Err: err}
   327  	}
   328  	err = md.branchDb.Put(branchKey, buf, nil)
   329  	if err != nil {
   330  		return kbfsmd.ServerError{Err: err}
   331  	}
   332  
   333  	return nil
   334  }
   335  
   336  func (md *MDServerDisk) deleteBranchID(ctx context.Context, id tlf.ID) error {
   337  	md.lock.Lock()
   338  	defer md.lock.Unlock()
   339  	err := md.checkShutdownLocked()
   340  	if err != nil {
   341  		return err
   342  	}
   343  
   344  	branchKey, err := md.getBranchKey(ctx, id)
   345  	if err != nil {
   346  		return kbfsmd.ServerError{Err: err}
   347  	}
   348  	err = md.branchDb.Delete(branchKey, nil)
   349  	if err != nil {
   350  		return kbfsmd.ServerError{Err: err}
   351  	}
   352  	return nil
   353  }
   354  
   355  // GetForTLF implements the MDServer interface for MDServerDisk.
   356  func (md *MDServerDisk) GetForTLF(ctx context.Context, id tlf.ID,
   357  	bid kbfsmd.BranchID, mStatus kbfsmd.MergeStatus, _ *keybase1.LockID) (
   358  	*RootMetadataSigned, error) {
   359  	if err := checkContext(ctx); err != nil {
   360  		return nil, err
   361  	}
   362  
   363  	// Lookup the branch ID if not supplied
   364  	if mStatus == kbfsmd.Unmerged && bid == kbfsmd.NullBranchID {
   365  		var err error
   366  		bid, err = md.getBranchID(ctx, id)
   367  		if err != nil {
   368  			return nil, err
   369  		}
   370  		if bid == kbfsmd.NullBranchID {
   371  			return nil, nil
   372  		}
   373  	}
   374  
   375  	session, err := md.config.currentSessionGetter().GetCurrentSession(ctx)
   376  	if err != nil {
   377  		return nil, kbfsmd.ServerError{Err: err}
   378  	}
   379  
   380  	tlfStorage, err := md.getStorage(id)
   381  	if err != nil {
   382  		return nil, err
   383  	}
   384  
   385  	return tlfStorage.getForTLF(ctx, session.UID, bid)
   386  }
   387  
   388  // GetForTLFByTime implements the MDServer interface for MDServerDisk.
   389  func (md *MDServerDisk) GetForTLFByTime(
   390  	ctx context.Context, id tlf.ID, serverTime time.Time) (
   391  	*RootMetadataSigned, error) {
   392  	if err := checkContext(ctx); err != nil {
   393  		return nil, err
   394  	}
   395  
   396  	session, err := md.config.currentSessionGetter().GetCurrentSession(ctx)
   397  	if err != nil {
   398  		return nil, kbfsmd.ServerError{Err: err}
   399  	}
   400  
   401  	tlfStorage, err := md.getStorage(id)
   402  	if err != nil {
   403  		return nil, err
   404  	}
   405  
   406  	rmd, err := tlfStorage.getForTLF(ctx, session.UID, kbfsmd.NullBranchID)
   407  	if err != nil {
   408  		return nil, err
   409  	}
   410  
   411  	// Do a linear backwards search to find the RMD that comes just
   412  	// before or at `serverTime`.
   413  	for rmd.untrustedServerTimestamp.After(serverTime) {
   414  		nextRev := rmd.MD.RevisionNumber() - 1
   415  		if nextRev == kbfsmd.RevisionUninitialized {
   416  			return nil, errors.Errorf(
   417  				"No MD found for TLF %s and serverTime %s", id, serverTime)
   418  		}
   419  		mds, err := tlfStorage.getRange(
   420  			ctx, session.UID, kbfsmd.NullBranchID, nextRev, nextRev)
   421  		if err != nil {
   422  			return nil, err
   423  		}
   424  		if len(mds) != 1 {
   425  			return nil, errors.Errorf(
   426  				"No MD found for TLF %s and serverTime %s", id, serverTime)
   427  		}
   428  		rmd = mds[0]
   429  	}
   430  
   431  	return rmd, nil
   432  }
   433  
   434  // GetRange implements the MDServer interface for MDServerDisk.
   435  func (md *MDServerDisk) GetRange(ctx context.Context, id tlf.ID,
   436  	bid kbfsmd.BranchID, mStatus kbfsmd.MergeStatus, start, stop kbfsmd.Revision,
   437  	_ *keybase1.LockID) ([]*RootMetadataSigned, error) {
   438  	if err := checkContext(ctx); err != nil {
   439  		return nil, err
   440  	}
   441  
   442  	md.log.CDebugf(ctx, "GetRange %d %d (%s)", start, stop, mStatus)
   443  
   444  	// Lookup the branch ID if not supplied
   445  	if mStatus == kbfsmd.Unmerged && bid == kbfsmd.NullBranchID {
   446  		var err error
   447  		bid, err = md.getBranchID(ctx, id)
   448  		if err != nil {
   449  			return nil, err
   450  		}
   451  		if bid == kbfsmd.NullBranchID {
   452  			return nil, nil
   453  		}
   454  	}
   455  
   456  	session, err := md.config.currentSessionGetter().GetCurrentSession(ctx)
   457  	if err != nil {
   458  		return nil, kbfsmd.ServerError{Err: err}
   459  	}
   460  
   461  	tlfStorage, err := md.getStorage(id)
   462  	if err != nil {
   463  		return nil, err
   464  	}
   465  
   466  	return tlfStorage.getRange(ctx, session.UID, bid, start, stop)
   467  }
   468  
   469  // Put implements the MDServer interface for MDServerDisk.
   470  func (md *MDServerDisk) Put(ctx context.Context, rmds *RootMetadataSigned,
   471  	extra kbfsmd.ExtraMetadata, _ *keybase1.LockContext, _ keybase1.MDPriority) error {
   472  	if err := checkContext(ctx); err != nil {
   473  		return err
   474  	}
   475  
   476  	session, err := md.config.currentSessionGetter().GetCurrentSession(ctx)
   477  	if err != nil {
   478  		return kbfsmd.ServerError{Err: err}
   479  	}
   480  
   481  	tlfStorage, err := md.getStorage(rmds.MD.TlfID())
   482  	if err != nil {
   483  		return err
   484  	}
   485  
   486  	recordBranchID, err := tlfStorage.put(
   487  		ctx, session.UID, session.VerifyingKey, rmds, extra)
   488  	if err != nil {
   489  		return err
   490  	}
   491  
   492  	// Record branch ID
   493  	if recordBranchID {
   494  		err = md.putBranchID(ctx, rmds.MD.TlfID(), rmds.MD.BID())
   495  		if err != nil {
   496  			return kbfsmd.ServerError{Err: err}
   497  		}
   498  	}
   499  
   500  	mStatus := rmds.MD.MergedStatus()
   501  	if mStatus == kbfsmd.Merged &&
   502  		// Don't send notifies if it's just a rekey (the real mdserver
   503  		// sends a "folder needs rekey" notification in this case).
   504  		!(rmds.MD.IsRekeySet() && rmds.MD.IsWriterMetadataCopiedSet()) {
   505  		md.updateManager.setHead(rmds.MD.TlfID(), md)
   506  	}
   507  
   508  	return nil
   509  }
   510  
   511  // Lock (does not) implement the MDServer interface for MDServerDisk.
   512  func (*MDServerDisk) Lock(ctx context.Context,
   513  	tlfID tlf.ID, lockID keybase1.LockID) error {
   514  	panic("Lock called on *MDServerDisk")
   515  }
   516  
   517  // ReleaseLock (does not) implement the MDServer interface for MDServerDisk.
   518  func (*MDServerDisk) ReleaseLock(ctx context.Context,
   519  	tlfID tlf.ID, lockID keybase1.LockID) error {
   520  	panic("ReleaseLock called on *MDServerDisk")
   521  }
   522  
   523  // StartImplicitTeamMigration implements the MDServer interface.
   524  func (md *MDServerDisk) StartImplicitTeamMigration(
   525  	ctx context.Context, id tlf.ID) (err error) {
   526  	panic("StartImplicitTeamMigration called on *MDServerDisk")
   527  }
   528  
   529  // PruneBranch implements the MDServer interface for MDServerDisk.
   530  func (md *MDServerDisk) PruneBranch(ctx context.Context, id tlf.ID, bid kbfsmd.BranchID) error {
   531  	if err := checkContext(ctx); err != nil {
   532  		return err
   533  	}
   534  
   535  	if bid == kbfsmd.NullBranchID {
   536  		return kbfsmd.ServerErrorBadRequest{Reason: "Invalid branch ID"}
   537  	}
   538  
   539  	currBID, err := md.getBranchID(ctx, id)
   540  	if err != nil {
   541  		return err
   542  	}
   543  	if currBID == kbfsmd.NullBranchID || bid != currBID {
   544  		return kbfsmd.ServerErrorBadRequest{Reason: "Invalid branch ID"}
   545  	}
   546  
   547  	// Don't actually delete unmerged history. This is intentional
   548  	// to be consistent with the mdserver behavior-- it garbage
   549  	// collects discarded branches in the background.
   550  	return md.deleteBranchID(ctx, id)
   551  }
   552  
   553  func (md *MDServerDisk) getCurrentMergedHeadRevision(
   554  	ctx context.Context, id tlf.ID) (rev kbfsmd.Revision, err error) {
   555  	head, err := md.GetForTLF(ctx, id, kbfsmd.NullBranchID, kbfsmd.Merged, nil)
   556  	if err != nil {
   557  		return 0, err
   558  	}
   559  	if head != nil {
   560  		rev = head.MD.RevisionNumber()
   561  	}
   562  	return
   563  }
   564  
   565  // RegisterForUpdate implements the MDServer interface for MDServerDisk.
   566  func (md *MDServerDisk) RegisterForUpdate(ctx context.Context, id tlf.ID,
   567  	currHead kbfsmd.Revision) (<-chan error, error) {
   568  	if err := checkContext(ctx); err != nil {
   569  		return nil, err
   570  	}
   571  
   572  	// are we already past this revision?  If so, fire observer
   573  	// immediately
   574  	currMergedHeadRev, err := md.getCurrentMergedHeadRevision(ctx, id)
   575  	if err != nil {
   576  		return nil, err
   577  	}
   578  
   579  	c := md.updateManager.registerForUpdate(id, currHead, currMergedHeadRev, md)
   580  	return c, nil
   581  }
   582  
   583  // CancelRegistration implements the MDServer interface for MDServerDisk.
   584  func (md *MDServerDisk) CancelRegistration(_ context.Context, id tlf.ID) {
   585  	md.updateManager.cancel(id, md)
   586  }
   587  
   588  // TruncateLock implements the MDServer interface for MDServerDisk.
   589  func (md *MDServerDisk) TruncateLock(ctx context.Context, id tlf.ID) (
   590  	bool, error) {
   591  	if err := checkContext(ctx); err != nil {
   592  		return false, err
   593  	}
   594  
   595  	session, err := md.config.currentSessionGetter().GetCurrentSession(ctx)
   596  	if err != nil {
   597  		return false, kbfsmd.ServerError{Err: err}
   598  	}
   599  
   600  	md.lock.Lock()
   601  	defer md.lock.Unlock()
   602  	err = md.checkShutdownLocked()
   603  	if err != nil {
   604  		return false, err
   605  	}
   606  
   607  	return md.truncateLockManager.truncateLock(session.CryptPublicKey, id)
   608  }
   609  
   610  // TruncateUnlock implements the MDServer interface for MDServerDisk.
   611  func (md *MDServerDisk) TruncateUnlock(ctx context.Context, id tlf.ID) (
   612  	bool, error) {
   613  	if err := checkContext(ctx); err != nil {
   614  		return false, err
   615  	}
   616  
   617  	session, err := md.config.currentSessionGetter().GetCurrentSession(ctx)
   618  	if err != nil {
   619  		return false, kbfsmd.ServerError{Err: err}
   620  	}
   621  
   622  	md.lock.Lock()
   623  	defer md.lock.Unlock()
   624  	err = md.checkShutdownLocked()
   625  	if err != nil {
   626  		return false, err
   627  	}
   628  
   629  	return md.truncateLockManager.truncateUnlock(session.CryptPublicKey, id)
   630  }
   631  
   632  // Shutdown implements the MDServer interface for MDServerDisk.
   633  func (md *MDServerDisk) Shutdown() {
   634  	md.lock.Lock()
   635  	defer md.lock.Unlock()
   636  	if md.handleDb == nil {
   637  		return
   638  	}
   639  
   640  	// Make further accesses error out.
   641  
   642  	md.handleDb.Close()
   643  	md.handleDb = nil
   644  
   645  	md.branchDb.Close()
   646  	md.branchDb = nil
   647  
   648  	tlfStorage := md.tlfStorage
   649  	md.tlfStorage = nil
   650  
   651  	for _, s := range tlfStorage {
   652  		s.shutdown()
   653  	}
   654  
   655  	if md.shutdownFunc != nil {
   656  		md.shutdownFunc(md.log)
   657  	}
   658  }
   659  
   660  // IsConnected implements the MDServer interface for MDServerDisk.
   661  func (md *MDServerDisk) IsConnected() bool {
   662  	return !md.isShutdown()
   663  }
   664  
   665  // RefreshAuthToken implements the MDServer interface for MDServerDisk.
   666  func (md *MDServerDisk) RefreshAuthToken(ctx context.Context) {}
   667  
   668  // This should only be used for testing with an in-memory server.
   669  func (md *MDServerDisk) copy(config mdServerLocalConfig) mdServerLocal {
   670  	// NOTE: observers and sessionHeads are copied shallowly on
   671  	// purpose, so that the MD server that gets a Put will notify all
   672  	// observers correctly no matter where they got on the list.
   673  	log := config.MakeLogger("")
   674  	return &MDServerDisk{config, log, md.mdServerDiskShared}
   675  }
   676  
   677  // isShutdown returns whether the logical, shared MDServer instance
   678  // has been shut down.
   679  func (md *MDServerDisk) isShutdown() bool {
   680  	md.lock.RLock()
   681  	defer md.lock.RUnlock()
   682  	return md.checkShutdownLocked() != nil
   683  }
   684  
   685  // DisableRekeyUpdatesForTesting implements the MDServer interface.
   686  func (md *MDServerDisk) DisableRekeyUpdatesForTesting() {
   687  	// Nothing to do.
   688  }
   689  
   690  // CheckForRekeys implements the MDServer interface.
   691  func (md *MDServerDisk) CheckForRekeys(ctx context.Context) <-chan error {
   692  	// Nothing to do
   693  	c := make(chan error, 1)
   694  	c <- nil
   695  	return c
   696  }
   697  
   698  func (md *MDServerDisk) addNewAssertionForTest(uid keybase1.UID,
   699  	newAssertion keybase1.SocialAssertion) error {
   700  	md.lock.Lock()
   701  	defer md.lock.Unlock()
   702  	err := md.checkShutdownLocked()
   703  	if err != nil {
   704  		return err
   705  	}
   706  
   707  	// Iterate through all the handles, and add handles for ones
   708  	// containing newAssertion to now include the uid.
   709  	iter := md.handleDb.NewIterator(nil, nil)
   710  	defer iter.Release()
   711  	for iter.Next() {
   712  		handleBytes := iter.Key()
   713  		var handle tlf.Handle
   714  		err := md.config.Codec().Decode(handleBytes, &handle)
   715  		if err != nil {
   716  			return err
   717  		}
   718  		assertions := map[keybase1.SocialAssertion]keybase1.UID{
   719  			newAssertion: uid,
   720  		}
   721  		newHandle := handle.ResolveAssertions(assertions)
   722  		if reflect.DeepEqual(handle, newHandle) {
   723  			continue
   724  		}
   725  		newHandleBytes, err := md.config.Codec().Encode(newHandle)
   726  		if err != nil {
   727  			return err
   728  		}
   729  		id := iter.Value()
   730  		if err := md.handleDb.Put(newHandleBytes, id, nil); err != nil {
   731  			return err
   732  		}
   733  	}
   734  	return iter.Error()
   735  }
   736  
   737  // GetLatestHandleForTLF implements the MDServer interface for MDServerDisk.
   738  func (md *MDServerDisk) GetLatestHandleForTLF(ctx context.Context, id tlf.ID) (
   739  	tlf.Handle, error) {
   740  	if err := checkContext(ctx); err != nil {
   741  		return tlf.Handle{}, err
   742  	}
   743  
   744  	md.lock.RLock()
   745  	defer md.lock.RUnlock()
   746  	err := md.checkShutdownLocked()
   747  	if err != nil {
   748  		return tlf.Handle{}, err
   749  	}
   750  
   751  	var handle tlf.Handle
   752  	iter := md.handleDb.NewIterator(nil, nil)
   753  	defer iter.Release()
   754  	for iter.Next() {
   755  		var dbID tlf.ID
   756  		idBytes := iter.Value()
   757  		err := dbID.UnmarshalBinary(idBytes)
   758  		if err != nil {
   759  			return tlf.Handle{}, err
   760  		}
   761  		if id != dbID {
   762  			continue
   763  		}
   764  		handleBytes := iter.Key()
   765  		handle = tlf.Handle{}
   766  		err = md.config.Codec().Decode(handleBytes, &handle)
   767  		if err != nil {
   768  			return tlf.Handle{}, err
   769  		}
   770  	}
   771  	return handle, nil
   772  }
   773  
   774  // OffsetFromServerTime implements the MDServer interface for
   775  // MDServerDisk.
   776  func (md *MDServerDisk) OffsetFromServerTime() (time.Duration, bool) {
   777  	return 0, true
   778  }
   779  
   780  // GetKeyBundles implements the MDServer interface for MDServerDisk.
   781  func (md *MDServerDisk) GetKeyBundles(ctx context.Context,
   782  	tlfID tlf.ID, wkbID kbfsmd.TLFWriterKeyBundleID, rkbID kbfsmd.TLFReaderKeyBundleID) (
   783  	*kbfsmd.TLFWriterKeyBundleV3, *kbfsmd.TLFReaderKeyBundleV3, error) {
   784  	if err := checkContext(ctx); err != nil {
   785  		return nil, nil, err
   786  	}
   787  
   788  	tlfStorage, err := md.getStorage(tlfID)
   789  	if err != nil {
   790  		return nil, nil, err
   791  	}
   792  
   793  	return tlfStorage.getKeyBundles(tlfID, wkbID, rkbID)
   794  }
   795  
   796  // CheckReachability implements the MDServer interface for MDServerDisk.
   797  func (md *MDServerDisk) CheckReachability(ctx context.Context) {}
   798  
   799  // FastForwardBackoff implements the MDServer interface for MDServerDisk.
   800  func (md *MDServerDisk) FastForwardBackoff() {}
   801  
   802  // FindNextMD implements the MDServer interface for MDServerDisk.
   803  func (md *MDServerDisk) FindNextMD(
   804  	ctx context.Context, tlfID tlf.ID, rootSeqno keybase1.Seqno) (
   805  	nextKbfsRoot *kbfsmd.MerkleRoot, nextMerkleNodes [][]byte,
   806  	nextRootSeqno keybase1.Seqno, err error) {
   807  	return nil, nil, 0, nil
   808  }
   809  
   810  // GetMerkleRootLatest implements the MDServer interface for MDServerDisk.
   811  func (md *MDServerDisk) GetMerkleRootLatest(
   812  	ctx context.Context, treeID keybase1.MerkleTreeID) (
   813  	root *kbfsmd.MerkleRoot, err error) {
   814  	md.lock.RLock()
   815  	defer md.lock.RUnlock()
   816  	return md.merkleRoots[treeID], nil
   817  }