Skip to content

Commit 67e0ff0

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 b4fa530 commit 67e0ff0

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
@@ -242,6 +242,12 @@ func TestOpen_WALFailover(t *testing.T) {
242242
switch cmdArg.Key {
243243
case "path":
244244
o.FS, dataDir = extractFSAndPath(cmdArg)
245+
case "wal-dir":
246+
fs, dir := extractFSAndPath(cmdArg)
247+
if fs != o.FS {
248+
td.Fatalf(t, "WAL fs differs from data fs")
249+
}
250+
o.WALDir = dir
245251
case "secondary":
246252
fs, dir := extractFSAndPath(cmdArg)
247253
o.WALFailover = &WALFailoverOptions{
@@ -250,6 +256,8 @@ func TestOpen_WALFailover(t *testing.T) {
250256
case "wal-recovery-dir":
251257
fs, dir := extractFSAndPath(cmdArg)
252258
o.WALRecoveryDirs = append(o.WALRecoveryDirs, wal.Dir{FS: fs, Dirname: dir})
259+
case "allow-missing-wal-dirs":
260+
o.Unsafe.AllowMissingWALDirs = true
253261
default:
254262
return fmt.Sprintf("unrecognized cmdArg %q", cmdArg.Key)
255263
}

options.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1128,7 +1128,8 @@ type Options struct {
11281128
// the current database state.
11291129
//
11301130
// If a previous WAL configuration may have stored WALs elsewhere but there
1131-
// is not a corresponding entry in WALRecoveryDirs, Open will error.
1131+
// is not a corresponding entry in WALRecoveryDirs, Open will error (unless
1132+
// Unsafe.AllowMissingWALDirs is true).
11321133
WALRecoveryDirs []wal.Dir
11331134

11341135
// WALMinSyncInterval is the minimum duration between syncs of the WAL. If
@@ -1159,6 +1160,19 @@ type Options struct {
11591160
// preemptively reduce internal fragmentation when loaded into the block cache.
11601161
AllocatorSizeClasses []int
11611162

1163+
// Unsafe contains options that must be used very carefully and in exceptional
1164+
// circumstances.
1165+
Unsafe struct {
1166+
// AllowMissingWALDirs, if set to true, allows opening a DB when the WAL or
1167+
// WAL secondary directory was changed and the previous directory is not in
1168+
// WALRecoveryDirs. This can be used to move WALs without having to keep the
1169+
// previous directory in the options forever.
1170+
//
1171+
// CAUTION: Enabling this option will lead to data loss if the missing
1172+
// directory contained any WAL files that were not flushed to sstables.
1173+
AllowMissingWALDirs bool
1174+
}
1175+
11621176
// private options are only used by internal tests or are used internally
11631177
// for facilitating upgrade paths of unconfigurable functionality.
11641178
private struct {
@@ -2482,6 +2496,11 @@ func (o *Options) checkWALDir(storeDir, walDir, errContext string) error {
24822496
}
24832497
}
24842498

2499+
if o.Unsafe.AllowMissingWALDirs {
2500+
o.Logger.Infof("directory %q may contain relevant WALs but is not in WALRecoveryDirs (AllowMissingWALDirs enabled)", walDir)
2501+
return nil
2502+
}
2503+
24852504
var buf bytes.Buffer
24862505
fmt.Fprintf(&buf, "\n %s\n", errContext)
24872506
fmt.Fprintf(&buf, " o.WALDir: %q\n", o.WALDir)
@@ -2492,6 +2511,7 @@ func (o *Options) checkWALDir(storeDir, walDir, errContext string) error {
24922511
for _, d := range o.WALRecoveryDirs {
24932512
fmt.Fprintf(&buf, "\n %q", d.Dirname)
24942513
}
2514+
24952515
return ErrMissingWALRecoveryDir{Dir: walPath, ExtraInfo: buf.String()}
24962516
}
24972517

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)