Skip to content

Commit

Permalink
fix empty tree handling
Browse files Browse the repository at this point in the history
  • Loading branch information
kocubinski committed Nov 30, 2023
1 parent 0354296 commit afbb627
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 79 deletions.
58 changes: 51 additions & 7 deletions migrate/v0/migrate_v0.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,21 @@ func Command() *cobra.Command {
Use: "v0",
Short: "migrate latest iavl v0 application.db state to iavl v2 in sqlite",
}
cmd.AddCommand(allCommand(), snapshotCommand(), metadataCommand())
cmd.AddCommand(allCommand(), snapshotCommand(), metadataCommand(), latestVersionCommand())
return cmd
}

const (
latestVersionKey = "s/latest"
commitInfoKeyFmt = "s/%d" // s/<version>
appVersionKey = "s/appversion"
)

func metadataCommand() *cobra.Command {
var (
dbv0 string
dbv2 string
)
const (
latestVersionKey = "s/latest"
commitInfoKeyFmt = "s/%d" // s/<version>
appVersionKey = "s/appversion"
)
cmd := &cobra.Command{
Use: "v45-metadata",
Short: "migrate CosmosSDK v0.45 store metadata stored in application.db state to iavl v2 in sqlite",
Expand Down Expand Up @@ -95,6 +96,49 @@ func metadataCommand() *cobra.Command {
return cmd
}

func latestVersionCommand() *cobra.Command {
var (
db string
version int
set bool
)
cmd := &cobra.Command{
Use: "latest-version",
Short: "get/set the latest version in the metadata.sqlite",
RunE: func(cmd *cobra.Command, args []string) error {
kv, err := iavlv2.NewSqliteKVStore(iavlv2.SqliteDbOptions{Path: db})
if err != nil {
return err
}
if set && version == -1 {
return fmt.Errorf("version must be set")
}
if set {

} else {
bz, err := kv.Get([]byte(latestVersionKey))
if err != nil {
return err
}
i64 := &types.Int64Value{}
err = proto.Unmarshal(bz, i64)
if err != nil {
return err
}
fmt.Printf("latest version: %d\n", i64.Value)
}
return nil
},
}
cmd.Flags().StringVar(&db, "db", "", "Path to the metadata.sqlite")
if err := cmd.MarkFlagRequired("db"); err != nil {
panic(err)
}
cmd.Flags().IntVar(&version, "version", -1, "Version to set")
cmd.Flags().BoolVar(&set, "set", false, "Set the latest version")
return cmd
}

func snapshotCommand() *cobra.Command {
var (
dbv0 string
Expand Down Expand Up @@ -302,7 +346,7 @@ func allCommand() *cobra.Command {
}

root, err := sql.WriteSnapshot(cmd.Context(), tree.Version(), nextNodeFn,
iavlv2.SnapshotOptions{StoreLeafValues: true, SaveTree: true})
iavlv2.SnapshotOptions{StoreLeafValues: true, WriteCheckpoint: true})
if err != nil {
panic(err)
}
Expand Down
18 changes: 13 additions & 5 deletions node.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ type Node struct {
poolId uint64
}

func (node *Node) String() string {
return fmt.Sprintf("Node{hash: %x, nodeKey: %s, leftNodeKey: %v, rightNodeKey: %v, size: %d, subtreeHeight: %d, poolId: %d}",
node.hash, node.nodeKey, node.leftNodeKey, node.rightNodeKey, node.size, node.subtreeHeight, node.poolId)
}

func (node *Node) isLeaf() bool {
return node.subtreeHeight == 0
}
Expand Down Expand Up @@ -330,11 +335,14 @@ func (node *Node) get(t *Tree, key []byte) (index int64, value []byte, err error
return index, value, nil
}

var hashPool = &sync.Pool{
New: func() any {
return sha256.New()
},
}
var (
hashPool = &sync.Pool{
New: func() any {
return sha256.New()
},
}
emptyHash = sha256.New().Sum(nil)
)

// Computes the hash of the node without computing its descendants. Must be
// called on nodes which have descendant node hashes already computed.
Expand Down
11 changes: 6 additions & 5 deletions snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,10 @@ func (sql *SqliteDb) Snapshot(ctx context.Context, tree *Tree) error {
}

type SnapshotOptions struct {
StoreLeafValues bool
SaveTree bool
TraverseOrder TraverseOrderType
StoreLeafValues bool
WriteCheckpoint bool
DontWriteSnapshot bool
TraverseOrder TraverseOrderType
}

func NewIngestSnapshotConnection(snapshotDbPath string) (*sqlite3.Conn, error) {
Expand Down Expand Up @@ -245,7 +246,7 @@ func (sql *SqliteDb) WriteSnapshot(
log: log.With().Str("path", filepath.Base(sql.opts.Path)).Logger(),
writeTree: true,
}
if opts.SaveTree {
if opts.WriteCheckpoint {
if err := sql.NextShard(); err != nil {
return nil, err
}
Expand Down Expand Up @@ -284,7 +285,7 @@ func (sql *SqliteDb) WriteSnapshot(
return nil, err
}

if err = sql.SaveRoot(version, root, false); err != nil {
if err = sql.SaveRoot(version, root, true); err != nil {
return nil, err
}

Expand Down
34 changes: 22 additions & 12 deletions sqlite.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func (opts SqliteDbOptions) EstimateMmapSize() (int, error) {
if err != nil {
return 0, err
}
q, err := conn.Prepare("SELECT SUM(pgsize) FROM dbstat WHERE name = 'leaf'")
q, err := conn.Prepare("SELECT SUM(pgsize) FROM dbstat WHERE name = 'latest'")
if err != nil {
return 0, err
}
Expand Down Expand Up @@ -120,7 +120,7 @@ func (opts SqliteDbOptions) EstimateMmapSize() (int, error) {
}

func NewInMemorySqliteDb(pool *NodePool) (*SqliteDb, error) {
opts := defaultSqliteDbOptions(SqliteDbOptions{ConnArgs: "mode=memory"})
opts := defaultSqliteDbOptions(SqliteDbOptions{ConnArgs: "mode=memory&cache=shared"})
return NewSqliteDb(pool, opts)
}

Expand Down Expand Up @@ -245,7 +245,7 @@ func (sql *SqliteDb) newReadConn() (*sqlite3.Conn, error) {
if err != nil {
return nil, err
}
err = conn.Exec(fmt.Sprintf("ATTACH DATABASE '%s/changelog.sqlite' AS changelog;", sql.opts.Path))
err = conn.Exec(fmt.Sprintf("ATTACH DATABASE '%s' AS changelog;", sql.opts.leafConnectionString()))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -485,12 +485,17 @@ func (sql *SqliteDb) IndexShard(shardId int64) error {
}

func (sql *SqliteDb) SaveRoot(version int64, node *Node, isCheckpoint bool) error {
bz, err := node.Bytes()
if err != nil {
return err
if node != nil {
bz, err := node.Bytes()
if err != nil {
return err
}
return sql.treeWrite.Exec("INSERT OR REPLACE INTO root(version, node_version, node_sequence, bytes, checkpoint) VALUES (?, ?, ?, ?, ?)",
version, node.nodeKey.Version(), int(node.nodeKey.Sequence()), bz, isCheckpoint)
} else {
// for an empty root a sentinel is saved
return sql.treeWrite.Exec("INSERT OR REPLACE INTO root(version, checkpoint) VALUES (?, ?)", version, isCheckpoint)
}
return sql.treeWrite.Exec("INSERT INTO root(version, node_version, node_sequence, bytes, checkpoint) VALUES (?, ?, ?, ?, ?)",
version, node.nodeKey.Version(), int(node.nodeKey.Sequence()), bz, isCheckpoint)
}

func (sql *SqliteDb) LoadRoot(version int64) (*Node, error) {
Expand Down Expand Up @@ -519,10 +524,15 @@ func (sql *SqliteDb) LoadRoot(version int64) (*Node, error) {
if err != nil {
return nil, err
}
rootKey := NewNodeKey(nodeVersion, uint32(nodeSeq))
root, err := MakeNode(sql.pool, rootKey, nodeBz)
if err != nil {
return nil, err

// if nodeBz is nil then a (valid) empty tree was saved, which a nil root represents
var root *Node
if nodeBz != nil {
rootKey := NewNodeKey(nodeVersion, uint32(nodeSeq))
root, err = MakeNode(sql.pool, rootKey, nodeBz)
if err != nil {
return nil, err
}
}

if err := rootQuery.Close(); err != nil {
Expand Down
14 changes: 10 additions & 4 deletions sqlite_batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ func (b *sqliteBatch) newChangeLogBatch() (err error) {
if err = b.sql.leafWrite.Begin(); err != nil {
return err
}
b.leafInsert, err = b.sql.leafWrite.Prepare("INSERT INTO leaf (version, sequence, bytes) VALUES (?, ?, ?)")
b.leafInsert, err = b.sql.leafWrite.Prepare("INSERT OR REPLACE INTO leaf (version, sequence, bytes) VALUES (?, ?, ?)")
if err != nil {
return err
}
b.deleteInsert, err = b.sql.leafWrite.Prepare("INSERT INTO leaf_delete (version, sequence, key) VALUES (?, ?, ?)")
b.deleteInsert, err = b.sql.leafWrite.Prepare("INSERT OR REPLACE INTO leaf_delete (version, sequence, key) VALUES (?, ?, ?)")
if err != nil {
return err
}
Expand Down Expand Up @@ -148,7 +148,7 @@ func (b *sqliteBatch) saveTree(tree *Tree) (n int64, versions []int64, err error
bz []byte
val []byte
)
for _, leaf := range tree.leaves {
for i, leaf := range tree.leaves {
b.count++
if tree.storeLatestLeaves {
val = leaf.value
Expand All @@ -171,7 +171,13 @@ func (b *sqliteBatch) saveTree(tree *Tree) (n int64, versions []int64, err error
return 0, versions, err
}
if tree.heightFilter > 0 {
b.sql.pool.Put(leaf)
if i != 0 {
// evict leaf
b.sql.pool.Put(leaf)
} else if leaf.nodeKey != tree.root.nodeKey {
// never evict the root if it's a leaf
b.sql.pool.Put(leaf)
}
}
}

Expand Down
Loading

0 comments on commit afbb627

Please sign in to comment.