misc: export more functions, make save/load to db default.

This commit is contained in:
Tzu-Jung Lee 2018-08-14 19:50:42 -07:00
parent 372cd7a72f
commit feebb96caa
7 changed files with 132 additions and 110 deletions

View file

@ -47,7 +47,8 @@ func (c *Claim) expireAt() Height {
return c.Accepted + paramOriginalClaimExpirationTime return c.Accepted + paramOriginalClaimExpirationTime
} }
func isActiveAt(c *Claim, ht Height) bool { // IsActiveAt ...
func IsActiveAt(c *Claim, ht Height) bool {
return c != nil && c.ActiveAt <= ht && c.expireAt() > ht return c != nil && c.ActiveAt <= ht && c.expireAt() > ht
} }

View file

@ -1,22 +1,22 @@
package claim package claim
type list []*Claim type List []*Claim
type comparator func(c *Claim) bool type Comparator func(c *Claim) bool
func byOP(op OutPoint) comparator { func ByOP(op OutPoint) Comparator {
return func(c *Claim) bool { return func(c *Claim) bool {
return c.OutPoint == op return c.OutPoint == op
} }
} }
func byID(id ID) comparator { func ByID(id ID) Comparator {
return func(c *Claim) bool { return func(c *Claim) bool {
return c.ID == id return c.ID == id
} }
} }
func remove(l list, cmp comparator) (list, *Claim) { func Remove(l List, cmp Comparator) (List, *Claim) {
last := len(l) - 1 last := len(l) - 1
for i, v := range l { for i, v := range l {
if !cmp(v) { if !cmp(v) {
@ -30,7 +30,7 @@ func remove(l list, cmp comparator) (list, *Claim) {
return l, nil return l, nil
} }
func find(cmp comparator, lists ...list) *Claim { func Find(cmp Comparator, lists ...List) *Claim {
for _, l := range lists { for _, l := range lists {
for _, v := range l { for _, v := range l {
if cmp(v) { if cmp(v) {

View file

@ -16,11 +16,11 @@ type Node struct {
best *Claim best *Claim
tookover Height tookover Height
claims list claims List
supports list supports List
// refer to updateClaim. // refer to updateClaim.
removed list removed List
} }
// NewNode returns a new Node. // NewNode returns a new Node.
@ -28,6 +28,11 @@ func NewNode(name string) *Node {
return &Node{name: name} return &Node{name: name}
} }
// Name returns the Name where the Node blongs.
func (n *Node) Name() string {
return n.name
}
// Height returns the current height. // Height returns the current height.
func (n *Node) Height() Height { func (n *Node) Height() Height {
return n.height return n.height
@ -38,15 +43,30 @@ func (n *Node) BestClaim() *Claim {
return n.best return n.best
} }
// Tookover returns the the height at when the current BestClaim tookover.
func (n *Node) Tookover() Height {
return n.tookover
}
// Claims returns the claims at the current height.
func (n *Node) Claims() List {
return n.claims
}
// Supports returns the supports at the current height.
func (n *Node) Supports() List {
return n.supports
}
// AddClaim adds a Claim to the Node. // AddClaim adds a Claim to the Node.
func (n *Node) AddClaim(op OutPoint, amt Amount) error { func (n *Node) AddClaim(op OutPoint, amt Amount, val []byte) error {
if find(byOP(op), n.claims, n.supports) != nil { if Find(ByOP(op), n.claims, n.supports) != nil {
return ErrDuplicate return ErrDuplicate
} }
accepted := n.height + 1 accepted := n.height + 1
c := New(op, amt).setID(NewID(op)).setAccepted(accepted) c := New(op, amt).setID(NewID(op)).setAccepted(accepted).setValue(val)
c.setActiveAt(accepted + calDelay(accepted, n.tookover)) c.setActiveAt(accepted + calDelay(accepted, n.tookover))
if !isActiveAt(n.best, accepted) { if !IsActiveAt(n.best, accepted) {
c.setActiveAt(accepted) c.setActiveAt(accepted)
n.best, n.tookover = c, accepted n.best, n.tookover = c, accepted
} }
@ -57,7 +77,7 @@ func (n *Node) AddClaim(op OutPoint, amt Amount) error {
// SpendClaim spends a Claim in the Node. // SpendClaim spends a Claim in the Node.
func (n *Node) SpendClaim(op OutPoint) error { func (n *Node) SpendClaim(op OutPoint) error {
var c *Claim var c *Claim
if n.claims, c = remove(n.claims, byOP(op)); c == nil { if n.claims, c = Remove(n.claims, ByOP(op)); c == nil {
return ErrNotFound return ErrNotFound
} }
n.removed = append(n.removed, c) n.removed = append(n.removed, c)
@ -74,17 +94,17 @@ func (n *Node) SpendClaim(op OutPoint) error {
// //
// For each block, all the spent claims are kept in n.removed until committed. // For each block, all the spent claims are kept in n.removed until committed.
// The paired (spend, update) commands has to happen in the same trasaction. // The paired (spend, update) commands has to happen in the same trasaction.
func (n *Node) UpdateClaim(op OutPoint, amt Amount, id ID) error { func (n *Node) UpdateClaim(op OutPoint, amt Amount, id ID, val []byte) error {
if find(byOP(op), n.claims, n.supports) != nil { if Find(ByOP(op), n.claims, n.supports) != nil {
return ErrDuplicate return ErrDuplicate
} }
var c *Claim var c *Claim
if n.removed, c = remove(n.removed, byID(id)); c == nil { if n.removed, c = Remove(n.removed, ByID(id)); c == nil {
return errors.Wrapf(ErrNotFound, "remove(n.removed, byID(%s)", id) return errors.Wrapf(ErrNotFound, "remove(n.removed, byID(%s)", id)
} }
accepted := n.height + 1 accepted := n.height + 1
c.setOutPoint(op).setAmt(amt).setAccepted(accepted) c.setOutPoint(op).setAmt(amt).setAccepted(accepted).setValue(val)
c.setActiveAt(accepted + calDelay(accepted, n.tookover)) c.setActiveAt(accepted + calDelay(accepted, n.tookover))
if n.best != nil && n.best.ID == id { if n.best != nil && n.best.ID == id {
c.setActiveAt(n.tookover) c.setActiveAt(n.tookover)
@ -95,12 +115,12 @@ func (n *Node) UpdateClaim(op OutPoint, amt Amount, id ID) error {
// AddSupport adds a Support to the Node. // AddSupport adds a Support to the Node.
func (n *Node) AddSupport(op OutPoint, amt Amount, id ID) error { func (n *Node) AddSupport(op OutPoint, amt Amount, id ID) error {
if find(byOP(op), n.claims, n.supports) != nil { if Find(ByOP(op), n.claims, n.supports) != nil {
return ErrDuplicate return ErrDuplicate
} }
// Accepted by rules. No effects on bidding result though. // Accepted by rules. No effects on bidding result though.
// It may be spent later. // It may be spent later.
if find(byID(id), n.claims, n.removed) == nil { if Find(ByID(id), n.claims, n.removed) == nil {
// fmt.Printf("INFO: can't find suooported claim ID: %s for %s\n", id, n.name) // fmt.Printf("INFO: can't find suooported claim ID: %s for %s\n", id, n.name)
} }
@ -117,7 +137,7 @@ func (n *Node) AddSupport(op OutPoint, amt Amount, id ID) error {
// SpendSupport spends a support in the Node. // SpendSupport spends a support in the Node.
func (n *Node) SpendSupport(op OutPoint) error { func (n *Node) SpendSupport(op OutPoint) error {
var s *Claim var s *Claim
if n.supports, s = remove(n.supports, byOP(op)); s != nil { if n.supports, s = Remove(n.supports, ByOP(op)); s != nil {
return nil return nil
} }
return ErrNotFound return ErrNotFound
@ -147,7 +167,7 @@ func (n *Node) AdjustTo(ht Height) *Node {
// When no pending updates exist, current height is returned. // When no pending updates exist, current height is returned.
func (n *Node) NextUpdate() Height { func (n *Node) NextUpdate() Height {
next := Height(math.MaxInt32) next := Height(math.MaxInt32)
min := func(l list) Height { min := func(l List) Height {
for _, v := range l { for _, v := range l {
exp := v.expireAt() exp := v.expireAt()
if n.height >= exp { if n.height >= exp {
@ -187,15 +207,15 @@ func (n *Node) bid() {
n.removed = nil n.removed = nil
} }
func updateEffectiveAmounts(ht Height, claims, supports list) { func updateEffectiveAmounts(ht Height, claims, supports List) {
for _, c := range claims { for _, c := range claims {
c.EffAmt = 0 c.EffAmt = 0
if !isActiveAt(c, ht) { if !IsActiveAt(c, ht) {
continue continue
} }
c.EffAmt = c.Amt c.EffAmt = c.Amt
for _, s := range supports { for _, s := range supports {
if !isActiveAt(s, ht) || s.ID != c.ID { if !IsActiveAt(s, ht) || s.ID != c.ID {
continue continue
} }
c.EffAmt += s.Amt c.EffAmt += s.Amt
@ -203,7 +223,7 @@ func updateEffectiveAmounts(ht Height, claims, supports list) {
} }
} }
func updateActiveHeights(n *Node, lists ...list) { func updateActiveHeights(n *Node, lists ...List) {
for _, l := range lists { for _, l := range lists {
for _, v := range l { for _, v := range l {
v.ActiveAt = v.Accepted + calDelay(n.height, n.tookover) v.ActiveAt = v.Accepted + calDelay(n.height, n.tookover)
@ -211,11 +231,11 @@ func updateActiveHeights(n *Node, lists ...list) {
} }
} }
func findCandiadte(ht Height, claims list) *Claim { func findCandiadte(ht Height, claims List) *Claim {
var c *Claim var c *Claim
for _, v := range claims { for _, v := range claims {
switch { switch {
case !isActiveAt(v, ht): case !IsActiveAt(v, ht):
continue continue
case c == nil: case c == nil:
c = v c = v

View file

@ -17,8 +17,8 @@ func export(n *Node) interface{} {
Tookover Height Tookover Height
NextUpdate Height NextUpdate Height
BestClaim *Claim BestClaim *Claim
Claims list Claims List
Supports list Supports List
}{ }{
Height: n.height, Height: n.height,
Hash: hash, Hash: hash,

View file

@ -3,6 +3,7 @@ package claimtrie
import ( import (
"fmt" "fmt"
"github.com/lbryio/claimtrie/cfg"
"github.com/lbryio/claimtrie/change" "github.com/lbryio/claimtrie/change"
"github.com/lbryio/claimtrie/claim" "github.com/lbryio/claimtrie/claim"
"github.com/lbryio/claimtrie/nodemgr" "github.com/lbryio/claimtrie/nodemgr"
@ -18,41 +19,71 @@ type ClaimTrie struct {
cm *CommitMgr cm *CommitMgr
nm *nodemgr.NodeMgr nm *nodemgr.NodeMgr
tr *trie.Trie tr *trie.Trie
cleanup func() error
} }
// New returns a ClaimTrie. // New returns a ClaimTrie.
func New(dbCommit, dbTrie, dbNodeMgr *leveldb.DB) *ClaimTrie { func New() (*ClaimTrie, error) {
nm := nodemgr.New(dbNodeMgr) path := cfg.DefaultConfig(cfg.TrieDB)
cm := NewCommitMgr(dbCommit) dbTrie, err := leveldb.OpenFile(path, nil)
if err != nil {
return nil, errors.Wrapf(err, "can't open %s", path)
}
return &ClaimTrie{ path = cfg.DefaultConfig(cfg.NodeDB)
dbNodeMgr, err := leveldb.OpenFile(path, nil)
if err != nil {
return nil, errors.Wrapf(err, "can't open %s", path)
}
path = cfg.DefaultConfig(cfg.CommitDB)
dbCommit, err := leveldb.OpenFile(path, nil)
if err != nil {
return nil, errors.Wrapf(err, "can't open %s", path)
}
cm := NewCommitMgr(dbCommit)
if err := cm.Load(); err != nil {
return nil, errors.Wrapf(err, "cm.Load()")
}
fmt.Printf("%d of commits loaded. Head: %d\n", len(cm.commits), cm.head.Meta.Height)
nm := nodemgr.New(dbNodeMgr)
nm.Load(cm.head.Meta.Height)
fmt.Printf("%d of nodes loaded.\n", nm.Size())
tr := trie.New(nm, dbTrie)
tr.SetRoot(cm.Head().MerkleRoot)
fmt.Printf("ClaimTrie Root: %s.\n", tr.MerkleHash())
ct := &ClaimTrie{
cm: cm, cm: cm,
nm: nm, nm: nm,
tr: trie.New(nm, dbTrie), tr: tr,
cleanup: func() error {
if err := cm.Save(); err != nil {
return errors.Wrapf(err, "cm.Save()")
}
if err := dbTrie.Close(); err != nil {
return errors.Wrapf(err, "dbTrie.Close()")
}
if err := dbNodeMgr.Close(); err != nil {
return errors.Wrapf(err, "dbNodeMgr.Close()")
}
if err := dbCommit.Close(); err != nil {
return errors.Wrapf(err, "dbCommit.Close()")
}
return nil
},
} }
return ct, nil
} }
// Load loads ClaimTrie, NodeManager, Trie from databases. // Close saves ClaimTrie state to database.
func (ct *ClaimTrie) Load() error { func (ct *ClaimTrie) Close() error {
if err := ct.cm.Load(); err != nil { return ct.cleanup()
return errors.Wrapf(err, "cm.Load()")
}
fmt.Printf("%d of commits loaded. Head: %d\n", len(ct.cm.commits), ct.cm.head.Meta.Height)
ct.nm.Load(ct.Height())
fmt.Printf("%d of nodes loaded.\n", ct.nm.Size())
ct.tr.SetRoot(ct.cm.Head().MerkleRoot)
fmt.Printf("Trie root: %s.\n", ct.MerkleHash())
return nil
}
// Save saves ClaimTrie state to database.
func (ct *ClaimTrie) Save() error {
if err := ct.cm.Save(); err != nil {
return errors.Wrapf(err, "cm.Save()")
}
return nil
} }
// Height returns the highest height of blocks commited to the ClaimTrie. // Height returns the highest height of blocks commited to the ClaimTrie.

View file

@ -149,22 +149,6 @@ func main() {
Action: cmdImport, Action: cmdImport,
Flags: []cli.Flag{flagHeight, flagCheck, flagVerbose}, Flags: []cli.Flag{flagHeight, flagCheck, flagVerbose},
}, },
{
Name: "load",
Aliases: []string{"ld"},
Usage: "Load nodes from datbase.",
Before: parseArgs,
Action: cmdLoad,
Flags: []cli.Flag{},
},
{
Name: "save",
Aliases: []string{"sv"},
Usage: "Save nodes to datbase.",
Before: parseArgs,
Action: cmdSave,
Flags: []cli.Flag{},
},
{ {
Name: "erase", Name: "erase",
Usage: "Erase datbase", Usage: "Erase datbase",
@ -181,28 +165,10 @@ func main() {
}, },
} }
path := cfg.DefaultConfig(cfg.TrieDB) var err error
dbTrie, err := leveldb.OpenFile(path, nil) if ct, err = claimtrie.New(); err != nil {
if err != nil { log.Fatalf("can'y create ClaimTrie, err: %s", err)
log.Fatalf("can't open %s, err: %s\n", path, err)
} }
fmt.Printf("opened %q\n", path)
path = cfg.DefaultConfig(cfg.NodeDB)
dbNodeMgr, err := leveldb.OpenFile(path, nil)
if err != nil {
log.Fatalf("can't open %s, err: %s\n", path, err)
}
fmt.Printf("opened %q\n", path)
path = cfg.DefaultConfig(cfg.CommitDB)
dbCommit, err := leveldb.OpenFile(path, nil)
if err != nil {
log.Fatalf("can't open %s, err: %s\n", path, err)
}
fmt.Printf("opened %q\n", path)
ct = claimtrie.New(dbCommit, dbTrie, dbNodeMgr)
if err := app.Run(os.Args); err != nil { if err := app.Run(os.Args); err != nil {
fmt.Printf("error: %s\n", err) fmt.Printf("error: %s\n", err)
} }
@ -283,14 +249,6 @@ func cmdImport(c *cli.Context) error {
return nil return nil
} }
func cmdLoad(c *cli.Context) error {
return ct.Load()
}
func cmdSave(c *cli.Context) error {
return ct.Save()
}
func cmdErase(c *cli.Context) error { func cmdErase(c *cli.Context) error {
if err := os.RemoveAll(cfg.DefaultConfig(cfg.CommitDB)); err != nil { if err := os.RemoveAll(cfg.DefaultConfig(cfg.CommitDB)); err != nil {
return err return err
@ -329,8 +287,8 @@ func cmdShell(app *cli.App) {
continue continue
} }
if text == "quit" || text == "q" { if text == "quit" || text == "q" {
if err = ct.Save(); err != nil { if err = ct.Close(); err != nil {
fmt.Printf("ct.Save() failed, err: %s\n", err) fmt.Printf("ct.Close() failed, err: %s\n", err)
} }
break break
} }

View file

@ -43,7 +43,7 @@ func (nm *NodeMgr) Load(ht claim.Height) {
// Get returns the latest node with name specified by key. // Get returns the latest node with name specified by key.
func (nm *NodeMgr) Get(key []byte) trie.Value { func (nm *NodeMgr) Get(key []byte) trie.Value {
return nm.nodeAt(string(key), nm.height) return nm.NodeAt(string(key), nm.height)
} }
// Reset resets all nodes to specified height. // Reset resets all nodes to specified height.
@ -66,8 +66,8 @@ func (nm *NodeMgr) load(name string, ht claim.Height) *claim.Node {
return NewFromChanges(name, c, ht) return NewFromChanges(name, c, ht)
} }
// nodeAt returns the node adjusted to specified height. // NodeAt returns the node adjusted to specified height.
func (nm *NodeMgr) nodeAt(name string, ht claim.Height) *claim.Node { func (nm *NodeMgr) NodeAt(name string, ht claim.Height) *claim.Node {
n, ok := nm.cache[name] n, ok := nm.cache[name]
if !ok { if !ok {
n = claim.NewNode(name) n = claim.NewNode(name)
@ -84,7 +84,7 @@ func (nm *NodeMgr) nodeAt(name string, ht claim.Height) *claim.Node {
// ModifyNode returns the node adjusted to specified height. // ModifyNode returns the node adjusted to specified height.
func (nm *NodeMgr) ModifyNode(name string, chg *change.Change) error { func (nm *NodeMgr) ModifyNode(name string, chg *change.Change) error {
ht := nm.height ht := nm.height
n := nm.nodeAt(name, ht) n := nm.NodeAt(name, ht)
n.AdjustTo(ht) n.AdjustTo(ht)
if err := execute(n, chg); err != nil { if err := execute(n, chg); err != nil {
return errors.Wrapf(err, "claim.execute(n,chg)") return errors.Wrapf(err, "claim.execute(n,chg)")
@ -100,12 +100,24 @@ func (nm *NodeMgr) CatchUp(ht claim.Height, notifier func(key []byte)) {
nm.height = ht nm.height = ht
for name := range nm.nextUpdates[ht] { for name := range nm.nextUpdates[ht] {
notifier([]byte(name)) notifier([]byte(name))
if next := nm.nodeAt(name, ht).NextUpdate(); next > ht { if next := nm.NodeAt(name, ht).NextUpdate(); next > ht {
nm.nextUpdates.set(name, next) nm.nextUpdates.set(name, next)
} }
} }
} }
// VisitFunc ...
type VisitFunc func(n *claim.Node) (stop bool)
// Visit visits every node in the cache with VisiFunc.
func (nm *NodeMgr) Visit(v VisitFunc) {
for _, n := range nm.cache {
if v(n) {
return
}
}
}
// Show is a conevenient function for debugging and velopment purpose. // Show is a conevenient function for debugging and velopment purpose.
// The proper way to handle user request would be a query function with filters specified. // The proper way to handle user request would be a query function with filters specified.
func (nm *NodeMgr) Show(name string, ht claim.Height, dump bool) error { func (nm *NodeMgr) Show(name string, ht claim.Height, dump bool) error {
@ -119,7 +131,7 @@ func (nm *NodeMgr) Show(name string, ht claim.Height, dump bool) error {
} }
sort.Strings(names) sort.Strings(names)
for _, name := range names { for _, name := range names {
n := nm.nodeAt(name, ht) n := nm.NodeAt(name, ht)
if n.BestClaim() == nil { if n.BestClaim() == nil {
continue continue
} }