diff --git a/br/pkg/storage/local.go b/br/pkg/storage/local.go index 3d3712db33fcb..dc8d3a33accf1 100644 --- a/br/pkg/storage/local.go +++ b/br/pkg/storage/local.go @@ -111,7 +111,11 @@ func (l *LocalStorage) WalkDir(_ context.Context, opt *WalkOption, fn func(strin if !f.Mode().IsRegular() { stat, err := os.Stat(filepath.Join(l.base, path)) if err != nil { - return errors.Trace(err) + // error may happen because of file deleted after walk started, or other errors + // like #49423. We just return 0 size and let the caller handle it in later + // logic. + log.Warn("failed to get file size", zap.String("path", path), zap.Error(err)) + return fn(path, 0) } size = stat.Size() } diff --git a/br/pkg/storage/local_test.go b/br/pkg/storage/local_test.go index 917dd94bd9a41..803842e6467c3 100644 --- a/br/pkg/storage/local_test.go +++ b/br/pkg/storage/local_test.go @@ -141,3 +141,93 @@ func TestLocalURI(t *testing.T) { obtained := store.URI() require.Equal(t, url, obtained) } +<<<<<<< HEAD +======= + +func TestLocalFileReadRange(t *testing.T) { + ctx := context.Background() + dir := t.TempDir() + sb, err := ParseBackend("file://"+filepath.ToSlash(dir), &BackendOptions{}) + require.NoError(t, err) + store, err := Create(ctx, sb, true) + require.NoError(t, err) + + name := "test_read_range" + + w, err := store.Create(ctx, name, nil) + require.NoError(t, err) + _, err = w.Write(ctx, []byte("0123456789")) + require.NoError(t, err) + require.NoError(t, w.Close(ctx)) + + checkContent := func(r ExternalFileReader, expected string) { + buf := make([]byte, 10) + n, _ := r.Read(buf) + require.Equal(t, expected, string(buf[:n])) + n, err = r.Read(buf) + require.Equal(t, 0, n) + require.ErrorIs(t, err, io.EOF) + } + + // [2, 6] + start, end := int64(2), int64(6) + r, err := store.Open(ctx, name, &ReaderOption{ + StartOffset: &start, + EndOffset: &end, + }) + require.NoError(t, err) + checkContent(r, "2345") + + // full range + r, err = store.Open(ctx, name, nil) + require.NoError(t, err) + checkContent(r, "0123456789") + + // [5, ...) + start = 5 + r, err = store.Open(ctx, name, &ReaderOption{ + StartOffset: &start, + }) + require.NoError(t, err) + checkContent(r, "56789") + + // [..., 5) + end = 5 + r, err = store.Open(ctx, name, &ReaderOption{ + EndOffset: &end, + }) + require.NoError(t, err) + checkContent(r, "01234") + + // test read into smaller buffer + smallBuf := make([]byte, 2) + start, end = int64(2), int64(6) + r, err = store.Open(ctx, name, &ReaderOption{ + StartOffset: &start, + EndOffset: &end, + }) + require.NoError(t, err) + n, _ := r.Read(smallBuf) + require.Equal(t, "23", string(smallBuf[:n])) +} + +func TestWalkBrokenSymLink(t *testing.T) { + ctx := context.Background() + dir := t.TempDir() + err := os.Symlink(filepath.Join(dir, "non-existing-file"), filepath.Join(dir, "file-that-should-be-ignored")) + require.NoError(t, err) + + sb, err := ParseBackend("file://"+filepath.ToSlash(dir), nil) + require.NoError(t, err) + store, err := New(ctx, sb, nil) + require.NoError(t, err) + + files := map[string]int64{} + err = store.WalkDir(ctx, nil, func(path string, size int64) error { + files[path] = size + return nil + }) + require.NoError(t, err) + require.Equal(t, map[string]int64{"file-that-should-be-ignored": 0}, files) +} +>>>>>>> 1fc92b32b05 (storage: local storage tolerates broken symlink when Walk (#51170))