From dab07c58b4ac70ab0ba614b3e8395628bc7654eb Mon Sep 17 00:00:00 2001 From: Benjamin Wang Date: Thu, 29 Dec 2022 09:10:57 +0800 Subject: [PATCH 1/2] Update test cases TestOpen_ReadPageSize_FromMeta1_OS and TestOpen_ReadPageSize_FromMeta1_Given Signed-off-by: Benjamin Wang --- db_test.go | 58 +++++++++++++++++------------------------------------- 1 file changed, 18 insertions(+), 40 deletions(-) diff --git a/db_test.go b/db_test.go index 6bf390894..5e9d7453d 100644 --- a/db_test.go +++ b/db_test.go @@ -215,14 +215,10 @@ func TestOpen_ErrChecksum(t *testing.T) { // The page size is expected to be the OS's page size in this case. func TestOpen_ReadPageSize_FromMeta1_OS(t *testing.T) { // Create empty database. - db := MustOpenDB() + db := btesting.MustCreateDB(t) path := db.Path() - defer db.MustClose() - - // Close database. - if err := db.DB.Close(); err != nil { - t.Fatal(err) - } + // Close the database + db.MustClose() // Read data file. buf, err := os.ReadFile(path) @@ -238,16 +234,9 @@ func TestOpen_ReadPageSize_FromMeta1_OS(t *testing.T) { } // Reopen data file. - if db, err := bolt.Open(path, 0666, nil); err != nil { - t.Fatalf("unexpected error: %s", err) - } else { - if db.Info().PageSize != os.Getpagesize() { - t.Fatalf("The page size is expected to be %d, but actually is %d", os.Getpagesize(), db.Info().PageSize) - } - if err := db.Close(); err != nil { - panic(err) - } - } + // Reopen data file. + 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) } // Ensure that it can read the page size from the second meta page if the first one is invalid. @@ -256,40 +245,29 @@ func TestOpen_ReadPageSize_FromMeta1_Given(t *testing.T) { // test page size from 1KB (1024<<0) to 16MB(1024<<14) for i := 0; i <= 14; i++ { givenPageSize := 1024 << uint(i) + t.Logf("Testing page size %d", givenPageSize) // Create empty database. - db := MustOpenWithOption(&bolt.Options{PageSize: givenPageSize}) + db := btesting.MustCreateDBWithOption(t, &bolt.Options{PageSize: givenPageSize}) path := db.Path() - defer db.MustClose() - - // Close database. - if err := db.DB.Close(); err != nil { - t.Fatal(err) - } + // Close the database + db.MustClose() // Read data file. buf, err := os.ReadFile(path) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Rewrite meta pages. meta0 := (*meta)(unsafe.Pointer(&buf[pageHeaderSize])) meta0.pgid++ - if err := os.WriteFile(path, buf, 0666); err != nil { - t.Fatal(err) - } + err = os.WriteFile(path, buf, 0666) + require.NoError(t, err) // Reopen data file. - if db, err := bolt.Open(path, 0666, &bolt.Options{PageSize: givenPageSize}); err != nil { - t.Fatalf("unexpected error: %s", err) - } else { - if db.Info().PageSize != givenPageSize { - t.Fatalf("The page size is expected to be %d, but actually is %d", givenPageSize, db.Info().PageSize) - } - if err := db.Close(); err != nil { - panic(err) - } - } + 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) + // The db.DB is set to nil in MustClose(), so the testing Cleanup + // will do nothing when executing PostTestCleanup(). + db.PostTestCleanup() } } From c19ea9b61308a12d685b137286c152099aca486c Mon Sep 17 00:00:00 2001 From: Benjamin Wang Date: Thu, 29 Dec 2022 10:26:07 +0800 Subject: [PATCH 2/2] Handle the case of io.EOF when reading the second meta page Signed-off-by: Benjamin Wang --- db.go | 4 +++- db_test.go | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/db.go b/db.go index 531fb6cf6..a74c2b66f 100644 --- a/db.go +++ b/db.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "hash/fnv" + "io" "os" "runtime" "sort" @@ -377,7 +378,8 @@ func (db *DB) getPageSizeFromSecondMeta() (int, bool, error) { if pos >= fileSize-1024 { 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 if m := db.pageInBuffer(buf[:], 0).meta(); m.validate() == nil { return int(m.pageSize), metaCanRead, nil diff --git a/db_test.go b/db_test.go index 5e9d7453d..65b44c85d 100644 --- a/db_test.go +++ b/db_test.go @@ -233,10 +233,9 @@ func TestOpen_ReadPageSize_FromMeta1_OS(t *testing.T) { t.Fatal(err) } - // Reopen data file. // Reopen data file. 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. @@ -257,17 +256,18 @@ func TestOpen_ReadPageSize_FromMeta1_Given(t *testing.T) { require.NoError(t, err) // Rewrite meta pages. - meta0 := (*meta)(unsafe.Pointer(&buf[pageHeaderSize])) - meta0.pgid++ - err = os.WriteFile(path, buf, 0666) - require.NoError(t, err) + if i%3 == 0 { + t.Logf("#%d: Intentionally corrupt the first meta page for pageSize %d", i, givenPageSize) + meta0 := (*meta)(unsafe.Pointer(&buf[pageHeaderSize])) + meta0.pgid++ + err = os.WriteFile(path, buf, 0666) + require.NoError(t, err) + } // Reopen data file. 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) - // The db.DB is set to nil in MustClose(), so the testing Cleanup - // will do nothing when executing PostTestCleanup(). - db.PostTestCleanup() + require.Equalf(t, givenPageSize, db.Info().PageSize, "check page size failed") + db.MustClose() } }