Skip to content

Commit

Permalink
check if pebble db is initialized
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangchiqing committed Dec 12, 2024
1 parent 66bc267 commit 52f2397
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 0 deletions.
55 changes: 55 additions & 0 deletions storage/pebble/open.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package pebble

import (
"fmt"
"os"
"path/filepath"

"errors"

Expand Down Expand Up @@ -55,6 +57,8 @@ func OpenRegisterPebbleDB(dir string) (*pebble.DB, error) {

// OpenDefaultPebbleDB opens a pebble database using default options,
// such as cache size and comparer
// If the pebbleDB is not bootstrapped at this folder, it will auto-bootstrap it,
// use MustOpenDefaultPebbleDB if you want to return error instead
func OpenDefaultPebbleDB(dir string) (*pebble.DB, error) {
cache := pebble.NewCache(DefaultPebbleCacheSize)
defer cache.Unref()
Expand All @@ -67,6 +71,57 @@ func OpenDefaultPebbleDB(dir string) (*pebble.DB, error) {
return db, nil
}

// MustOpenDefaultPebbleDB returns error if the pebbleDB is not bootstrapped at this folder
// if bootstrapped, then open the pebbleDB
func MustOpenDefaultPebbleDB(dir string) (*pebble.DB, error) {
err := IsPebbleInitialized(dir)
if err != nil {
return nil, fmt.Errorf("pebble db is not initialized: %w", err)
}

return OpenDefaultPebbleDB(dir)
}

// IsPebbleInitialized checks if the given folder contains a valid Pebble DB.
func IsPebbleInitialized(folderPath string) error {
// Check if the folder exists
info, err := os.Stat(folderPath)
if os.IsNotExist(err) {
return fmt.Errorf("directory does not exist: %s", folderPath)
}
if !info.IsDir() {
return fmt.Errorf("not a directory: %s", folderPath)
}

// Look for Pebble-specific files
requiredFiles := []string{"CURRENT", "MANIFEST-*"}
for _, pattern := range requiredFiles {
matches, err := filepath.Glob(filepath.Join(folderPath, pattern))
if err != nil {
return fmt.Errorf("error checking for files: %v", err)
}
if len(matches) == 0 {
return fmt.Errorf("missing required file: %s", pattern)
}
}

// Optionally, validate the CURRENT file references a MANIFEST file
currentPath := filepath.Join(folderPath, "CURRENT")
currentFile, err := os.Open(currentPath)
if err != nil {
return fmt.Errorf("error reading CURRENT file: %v", err)
}
defer currentFile.Close()

// Basic validation by ensuring the CURRENT file is non-empty
stat, err := currentFile.Stat()
if err != nil || stat.Size() == 0 {
return fmt.Errorf("CURRENT file is invalid")
}

return nil
}

// ReadHeightsFromBootstrappedDB reads the first and latest height from a bootstrapped register db
// If the register db is not bootstrapped, it returns storage.ErrNotBootstrapped
// If the register db is corrupted, it returns an error
Expand Down
27 changes: 27 additions & 0 deletions storage/pebble/open_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package pebble

import (
"errors"
"fmt"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -74,3 +75,29 @@ func TestNewBootstrappedRegistersWithPath(t *testing.T) {
require.NoError(t, db2.Close())
})
}

func TestMustOpenDefaultPebbleDB(t *testing.T) {
t.Parallel()
unittest.RunWithTempDir(t, func(dir string) {
// verify error is returned when the db is not bootstrapped
_, err := MustOpenDefaultPebbleDB(dir)
require.Error(t, err)
require.Contains(t, err.Error(), "not initialized")

// bootstrap the db
db, err := OpenDefaultPebbleDB(dir)
require.NoError(t, err)
require.NoError(t, initHeights(db, uint64(10)))
require.NoError(t, db.Close())
fmt.Println(dir)

// verify no error is returned when the db is bootstrapped
db, err = MustOpenDefaultPebbleDB(dir)
require.NoError(t, err)

h, err := latestStoredHeight(db)
require.NoError(t, err)
require.Equal(t, uint64(10), h)
require.NoError(t, db.Close())
})
}

0 comments on commit 52f2397

Please sign in to comment.