@@ -12,6 +12,7 @@ import (
1212
1313 "github.com/cockroachdb/crlib/crtime"
1414 "github.com/cockroachdb/errors"
15+ errorsjoin "github.com/cockroachdb/errors/join"
1516 "github.com/cockroachdb/pebble/internal/base"
1617 "github.com/cockroachdb/pebble/internal/humanize"
1718 "github.com/cockroachdb/pebble/internal/invariants"
@@ -1144,23 +1145,25 @@ func (r *lowDiskSpaceReporter) findThreshold(
11441145 return threshold , ok
11451146}
11461147
1147- func (d * DB ) reportCorruption (meta any , err error ) {
1148+ // reportCorruption reports a corruption of a TableMetadata or BlobFileMetadata
1149+ // to the event listener and also adds a DataCorruptionInfo payload to the error.
1150+ func (d * DB ) reportCorruption (meta any , err error ) error {
11481151 switch meta := meta .(type ) {
11491152 case * manifest.TableMetadata :
1150- d .reportFileCorruption (base .FileTypeTable , meta .FileBacking .DiskFileNum , meta .UserKeyBounds (), err )
1153+ return d .reportFileCorruption (base .FileTypeTable , meta .FileBacking .DiskFileNum , meta .UserKeyBounds (), err )
11511154 case * manifest.BlobFileMetadata :
11521155 // TODO(jackson): Add bounds for blob files.
1153- d .reportFileCorruption (base .FileTypeBlob , meta .FileNum , base.UserKeyBounds {}, err )
1156+ return d .reportFileCorruption (base .FileTypeBlob , meta .FileNum , base.UserKeyBounds {}, err )
11541157 default :
11551158 panic (fmt .Sprintf ("unknown metadata type: %T" , meta ))
11561159 }
11571160}
11581161
11591162func (d * DB ) reportFileCorruption (
11601163 fileType base.FileType , fileNum base.DiskFileNum , userKeyBounds base.UserKeyBounds , err error ,
1161- ) {
1162- if invariants .Enabled && err == nil {
1163- panic ("nil error" )
1164+ ) error {
1165+ if invariants .Enabled && ! IsCorruptionError ( err ) {
1166+ panic ("not a corruption error" )
11641167 }
11651168
11661169 objMeta , lookupErr := d .objProvider .Lookup (fileType , fileNum )
@@ -1189,4 +1192,25 @@ func (d *DB) reportFileCorruption(
11891192 Details : err ,
11901193 }
11911194 d .opts .EventListener .DataCorruption (info )
1195+ // We don't use errors.Join() because that also annotates with this stack
1196+ // trace which would not be useful.
1197+ return errorsjoin .Join (err , & corruptionDetailError {info : info })
1198+ }
1199+
1200+ type corruptionDetailError struct {
1201+ info DataCorruptionInfo
1202+ }
1203+
1204+ func (e * corruptionDetailError ) Error () string {
1205+ return "<corruption detail carrier>"
1206+ }
1207+
1208+ // ExtractDataCorruptionInfo extracts the DataCorruptionInfo details from a
1209+ // corruption error. Returns nil if there is no such detail.
1210+ func ExtractDataCorruptionInfo (err error ) * DataCorruptionInfo {
1211+ var e * corruptionDetailError
1212+ if errors .As (err , & e ) {
1213+ return & e .info
1214+ }
1215+ return nil
11921216}
0 commit comments