|
|
|
@ -2,6 +2,7 @@ package graphvent
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type ListenerExt struct {
|
|
|
|
@ -41,15 +42,20 @@ func (ext *ListenerExt) Process(ctx *Context, princ_id NodeID, node *Node, signa
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ext *ListenerExt) Serialize() ([]byte, error) {
|
|
|
|
|
return json.MarshalIndent(ext.Buffer, "", " ")
|
|
|
|
|
func LoadLockableExt(ctx *Context, data []byte) (Extension, error) {
|
|
|
|
|
var ext LockableExt
|
|
|
|
|
err := json.Unmarshal(data, &ext)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type LockableExt struct {
|
|
|
|
|
Owner *NodeID `json:"owner"`
|
|
|
|
|
Requirements []NodeID `json:"requirements"`
|
|
|
|
|
Dependencies []NodeID `json:"dependencies"`
|
|
|
|
|
LocksHeld map[NodeID]*NodeID `json:"locks_held"`
|
|
|
|
|
ctx.Log.Logf("db", "DB_LOADING_LOCKABLE_EXT_JSON: %+v", ext)
|
|
|
|
|
|
|
|
|
|
return &ext, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ext *ListenerExt) Serialize() ([]byte, error) {
|
|
|
|
|
return json.MarshalIndent(ext.Buffer, "", " ")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const LockableExtType = ExtType("LOCKABLE")
|
|
|
|
@ -61,7 +67,15 @@ func (ext *LockableExt) Serialize() ([]byte, error) {
|
|
|
|
|
return json.MarshalIndent(ext, "", " ")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewLockableExt(owner *NodeID, requirements []NodeID, dependencies []NodeID, locks_held map[NodeID]*NodeID) *LockableExt {
|
|
|
|
|
func NewLockableExt(owner *NodeID, requirements map[NodeID]string, dependencies map[NodeID]string, locks_held map[NodeID]*NodeID) *LockableExt {
|
|
|
|
|
if requirements == nil {
|
|
|
|
|
requirements = map[NodeID]string{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if dependencies == nil {
|
|
|
|
|
dependencies = map[NodeID]string{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if locks_held == nil {
|
|
|
|
|
locks_held = map[NodeID]*NodeID{}
|
|
|
|
|
}
|
|
|
|
@ -74,22 +88,79 @@ func NewLockableExt(owner *NodeID, requirements []NodeID, dependencies []NodeID,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LoadLockableExt(ctx *Context, data []byte) (Extension, error) {
|
|
|
|
|
var ext LockableExt
|
|
|
|
|
err := json.Unmarshal(data, &ext)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
type LockableExt struct {
|
|
|
|
|
Owner *NodeID `json:"owner"`
|
|
|
|
|
Requirements map[NodeID]string `json:"requirements"`
|
|
|
|
|
Dependencies map[NodeID]string `json:"dependencies"`
|
|
|
|
|
LocksHeld map[NodeID]*NodeID `json:"locks_held"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx.Log.Logf("db", "DB_LOADING_LOCKABLE_EXT_JSON: %+v", ext)
|
|
|
|
|
func LinkRequirement(ctx *Context, dependency *Node, requirement NodeID) error {
|
|
|
|
|
dep_ext, err := GetExt[*LockableExt](dependency)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &ext, nil
|
|
|
|
|
_, exists := dep_ext.Requirements[requirement]
|
|
|
|
|
if exists == true {
|
|
|
|
|
return fmt.Errorf("%s is already a requirement of %s", requirement, dependency.ID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_, exists = dep_ext.Dependencies[requirement]
|
|
|
|
|
if exists == true {
|
|
|
|
|
return fmt.Errorf("%s is a dependency of %s, cannot link as requirement", requirement, dependency.ID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dep_ext.Requirements[requirement] = "start"
|
|
|
|
|
return ctx.Send(dependency.ID, requirement, NewLinkSignal("req_link"))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ext *LockableExt) HandleLinkSignal(ctx *Context, source NodeID, node *Node, signal LinkSignal) {
|
|
|
|
|
ctx.Log.Logf("lockable", "LINK_SIGNAL: %+v", signal)
|
|
|
|
|
ctx.Log.Logf("lockable", "LINK_SIGNAL: %s->%s %+v", source, node.ID, signal)
|
|
|
|
|
state := signal.State
|
|
|
|
|
switch state {
|
|
|
|
|
// sent by a node to link this node as a requirement
|
|
|
|
|
case "req_link":
|
|
|
|
|
_, exists := ext.Requirements[source]
|
|
|
|
|
if exists == false {
|
|
|
|
|
dep_state, exists := ext.Dependencies[source]
|
|
|
|
|
if exists == false {
|
|
|
|
|
ext.Dependencies[source] = "start"
|
|
|
|
|
ctx.Send(node.ID, source, NewLinkSignal("dep_link"))
|
|
|
|
|
} else if dep_state == "start" {
|
|
|
|
|
ext.Dependencies[source] = "linked"
|
|
|
|
|
ctx.Send(node.ID, source, NewLinkSignal("dep_linked"))
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
delete(ext.Requirements, source)
|
|
|
|
|
ctx.Send(node.ID, source, NewLinkSignal("req_reset"))
|
|
|
|
|
}
|
|
|
|
|
case "dep_link":
|
|
|
|
|
_, exists := ext.Dependencies[source]
|
|
|
|
|
if exists == false {
|
|
|
|
|
req_state, exists := ext.Requirements[source]
|
|
|
|
|
if exists == false {
|
|
|
|
|
ext.Requirements[source] = "start"
|
|
|
|
|
ctx.Send(node.ID, source, NewLinkSignal("req_link"))
|
|
|
|
|
} else if req_state == "start" {
|
|
|
|
|
ext.Requirements[source] = "linked"
|
|
|
|
|
ctx.Send(node.ID, source, NewLinkSignal("req_linked"))
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
delete(ext.Dependencies, source)
|
|
|
|
|
ctx.Send(node.ID, source, NewLinkSignal("dep_reset"))
|
|
|
|
|
}
|
|
|
|
|
case "dep_reset":
|
|
|
|
|
ctx.Log.Logf("lockable", "%s reset %s dependency state", node.ID, source)
|
|
|
|
|
case "req_reset":
|
|
|
|
|
ctx.Log.Logf("lockable", "%s reset %s requirement state", node.ID, source)
|
|
|
|
|
case "dep_linked":
|
|
|
|
|
ctx.Log.Logf("lockable", "%s is a dependency of %s", node.ID, source)
|
|
|
|
|
case "req_linked":
|
|
|
|
|
ctx.Log.Logf("lockable", "%s is a requirement of %s", node.ID, source)
|
|
|
|
|
default:
|
|
|
|
|
ctx.Log.Logf("lockable", "LINK_ERROR: unknown state %s", state)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ext *LockableExt) Process(ctx *Context, source NodeID, node *Node, signal Signal) {
|
|
|
|
@ -98,7 +169,7 @@ func (ext *LockableExt) Process(ctx *Context, source NodeID, node *Node, signal
|
|
|
|
|
switch signal.Direction() {
|
|
|
|
|
case Up:
|
|
|
|
|
owner_sent := false
|
|
|
|
|
for _, dependency := range(ext.Dependencies) {
|
|
|
|
|
for dependency, _ := range(ext.Dependencies) {
|
|
|
|
|
err := ctx.Send(node.ID, dependency, signal)
|
|
|
|
|
if err != nil {
|
|
|
|
|
ctx.Log.Logf("signal", "LOCKABLE_SIGNAL_ERR: %s->%s - %e", node.ID, dependency, err)
|
|
|
|
@ -120,16 +191,16 @@ func (ext *LockableExt) Process(ctx *Context, source NodeID, node *Node, signal
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case Down:
|
|
|
|
|
for _, requirement := range(ext.Requirements) {
|
|
|
|
|
for requirement, _ := range(ext.Requirements) {
|
|
|
|
|
err := ctx.Send(node.ID, requirement, signal)
|
|
|
|
|
if err != nil {
|
|
|
|
|
ctx.Log.Logf("signal", "LOCKABLE_SIGNAL_ERR: %s->%s - %e", node.ID, requirement, err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case Direct:
|
|
|
|
|
switch sig := signal.(type) {
|
|
|
|
|
case LinkSignal:
|
|
|
|
|
ext.HandleLinkSignal(ctx, source, node, sig)
|
|
|
|
|
switch signal.Type() {
|
|
|
|
|
case LinkSignalType:
|
|
|
|
|
ext.HandleLinkSignal(ctx, source, node, signal.(LinkSignal))
|
|
|
|
|
default:
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|