Fixed lockable link sequences

gql_cataclysm
noah metz 2023-07-27 23:05:19 -06:00
parent 027bb74887
commit c763725a34
2 changed files with 63 additions and 56 deletions

@ -113,7 +113,7 @@ func LinkRequirement(ctx *Context, dependency *Node, requirement NodeID) error {
} }
dep_ext.Requirements[requirement] = ReqState{"linking", "unlocked"} dep_ext.Requirements[requirement] = ReqState{"linking", "unlocked"}
return ctx.Send(dependency.ID, requirement, NewLinkSignal("req_link")) return ctx.Send(dependency.ID, requirement, NewLinkSignal("link_as_req"))
} }
func (ext *LockableExt) HandleLockSignal(ctx *Context, source NodeID, node *Node, signal StateSignal) { func (ext *LockableExt) HandleLockSignal(ctx *Context, source NodeID, node *Node, signal StateSignal) {
@ -272,62 +272,69 @@ func (ext *LockableExt) HandleLockSignal(ctx *Context, source NodeID, node *Node
} }
// TODO: don't allow changes to requirements or dependencies while being locked or locked // TODO: don't allow changes to requirements or dependencies while being locked or locked
// TODO: add unlink
func (ext *LockableExt) HandleLinkSignal(ctx *Context, source NodeID, node *Node, signal StateSignal) { func (ext *LockableExt) HandleLinkSignal(ctx *Context, source NodeID, node *Node, signal StateSignal) {
ctx.Log.Logf("lockable", "LINK_SIGNAL: %s->%s %+v", source, node.ID, signal) ctx.Log.Logf("lockable", "LINK_SIGNAL: %s->%s %+v", source, node.ID, signal)
state := signal.State state := signal.State
switch state { switch state {
// sent by a node to link this node as a requirement case "link_as_dep":
case "req_link": state, exists := ext.Requirements[source]
_, exists := ext.Requirements[source] if exists == true && state.Link == "linked" {
if exists == false { ctx.Send(node.ID, source, NewLinkSignal("already_req"))
dep_state, exists := ext.Dependencies[source] } else if state.Link == "linking" {
if exists == false { state.Link = "linked"
ext.Dependencies[source] = "linking" ext.Requirements[source] = state
ctx.Send(node.ID, source, NewLinkSignal("dep_link")) ctx.Send(node.ID, source, NewLinkSignal("linked_as_dep"))
} else if dep_state == "linking" { } else if ext.PendingOwner != ext.Owner {
ext.Dependencies[source] = "linked" if ext.Owner == nil {
ctx.Send(node.ID, source, NewLinkSignal("dep_linked")) ctx.Send(node.ID, source, NewLinkSignal("locking"))
} else {
ctx.Send(node.ID, source, NewLinkSignal("unlocking"))
} }
} else { } else {
delete(ext.Requirements, source) ext.Requirements[source] = ReqState{"linking", "unlocked"}
ctx.Send(node.ID, source, NewLinkSignal("req_reset")) ctx.Send(node.ID, source, NewLinkSignal("link_as_req"))
} }
case "dep_link":
_, exists := ext.Dependencies[source] case "link_as_req":
if exists == false { state, exists := ext.Dependencies[source]
req_state, exists := ext.Requirements[source] if exists == true && state == "linked" {
if exists == false { ctx.Send(node.ID, source, NewLinkSignal("already_dep"))
ext.Requirements[source] = ReqState{"linking", "unlocked"} } else if state == "linking" {
ctx.Send(node.ID, source, NewLinkSignal("req_link")) ext.Dependencies[source] = "linked"
} else if req_state.Link == "linking" { ctx.Send(node.ID, source, NewLinkSignal("linked_as_req"))
req_state.Link = "linked" } else if ext.PendingOwner != ext.Owner {
ext.Requirements[source] = req_state if ext.Owner == nil {
ctx.Send(node.ID, source, NewLinkSignal("req_linked")) ctx.Send(node.ID, source, NewLinkSignal("locking"))
} else {
ctx.Send(node.ID, source, NewLinkSignal("unlocking"))
} }
} else { } else {
delete(ext.Dependencies, source) ext.Dependencies[source] = "linking"
ctx.Send(node.ID, source, NewLinkSignal("dep_reset")) ctx.Send(node.ID, source, NewLinkSignal("link_as_dep"))
} }
case "dep_reset": case "linked_as_dep":
ctx.Log.Logf("lockable", "%s reset %s dependency state", node.ID, source) state, exists := ext.Dependencies[source]
case "req_reset": if exists == false {
ctx.Log.Logf("lockable", "%s reset %s requirement state", node.ID, source) ctx.Send(node.ID, source, NewLinkSignal("not_linking"))
case "dep_linked": } else if state == "linked" {
ctx.Log.Logf("lockable", "%s is a dependency of %s", node.ID, source) } else if state == "linking" {
req_state, exists := ext.Requirements[source] ext.Dependencies[source] = "linked"
if exists == true && req_state.Link == "linking" { ctx.Send(node.ID, source, NewLinkSignal("linked_as_req"))
req_state.Link = "linked"
ext.Requirements[source] = req_state
ctx.Send(node.ID, source, NewLinkSignal("req_linked"))
} }
ctx.Log.Logf("lockable", "%s is a dependency of %s", node.ID, source)
case "req_linked": case "linked_as_req":
ctx.Log.Logf("lockable", "%s is a requirement of %s", node.ID, source) state, exists := ext.Requirements[source]
dep_state, exists := ext.Dependencies[source] if exists == false {
if exists == true && dep_state == "linking" { ctx.Send(node.ID, source, NewLinkSignal("not_linking"))
ext.Dependencies[source] = "linked" } else if state.Link == "linked" {
ctx.Send(node.ID, source, NewLinkSignal("dep_linked")) } else if state.Link == "linking" {
state.Link = "linked"
ext.Requirements[source] = state
ctx.Send(node.ID, source, NewLinkSignal("linked_as_dep"))
} }
ctx.Log.Logf("lockable", "%s is a requirement of %s", node.ID, source)
default: default:
ctx.Log.Logf("lockable", "LINK_ERROR: unknown state %s", state) ctx.Log.Logf("lockable", "LINK_ERROR: unknown state %s", state)

@ -20,7 +20,7 @@ var link_policy = NewAllNodesPolicy([]SignalType{LinkSignalType, StatusSignalTyp
var lock_policy = NewAllNodesPolicy([]SignalType{LinkSignalType, LockSignalType, StatusSignalType}) var lock_policy = NewAllNodesPolicy([]SignalType{LinkSignalType, LockSignalType, StatusSignalType})
func TestLink(t *testing.T) { func TestLink(t *testing.T) {
ctx := lockableTestContext(t, []string{}) ctx := lockableTestContext(t, []string{"lockable"})
l1_listener := NewListenerExt(10) l1_listener := NewListenerExt(10)
l1 := NewNode(ctx, RandID(), TestLockableType, nil, l1 := NewNode(ctx, RandID(), TestLockableType, nil,
@ -39,8 +39,8 @@ func TestLink(t *testing.T) {
err := LinkRequirement(ctx, l1, l2.ID) err := LinkRequirement(ctx, l1, l2.ID)
fatalErr(t, err) fatalErr(t, err)
(*GraphTester)(t).WaitForState(ctx, l1_listener, LinkSignalType, "dep_linked", time.Millisecond*10, "No dep_link") (*GraphTester)(t).WaitForState(ctx, l1_listener, LinkSignalType, "linked_as_req", time.Millisecond*10, "No linked_as_req")
(*GraphTester)(t).WaitForState(ctx, l2_listener, LinkSignalType, "req_linked", time.Millisecond*10, "No req_linked") (*GraphTester)(t).WaitForState(ctx, l2_listener, LinkSignalType, "linked_as_dep", time.Millisecond*10, "No req_linked")
err = ctx.Send(l2.ID, l2.ID, NewStatusSignal("TEST", l2.ID)) err = ctx.Send(l2.ID, l2.ID, NewStatusSignal("TEST", l2.ID))
fatalErr(t, err) fatalErr(t, err)
@ -50,7 +50,7 @@ func TestLink(t *testing.T) {
} }
func TestLock(t *testing.T) { func TestLock(t *testing.T) {
ctx := lockableTestContext(t, []string{"lockable"}) ctx := lockableTestContext(t, []string{})
NewLockable := func()(*Node, *ListenerExt) { NewLockable := func()(*Node, *ListenerExt) {
listener := NewListenerExt(10) listener := NewListenerExt(10)
@ -89,15 +89,15 @@ func TestLock(t *testing.T) {
err = LinkRequirement(ctx, l0, l5.ID) err = LinkRequirement(ctx, l0, l5.ID)
fatalErr(t, err) fatalErr(t, err)
(*GraphTester)(t).WaitForState(ctx, l1_listener, LinkSignalType, "dep_linked", time.Millisecond*10, "No dep_link") (*GraphTester)(t).WaitForState(ctx, l1_listener, LinkSignalType, "linked_as_req", time.Millisecond*10, "No linked_as_req")
(*GraphTester)(t).WaitForState(ctx, l1_listener, LinkSignalType, "dep_linked", time.Millisecond*10, "No dep_link") (*GraphTester)(t).WaitForState(ctx, l1_listener, LinkSignalType, "linked_as_req", time.Millisecond*10, "No linked_as_req")
(*GraphTester)(t).WaitForState(ctx, l1_listener, LinkSignalType, "dep_linked", time.Millisecond*10, "No dep_link") (*GraphTester)(t).WaitForState(ctx, l1_listener, LinkSignalType, "linked_as_req", time.Millisecond*10, "No linked_as_req")
(*GraphTester)(t).WaitForState(ctx, l1_listener, LinkSignalType, "dep_linked", time.Millisecond*10, "No dep_link") (*GraphTester)(t).WaitForState(ctx, l1_listener, LinkSignalType, "linked_as_req", time.Millisecond*10, "No linked_as_req")
(*GraphTester)(t).WaitForState(ctx, l0_listener, LinkSignalType, "dep_linked", time.Millisecond*10, "No dep_link") (*GraphTester)(t).WaitForState(ctx, l0_listener, LinkSignalType, "linked_as_req", time.Millisecond*10, "No linked_as_req")
(*GraphTester)(t).WaitForState(ctx, l0_listener, LinkSignalType, "dep_linked", time.Millisecond*10, "No dep_link") (*GraphTester)(t).WaitForState(ctx, l0_listener, LinkSignalType, "linked_as_req", time.Millisecond*10, "No linked_as_req")
(*GraphTester)(t).WaitForState(ctx, l0_listener, LinkSignalType, "dep_linked", time.Millisecond*10, "No dep_link") (*GraphTester)(t).WaitForState(ctx, l0_listener, LinkSignalType, "linked_as_req", time.Millisecond*10, "No linked_as_req")
(*GraphTester)(t).WaitForState(ctx, l0_listener, LinkSignalType, "dep_linked", time.Millisecond*10, "No dep_link") (*GraphTester)(t).WaitForState(ctx, l0_listener, LinkSignalType, "linked_as_req", time.Millisecond*10, "No linked_as_req")
err = LockLockable(ctx, l1) err = LockLockable(ctx, l1)
fatalErr(t, err) fatalErr(t, err)