github.com/jfrog/jfrog-cli-core/v2@v2.51.0/artifactory/commands/transferfiles/state/transfersnapshot.go (about) 1 package state 2 3 import ( 4 "sync" 5 "time" 6 7 "github.com/jfrog/jfrog-cli-core/v2/utils/reposnapshot" 8 "github.com/jfrog/jfrog-client-go/utils/errorutils" 9 ) 10 11 var saveRepoSnapshotMutex sync.Mutex 12 13 type SnapshotActionFunc func(rts *RepoTransferSnapshot) error 14 15 var snapshotSaveIntervalMin = snapshotSaveIntervalMinDefault 16 17 const snapshotSaveIntervalMinDefault = 10 18 19 // RepoTransferSnapshot handles saving and loading the repository's transfer snapshot. 20 // A repository transfer snapshot stores the progress of transferring a repository, as explained in RepoSnapshotManager. 21 // In case a transfer is interrupted, the transfer can continue from it's saved snapshot instead of starting from scratch. 22 type RepoTransferSnapshot struct { 23 snapshotManager reposnapshot.RepoSnapshotManager 24 lastSaveTimestamp time.Time 25 // This boolean marks that this snapshot continues a previous run. It allows skipping certain checks if it was not loaded, because some data is known to be new. 26 loadedFromSnapshot bool 27 } 28 29 // Runs the provided action on the snapshot manager, and periodically saves the repo state and snapshot to the snapshot dir. 30 func (ts *TransferStateManager) snapshotAction(action SnapshotActionFunc) (err error) { 31 if ts.repoTransferSnapshot == nil { 32 return errorutils.CheckErrorf("invalid call to snapshot manager before it was initialized") 33 } 34 if err = action(ts.repoTransferSnapshot); err != nil { 35 return err 36 } 37 38 now := time.Now() 39 if now.Sub(ts.repoTransferSnapshot.lastSaveTimestamp).Minutes() < float64(snapshotSaveIntervalMin) { 40 return nil 41 } 42 43 if !saveRepoSnapshotMutex.TryLock() { 44 return nil 45 } 46 defer saveRepoSnapshotMutex.Unlock() 47 48 ts.repoTransferSnapshot.lastSaveTimestamp = now 49 if err = ts.repoTransferSnapshot.snapshotManager.PersistRepoSnapshot(); err != nil { 50 return err 51 } 52 53 return ts.persistTransferState(true) 54 } 55 56 func (ts *TransferStateManager) LookUpNode(relativePath string) (requestedNode *reposnapshot.Node, err error) { 57 err = ts.snapshotAction(func(rts *RepoTransferSnapshot) error { 58 requestedNode, err = rts.snapshotManager.LookUpNode(relativePath) 59 return err 60 }) 61 return 62 } 63 64 func (ts *TransferStateManager) WasSnapshotLoaded() bool { 65 return ts.repoTransferSnapshot.loadedFromSnapshot 66 } 67 68 func (ts *TransferStateManager) GetDirectorySnapshotNodeWithLru(relativePath string) (node *reposnapshot.Node, err error) { 69 err = ts.snapshotAction(func(rts *RepoTransferSnapshot) error { 70 node, err = rts.snapshotManager.GetDirectorySnapshotNodeWithLru(relativePath) 71 return err 72 }) 73 return 74 } 75 76 func (ts *TransferStateManager) DisableRepoTransferSnapshot() { 77 ts.repoTransferSnapshot = nil 78 } 79 80 func (ts *TransferStateManager) IsRepoTransferSnapshotEnabled() bool { 81 return ts.repoTransferSnapshot != nil 82 } 83 84 func loadRepoTransferSnapshot(repoKey, snapshotFilePath string) (*RepoTransferSnapshot, bool, error) { 85 snapshotManager, exists, err := reposnapshot.LoadRepoSnapshotManager(repoKey, snapshotFilePath) 86 if err != nil || !exists { 87 return nil, exists, err 88 } 89 return &RepoTransferSnapshot{snapshotManager: snapshotManager, lastSaveTimestamp: time.Now(), loadedFromSnapshot: true}, true, nil 90 } 91 92 func createRepoTransferSnapshot(repoKey, snapshotFilePath string) *RepoTransferSnapshot { 93 return &RepoTransferSnapshot{snapshotManager: reposnapshot.CreateRepoSnapshotManager(repoKey, snapshotFilePath), lastSaveTimestamp: time.Now()} 94 }