storage: fileStorage.GetManifest() should returns error with type of ErrCorrupted if corruption detected (fixes #121)
diff --git a/leveldb/errors/errors.go b/leveldb/errors/errors.go
index 84b5d6b..dacbf13 100644
--- a/leveldb/errors/errors.go
+++ b/leveldb/errors/errors.go
@@ -52,12 +52,14 @@
switch err.(type) {
case *ErrCorrupted:
return true
+ case *storage.ErrCorrupted:
+ return true
}
return false
}
// ErrMissingFiles is the type that indicating a corruption due to missing
-// files.
+// files. ErrMissingFiles always wrapped with ErrCorrupted.
type ErrMissingFiles struct {
Files []*storage.FileInfo
}
diff --git a/leveldb/storage/file_storage.go b/leveldb/storage/file_storage.go
index 46cc9d0..f671b2e 100644
--- a/leveldb/storage/file_storage.go
+++ b/leveldb/storage/file_storage.go
@@ -243,7 +243,10 @@
rem = append(rem, fn)
}
if !pend1 || cerr == nil {
- cerr = fmt.Errorf("leveldb/storage: corrupted or incomplete %s file", fn)
+ cerr = &ErrCorrupted{
+ File: fsParseName(filepath.Base(fn)),
+ Err: errors.New("leveldb/storage: corrupted or incomplete manifest file"),
+ }
}
} else if f != nil && f1.Num() < f.Num() {
fs.log(fmt.Sprintf("skipping %s: obsolete", fn))
@@ -505,30 +508,37 @@
return filepath.Join(f.fs.path, f.name())
}
-func (f *file) parse(name string) bool {
- var num uint64
+func fsParseName(name string) *FileInfo {
+ fi := &FileInfo{}
var tail string
- _, err := fmt.Sscanf(name, "%d.%s", &num, &tail)
+ _, err := fmt.Sscanf(name, "%d.%s", &fi.Num, &tail)
if err == nil {
switch tail {
case "log":
- f.t = TypeJournal
+ fi.Type = TypeJournal
case "ldb", "sst":
- f.t = TypeTable
+ fi.Type = TypeTable
case "tmp":
- f.t = TypeTemp
+ fi.Type = TypeTemp
default:
- return false
+ return nil
}
- f.num = num
- return true
+ return fi
}
- n, _ := fmt.Sscanf(name, "MANIFEST-%d%s", &num, &tail)
+ n, _ := fmt.Sscanf(name, "MANIFEST-%d%s", &fi.Num, &tail)
if n == 1 {
- f.t = TypeManifest
- f.num = num
- return true
+ fi.Type = TypeManifest
+ return fi
}
+ return nil
+}
- return false
+func (f *file) parse(name string) bool {
+ fi := fsParseName(name)
+ if fi == nil {
+ return false
+ }
+ f.t = fi.Type
+ f.num = fi.Num
+ return true
}
diff --git a/leveldb/storage/storage.go b/leveldb/storage/storage.go
index 85dd70b..a4e037c 100644
--- a/leveldb/storage/storage.go
+++ b/leveldb/storage/storage.go
@@ -46,6 +46,22 @@
ErrClosed = errors.New("leveldb/storage: closed")
)
+// ErrCorrupted is the type that wraps errors that indicate corruption of
+// a file. Package storage has its own type instead of using
+// errors.ErrCorrupted to prevent circular import.
+type ErrCorrupted struct {
+ File *FileInfo
+ Err error
+}
+
+func (e *ErrCorrupted) Error() string {
+ if e.File != nil {
+ return fmt.Sprintf("%v [file=%v]", e.Err, e.File)
+ } else {
+ return e.Err.Error()
+ }
+}
+
// Syncer is the interface that wraps basic Sync method.
type Syncer interface {
// Sync commits the current contents of the file to stable storage.