tsdb/wlog: use Go standard errors package

Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
This commit is contained in:
Matthieu MOREL 2023-11-08 21:45:14 +01:00
parent ab2a7bb74f
commit fb48a351f0
5 changed files with 57 additions and 59 deletions

View file

@ -15,6 +15,7 @@
package wlog package wlog
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"math" "math"
@ -25,7 +26,6 @@ import (
"github.com/go-kit/log" "github.com/go-kit/log"
"github.com/go-kit/log/level" "github.com/go-kit/log/level"
"github.com/pkg/errors"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
"github.com/prometheus/prometheus/tsdb/chunks" "github.com/prometheus/prometheus/tsdb/chunks"
@ -102,8 +102,8 @@ func Checkpoint(logger log.Logger, w *WL, from, to int, keep func(id chunks.Head
{ {
var sgmRange []SegmentRange var sgmRange []SegmentRange
dir, idx, err := LastCheckpoint(w.Dir()) dir, idx, err := LastCheckpoint(w.Dir())
if err != nil && err != record.ErrNotFound { if err != nil && !errors.Is(err, record.ErrNotFound) {
return nil, errors.Wrap(err, "find last checkpoint") return nil, fmt.Errorf("find last checkpoint: %w", err)
} }
last := idx + 1 last := idx + 1
if err == nil { if err == nil {
@ -119,7 +119,7 @@ func Checkpoint(logger log.Logger, w *WL, from, to int, keep func(id chunks.Head
sgmRange = append(sgmRange, SegmentRange{Dir: w.Dir(), First: from, Last: to}) sgmRange = append(sgmRange, SegmentRange{Dir: w.Dir(), First: from, Last: to})
sgmReader, err = NewSegmentsRangeReader(sgmRange...) sgmReader, err = NewSegmentsRangeReader(sgmRange...)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "create segment reader") return nil, fmt.Errorf("create segment reader: %w", err)
} }
defer sgmReader.Close() defer sgmReader.Close()
} }
@ -128,15 +128,15 @@ func Checkpoint(logger log.Logger, w *WL, from, to int, keep func(id chunks.Head
cpdirtmp := cpdir + ".tmp" cpdirtmp := cpdir + ".tmp"
if err := os.RemoveAll(cpdirtmp); err != nil { if err := os.RemoveAll(cpdirtmp); err != nil {
return nil, errors.Wrap(err, "remove previous temporary checkpoint dir") return nil, fmt.Errorf("remove previous temporary checkpoint dir: %w", err)
} }
if err := os.MkdirAll(cpdirtmp, 0o777); err != nil { if err := os.MkdirAll(cpdirtmp, 0o777); err != nil {
return nil, errors.Wrap(err, "create checkpoint dir") return nil, fmt.Errorf("create checkpoint dir: %w", err)
} }
cp, err := New(nil, nil, cpdirtmp, w.CompressionType()) cp, err := New(nil, nil, cpdirtmp, w.CompressionType())
if err != nil { if err != nil {
return nil, errors.Wrap(err, "open checkpoint") return nil, fmt.Errorf("open checkpoint: %w", err)
} }
// Ensures that an early return caused by an error doesn't leave any tmp files. // Ensures that an early return caused by an error doesn't leave any tmp files.
@ -174,7 +174,7 @@ func Checkpoint(logger log.Logger, w *WL, from, to int, keep func(id chunks.Head
case record.Series: case record.Series:
series, err = dec.Series(rec, series) series, err = dec.Series(rec, series)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "decode series") return nil, fmt.Errorf("decode series: %w", err)
} }
// Drop irrelevant series in place. // Drop irrelevant series in place.
repl := series[:0] repl := series[:0]
@ -192,7 +192,7 @@ func Checkpoint(logger log.Logger, w *WL, from, to int, keep func(id chunks.Head
case record.Samples: case record.Samples:
samples, err = dec.Samples(rec, samples) samples, err = dec.Samples(rec, samples)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "decode samples") return nil, fmt.Errorf("decode samples: %w", err)
} }
// Drop irrelevant samples in place. // Drop irrelevant samples in place.
repl := samples[:0] repl := samples[:0]
@ -210,7 +210,7 @@ func Checkpoint(logger log.Logger, w *WL, from, to int, keep func(id chunks.Head
case record.HistogramSamples: case record.HistogramSamples:
histogramSamples, err = dec.HistogramSamples(rec, histogramSamples) histogramSamples, err = dec.HistogramSamples(rec, histogramSamples)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "decode histogram samples") return nil, fmt.Errorf("decode histogram samples: %w", err)
} }
// Drop irrelevant histogramSamples in place. // Drop irrelevant histogramSamples in place.
repl := histogramSamples[:0] repl := histogramSamples[:0]
@ -228,7 +228,7 @@ func Checkpoint(logger log.Logger, w *WL, from, to int, keep func(id chunks.Head
case record.Tombstones: case record.Tombstones:
tstones, err = dec.Tombstones(rec, tstones) tstones, err = dec.Tombstones(rec, tstones)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "decode deletes") return nil, fmt.Errorf("decode deletes: %w", err)
} }
// Drop irrelevant tombstones in place. // Drop irrelevant tombstones in place.
repl := tstones[:0] repl := tstones[:0]
@ -249,7 +249,7 @@ func Checkpoint(logger log.Logger, w *WL, from, to int, keep func(id chunks.Head
case record.Exemplars: case record.Exemplars:
exemplars, err = dec.Exemplars(rec, exemplars) exemplars, err = dec.Exemplars(rec, exemplars)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "decode exemplars") return nil, fmt.Errorf("decode exemplars: %w", err)
} }
// Drop irrelevant exemplars in place. // Drop irrelevant exemplars in place.
repl := exemplars[:0] repl := exemplars[:0]
@ -266,7 +266,7 @@ func Checkpoint(logger log.Logger, w *WL, from, to int, keep func(id chunks.Head
case record.Metadata: case record.Metadata:
metadata, err := dec.Metadata(rec, metadata) metadata, err := dec.Metadata(rec, metadata)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "decode metadata") return nil, fmt.Errorf("decode metadata: %w", err)
} }
// Only keep reference to the latest found metadata for each refID. // Only keep reference to the latest found metadata for each refID.
repl := 0 repl := 0
@ -292,7 +292,7 @@ func Checkpoint(logger log.Logger, w *WL, from, to int, keep func(id chunks.Head
// Flush records in 1 MB increments. // Flush records in 1 MB increments.
if len(buf) > 1*1024*1024 { if len(buf) > 1*1024*1024 {
if err := cp.Log(recs...); err != nil { if err := cp.Log(recs...); err != nil {
return nil, errors.Wrap(err, "flush records") return nil, fmt.Errorf("flush records: %w", err)
} }
buf, recs = buf[:0], recs[:0] buf, recs = buf[:0], recs[:0]
} }
@ -300,12 +300,12 @@ func Checkpoint(logger log.Logger, w *WL, from, to int, keep func(id chunks.Head
// If we hit any corruption during checkpointing, repairing is not an option. // If we hit any corruption during checkpointing, repairing is not an option.
// The head won't know which series records are lost. // The head won't know which series records are lost.
if r.Err() != nil { if r.Err() != nil {
return nil, errors.Wrap(r.Err(), "read segments") return nil, fmt.Errorf("read segments: %w", r.Err())
} }
// Flush remaining records. // Flush remaining records.
if err := cp.Log(recs...); err != nil { if err := cp.Log(recs...); err != nil {
return nil, errors.Wrap(err, "flush records") return nil, fmt.Errorf("flush records: %w", err)
} }
// Flush latest metadata records for each series. // Flush latest metadata records for each series.
@ -315,29 +315,29 @@ func Checkpoint(logger log.Logger, w *WL, from, to int, keep func(id chunks.Head
latestMetadata = append(latestMetadata, m) latestMetadata = append(latestMetadata, m)
} }
if err := cp.Log(enc.Metadata(latestMetadata, buf[:0])); err != nil { if err := cp.Log(enc.Metadata(latestMetadata, buf[:0])); err != nil {
return nil, errors.Wrap(err, "flush metadata records") return nil, fmt.Errorf("flush metadata records: %w", err)
} }
} }
if err := cp.Close(); err != nil { if err := cp.Close(); err != nil {
return nil, errors.Wrap(err, "close checkpoint") return nil, fmt.Errorf("close checkpoint: %w", err)
} }
// Sync temporary directory before rename. // Sync temporary directory before rename.
df, err := fileutil.OpenDir(cpdirtmp) df, err := fileutil.OpenDir(cpdirtmp)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "open temporary checkpoint directory") return nil, fmt.Errorf("open temporary checkpoint directory: %w", err)
} }
if err := df.Sync(); err != nil { if err := df.Sync(); err != nil {
df.Close() df.Close()
return nil, errors.Wrap(err, "sync temporary checkpoint directory") return nil, fmt.Errorf("sync temporary checkpoint directory: %w", err)
} }
if err = df.Close(); err != nil { if err = df.Close(); err != nil {
return nil, errors.Wrap(err, "close temporary checkpoint directory") return nil, fmt.Errorf("close temporary checkpoint directory: %w", err)
} }
if err := fileutil.Replace(cpdirtmp, cpdir); err != nil { if err := fileutil.Replace(cpdirtmp, cpdir); err != nil {
return nil, errors.Wrap(err, "rename checkpoint directory") return nil, fmt.Errorf("rename checkpoint directory: %w", err)
} }
return stats, nil return stats, nil
@ -364,7 +364,7 @@ func listCheckpoints(dir string) (refs []checkpointRef, err error) {
continue continue
} }
if !fi.IsDir() { if !fi.IsDir() {
return nil, errors.Errorf("checkpoint %s is not a directory", fi.Name()) return nil, fmt.Errorf("checkpoint %s is not a directory", fi.Name())
} }
idx, err := strconv.Atoi(fi.Name()[len(checkpointPrefix):]) idx, err := strconv.Atoi(fi.Name()[len(checkpointPrefix):])
if err != nil { if err != nil {

View file

@ -23,7 +23,6 @@ import (
"testing" "testing"
"github.com/go-kit/log" "github.com/go-kit/log"
"github.com/pkg/errors"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/prometheus/prometheus/model/histogram" "github.com/prometheus/prometheus/model/histogram"
@ -325,7 +324,7 @@ func TestCheckpointNoTmpFolderAfterError(t *testing.T) {
// Walk the wlog dir to make sure there are no tmp folder left behind after the error. // Walk the wlog dir to make sure there are no tmp folder left behind after the error.
err = filepath.Walk(w.Dir(), func(path string, info os.FileInfo, err error) error { err = filepath.Walk(w.Dir(), func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return errors.Wrapf(err, "access err %q: %v", path, err) return fmt.Errorf("access err %q: %w", path, err)
} }
if info.IsDir() && strings.HasSuffix(info.Name(), ".tmp") { if info.IsDir() && strings.HasSuffix(info.Name(), ".tmp") {
return fmt.Errorf("wlog dir contains temporary folder:%s", info.Name()) return fmt.Errorf("wlog dir contains temporary folder:%s", info.Name())

View file

@ -16,6 +16,7 @@ package wlog
import ( import (
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"hash/crc32" "hash/crc32"
"io" "io"
@ -24,7 +25,6 @@ import (
"github.com/go-kit/log/level" "github.com/go-kit/log/level"
"github.com/golang/snappy" "github.com/golang/snappy"
"github.com/klauspost/compress/zstd" "github.com/klauspost/compress/zstd"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@ -135,7 +135,7 @@ func (r *LiveReader) Next() bool {
switch ok, err := r.buildRecord(); { switch ok, err := r.buildRecord(); {
case ok: case ok:
return true return true
case err != nil && err != io.EOF: case err != nil && !errors.Is(err, io.EOF):
r.err = err r.err = err
return false return false
} }
@ -157,7 +157,7 @@ func (r *LiveReader) Next() bool {
if r.writeIndex != pageSize { if r.writeIndex != pageSize {
n, err := r.fillBuffer() n, err := r.fillBuffer()
if n == 0 || (err != nil && err != io.EOF) { if n == 0 || (err != nil && !errors.Is(err, io.EOF)) {
r.err = err r.err = err
return false return false
} }
@ -265,7 +265,7 @@ func validateRecord(typ recType, i int) error {
} }
return nil return nil
default: default:
return errors.Errorf("unexpected record type %d", typ) return fmt.Errorf("unexpected record type %d", typ)
} }
} }
@ -322,7 +322,7 @@ func (r *LiveReader) readRecord() ([]byte, int, error) {
rec := r.buf[r.readIndex+recordHeaderSize : r.readIndex+recordHeaderSize+length] rec := r.buf[r.readIndex+recordHeaderSize : r.readIndex+recordHeaderSize+length]
if c := crc32.Checksum(rec, castagnoliTable); c != crc { if c := crc32.Checksum(rec, castagnoliTable); c != crc {
return nil, 0, errors.Errorf("unexpected checksum %x, expected %x", c, crc) return nil, 0, fmt.Errorf("unexpected checksum %x, expected %x", c, crc)
} }
return rec, length + recordHeaderSize, nil return rec, length + recordHeaderSize, nil

View file

@ -16,12 +16,13 @@ package wlog
import ( import (
"encoding/binary" "encoding/binary"
"errors"
"fmt"
"hash/crc32" "hash/crc32"
"io" "io"
"github.com/golang/snappy" "github.com/golang/snappy"
"github.com/klauspost/compress/zstd" "github.com/klauspost/compress/zstd"
"github.com/pkg/errors"
) )
// Reader reads WAL records from an io.Reader. // Reader reads WAL records from an io.Reader.
@ -47,7 +48,7 @@ func NewReader(r io.Reader) *Reader {
// It must not be called again after it returned false. // It must not be called again after it returned false.
func (r *Reader) Next() bool { func (r *Reader) Next() bool {
err := r.next() err := r.next()
if errors.Is(err, io.EOF) { if err != nil && errors.Is(err, io.EOF) {
// The last WAL segment record shouldn't be torn(should be full or last). // The last WAL segment record shouldn't be torn(should be full or last).
// The last record would be torn after a crash just before // The last record would be torn after a crash just before
// the last record part could be persisted to disk. // the last record part could be persisted to disk.
@ -72,7 +73,7 @@ func (r *Reader) next() (err error) {
i := 0 i := 0
for { for {
if _, err = io.ReadFull(r.rdr, hdr[:1]); err != nil { if _, err = io.ReadFull(r.rdr, hdr[:1]); err != nil {
return errors.Wrap(err, "read first header byte") return fmt.Errorf("read first header byte: %w", err)
} }
r.total++ r.total++
r.curRecTyp = recTypeFromHeader(hdr[0]) r.curRecTyp = recTypeFromHeader(hdr[0])
@ -95,7 +96,7 @@ func (r *Reader) next() (err error) {
} }
n, err := io.ReadFull(r.rdr, buf[:k]) n, err := io.ReadFull(r.rdr, buf[:k])
if err != nil { if err != nil {
return errors.Wrap(err, "read remaining zeros") return fmt.Errorf("read remaining zeros: %w", err)
} }
r.total += int64(n) r.total += int64(n)
@ -108,7 +109,7 @@ func (r *Reader) next() (err error) {
} }
n, err := io.ReadFull(r.rdr, hdr[1:]) n, err := io.ReadFull(r.rdr, hdr[1:])
if err != nil { if err != nil {
return errors.Wrap(err, "read remaining header") return fmt.Errorf("read remaining header: %w", err)
} }
r.total += int64(n) r.total += int64(n)
@ -118,7 +119,7 @@ func (r *Reader) next() (err error) {
) )
if length > pageSize-recordHeaderSize { if length > pageSize-recordHeaderSize {
return errors.Errorf("invalid record size %d", length) return fmt.Errorf("invalid record size %d", length)
} }
n, err = io.ReadFull(r.rdr, buf[:length]) n, err = io.ReadFull(r.rdr, buf[:length])
if err != nil { if err != nil {
@ -127,10 +128,10 @@ func (r *Reader) next() (err error) {
r.total += int64(n) r.total += int64(n)
if n != int(length) { if n != int(length) {
return errors.Errorf("invalid size: expected %d, got %d", length, n) return fmt.Errorf("invalid size: expected %d, got %d", length, n)
} }
if c := crc32.Checksum(buf[:length], castagnoliTable); c != crc { if c := crc32.Checksum(buf[:length], castagnoliTable); c != crc {
return errors.Errorf("unexpected checksum %x, expected %x", c, crc) return fmt.Errorf("unexpected checksum %x, expected %x", c, crc)
} }
if isSnappyCompressed || isZstdCompressed { if isSnappyCompressed || isZstdCompressed {

View file

@ -17,6 +17,7 @@ package wlog
import ( import (
"bufio" "bufio"
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"hash/crc32" "hash/crc32"
"io" "io"
@ -30,7 +31,6 @@ import (
"github.com/go-kit/log/level" "github.com/go-kit/log/level"
"github.com/golang/snappy" "github.com/golang/snappy"
"github.com/klauspost/compress/zstd" "github.com/klauspost/compress/zstd"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
@ -137,7 +137,7 @@ func OpenWriteSegment(logger log.Logger, dir string, k int) (*Segment, error) {
level.Warn(logger).Log("msg", "Last page of the wlog is torn, filling it with zeros", "segment", segName) level.Warn(logger).Log("msg", "Last page of the wlog is torn, filling it with zeros", "segment", segName)
if _, err := f.Write(make([]byte, pageSize-d)); err != nil { if _, err := f.Write(make([]byte, pageSize-d)); err != nil {
f.Close() f.Close()
return nil, errors.Wrap(err, "zero-pad torn page") return nil, fmt.Errorf("zero-pad torn page: %w", err)
} }
} }
return &Segment{SegmentFile: f, i: k, dir: dir}, nil return &Segment{SegmentFile: f, i: k, dir: dir}, nil
@ -298,7 +298,7 @@ func NewSize(logger log.Logger, reg prometheus.Registerer, dir string, segmentSi
return nil, errors.New("invalid segment size") return nil, errors.New("invalid segment size")
} }
if err := os.MkdirAll(dir, 0o777); err != nil { if err := os.MkdirAll(dir, 0o777); err != nil {
return nil, errors.Wrap(err, "create dir") return nil, fmt.Errorf("create dir: %w", err)
} }
if logger == nil { if logger == nil {
logger = log.NewNopLogger() logger = log.NewNopLogger()
@ -331,7 +331,7 @@ func NewSize(logger log.Logger, reg prometheus.Registerer, dir string, segmentSi
_, last, err := Segments(w.Dir()) _, last, err := Segments(w.Dir())
if err != nil { if err != nil {
return nil, errors.Wrap(err, "get segment range") return nil, fmt.Errorf("get segment range: %w", err)
} }
// Index of the Segment we want to open and write to. // Index of the Segment we want to open and write to.
@ -414,11 +414,9 @@ func (w *WL) Repair(origErr error) error {
// But that's not generally applicable if the records have any kind of causality. // But that's not generally applicable if the records have any kind of causality.
// Maybe as an extra mode in the future if mid-WAL corruptions become // Maybe as an extra mode in the future if mid-WAL corruptions become
// a frequent concern. // a frequent concern.
err := errors.Cause(origErr) // So that we can pick up errors even if wrapped. var cerr *CorruptionErr
if !errors.As(origErr, &cerr) {
cerr, ok := err.(*CorruptionErr) return fmt.Errorf("cannot handle error: %w", origErr)
if !ok {
return errors.Wrap(origErr, "cannot handle error")
} }
if cerr.Segment < 0 { if cerr.Segment < 0 {
return errors.New("corruption error does not specify position") return errors.New("corruption error does not specify position")
@ -429,7 +427,7 @@ func (w *WL) Repair(origErr error) error {
// All segments behind the corruption can no longer be used. // All segments behind the corruption can no longer be used.
segs, err := listSegments(w.Dir()) segs, err := listSegments(w.Dir())
if err != nil { if err != nil {
return errors.Wrap(err, "list segments") return fmt.Errorf("list segments: %w", err)
} }
level.Warn(w.logger).Log("msg", "Deleting all segments newer than corrupted segment", "segment", cerr.Segment) level.Warn(w.logger).Log("msg", "Deleting all segments newer than corrupted segment", "segment", cerr.Segment)
@ -440,14 +438,14 @@ func (w *WL) Repair(origErr error) error {
// as we set the current segment to repaired file // as we set the current segment to repaired file
// below. // below.
if err := w.segment.Close(); err != nil { if err := w.segment.Close(); err != nil {
return errors.Wrap(err, "close active segment") return fmt.Errorf("close active segment: %w", err)
} }
} }
if s.index <= cerr.Segment { if s.index <= cerr.Segment {
continue continue
} }
if err := os.Remove(filepath.Join(w.Dir(), s.name)); err != nil { if err := os.Remove(filepath.Join(w.Dir(), s.name)); err != nil {
return errors.Wrapf(err, "delete segment:%v", s.index) return fmt.Errorf("delete segment:%v: %w", s.index, err)
} }
} }
// Regardless of the corruption offset, no record reaches into the previous segment. // Regardless of the corruption offset, no record reaches into the previous segment.
@ -472,7 +470,7 @@ func (w *WL) Repair(origErr error) error {
f, err := os.Open(tmpfn) f, err := os.Open(tmpfn)
if err != nil { if err != nil {
return errors.Wrap(err, "open segment") return fmt.Errorf("open segment: %w", err)
} }
defer f.Close() defer f.Close()
@ -484,24 +482,24 @@ func (w *WL) Repair(origErr error) error {
break break
} }
if err := w.Log(r.Record()); err != nil { if err := w.Log(r.Record()); err != nil {
return errors.Wrap(err, "insert record") return fmt.Errorf("insert record: %w", err)
} }
} }
// We expect an error here from r.Err(), so nothing to handle. // We expect an error here from r.Err(), so nothing to handle.
// We need to pad to the end of the last page in the repaired segment // We need to pad to the end of the last page in the repaired segment
if err := w.flushPage(true); err != nil { if err := w.flushPage(true); err != nil {
return errors.Wrap(err, "flush page in repair") return fmt.Errorf("flush page in repair: %w", err)
} }
// We explicitly close even when there is a defer for Windows to be // We explicitly close even when there is a defer for Windows to be
// able to delete it. The defer is in place to close it in-case there // able to delete it. The defer is in place to close it in-case there
// are errors above. // are errors above.
if err := f.Close(); err != nil { if err := f.Close(); err != nil {
return errors.Wrap(err, "close corrupted file") return fmt.Errorf("close corrupted file: %w", err)
} }
if err := os.Remove(tmpfn); err != nil { if err := os.Remove(tmpfn); err != nil {
return errors.Wrap(err, "delete corrupted segment") return fmt.Errorf("delete corrupted segment: %w", err)
} }
// Explicitly close the segment we just repaired to avoid issues with Windows. // Explicitly close the segment we just repaired to avoid issues with Windows.
@ -553,7 +551,7 @@ func (w *WL) nextSegment(async bool) (int, error) {
} }
next, err := CreateSegment(w.Dir(), w.segment.Index()+1) next, err := CreateSegment(w.Dir(), w.segment.Index()+1)
if err != nil { if err != nil {
return 0, errors.Wrap(err, "create new segment file") return 0, fmt.Errorf("create new segment file: %w", err)
} }
prev := w.segment prev := w.segment
if err := w.setSegment(next); err != nil { if err := w.setSegment(next); err != nil {
@ -940,7 +938,7 @@ func NewSegmentsRangeReader(sr ...SegmentRange) (io.ReadCloser, error) {
for _, sgmRange := range sr { for _, sgmRange := range sr {
refs, err := listSegments(sgmRange.Dir) refs, err := listSegments(sgmRange.Dir)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "list segment in dir:%v", sgmRange.Dir) return nil, fmt.Errorf("list segment in dir:%v: %w", sgmRange.Dir, err)
} }
for _, r := range refs { for _, r := range refs {
@ -952,7 +950,7 @@ func NewSegmentsRangeReader(sr ...SegmentRange) (io.ReadCloser, error) {
} }
s, err := OpenReadSegment(filepath.Join(sgmRange.Dir, r.name)) s, err := OpenReadSegment(filepath.Join(sgmRange.Dir, r.name))
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "open segment:%v in dir:%v", r.name, sgmRange.Dir) return nil, fmt.Errorf("open segment:%v in dir:%v: %w", r.name, sgmRange.Dir, err)
} }
segs = append(segs, s) segs = append(segs, s)
} }
@ -1017,7 +1015,7 @@ func (r *segmentBufReader) Read(b []byte) (n int, err error) {
r.off += n r.off += n
// If we succeeded, or hit a non-EOF, we can stop. // If we succeeded, or hit a non-EOF, we can stop.
if err == nil || err != io.EOF { if err == nil || !errors.Is(err, io.EOF) {
return n, err return n, err
} }