From be2856ebbd0a90092a775a34b36ff52340e4b379 Mon Sep 17 00:00:00 2001 From: Gilbert Chen Date: Wed, 21 Mar 2018 22:34:14 -0400 Subject: [PATCH] Add a -vss-timeout option to set VSS creation timeout --- duplicacy/duplicacy_main.go | 9 ++++++++- src/duplicacy_backupmanager.go | 4 ++-- src/duplicacy_backupmanager_test.go | 8 ++++---- src/duplicacy_shadowcopy.go | 2 +- src/duplicacy_shadowcopy_windows.go | 11 +++++++---- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/duplicacy/duplicacy_main.go b/duplicacy/duplicacy_main.go index 578966e..8c5015e 100644 --- a/duplicacy/duplicacy_main.go +++ b/duplicacy/duplicacy_main.go @@ -689,6 +689,7 @@ func backupRepository(context *cli.Context) { showStatistics := context.Bool("stats") enableVSS := context.Bool("vss") + vssTimeout := context.Int("vss-timeout") dryRun := context.Bool("dry-run") uploadRateLimit := context.Int("limit-rate") @@ -698,7 +699,7 @@ func backupRepository(context *cli.Context) { backupManager.SetupSnapshotCache(preference.Name) backupManager.SetDryRun(dryRun) - backupManager.Backup(repository, quickMode, threads, context.String("t"), showStatistics, enableVSS) + backupManager.Backup(repository, quickMode, threads, context.String("t"), showStatistics, enableVSS, vssTimeout) runScript(context, preference.Name, "post") } @@ -1325,6 +1326,12 @@ func main() { Name: "vss", Usage: "enable the Volume Shadow Copy service (Windows only)", }, + cli.IntFlag{ + Name: "vss-timeout", + Value: 0, + Usage: "the timeout in seconds to wait for the Volume Shadow Copy operation to complete", + Argument: "", + }, cli.StringFlag{ Name: "storage", Usage: "backup to the specified storage instead of the default one", diff --git a/src/duplicacy_backupmanager.go b/src/duplicacy_backupmanager.go index f45a8b6..b8a59bc 100644 --- a/src/duplicacy_backupmanager.go +++ b/src/duplicacy_backupmanager.go @@ -159,7 +159,7 @@ func setEntryContent(entries []*Entry, chunkLengths []int, offset int) { // unmodified files with last backup). Otherwise (or if this is the first backup), the entire repository will // be scanned to create the snapshot. 'tag' is the tag assigned to the new snapshot. func (manager *BackupManager) Backup(top string, quickMode bool, threads int, tag string, - showStatistics bool, shadowCopy bool) bool { + showStatistics bool, shadowCopy bool, shadowCopyTimeout int) bool { var err error top, err = filepath.Abs(top) @@ -180,7 +180,7 @@ func (manager *BackupManager) Backup(top string, quickMode bool, threads int, ta LOG_INFO("BACKUP_START", "Last backup at revision %d found", remoteSnapshot.Revision) } - shadowTop := CreateShadowCopy(top, shadowCopy) + shadowTop := CreateShadowCopy(top, shadowCopy, shadowCopyTimeout) defer DeleteShadowCopy() LOG_INFO("BACKUP_INDEXING", "Indexing %s", top) diff --git a/src/duplicacy_backupmanager_test.go b/src/duplicacy_backupmanager_test.go index ecb73ea..e463e93 100644 --- a/src/duplicacy_backupmanager_test.go +++ b/src/duplicacy_backupmanager_test.go @@ -243,7 +243,7 @@ func TestBackupManager(t *testing.T) { backupManager.SetupSnapshotCache("default") SetDuplicacyPreferencePath(testDir + "/repository1/.duplicacy") - backupManager.Backup(testDir+"/repository1" /*quickMode=*/, true, threads, "first", false, false) + backupManager.Backup(testDir+"/repository1" /*quickMode=*/, true, threads, "first", false, false, 0) time.Sleep(time.Duration(delay) * time.Second) SetDuplicacyPreferencePath(testDir + "/repository2/.duplicacy") backupManager.Restore(testDir+"/repository2", threads, /*inPlace=*/false, /*quickMode=*/false, threads, /*overwrite=*/true, @@ -267,7 +267,7 @@ func TestBackupManager(t *testing.T) { modifyFile(testDir+"/repository1/dir1/file3", 0.3) SetDuplicacyPreferencePath(testDir + "/repository1/.duplicacy") - backupManager.Backup(testDir+"/repository1" /*quickMode=*/, true, threads, "second", false, false) + backupManager.Backup(testDir+"/repository1" /*quickMode=*/, true, threads, "second", false, false, 0) time.Sleep(time.Duration(delay) * time.Second) SetDuplicacyPreferencePath(testDir + "/repository2/.duplicacy") backupManager.Restore(testDir+"/repository2", 2, /*inPlace=*/true, /*quickMode=*/true, threads, /*overwrite=*/true, @@ -287,7 +287,7 @@ func TestBackupManager(t *testing.T) { os.Mkdir(testDir+"/repository1/dir2/dir3", 0700) os.Mkdir(testDir+"/repository1/dir4", 0700) SetDuplicacyPreferencePath(testDir + "/repository1/.duplicacy") - backupManager.Backup(testDir+"/repository1" /*quickMode=*/, false, threads, "third", false, false) + backupManager.Backup(testDir+"/repository1" /*quickMode=*/, false, threads, "third", false, false, 0) time.Sleep(time.Duration(delay) * time.Second) // Create some directories and files under repository2 that will be deleted during restore @@ -350,7 +350,7 @@ func TestBackupManager(t *testing.T) { } backupManager.SnapshotManager.CheckSnapshots( /*snapshotID*/ "host1" /*revisions*/, []int{2, 3} /*tag*/, "", /*showStatistics*/ false /*showTabular*/, false /*checkFiles*/, false /*searchFossils*/, false /*resurrect*/, false) - backupManager.Backup(testDir+"/repository1" /*quickMode=*/, false, threads, "fourth", false, false) + backupManager.Backup(testDir+"/repository1" /*quickMode=*/, false, threads, "fourth", false, false, 0) backupManager.SnapshotManager.PruneSnapshots("host1", "host1" /*revisions*/, nil /*tags*/, nil /*retentions*/, nil, /*exhaustive*/ false /*exclusive=*/, true /*ignoredIDs*/, nil /*dryRun*/, false /*deleteOnly*/, false /*collectOnly*/, false) numberOfSnapshots = backupManager.SnapshotManager.ListSnapshots( /*snapshotID*/ "host1" /*revisionsToList*/, nil /*tag*/, "" /*showFiles*/, false /*showChunks*/, false) diff --git a/src/duplicacy_shadowcopy.go b/src/duplicacy_shadowcopy.go index 8ff51e3..0e75ac2 100644 --- a/src/duplicacy_shadowcopy.go +++ b/src/duplicacy_shadowcopy.go @@ -6,7 +6,7 @@ package duplicacy -func CreateShadowCopy(top string, shadowCopy bool) (shadowTop string) { +func CreateShadowCopy(top string, shadowCopy bool, timeoutInSeconds int) (shadowTop string) { return top } diff --git a/src/duplicacy_shadowcopy_windows.go b/src/duplicacy_shadowcopy_windows.go index e2c187e..58d003f 100644 --- a/src/duplicacy_shadowcopy_windows.go +++ b/src/duplicacy_shadowcopy_windows.go @@ -353,12 +353,15 @@ func DeleteShadowCopy() { ole.CoUninitialize() } -func CreateShadowCopy(top string, shadowCopy bool) (shadowTop string) { +func CreateShadowCopy(top string, shadowCopy bool, timeoutInSeconds int) (shadowTop string) { if !shadowCopy { return top } + if timeoutInSeconds <= 60 { + timeoutInSeconds = 60 + } ole.CoInitialize(0) defer ole.CoUninitialize() @@ -416,7 +419,7 @@ func CreateShadowCopy(top string, shadowCopy bool) (shadowTop string) { return top } - if !async.Wait(60) { + if !async.Wait(timeoutInSeconds) { LOG_ERROR("VSS_GATHER", "Shadow copy creation failed: GatherWriterMetadata didn't finish properly") return top } @@ -456,7 +459,7 @@ func CreateShadowCopy(top string, shadowCopy bool) (shadowTop string) { return top } - if !async.Wait(60) { + if !async.Wait(timeoutInSeconds) { LOG_ERROR("VSS_PREPARE", "Shadow copy creation failed: PrepareForBackup didn't finish properly") return top } @@ -473,7 +476,7 @@ func CreateShadowCopy(top string, shadowCopy bool) (shadowTop string) { return top } - if !async.Wait(180) { + if !async.Wait(timeoutInSeconds) { LOG_ERROR("VSS_SNAPSHOT", "Shadow copy creation failed: DoSnapshotSet didn't finish properly") return top }