Skip to content

Commit 2cdfc4f

Browse files
authored
Merge pull request #1133 from percona/PBM-1553-improve-mongod-phys-restore-logging
PBM-1553: Improve mongod logging during physical restore
2 parents 97431be + c1e04c9 commit 2cdfc4f

File tree

2 files changed

+232
-11
lines changed

2 files changed

+232
-11
lines changed

pbm/restore/physical.go

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -220,16 +220,12 @@ func (r *PhysRestore) close(noerr, cleanup bool) {
220220
r.log.Error("remove tmp config %s: %v", r.tmpConf.Name(), err)
221221
}
222222
}
223-
// clean-up internal mongod log only if there is no error
223+
224+
// if there is no error clean-up internal restore files, internal log file(s) should stay
224225
if noerr {
225-
r.log.Debug("rm tmp logs")
226-
err := os.Remove(path.Join(r.dbpath, internalMongodLog))
227-
if err != nil {
228-
r.log.Warning("remove tmp mongod logs %s: %v", path.Join(r.dbpath, internalMongodLog), err)
229-
}
230226
extMeta := filepath.Join(r.dbpath,
231227
fmt.Sprintf(defs.ExternalRsMetaFile, util.MakeReverseRSMapFunc(r.rsMap)(r.nodeInfo.SetName)))
232-
err = os.Remove(extMeta)
228+
err := os.Remove(extMeta)
233229
if err != nil && !errors.Is(err, os.ErrNotExist) {
234230
r.log.Warning("remove external rs meta <%s>: %v", extMeta, err)
235231
}
@@ -252,7 +248,7 @@ func (r *PhysRestore) close(noerr, cleanup bool) {
252248
}
253249
} else if cleanup { // clean-up dbpath on err if needed (cluster is done or partlyDone)
254250
r.log.Debug("clean-up dbpath")
255-
err := removeAll(r.dbpath, nil, r.log)
251+
err := removeAll(r.dbpath, r.log, getInternalLogFileSkipRule())
256252
if err != nil {
257253
r.log.Error("flush dbpath %s: %v", r.dbpath, err)
258254
}
@@ -378,6 +374,10 @@ func (r *PhysRestore) migrateDBDirToFallbackDir() error {
378374
if err != nil {
379375
return errors.Wrap(err, "remove fallback db path")
380376
}
377+
err = removeInternalMongoLogs(dbpath, r.log)
378+
if err != nil {
379+
return errors.Wrap(err, "remove internal mongod log(s)")
380+
}
381381

382382
r.log.Debug("create %s", fallbackPath)
383383
info, err := os.Stat(dbpath)
@@ -402,7 +402,7 @@ func (r *PhysRestore) migrateDBDirToFallbackDir() error {
402402
// moves all content from fallback path.
403403
func (r *PhysRestore) migrateFromFallbackDirToDBDir() error {
404404
r.log.Debug("clean-up dbpath")
405-
err := removeAll(r.dbpath, []string{fallbackDir}, r.log)
405+
err := removeAll(r.dbpath, r.log, getFallbackSyncFileSkipRule(), getInternalLogFileSkipRule())
406406
if err != nil {
407407
r.log.Error("flush dbpath %s: %v", r.dbpath, err)
408408
return errors.Wrap(err, "remove all from dbpath")
@@ -2592,7 +2592,9 @@ func moveAll(fromDir, toDir string, toIgnore []string, l log.LogEvent) error {
25922592
return nil
25932593
}
25942594

2595-
func removeAll(dir string, toIgnore []string, l log.LogEvent) error {
2595+
// removeAll removes all files and directories from specified dir.
2596+
// It ignores files selected with filesSkipRules parameter.
2597+
func removeAll(dir string, l log.LogEvent, fileSkipRules ...fileSkipRule) error {
25962598
d, err := os.Open(dir)
25972599
if err != nil {
25982600
return errors.Wrap(err, "open dir")
@@ -2604,7 +2606,7 @@ func removeAll(dir string, toIgnore []string, l log.LogEvent) error {
26042606
return errors.Wrap(err, "read file names")
26052607
}
26062608
for _, n := range names {
2607-
if n == internalMongodLog || slices.Contains(toIgnore, n) {
2609+
if isFileToSkip(n, fileSkipRules...) {
26082610
continue
26092611
}
26102612
err = os.RemoveAll(filepath.Join(dir, n))
@@ -2616,6 +2618,65 @@ func removeAll(dir string, toIgnore []string, l log.LogEvent) error {
26162618
return nil
26172619
}
26182620

2621+
// removeInternalMongoLogs removes internal mongod logs from directory.
2622+
// It'll remove everything that starts with 'pbm.restore.log'
2623+
func removeInternalMongoLogs(dir string, l log.LogEvent) error {
2624+
d, err := os.Open(dir)
2625+
if err != nil {
2626+
return errors.Wrap(err, "open dir")
2627+
}
2628+
defer d.Close()
2629+
2630+
names, err := d.Readdirnames(-1)
2631+
if err != nil {
2632+
return errors.Wrap(err, "read file names")
2633+
}
2634+
for _, n := range names {
2635+
if isInternalMongoLog(n) {
2636+
err = os.RemoveAll(filepath.Join(dir, n))
2637+
if err != nil {
2638+
return errors.Wrapf(err, "remove '%s", n)
2639+
}
2640+
2641+
l.Debug("remove %s", filepath.Join(dir, n))
2642+
}
2643+
}
2644+
2645+
return nil
2646+
}
2647+
2648+
// isInternalMongoLog checks whether the file with the name f
2649+
// is internal mongo log file
2650+
func isInternalMongoLog(f string) bool {
2651+
return strings.HasPrefix(f, internalMongodLog)
2652+
}
2653+
2654+
type fileSkipRule func(string) bool
2655+
2656+
// isFileToSkip for the given file name f and the given set of skip rules: skipRules,
2657+
// function returns true if at least one rule is satisfied. In case when all rules
2658+
// are false it returns false, which means that file shouldn't be skipped.
2659+
func isFileToSkip(f string, skipRules ...fileSkipRule) bool {
2660+
for _, rule := range skipRules {
2661+
if rule(f) {
2662+
return true
2663+
}
2664+
}
2665+
return false
2666+
}
2667+
2668+
func getInternalLogFileSkipRule() fileSkipRule {
2669+
return func(f string) bool {
2670+
return isInternalMongoLog(f)
2671+
}
2672+
}
2673+
2674+
func getFallbackSyncFileSkipRule() fileSkipRule {
2675+
return func(f string) bool {
2676+
return f == fallbackDir
2677+
}
2678+
}
2679+
26192680
func majmin(v string) string {
26202681
if len(v) == 0 {
26212682
return v

pbm/restore/physical_test.go

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"net"
66
"os"
7+
"path"
78
"path/filepath"
89
"strings"
910
"testing"
@@ -181,3 +182,162 @@ func TestWaitMgoFreePort(t *testing.T) {
181182
}
182183
})
183184
}
185+
186+
func TestRemoveAll(t *testing.T) {
187+
t.Run("removes all files in dir", func(t *testing.T) {
188+
tmpDir := setupTestFiles(t)
189+
190+
err := removeAll(tmpDir, log.DiscardEvent)
191+
if err != nil {
192+
t.Fatalf("got error when removing all files, err=%v", err)
193+
}
194+
195+
files := readDir(t, tmpDir)
196+
if len(files) != 0 {
197+
t.Fatalf("dir should be empty, got=%d files", len(files))
198+
}
199+
})
200+
201+
t.Run("skipping internal mongod log files", func(t *testing.T) {
202+
tmpDir := setupTestFiles(t)
203+
204+
err := removeAll(tmpDir, log.DiscardEvent, getInternalLogFileSkipRule())
205+
if err != nil {
206+
t.Fatalf("got error when removing all files, err=%v", err)
207+
}
208+
209+
files := readDir(t, tmpDir)
210+
if len(files) != 3 {
211+
t.Fatalf("expected to have 3 log files, got=%d files, names=%s", len(files), files)
212+
}
213+
})
214+
215+
t.Run("skipping fallback dir", func(t *testing.T) {
216+
tmpDir := setupTestFiles(t)
217+
218+
err := removeAll(tmpDir, log.DiscardEvent, getFallbackSyncFileSkipRule())
219+
if err != nil {
220+
t.Fatalf("got error when removing all files, err=%v", err)
221+
}
222+
223+
files := readDir(t, tmpDir)
224+
if len(files) != 1 || files[0] != fallbackDir {
225+
t.Fatalf("expected to have fallback dir, got=%d files/dirs, names=%s", len(files), files)
226+
}
227+
228+
files = readDir(t, path.Join(tmpDir, fallbackDir))
229+
if len(files) != 1 || files[0] != "file.fallback" {
230+
t.Fatalf("expected to have 1 file within fallback dir, got=%d files/dirs, names=%s", len(files), files)
231+
}
232+
})
233+
234+
t.Run("skipping all pbm related", func(t *testing.T) {
235+
tmpDir := setupTestFiles(t)
236+
237+
err := removeAll(tmpDir, log.DiscardEvent, getFallbackSyncFileSkipRule(), getInternalLogFileSkipRule())
238+
if err != nil {
239+
t.Fatalf("got error when removing all files, err=%v", err)
240+
}
241+
242+
files := readDir(t, tmpDir)
243+
if len(files) != 4 {
244+
t.Fatalf("expected to have fallback dir and mongod log file, got=%d files/dirs, names=%s", len(files), files)
245+
}
246+
})
247+
}
248+
249+
func TestRemoveInternalMongoLogs(t *testing.T) {
250+
tmpDir := setupTestFiles(t)
251+
252+
err := removeInternalMongoLogs(tmpDir, log.DiscardEvent)
253+
if err != nil {
254+
t.Fatalf("got error when removing internal mongod logs, err=%v", err)
255+
}
256+
257+
files := readDir(t, tmpDir)
258+
if len(files) != 6 {
259+
t.Fatalf("only mongod log files should be removed, expected 6 files, got=%d files", len(files))
260+
}
261+
for _, f := range files {
262+
if strings.HasPrefix(f, internalMongodLog) {
263+
t.Fatalf("internal mongod log file is not deleted: %s", f)
264+
}
265+
}
266+
}
267+
268+
func readDir(t *testing.T, dir string) []string {
269+
t.Helper()
270+
271+
d, err := os.Open(dir)
272+
if err != nil {
273+
t.Fatalf("failing opening dir, err=%v", err)
274+
}
275+
defer d.Close()
276+
277+
files, err := d.Readdirnames(-1)
278+
if err != nil {
279+
t.Fatalf("failing reading dir, err=%v", err)
280+
}
281+
282+
return files
283+
}
284+
285+
func setupTestFiles(t *testing.T) string {
286+
tmpDir, err := os.MkdirTemp("", "phys-test-*")
287+
if err != nil {
288+
t.Fatalf("error while creating setup files: %v", err)
289+
}
290+
291+
t.Cleanup(func() {
292+
os.RemoveAll(tmpDir)
293+
})
294+
295+
// tmpDir/
296+
// - file1.txt
297+
// - file2.log
298+
// - file3.txt.tmp
299+
// - subdir/
300+
// - file4.txt
301+
// - file5.log
302+
// - file6.txt.tmp
303+
// - empty/
304+
// - pbm.restore.log
305+
// - pbm.restore.log.2025-05-15T14-33-34
306+
// - pbm.restore.log.2025-05-15T14-37-34
307+
// - .fallbacksync/
308+
// - file.fs.txt
309+
createTestFile(t, filepath.Join(tmpDir, "file1.txt"), "content1")
310+
createTestFile(t, filepath.Join(tmpDir, "file2.log"), "content2")
311+
createTestFile(t, filepath.Join(tmpDir, "file3.txt.tmp"), "content3")
312+
313+
createTestDir(t, filepath.Join(tmpDir, "subdir"))
314+
createTestFile(t, filepath.Join(tmpDir, "subdir", "file4.txt"), "content4")
315+
createTestFile(t, filepath.Join(tmpDir, "subdir", "file5.log"), "content5")
316+
createTestFile(t, filepath.Join(tmpDir, "subdir", "file6.txt.tmp"), "content6")
317+
318+
createTestDir(t, filepath.Join(tmpDir, "empty"))
319+
320+
// files & dirs with additional semantic:
321+
createTestFile(t, filepath.Join(tmpDir, "pbm.restore.log"), "log-content-1")
322+
createTestFile(t, filepath.Join(tmpDir, "pbm.restore.log.2025-05-15T14-33-34"), "log-content-2")
323+
createTestFile(t, filepath.Join(tmpDir, "pbm.restore.log.2025-05-15T14-37-34"), "log-content-3")
324+
325+
createTestDir(t, filepath.Join(tmpDir, fallbackDir))
326+
createTestFile(t, filepath.Join(tmpDir, fallbackDir, "file.fallback"), "content")
327+
328+
return tmpDir
329+
}
330+
331+
func createTestFile(t *testing.T, path, content string) {
332+
t.Helper()
333+
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
334+
t.Fatalf("error while creating file %s: %v", path, err)
335+
}
336+
}
337+
338+
func createTestDir(t *testing.T, path string) {
339+
t.Helper()
340+
if err := os.Mkdir(path, 0o755); err != nil {
341+
t.Fatalf("error while creating dir %s: %v", path, err)
342+
}
343+
}

0 commit comments

Comments
 (0)