mirror of https://github.com/etcd-io/bbolt.git
Handle the case of io.EOF when reading the second meta page
Signed-off-by: Benjamin Wang <wachao@vmware.com>pull/367/head
parent
dab07c58b4
commit
c19ea9b613
4
db.go
4
db.go
|
@ -4,6 +4,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash/fnv"
|
"hash/fnv"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -377,7 +378,8 @@ func (db *DB) getPageSizeFromSecondMeta() (int, bool, error) {
|
||||||
if pos >= fileSize-1024 {
|
if pos >= fileSize-1024 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if bw, err := db.file.ReadAt(buf[:], pos); err == nil && bw == len(buf) {
|
bw, err := db.file.ReadAt(buf[:], pos)
|
||||||
|
if (err == nil && bw == len(buf)) || (err == io.EOF && int64(bw) == (fileSize-pos)) {
|
||||||
metaCanRead = true
|
metaCanRead = true
|
||||||
if m := db.pageInBuffer(buf[:], 0).meta(); m.validate() == nil {
|
if m := db.pageInBuffer(buf[:], 0).meta(); m.validate() == nil {
|
||||||
return int(m.pageSize), metaCanRead, nil
|
return int(m.pageSize), metaCanRead, nil
|
||||||
|
|
20
db_test.go
20
db_test.go
|
@ -233,10 +233,9 @@ func TestOpen_ReadPageSize_FromMeta1_OS(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reopen data file.
|
|
||||||
// Reopen data file.
|
// Reopen data file.
|
||||||
db = btesting.MustOpenDBWithOption(t, path, nil)
|
db = btesting.MustOpenDBWithOption(t, path, nil)
|
||||||
require.Equalf(t, os.Getpagesize(), db.Info().PageSize, "The page size is expected to be %d, but actually is %d", os.Getpagesize(), db.Info().PageSize)
|
require.Equalf(t, os.Getpagesize(), db.Info().PageSize, "check page size failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that it can read the page size from the second meta page if the first one is invalid.
|
// Ensure that it can read the page size from the second meta page if the first one is invalid.
|
||||||
|
@ -257,17 +256,18 @@ func TestOpen_ReadPageSize_FromMeta1_Given(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Rewrite meta pages.
|
// Rewrite meta pages.
|
||||||
meta0 := (*meta)(unsafe.Pointer(&buf[pageHeaderSize]))
|
if i%3 == 0 {
|
||||||
meta0.pgid++
|
t.Logf("#%d: Intentionally corrupt the first meta page for pageSize %d", i, givenPageSize)
|
||||||
err = os.WriteFile(path, buf, 0666)
|
meta0 := (*meta)(unsafe.Pointer(&buf[pageHeaderSize]))
|
||||||
require.NoError(t, err)
|
meta0.pgid++
|
||||||
|
err = os.WriteFile(path, buf, 0666)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
// Reopen data file.
|
// Reopen data file.
|
||||||
db = btesting.MustOpenDBWithOption(t, path, nil)
|
db = btesting.MustOpenDBWithOption(t, path, nil)
|
||||||
require.Equalf(t, givenPageSize, db.Info().PageSize, "The page size is expected to be %d, but actually is %d", givenPageSize, db.Info().PageSize)
|
require.Equalf(t, givenPageSize, db.Info().PageSize, "check page size failed")
|
||||||
// The db.DB is set to nil in MustClose(), so the testing Cleanup
|
db.MustClose()
|
||||||
// will do nothing when executing PostTestCleanup().
|
|
||||||
db.PostTestCleanup()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue