From 999963e87a33c76fb5ebf48e8d795528b070d1f0 Mon Sep 17 00:00:00 2001 From: TATAUFO Date: Sun, 1 Mar 2020 14:11:12 +0800 Subject: [PATCH] refactor DAG, setting the number of roots when DAG is created --- core/universe.go | 22 ++++++++++--------- core/universe_test.go | 3 ++- dag/dag.go | 51 ++++++++++++++++++++++++++++++++++--------- dag/dag_test.go | 46 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 99 insertions(+), 23 deletions(-) diff --git a/core/universe.go b/core/universe.go index 1a26c41..3dc0170 100644 --- a/core/universe.go +++ b/core/universe.go @@ -87,7 +87,7 @@ func NewUniverse(Eve, Adam *User) (*Universe, error) { if err != nil { return nil, err } - userD, err := dag.NewDAG(EveVertex, AdamVertex) + userD, err := dag.NewDAG(2, EveVertex, AdamVertex) if err != nil { return nil, err } @@ -202,7 +202,7 @@ func (u *Universe) initializeSpaceTime(msgSpaceTime *Message, ref *MsgReference) return err } if u.stD == nil { - stD, err := dag.NewDAG(stVertex) + stD, err := dag.NewDAG(1, stVertex) if err != nil { return err } @@ -280,7 +280,7 @@ func (u *Universe) initializeMsgD(msg *Message) error { if err != nil { return err } - msgD, err := dag.NewDAG(msgVertex) + msgD, err := dag.NewDAG(1, msgVertex) if err != nil { return err } @@ -306,7 +306,7 @@ func (u *Universe) createSpaceTime(msg *Message, ref *MsgReference) (*SpaceTime, if err != nil { return nil, err } - timeProofDag, err := dag.NewDAG(timeVertex) + timeProofDag, err := dag.NewDAG(1, timeVertex) if err != nil { return nil, err } @@ -347,7 +347,7 @@ func (u *Universe) createSpaceTime(msg *Message, ref *MsgReference) (*SpaceTime, } func (u Universe) createUserStateD(st *SpaceTime, ref *MsgReference) (*dag.DAG, error) { - newUserStateD, err := dag.NewDAG() + newUserStateD, err := dag.NewDAG(2) if err != nil { return nil, err } @@ -367,6 +367,7 @@ func (u Universe) createUserStateD(st *SpaceTime, ref *MsgReference) (*dag.DAG, if err != nil { return nil, err } + newUserStateD.AddVertex(userStateVertex) } return newUserStateD, nil @@ -376,6 +377,7 @@ func (u *Universe) updateTimeProof(msg *Message) error { if vertex := u.stD.GetVertex(msg.SenderID); vertex != nil { st := vertex.Value().(*SpaceTime) var currentSeq uint64 = 1 + var ref interface{} for _, r := range msg.Reference { if r.SenderID == msg.SenderID { refVertex := st.timeProofD.GetVertex(r.MsgID) @@ -383,11 +385,12 @@ func (u *Universe) updateTimeProof(msg *Message) error { refSeq := refVertex.Value().(uint64) if currentSeq <= refSeq { currentSeq = refSeq + 1 + ref = r.MsgID } } } } - timeVertex, err := dag.NewVertex(msg.ID(), currentSeq) + timeVertex, err := dag.NewVertex(msg.ID(), currentSeq, ref) if err != nil { return err } @@ -421,13 +424,12 @@ func (u *Universe) addUserByMsg(msg *Message) error { userAdded := false for _, ref := range msg.Reference { if err := u.addUserToSpaceTime(ref, dobContent, user); err != nil { - continue - } else { - // at least add into one space time - userAdded = true } + // at least add into one space time + userAdded = true } + if !userAdded { return errNewUserAddFail } diff --git a/core/universe_test.go b/core/universe_test.go index 10f1208..0e66d54 100644 --- a/core/universe_test.go +++ b/core/universe_test.go @@ -20,11 +20,12 @@ import ( "encoding/json" "errors" "fmt" + "testing" + "github.com/pdupub/go-pdu/common" "github.com/pdupub/go-pdu/common/log" "github.com/pdupub/go-pdu/core/rule" "github.com/pdupub/go-pdu/crypto" - "testing" ) var ( diff --git a/dag/dag.go b/dag/dag.go index c84db40..8faae86 100644 --- a/dag/dag.go +++ b/dag/dag.go @@ -34,6 +34,7 @@ import ( var ( errRootVertexParentsExist = errors.New("root vertex parents exist") + errRootNumberOutOfRange = errors.New("root number is out of range") errVertexAlreadyExist = errors.New("vertex already exist") errVertexNotExist = errors.New("vertex not exist") errVertexHasChildren = errors.New("vertex has children") @@ -41,24 +42,36 @@ var ( errVertexParentNumberOutOfRange = errors.New("parent number is out of range") ) +const ( + defaultMaxParentsCount = 255 +) + // DAG is directed acyclic graph type DAG struct { mu sync.Mutex - maxParentsCount int // 0 = unlimited + maxParentsCount int + strict bool store map[interface{}]*Vertex ids []interface{} + rufd uint // unfilled root count } // NewDAG create new DAG by root vertexes -func NewDAG(rootVertex ...*Vertex) (*DAG, error) { +func NewDAG(rootCnt uint, rootVertex ...*Vertex) (*DAG, error) { dag := &DAG{ - store: make(map[interface{}]*Vertex), - ids: []interface{}{}, + maxParentsCount: defaultMaxParentsCount, + strict: true, + store: make(map[interface{}]*Vertex), + ids: []interface{}{}, + rufd: rootCnt, } for _, vertex := range rootVertex { - if len(vertex.Parents()) == 0 { + if dag.rufd == 0 { + return nil, errRootNumberOutOfRange + } else if len(vertex.Parents()) == 0 { dag.store[vertex.ID()] = vertex dag.ids = append(dag.ids, vertex.ID()) + dag.rufd-- } else { return nil, errRootVertexParentsExist } @@ -66,19 +79,28 @@ func NewDAG(rootVertex ...*Vertex) (*DAG, error) { return dag, nil } +// IsStrict return if all parents must exist when add vertex +func (d *DAG) IsStrict() bool { + return d.strict +} + +// SetStrict set if the parents rule is strict or not +func (d *DAG) SetStrict(b bool) { + d.strict = b +} + // SetMaxParentsCount set the max number of parents one vertex can get func (d *DAG) SetMaxParentsCount(maxCount int) { d.maxParentsCount = maxCount } // GetMaxParentsCount get the max number of parents -func (d DAG) GetMaxParentsCount() int { +func (d *DAG) GetMaxParentsCount() int { return d.maxParentsCount } // GetVertex can get vertex by ID func (d *DAG) GetVertex(id interface{}) *Vertex { - if _, ok := d.store[id]; !ok { return nil } @@ -94,14 +116,23 @@ func (d *DAG) AddVertex(vertex *Vertex) error { return errVertexAlreadyExist } - if d.maxParentsCount != 0 && len(vertex.Parents()) > d.maxParentsCount { + if len(vertex.Parents()) > d.maxParentsCount { return errVertexParentNumberOutOfRange } // check parents cloud be found + sequenceExist := false for _, pid := range vertex.Parents() { if _, ok := d.store[pid]; !ok { return errVertexParentNotExist } + sequenceExist = true + } + if !sequenceExist { + if d.rufd == 0 { + return errRootNumberOutOfRange + } else { + d.rufd-- + } } // add vertex into store d.store[vertex.ID()] = vertex @@ -141,12 +172,12 @@ func (d *DAG) DelVertex(id interface{}) error { } // GetIDs get id list of DAG -func (d DAG) GetIDs() []interface{} { +func (d *DAG) GetIDs() []interface{} { return d.ids } // String is used to print the DAG content -func (d DAG) String() string { +func (d *DAG) String() string { result := fmt.Sprintf("maxParentsCount : %d - storeSize : %d \n", d.maxParentsCount, len(d.store)) for k, v := range d.store { result += fmt.Sprintf("k = %v \n", k) diff --git a/dag/dag_test.go b/dag/dag_test.go index df40352..a507160 100644 --- a/dag/dag_test.go +++ b/dag/dag_test.go @@ -23,7 +23,7 @@ import ( func TestDAG_AddVertex(t *testing.T) { v1, _ := NewVertex("id-1", "hello world") v2, _ := NewVertex("id-2", "hello you") - dag, err := NewDAG(v1, v2) + dag, err := NewDAG(2, v1, v2) if err != nil { t.Errorf("create DAG fail , err : %s", err) } @@ -66,10 +66,52 @@ func TestDAG_AddVertex(t *testing.T) { } } +func TestDAG_AddVertex2(t *testing.T) { + v1, _ := NewVertex("id-1", "hello world") + v2, _ := NewVertex("id-2", "hello you") + + dag, err := NewDAG(3) + if err != nil { + t.Errorf("create DAG fail , err : %s", err) + } + + if len(dag.GetIDs()) != 0 { + t.Errorf("id number not match, should be %d, dag getIDs is %d", 0, dag.GetIDs()) + } + + if err := dag.AddVertex(v1); err != nil { + t.Errorf("add vertex fail, err : %s", err) + } + + if err := dag.AddVertex(v2); err != nil { + t.Errorf("add vertex fail, err : %s", err) + } + + v3, _ := NewVertex("id-3", "hello you", v1, v2) + if err := dag.AddVertex(v3); err != nil { + t.Errorf("add vertex fail, err : %s", err) + } + + v4, _ := NewVertex("id-4", "hello you", v1, v3) + if err := dag.AddVertex(v4); err != nil { + t.Errorf("add vertex fail, err : %s", err) + } + + v5, _ := NewVertex("id-5", "hello you too") + if err := dag.AddVertex(v5); err != nil { + t.Errorf("add vertex fail, err : %s", err) + } + + v6, _ := NewVertex("id-6", "hello you too") + if err := dag.AddVertex(v6); err != errRootNumberOutOfRange { + t.Errorf("add vertex should fail, err should be %s not %s", errRootNumberOutOfRange, err) + } +} + func TestDAG_DelVertex(t *testing.T) { v1, _ := NewVertex("id-1", "hello world") v2, _ := NewVertex("id-2", "hello you") - dag, err := NewDAG(v1, v2) + dag, err := NewDAG(2, v1, v2) if err != nil { t.Errorf("create DAG fail , err : %s", err) }