go: doltcore/env/actions: remotes: Only use clone on the backup path if the src TableFileStore does not include a chunk journal.

This commit is contained in:
Aaron Son
2023-05-02 20:26:21 -07:00
parent de75a3c30d
commit 78ddc3758c
4 changed files with 61 additions and 4 deletions
+23
View File
@@ -1487,6 +1487,29 @@ func (ddb *DoltDB) Clone(ctx context.Context, destDB *DoltDB, eventCh chan<- pul
return pull.Clone(ctx, datas.ChunkStoreFromDatabase(ddb.db), datas.ChunkStoreFromDatabase(destDB.db), eventCh)
}
// Returns |true| if the underlying ChunkStore for this DoltDB implements |chunks.TableFileStore|.
func (ddb *DoltDB) IsTableFileStore() bool {
_, ok := datas.ChunkStoreFromDatabase(ddb.db).(chunks.TableFileStore)
return ok
}
func (ddb *DoltDB) TableFileStoreHasJournal(ctx context.Context) (bool, error) {
tableFileStore, ok := datas.ChunkStoreFromDatabase(ddb.db).(chunks.TableFileStore)
if !ok {
return false, errors.New("unsupported operation, DoltDB.TableFileStoreHasManifest on non-TableFileStore")
}
_, tableFiles, _, err := tableFileStore.Sources(ctx)
if err != nil {
return false, err
}
for _, tableFile := range tableFiles {
if tableFile.FileID() == chunks.JournalFileID {
return true, nil
}
}
return false, nil
}
func (ddb *DoltDB) SetCommitHooks(ctx context.Context, postHooks []CommitHook) *DoltDB {
ddb.db = ddb.db.SetCommitHooks(ctx, postHooks)
return ddb
+34 -3
View File
@@ -455,6 +455,35 @@ func FetchRefSpecs(ctx context.Context, dbData env.DbData, srcDB *doltdb.DoltDB,
return nil
}
// SyncRoots is going to copy the root hash of the database from srcDb to destDb.
// We can do this |Clone| if (1) destDb is empty, (2) destDb and srcDb are both
// |TableFileStore|s, and (3) srcDb does *not* have a journal file. The most
// common scenario where this occurs is when we are restoring a backup.
//
// The journal's interaction with TableFileStore is not great currently ---
// when accessing a journal file through TableFileStore, the Reader() should in
// reality return something which is going to result in reading an actual table
// file. For now, we avoid the |Clone| path when the journal file is present.
func canSyncRootsWithClone(ctx context.Context, srcDb, destDb *doltdb.DoltDB, destDbRoot hash.Hash) (bool, error) {
if !destDbRoot.IsEmpty() {
return false, nil
}
if !srcDb.IsTableFileStore() {
return false, nil
}
if !destDb.IsTableFileStore() {
return false, nil
}
srcHasJournal, err := srcDb.TableFileStoreHasJournal(ctx)
if err != nil {
return false, err
}
if srcHasJournal {
return false, nil
}
return true, nil
}
// SyncRoots copies the entire chunkstore from srcDb to destDb and rewrites the remote manifest. Used to
// streamline database backup and restores.
// TODO: this should read/write a backup lock file specific to the client who created the backup
@@ -484,10 +513,12 @@ func SyncRoots(ctx context.Context, srcDb, destDb *doltdb.DoltDB, tempTableDir s
}
}()
if destRoot.IsEmpty() {
// In this case, we can clone into the dest root, if both src and destination support it.
// We will try to translate the stats from the table file events to the statsCh.
canClone, err := canSyncRootsWithClone(ctx, srcDb, destDb, destRoot)
if err != nil {
return err
}
if canClone {
tfCh := make(chan pull.TableFileEvent)
go func() {
start := time.Now()
+2
View File
@@ -21,6 +21,8 @@ import (
"github.com/dolthub/dolt/go/store/hash"
)
const JournalFileID = "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv"
// TableFile is an interface for working with an existing table file
type TableFile interface {
// FileID gets the id of the file
+2 -1
View File
@@ -26,6 +26,7 @@ import (
"github.com/dolthub/swiss"
"golang.org/x/sync/errgroup"
"github.com/dolthub/dolt/go/store/chunks"
"github.com/dolthub/dolt/go/store/hash"
)
@@ -36,7 +37,7 @@ const (
// but we don't have a hard limit on record size right now
journalWriterBuffSize = 1024 * 1024
chunkJournalAddr = "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv"
chunkJournalAddr = chunks.JournalFileID
journalIndexFileName = "journal.idx"