Repository: kopia/kopia
Pull request #2468 (2022-10-01 17:46:46)

fix(repository): fixed frequent repository refreshes for older repositories
This is a regression in 0.12.0 and was reported on Slack by Amir Zarrinkafsh.

Repository connections made using old version of Kopia did not properly save format blob cache duration so it was defaulting to 0s instead of 15 minutes causing endless format refreshes, slowing things down and causing unnecessary read traffic to blob storage.

codecov[bot]: # [Codecov](https://codecov.io/gh/kopia/kopia/pull/2468?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia) Report
Base: **74.39**% // Head: **74.44**% // Increases project coverage by **`+0.05%`** :tada:
> Coverage data is based on head [(`9eaad62`)](https://codecov.io/gh/kopia/kopia/pull/2468?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia) compared to base [(`11ce91d`)](https://codecov.io/gh/kopia/kopia/commit/11ce91dd5ac08e6e93fa2aa11bcd2913f87eca68?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia).
> Patch coverage: 100.00% of modified lines in pull request are covered.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master    #2468      +/-   ##
==========================================
+ Coverage   74.39%   74.44%   +0.05%     
==========================================
  Files         442      442              
  Lines       34972    34974       +2     
==========================================
+ Hits        26018    26038      +20     
+ Misses       7058     7042      -16     
+ Partials     1896     1894       -2     
```


| [Impacted Files](https://codecov.io/gh/kopia/kopia/pull/2468?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia) | Coverage Δ | |
|---|---|---|
| [repo/open.go](https://codecov.io/gh/kopia/kopia/pull/2468/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia#diff-cmVwby9vcGVuLmdv) | `75.82% <100.00%> (+0.17%)` | :arrow_up: |
| [internal/server/source\_manager.go](https://codecov.io/gh/kopia/kopia/pull/2468/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia#diff-aW50ZXJuYWwvc2VydmVyL3NvdXJjZV9tYW5hZ2VyLmdv) | `81.28% <0.00%> (-1.54%)` | :arrow_down: |
| [internal/server/server.go](https://codecov.io/gh/kopia/kopia/pull/2468/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia#diff-aW50ZXJuYWwvc2VydmVyL3NlcnZlci5nbw==) | `73.16% <0.00%> (+0.56%)` | :arrow_up: |
| [snapshot/snapshotfs/upload.go](https://codecov.io/gh/kopia/kopia/pull/2468/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia#diff-c25hcHNob3Qvc25hcHNob3Rmcy91cGxvYWQuZ28=) | `85.01% <0.00%> (+1.10%)` | :arrow_up: |
| [snapshot/snapshotfs/repofs.go](https://codecov.io/gh/kopia/kopia/pull/2468/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia#diff-c25hcHNob3Qvc25hcHNob3Rmcy9yZXBvZnMuZ28=) | `80.80% <0.00%> (+1.51%)` | :arrow_up: |
| [cli/command\_content\_verify.go](https://codecov.io/gh/kopia/kopia/pull/2468/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia#diff-Y2xpL2NvbW1hbmRfY29udGVudF92ZXJpZnkuZ28=) | `81.03% <0.00%> (+6.03%)` | :arrow_up: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/kopia/kopia/pull/2468?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kopia).


Patch:
diff --git a/repo/open.go b/repo/open.go
index 67633d9b..5b77b2ad 100644
--- a/repo/open.go
+++ b/repo/open.go
@@ -190,7 +190,9 @@ func openDirect(ctx context.Context, configFile string, lc *LocalConfig, passwor
 		st = readonly.NewWrapper(st)
 	}
 
-	r, err := openWithConfig(ctx, st, lc, password, options, lc.Caching, configFile)
+	cliOpts := lc.ApplyDefaults(ctx, "Repository in "+st.DisplayName())
+
+	r, err := openWithConfig(ctx, st, cliOpts, password, options, lc.Caching, configFile)
 	if err != nil {
 		st.Close(ctx) //nolint:errcheck
 		return nil, err
@@ -202,14 +204,14 @@ func openDirect(ctx context.Context, configFile string, lc *LocalConfig, passwor
 // openWithConfig opens the repository with a given configuration, avoiding the need for a config file.
 //
 //nolint:funlen,gocyclo
-func openWithConfig(ctx context.Context, st blob.Storage, lc *LocalConfig, password string, options *Options, cacheOpts *content.CachingOptions, configFile string) (DirectRepository, error) {
+func openWithConfig(ctx context.Context, st blob.Storage, cliOpts ClientOptions, password string, options *Options, cacheOpts *content.CachingOptions, configFile string) (DirectRepository, error) {
 	cacheOpts = cacheOpts.CloneOrDefault()
 	cmOpts := &content.ManagerOptions{
 		TimeNow:            defaultTime(options.TimeNowFunc),
 		DisableInternalLog: options.DisableInternalLog,
 	}
 
-	fmgr, ferr := format.NewManager(ctx, st, cacheOpts.CacheDirectory, lc.FormatBlobCacheDuration, password, cmOpts.TimeNow)
+	fmgr, ferr := format.NewManager(ctx, st, cacheOpts.CacheDirectory, cliOpts.FormatBlobCacheDuration, password, cmOpts.TimeNow)
 	if ferr != nil {
 		return nil, errors.Wrap(ferr, "unable to create format manager")
 	}
@@ -246,8 +248,8 @@ func openWithConfig(ctx context.Context, st blob.Storage, lc *LocalConfig, passw
 	}
 
 	limits := throttlingLimitsFromConnectionInfo(ctx, st.ConnectionInfo())
-	if lc.Throttling != nil {
-		limits = *lc.Throttling
+	if cliOpts.Throttling != nil {
+		limits = *cliOpts.Throttling
 	}
 
 	st, throttler, ferr := addThrottler(st, limits)
@@ -284,8 +286,8 @@ func openWithConfig(ctx context.Context, st blob.Storage, lc *LocalConfig, passw
 	}
 
 	cm := content.NewWriteManager(ctx, scm, content.SessionOptions{
-		SessionUser: lc.Username,
-		SessionHost: lc.Hostname,
+		SessionUser: cliOpts.Username,
+		SessionHost: cliOpts.Hostname,
 	}, "")
 
 	om, ferr := object.NewObjectManager(ctx, cm, fmgr.ObjectFormat())
@@ -308,7 +310,7 @@ func openWithConfig(ctx context.Context, st blob.Storage, lc *LocalConfig, passw
 			cachingOptions: *cacheOpts,
 			fmgr:           fmgr,
 			timeNow:        cmOpts.TimeNow,
-			cliOpts:        lc.ClientOptions.ApplyDefaults(ctx, "Repository in "+st.DisplayName()),
+			cliOpts:        cliOpts,
 			configFile:     configFile,
 			nextWriterID:   new(int32),
 			throttler:      throttler,


Test patch:
diff --git a/tests/compat_test/compat_test.go b/tests/compat_test/compat_test.go
index 389d9457..b140de7b 100644
--- a/tests/compat_test/compat_test.go
+++ b/tests/compat_test/compat_test.go
@@ -2,7 +2,11 @@
 
 import (
 	"os"
+	"path/filepath"
 	"testing"
+	"time"
+
+	"github.com/stretchr/testify/require"
 
 	"github.com/kopia/kopia/tests/testenv"
 )
@@ -50,6 +54,43 @@ func TestRepoCreatedWith08CanBeOpenedWithCurrent(t *testing.T) {
 	e1.RunAndExpectFailure(t, "snap", "ls")
 }
 
+func TestRepoCreatedWith08ProperlyRefreshes(t *testing.T) {
+	t.Parallel()
+
+	if kopiaCurrentExe == "" {
+		t.Skip()
+	}
+
+	runner08 := testenv.NewExeRunnerWithBinary(t, kopia08exe)
+
+	// create repository using v0.8
+	e1 := testenv.NewCLITest(t, testenv.RepoFormatNotImportant, runner08)
+	e1.RunAndExpectSuccess(t, "repo", "create", "filesystem", "--path", e1.RepoDir)
+	e1.RunAndExpectSuccess(t, "snap", "create", ".")
+
+	// switch to using latest runner
+	e1.Runner = testenv.NewExeRunnerWithBinary(t, kopiaCurrentExe)
+
+	// measure time of the cache file and ensure it stays the same
+	cachePath := e1.RunAndExpectSuccess(t, "cache", "info", "--path")[0]
+	cachedBlob := filepath.Join(cachePath, "kopia.repository")
+
+	time.Sleep(1 * time.Second)
+	// 0.12.0 had a bug where we would constantly refresh kopia.repository
+	// this was done all the time instead of every 15 minutes,
+	st1, err := os.Stat(cachedBlob)
+	require.NoError(t, err)
+
+	e1.RunAndExpectSuccess(t, "repo", "status")
+	time.Sleep(1 * time.Second)
+	e1.RunAndExpectSuccess(t, "repo", "status")
+
+	st2, err := os.Stat(cachedBlob)
+	require.NoError(t, err)
+
+	require.Equal(t, st1.ModTime(), st2.ModTime())
+}
+
 func TestRepoCreatedWithCurrentWithFormatVersion1CanBeOpenedWith08(t *testing.T) {
 	t.Parallel()