Skip to content

Commit 52ed0eb

Browse files
committed
options: add Unsafe.AllowMissingWALDir option
This unsafe option allows opening a store after moving or losing the previous WAL dir. This is understood to be risky and have associated data loss if any of the necessary WALs are not in the new directory. Fixes #5421
1 parent 04362d0 commit 52ed0eb

File tree

3 files changed

+78
-1
lines changed

3 files changed

+78
-1
lines changed

open_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,12 @@ func TestOpen_WALFailover(t *testing.T) {
240240
switch cmdArg.Key {
241241
case "path":
242242
o.FS, dataDir = extractFSAndPath(cmdArg)
243+
case "wal-dir":
244+
fs, dir := extractFSAndPath(cmdArg)
245+
if fs != o.FS {
246+
td.Fatalf(t, "WAL fs differs from data fs")
247+
}
248+
o.WALDir = dir
243249
case "secondary":
244250
fs, dir := extractFSAndPath(cmdArg)
245251
o.WALFailover = &WALFailoverOptions{
@@ -248,6 +254,8 @@ func TestOpen_WALFailover(t *testing.T) {
248254
case "wal-recovery-dir":
249255
fs, dir := extractFSAndPath(cmdArg)
250256
o.WALRecoveryDirs = append(o.WALRecoveryDirs, wal.Dir{FS: fs, Dirname: dir})
257+
case "allow-missing-wal-dirs":
258+
o.Unsafe.AllowMissingWALDirs = true
251259
default:
252260
return fmt.Sprintf("unrecognized cmdArg %q", cmdArg.Key)
253261
}

options.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1048,7 +1048,8 @@ type Options struct {
10481048
// the current database state.
10491049
//
10501050
// If a previous WAL configuration may have stored WALs elsewhere but there
1051-
// is not a corresponding entry in WALRecoveryDirs, Open will error.
1051+
// is not a corresponding entry in WALRecoveryDirs, Open will error (unless
1052+
// Unsafe.AllowMissingWALDirs is true).
10521053
WALRecoveryDirs []wal.Dir
10531054

10541055
// WALMinSyncInterval is the minimum duration between syncs of the WAL. If
@@ -1109,6 +1110,19 @@ type Options struct {
11091110
// preemptively reduce internal fragmentation when loaded into the block cache.
11101111
AllocatorSizeClasses []int
11111112

1113+
// Unsafe contains options that must be used very carefully and in exceptional
1114+
// circumstances.
1115+
Unsafe struct {
1116+
// AllowMissingWALDirs, if set to true, allows opening a DB when the WAL or
1117+
// WAL secondary directory was changed and the previous directory is not in
1118+
// WALRecoveryDirs. This can be used to move WALs without having to keep the
1119+
// previous directory in the options forever.
1120+
//
1121+
// CAUTION: Enabling this option will lead to data loss if the missing
1122+
// directory contained any WAL files that were not flushed to sstables.
1123+
AllowMissingWALDirs bool
1124+
}
1125+
11121126
// private options are only used by internal tests or are used internally
11131127
// for facilitating upgrade paths of unconfigurable functionality.
11141128
private struct {
@@ -2334,6 +2348,11 @@ func (o *Options) checkWALDir(storeDir, walDir, errContext string) error {
23342348
}
23352349
}
23362350

2351+
if o.Unsafe.AllowMissingWALDirs {
2352+
o.Logger.Infof("directory %q may contain relevant WALs but is not in WALRecoveryDirs (AllowMissingWALDirs enabled)", walDir)
2353+
return nil
2354+
}
2355+
23372356
var buf bytes.Buffer
23382357
fmt.Fprintf(&buf, "\n %s\n", errContext)
23392358
fmt.Fprintf(&buf, " o.WALDir: %q\n", o.WALDir)
@@ -2344,6 +2363,7 @@ func (o *Options) checkWALDir(storeDir, walDir, errContext string) error {
23442363
for _, d := range o.WALRecoveryDirs {
23452364
fmt.Fprintf(&buf, "\n %q", d.Dirname)
23462365
}
2366+
23472367
return ErrMissingWALRecoveryDir{Dir: walPath, ExtraInfo: buf.String()}
23482368
}
23492369

testdata/open_wal_failover

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,52 @@ directory "secondary-wals" may contain relevant WALs but is not in WALRecoveryDi
6969
open path=(a,data) wal-recovery-dir=(b,secondary-wals)
7070
----
7171
ok
72+
73+
open path=(c,data) wal-dir=(c,wal1)
74+
----
75+
ok
76+
77+
# We cannot change the WAL directory without providing the previous one as a recovery dir.
78+
open path=(c,data) wal-dir=(c,wal2)
79+
----
80+
directory "wal1" may contain relevant WALs but is not in WALRecoveryDirs
81+
WALDir changed from previous options
82+
o.WALDir: "wal2"
83+
o.WALRecoveryDirs: 0
84+
85+
open path=(c,data) wal-dir=(c,wal2) wal-recovery-dir=(c,wal1)
86+
----
87+
ok
88+
89+
# Once we opened the database once (and thus replayed any WALs in the previous
90+
# WAL dir), we can open without a recovery dir.
91+
open path=(c,data) wal-dir=(c,wal2)
92+
----
93+
ok
94+
95+
open path=(c,data) wal-dir=(c,wal3)
96+
----
97+
directory "wal2" may contain relevant WALs but is not in WALRecoveryDirs
98+
WALDir changed from previous options
99+
o.WALDir: "wal3"
100+
o.WALRecoveryDirs: 0
101+
102+
# Test the Unsafe.AllowMissingWALDirs option.
103+
open path=(c,data) wal-dir=(c,wal3) allow-missing-wal-dirs
104+
----
105+
ok
106+
107+
open path=(c,data) wal-dir=(c,wal3) secondary=(d,secondary)
108+
----
109+
ok
110+
111+
open path=(c,data) wal-dir=(c,wal3)
112+
----
113+
directory "secondary" may contain relevant WALs but is not in WALRecoveryDirs
114+
WALFailover.Secondary changed from previous options
115+
o.WALDir: "wal3"
116+
o.WALRecoveryDirs: 0
117+
118+
open path=(c,data) wal-dir=(c,wal3) allow-missing-wal-dirs
119+
----
120+
ok

0 commit comments

Comments
 (0)