Removed EventMangar

graph-rework
noah metz 2023-06-20 15:48:17 -06:00
parent 32434e7dfe
commit 9980be7c86
5 changed files with 276 additions and 352 deletions

@ -21,7 +21,7 @@ func (event * BaseEvent) PropagateUpdate(signal GraphSignal) {
event.rr_lock.Lock() event.rr_lock.Lock()
defer event.rr_lock.Unlock() defer event.rr_lock.Unlock()
for _, resource := range(event.required_resources) { for _, resource := range(event.resources) {
SendUpdate(resource, signal) SendUpdate(resource, signal)
} }
} else { } else {
@ -70,7 +70,8 @@ type Event interface {
UnlockParent() UnlockParent()
Action(action string) (func()(string, error), bool) Action(action string) (func()(string, error), bool)
Handler(signal_type string) (func(GraphSignal) (string, error), bool) Handler(signal_type string) (func(GraphSignal) (string, error), bool)
RequiredResources() []Resource Resources() []Resource
AddResource(Resource) error
DoneResource() Resource DoneResource() Resource
SetTimeout(end_time time.Time, action string) SetTimeout(end_time time.Time, action string)
ClearTimeout() ClearTimeout()
@ -84,6 +85,20 @@ type Event interface {
setParent(parent Event) setParent(parent Event)
} }
func (event * BaseEvent) AddResource(resource Resource) error {
event.resources_lock.Lock()
defer event.resources_lock.Unlock()
for _, r := range(event.resources) {
if r.ID() == resource.ID() {
return fmt.Errorf("%s is already required for %s, cannot add again", resource.Name(), event.Name())
}
}
event.resources = append(event.resources, resource)
return nil
}
func (event * BaseEvent) Signal() chan GraphSignal { func (event * BaseEvent) Signal() chan GraphSignal {
return event.signal return event.signal
} }
@ -112,7 +127,7 @@ func (event * BaseEvent) Handler(signal_type string) (func(GraphSignal)(string,
} }
func FindResources(event Event, resource_type reflect.Type) []Resource { func FindResources(event Event, resource_type reflect.Type) []Resource {
resources := event.RequiredResources() resources := event.Resources()
found := []Resource{} found := []Resource{}
for _, resource := range(resources) { for _, resource := range(resources) {
if reflect.TypeOf(resource) == resource_type { if reflect.TypeOf(resource) == resource_type {
@ -136,7 +151,7 @@ func FindResources(event Event, resource_type reflect.Type) []Resource {
} }
func FindRequiredResource(event Event, id string) Resource { func FindRequiredResource(event Event, id string) Resource {
for _, resource := range(event.RequiredResources()) { for _, resource := range(event.Resources()) {
if resource.ID() == id { if resource.ID() == id {
return resource return resource
} }
@ -179,9 +194,9 @@ func CheckInfoType(event Event, info EventInfo) bool {
return event.InfoType() == reflect.TypeOf(info) return event.InfoType() == reflect.TypeOf(info)
} }
func AddChild(event Event, child Event, info EventInfo) error { func LinkEvent(event Event, child Event, info EventInfo) error {
if CheckInfoType(event, info) == false { if CheckInfoType(event, info) == false {
return errors.New("AddChild got wrong type") return errors.New("LinkEvents got wrong type")
} }
event.LockParent() event.LockParent()
@ -215,6 +230,32 @@ func AddChild(event Event, child Event, info EventInfo) error {
return nil return nil
} }
func StartRootEvent(event Event) error {
log.Logf("event", "ROOT_EVEN_START")
err := LockResources(event)
if err != nil {
log.Logf("event", "ROOT_EVENT_LOCK_ERR: %s", err)
return err
}
err = RunEvent(event)
if err != nil {
log.Logf("event", "ROOT_EVENT_RUNE_ERR: %s", err)
return err
}
err = FinishEvent(event)
if err != nil {
log.Logf("event", "ROOT_EVENT_FINISH_ERR: %s", err)
return err
}
log.Logf("event", "ROOT_EVENT_DONE")
return nil
}
func RunEvent(event Event) error { func RunEvent(event Event) error {
log.Logf("event", "EVENT_RUN: %s", event.Name()) log.Logf("event", "EVENT_RUN: %s", event.Name())
SendUpdate(event, NewSignal(event, "event_start")) SendUpdate(event, NewSignal(event, "event_start"))
@ -252,10 +293,10 @@ func EventCancel(event Event) func(signal GraphSignal) (string, error) {
} }
func LockResources(event Event) error { func LockResources(event Event) error {
log.Logf("event", "RESOURCE_LOCKING for %s - %+v", event.Name(), event.RequiredResources()) log.Logf("event", "RESOURCE_LOCKING for %s - %+v", event.Name(), event.Resources())
locked_resources := []Resource{} locked_resources := []Resource{}
var lock_err error = nil var lock_err error = nil
for _, resource := range(event.RequiredResources()) { for _, resource := range(event.Resources()) {
err := LockResource(resource, event) err := LockResource(resource, event)
if err != nil { if err != nil {
lock_err = err lock_err = err
@ -279,7 +320,7 @@ func LockResources(event Event) error {
func FinishEvent(event Event) error { func FinishEvent(event Event) error {
log.Logf("event", "EVENT_FINISH: %s", event.Name()) log.Logf("event", "EVENT_FINISH: %s", event.Name())
for _, resource := range(event.RequiredResources()) { for _, resource := range(event.Resources()) {
err := UnlockResource(resource, event) err := UnlockResource(resource, event)
if err != nil { if err != nil {
panic(err) panic(err)
@ -313,7 +354,8 @@ type BaseEvent struct {
BaseNode BaseNode
done_resource Resource done_resource Resource
rr_lock sync.Mutex rr_lock sync.Mutex
required_resources []Resource resources []Resource
resources_lock sync.Mutex
children []Event children []Event
children_lock sync.Mutex children_lock sync.Mutex
child_info map[string]EventInfo child_info map[string]EventInfo
@ -351,15 +393,15 @@ func EventWait(event Event) (func() (string, error)) {
} }
} }
func NewBaseEvent(name string, description string, required_resources []Resource) (BaseEvent) { func NewBaseEvent(name string, description string) (BaseEvent) {
done_resource := NewResource("event_done", "signal that event is done", []Resource{}) done_resource, _ := NewResource("event_done", "signal that event is done", []Resource{})
event := BaseEvent{ event := BaseEvent{
BaseNode: NewBaseNode(name, description, randid()), BaseNode: NewBaseNode(name, description, randid()),
parent: nil, parent: nil,
children: []Event{}, children: []Event{},
child_info: map[string]EventInfo{}, child_info: map[string]EventInfo{},
done_resource: done_resource, done_resource: done_resource,
required_resources: required_resources, resources: []Resource{},
Actions: map[string]func()(string, error){}, Actions: map[string]func()(string, error){},
Handlers: map[string]func(GraphSignal)(string, error){}, Handlers: map[string]func(GraphSignal)(string, error){},
abort: make(chan string, 1), abort: make(chan string, 1),
@ -372,10 +414,25 @@ func NewBaseEvent(name string, description string, required_resources []Resource
return event return event
} }
func NewEvent(name string, description string, required_resources []Resource) (* BaseEvent) { func AddResources(event Event, resources []Resource) error {
event := NewBaseEvent(name, description, required_resources) for _, r := range(resources) {
err := event.AddResource(r)
if err != nil {
return err
}
}
return nil
}
func NewEvent(name string, description string, resources []Resource) (* BaseEvent, error) {
event := NewBaseEvent(name, description)
event_ptr := &event event_ptr := &event
err := AddResources(event_ptr, resources)
if err != nil {
return nil, err
}
event_ptr.Actions["wait"] = EventWait(event_ptr) event_ptr.Actions["wait"] = EventWait(event_ptr)
event_ptr.Handlers["abort"] = EventAbort(event_ptr) event_ptr.Handlers["abort"] = EventAbort(event_ptr)
event_ptr.Handlers["cancel"] = EventCancel(event_ptr) event_ptr.Handlers["cancel"] = EventCancel(event_ptr)
@ -384,7 +441,7 @@ func NewEvent(name string, description string, required_resources []Resource) (*
return "", nil return "", nil
} }
return event_ptr return event_ptr, nil
} }
func (event * BaseEvent) finish() error { func (event * BaseEvent) finish() error {
@ -414,12 +471,14 @@ func (queue * EventQueue) InfoType() reflect.Type {
return reflect.TypeOf((*EventQueueInfo)(nil)) return reflect.TypeOf((*EventQueueInfo)(nil))
} }
func NewEventQueue(name string, description string, required_resources []Resource) (* EventQueue) { func NewEventQueue(name string, description string, resources []Resource) (* EventQueue, error) {
queue := &EventQueue{ queue := &EventQueue{
BaseEvent: NewBaseEvent(name, description, required_resources), BaseEvent: NewBaseEvent(name, description),
listened_resources: map[string]Resource{}, listened_resources: map[string]Resource{},
} }
AddResources(queue, resources)
queue.Actions["wait"] = EventWait(queue) queue.Actions["wait"] = EventWait(queue)
queue.Handlers["abort"] = EventAbort(queue) queue.Handlers["abort"] = EventAbort(queue)
queue.Handlers["cancel"] = EventCancel(queue) queue.Handlers["cancel"] = EventCancel(queue)
@ -443,7 +502,7 @@ func NewEventQueue(name string, description string, required_resources []Resourc
needed_resources := map[string]Resource{} needed_resources := map[string]Resource{}
for _, event := range(copied_events) { for _, event := range(copied_events) {
// make sure all the required resources are registered to update the event // make sure all the required resources are registered to update the event
for _, resource := range(event.RequiredResources()) { for _, resource := range(event.Resources()) {
needed_resources[resource.ID()] = resource needed_resources[resource.ID()] = resource
} }
@ -501,15 +560,15 @@ func NewEventQueue(name string, description string, required_resources []Resourc
return "queue_event", nil return "queue_event", nil
} }
return queue return queue, nil
} }
func (event * BaseEvent) Parent() Event { func (event * BaseEvent) Parent() Event {
return event.parent return event.parent
} }
func (event * BaseEvent) RequiredResources() []Resource { func (event * BaseEvent) Resources() []Resource {
return event.required_resources return event.resources
} }
func (event * BaseEvent) DoneResource() Resource { func (event * BaseEvent) DoneResource() Resource {

@ -860,7 +860,7 @@ type GQLServer struct {
func NewGQLServer(listen string, extended_types map[reflect.Type]*graphql.Object, extended_queries map[string]*graphql.Field, extended_mutations map[string]*graphql.Field, extended_subscriptions map[string]*graphql.Field) * GQLServer { func NewGQLServer(listen string, extended_types map[reflect.Type]*graphql.Object, extended_queries map[string]*graphql.Field, extended_mutations map[string]*graphql.Field, extended_subscriptions map[string]*graphql.Field) * GQLServer {
server := &GQLServer{ server := &GQLServer{
BaseResource: NewBaseResource("GQL Server", "graphql server for event signals", []Resource{}), BaseResource: NewBaseResource("GQL Server", "graphql server for event signals"),
listen: listen, listen: listen,
abort: make(chan error, 1), abort: make(chan error, 1),
gql_channel: make(chan error, 1), gql_channel: make(chan error, 1),

@ -1,200 +0,0 @@
package graphvent
import (
"fmt"
"errors"
)
type EventManager struct {
dag_nodes map[string]Resource
Root Event
aborts []chan error
}
// root_event's requirements must be in dag_nodes, and dag_nodes must be ordered by dependency(children first)
func NewEventManager(root_event Event, dag_nodes []Resource) * EventManager {
manager := &EventManager{
dag_nodes: map[string]Resource{},
Root: nil,
aborts: []chan error{},
}
// Construct the DAG
for _, resource := range dag_nodes {
err := manager.AddResource(resource)
if err != nil {
log.Logf("manager", "Failed to add %s to EventManager: %s", resource.Name(), err)
return nil
}
}
err := manager.AddEvent(nil, root_event, nil)
if err != nil {
log.Logf("manager", "Failed to add %s to EventManager as root_event: %s", root_event.Name(), err)
}
return manager;
}
// Init to all resources(in a thread to handle reconnections), and start the first event
func (manager * EventManager) Run() error {
log.Logf("manager", "MANAGER_START")
abort := make(chan error, 1)
go func(abort chan error, manager * EventManager) {
<- abort
for _, c := range(manager.aborts) {
c <- nil
}
}(abort, manager)
err := LockResources(manager.Root)
if err != nil {
log.Logf("manager", "MANAGER_LOCK_ERR: %s", err)
abort <- nil
return err
}
err = RunEvent(manager.Root)
abort <- nil
if err != nil {
log.Logf("manager", "MANAGER_RUN_ERR: %s", err)
return err
}
err = FinishEvent(manager.Root)
if err != nil {
log.Logf("manager", "MANAGER_FINISH_ERR: %s", err)
return err
}
log.Logf("manager", "MANAGER_DONE")
return nil
}
func (manager * EventManager) FindResource(id string) Resource {
resource, exists := manager.dag_nodes[id]
if exists == false {
return nil
}
return resource
}
func (manager * EventManager) FindEvent(id string) Event {
event := FindChild(manager.Root, id)
return event
}
func (manager * EventManager) AddResource(resource Resource) error {
log.Logf("manager", "Adding resource %s", resource.Name())
_, exists := manager.dag_nodes[resource.ID()]
if exists == true {
error_str := fmt.Sprintf("%s is already in the resource DAG, cannot add again", resource.Name())
return errors.New(error_str)
}
for _, child := range resource.Children() {
_, exists := manager.dag_nodes[child.ID()]
if exists == false {
error_str := fmt.Sprintf("%s is not in the resource DAG, cannot add %s to DAG", child.Name(), resource.Name())
return errors.New(error_str)
}
}
manager.dag_nodes[resource.ID()] = resource
abort := make(chan error, 1)
abort_used := resource.Init(abort)
if abort_used == true {
manager.aborts = append(manager.aborts, abort)
}
for _, child := range resource.Children() {
AddParent(child, resource)
}
return nil
}
// Check that the node doesn't already exist in the tree
// Check the the selected parent exists in the tree
// Check that required resources exist in the DAG
// Check that created resources don't exist in the DAG
// Add resources created by the event to the DAG
// Add child to parent
func (manager * EventManager) CheckResources(event Event) error {
if event == nil {
return errors.New("Cannot check nil event for resources")
}
for _, r := range(event.RequiredResources()) {
res_found := false
for _, res := range(manager.dag_nodes) {
if res.ID() == r.ID() {
res_found = true
}
}
if res_found == false {
return errors.New(fmt.Sprintf("Failed to find %s in the resource forest for %s", r.Name(), event.Name()))
}
}
for _, c := range(event.Children()) {
err := manager.CheckResources(c)
if err != nil {
return err
}
}
return nil
}
func (manager * EventManager) AddDoneResources(event Event) {
if event == nil {
return
}
done_resource := event.DoneResource()
_, exists := manager.dag_nodes[done_resource.ID()]
if exists == false {
manager.AddResource(done_resource)
}
for _, child := range(event.Children()) {
manager.AddDoneResources(child)
}
}
func (manager * EventManager) AddEvent(parent Event, child Event, info EventInfo) error {
if child == nil {
return errors.New("Cannot add nil Event to EventManager")
}
err := manager.CheckResources(child)
if err != nil {
return fmt.Errorf("Failed to add event to event manager: %w", err)
}
manager.AddDoneResources(child)
if manager.Root == nil {
if parent != nil {
return fmt.Errorf("EventManager has no root, so can't add event to parent")
} else {
manager.Root = child
return nil
}
} else {
if parent == nil {
return fmt.Errorf("Replacing root event not implemented")
} else if FindChild(manager.Root, parent.ID()) == nil {
return fmt.Errorf("Parent does not exists in event tree")
} else if FindChild(manager.Root, child.ID()) != nil {
return fmt.Errorf("Child already exists in event tree")
} else {
AddChild(parent, child, info)
}
}
return nil
}

@ -53,16 +53,18 @@ func (t * GraphTester) CheckForNone(listener chan GraphSignal, str string) {
} }
} }
func TestNewResourceAdd(t *testing.T) { func TestNewEventWithResource(t *testing.T) {
name := "Test Resource" name := "Test Resource"
description := "A resource for testing" description := "A resource for testing"
children := []Resource{} children := []Resource{}
root_event := NewEvent("", "", []Resource{}) test_resource, _ := NewResource(name, description, children)
test_resource := NewResource(name, description, children) root_event, err := NewEvent("root_event", "", []Resource{test_resource})
event_manager := NewEventManager(root_event, []Resource{test_resource}) if err != nil {
res := event_manager.FindResource(test_resource.ID()) t.Fatal(err)
}
res := FindRequiredResource(root_event, test_resource.ID())
if res == nil { if res == nil {
t.Fatal("Failed to find Resource in EventManager after adding") t.Fatal("Failed to find Resource in EventManager after adding")
} }
@ -73,48 +75,47 @@ func TestNewResourceAdd(t *testing.T) {
} }
func TestDoubleResourceAdd(t * testing.T) { func TestDoubleResourceAdd(t * testing.T) {
root_event := NewEvent("", "", []Resource{}) test_resource, _ := NewResource("", "", []Resource{})
test_resource := NewResource("", "", []Resource{}) _, err := NewEvent("", "", []Resource{test_resource, test_resource})
event_manager := NewEventManager(root_event, []Resource{test_resource})
err := event_manager.AddResource(test_resource)
if err == nil {
t.Fatal("Second AddResource returned nil")
}
}
func TestMissingResourceAdd(t * testing.T) {
root_event := NewEvent("", "", []Resource{})
r1 := NewResource("r1", "", []Resource{})
r2 := NewResource("r2", "", []Resource{r1})
event_manager := NewEventManager(root_event, []Resource{})
err := event_manager.AddResource(r2)
if err == nil { if err == nil {
t.Fatal("AddResource with missing child returned nil") t.Fatal("NewEvent didn't return an error")
} }
} }
func TestTieredResource(t * testing.T) { func TestTieredResource(t * testing.T) {
root_event := NewEvent("", "", []Resource{}) r1, _ := NewResource("r1", "", []Resource{})
r1 := NewResource("r1", "", []Resource{}) r2, err := NewResource("r2", "", []Resource{r1})
r2 := NewResource("r2", "", []Resource{r1}) if err != nil {
t.Fatal(err)
}
_, err = NewEvent("", "", []Resource{r2})
event_manager := NewEventManager(root_event, []Resource{r1, r2}) if err != nil {
if event_manager == nil { t.Fatal("Failed to create event with tiered resources")
t.Fatal("Failed to create event manager with tiered resources")
} }
} }
func TestResourceUpdate(t * testing.T) { func TestResourceUpdate(t * testing.T) {
root_event := NewEvent("", "", []Resource{}) r1, err := NewResource("r1", "", []Resource{})
r1 := NewResource("r1", "", []Resource{}) if err != nil {
r2 := NewResource("r2", "", []Resource{}) t.Fatal(err)
r3 := NewResource("r3", "", []Resource{r1, r2}) }
r4 := NewResource("r4", "", []Resource{r3}) r2, err := NewResource("r2", "", []Resource{})
if err != nil {
event_manager := NewEventManager(root_event, []Resource{r1, r2, r3, r4}) t.Fatal(err)
if event_manager == nil { }
r3, err := NewResource("r3", "", []Resource{r1, r2})
if err != nil {
t.Fatal(err)
}
r4, err := NewResource("r4", "", []Resource{r3})
if err != nil {
t.Fatal(err)
}
_, err = NewEvent("", "", []Resource{r3, r4})
if err != nil {
t.Fatal("Failed to add initial tiered resources for test") t.Fatal("Failed to add initial tiered resources for test")
} }
@ -146,27 +147,21 @@ func TestResourceUpdate(t * testing.T) {
} }
func TestAddEvent(t * testing.T) { func TestAddEvent(t * testing.T) {
root_event := NewEvent("", "", []Resource{}) r1, _ := NewResource("r1", "", []Resource{})
r1 := NewResource("r1", "", []Resource{}) r2, _ := NewResource("r2", "", []Resource{r1})
r2 := NewResource("r2", "", []Resource{r1}) root_event, _ := NewEvent("", "", []Resource{r2})
name := "Test Event" name := "Test Event"
description := "A test event" description := "A test event"
resources := []Resource{r2} resources := []Resource{r2}
new_event := NewEvent(name, description, resources) new_event, _ := NewEvent(name, description, resources)
event_manager := NewEventManager(root_event, []Resource{r1})
err := event_manager.AddResource(r2)
if err != nil {
t.Fatal("Failed to add r2 to event_manager")
}
err = event_manager.AddEvent(root_event, new_event, nil) err := LinkEvent(root_event, new_event, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to add new_event to root_event: %s", err) t.Fatalf("Failed to add new_event to root_event: %s", err)
} }
res := event_manager.FindEvent(new_event.ID()) res := FindChild(root_event, new_event.ID())
if res == nil { if res == nil {
t.Fatalf("Failed to find new_event in event_manager: %s", err) t.Fatalf("Failed to find new_event in event_manager: %s", err)
} }
@ -175,7 +170,7 @@ func TestAddEvent(t * testing.T) {
t.Fatal("Event found in event_manager didn't match added") t.Fatal("Event found in event_manager didn't match added")
} }
res_required := res.RequiredResources() res_required := res.Resources()
if len(res_required) < 1 { if len(res_required) < 1 {
t.Fatal("Event found in event_manager didn't match added") t.Fatal("Event found in event_manager didn't match added")
} else if res_required[0].ID() != r2.ID() { } else if res_required[0].ID() != r2.ID() {
@ -184,23 +179,35 @@ func TestAddEvent(t * testing.T) {
} }
func TestLockResource(t * testing.T) { func TestLockResource(t * testing.T) {
root_event := NewEvent("", "", []Resource{}) r1, err := NewResource("r1", "", []Resource{})
test_event := NewEvent("", "", []Resource{}) if err != nil {
r1 := NewResource("r1", "", []Resource{}) t.Fatal(err)
r2 := NewResource("r2", "", []Resource{}) }
r3 := NewResource("r3", "", []Resource{r1, r2}) r2, err := NewResource("r2", "", []Resource{})
r4 := NewResource("r4", "", []Resource{r1, r2}) if err != nil {
t.Fatal(err)
event_manager := NewEventManager(root_event, []Resource{r1, r2, r3, r4}) }
r3, err := NewResource("r3", "", []Resource{r1, r2})
if event_manager == nil { if err != nil {
t.Fatal("Failed to add initial tiered resources for test") t.Fatal(err)
}
r4, err := NewResource("r4", "", []Resource{r1, r2})
if err != nil {
t.Fatal(err)
}
root_event, err := NewEvent("", "", []Resource{})
if err != nil {
t.Fatal(err)
}
test_event, err := NewEvent("", "", []Resource{})
if err != nil {
t.Fatal(err)
} }
r1_l := r1.UpdateChannel() r1_l := r1.UpdateChannel()
rel := root_event.UpdateChannel() rel := root_event.UpdateChannel()
err := LockResource(r3, root_event) err = LockResource(r3, root_event)
if err != nil { if err != nil {
t.Fatal("Failed to lock r3") t.Fatal("Failed to lock r3")
} }
@ -253,30 +260,29 @@ func TestLockResource(t * testing.T) {
} }
func TestAddToEventQueue(t * testing.T) { func TestAddToEventQueue(t * testing.T) {
queue := NewEventQueue("q", "", []Resource{}) queue, _ := NewEventQueue("q", "", []Resource{})
event_1 := NewEvent("1", "", []Resource{}) event_1, _ := NewEvent("1", "", []Resource{})
event_2 := NewEvent("2", "", []Resource{}) event_2, _ := NewEvent("2", "", []Resource{})
err := AddChild(queue, event_1, nil) err := LinkEvent(queue, event_1, nil)
if err == nil { if err == nil {
t.Fatal("suceeded in added nil info to queue") t.Fatal("suceeded in added nil info to queue")
} }
err = AddChild(queue, event_1, &EventQueueInfo{priority: 0}) err = LinkEvent(queue, event_1, &EventQueueInfo{priority: 0})
if err != nil { if err != nil {
t.Fatal("failed to add valid event + info to queue") t.Fatal("failed to add valid event + info to queue")
} }
err = AddChild(queue, event_2, &EventQueueInfo{priority: 1}) err = LinkEvent(queue, event_2, &EventQueueInfo{priority: 1})
if err != nil { if err != nil {
t.Fatal("failed to add valid event + info to queue") t.Fatal("failed to add valid event + info to queue")
} }
} }
func TestStartBaseEvent(t * testing.T) { func TestStartBaseEvent(t * testing.T) {
event_1 := NewEvent("TestStartBaseEvent event_1", "", []Resource{}) event_1, _ := NewEvent("TestStartBaseEvent event_1", "", []Resource{})
r := event_1.DoneResource() r := event_1.DoneResource()
manager := NewEventManager(event_1, []Resource{})
e_l := event_1.UpdateChannel() e_l := event_1.UpdateChannel()
r_l := r.UpdateChannel() r_l := r.UpdateChannel()
@ -287,7 +293,7 @@ func TestStartBaseEvent(t * testing.T) {
t.Fatal("r is not owned by event_1") t.Fatal("r is not owned by event_1")
} }
err := manager.Run() err := StartRootEvent(event_1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -302,25 +308,21 @@ func TestStartBaseEvent(t * testing.T) {
} }
func TestAbortEventQueue(t * testing.T) { func TestAbortEventQueue(t * testing.T) {
root_event := NewEventQueue("root_event", "", []Resource{}) r1, _ := NewResource("r1", "", []Resource{})
root_event, _ := NewEventQueue("root_event", "", []Resource{})
r := root_event.DoneResource() r := root_event.DoneResource()
manager := NewEventManager(root_event, []Resource{})
r1 := NewResource("r1", "", []Resource{})
err := manager.AddResource(r1)
if err != nil {
t.Fatal(err)
}
LockResource(r1, root_event) LockResource(r1, root_event)
e1 := NewEvent("event_1", "", []Resource{r1})
e1, _ := NewEvent("event_1", "", []Resource{r1})
e1_info := NewEventQueueInfo(1) e1_info := NewEventQueueInfo(1)
// Add an event so that the queue doesn't auto complete // Add an event so that the queue doesn't auto complete
err = manager.AddEvent(root_event, e1, e1_info) err := LinkEvent(root_event, e1, e1_info)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// Now that an event manager is constructed with a queue and 3 basic events // Now that the event is constructed with a queue and 3 basic events
// start the queue and check that all the events are executed // start the queue and check that all the events are executed
go func() { go func() {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
@ -328,9 +330,9 @@ func TestAbortEventQueue(t * testing.T) {
SendUpdate(root_event, abort_signal) SendUpdate(root_event, abort_signal)
}() }()
err = manager.Run() err = StartRootEvent(root_event)
if err == nil { if err == nil {
t.Fatal("event manager completed without error") t.Fatal("root_event completed without error")
} }
if r.Owner() == nil { if r.Owner() == nil {
@ -339,41 +341,40 @@ func TestAbortEventQueue(t * testing.T) {
} }
func TestStartEventQueue(t * testing.T) { func TestStartEventQueue(t * testing.T) {
root_event := NewEventQueue("root_event", "", []Resource{}) root_event, _ := NewEventQueue("root_event", "", []Resource{})
r := root_event.DoneResource() r := root_event.DoneResource()
rel := root_event.UpdateChannel(); rel := root_event.UpdateChannel();
res_1 := NewResource("test_resource_1", "", []Resource{}) res_1, _ := NewResource("test_resource_1", "", []Resource{})
res_2 := NewResource("test_resource_2", "", []Resource{}) res_2, _ := NewResource("test_resource_2", "", []Resource{})
manager := NewEventManager(root_event, []Resource{res_1, res_2})
e1:= NewEvent("e1", "", []Resource{res_1, res_2}) e1, _ := NewEvent("e1", "", []Resource{res_1, res_2})
e1_l := e1.UpdateChannel() e1_l := e1.UpdateChannel()
e1_r := e1.DoneResource() e1_r := e1.DoneResource()
e1_info := NewEventQueueInfo(1) e1_info := NewEventQueueInfo(1)
err := manager.AddEvent(root_event, e1, e1_info) err := LinkEvent(root_event, e1, e1_info)
if err != nil { if err != nil {
t.Fatal("Failed to add e1 to manager") t.Fatal("Failed to add e1 to root_event")
} }
(*GraphTester)(t).WaitForValue(rel, "child_added", root_event, time.Second, "No update on root_event after adding e1") (*GraphTester)(t).WaitForValue(rel, "child_added", root_event, time.Second, "No update on root_event after adding e1")
e2 := NewEvent("e2", "", []Resource{res_1}) e2, _ := NewEvent("e2", "", []Resource{res_1})
e2_l := e2.UpdateChannel() e2_l := e2.UpdateChannel()
e2_r := e2.DoneResource() e2_r := e2.DoneResource()
e2_info := NewEventQueueInfo(2) e2_info := NewEventQueueInfo(2)
err = manager.AddEvent(root_event, e2, e2_info) err = LinkEvent(root_event, e2, e2_info)
if err != nil { if err != nil {
t.Fatal("Failed to add e2 to manager") t.Fatal("Failed to add e2 to root_event")
} }
(*GraphTester)(t).WaitForValue(rel, "child_added", root_event, time.Second, "No update on root_event after adding e2") (*GraphTester)(t).WaitForValue(rel, "child_added", root_event, time.Second, "No update on root_event after adding e2")
e3 := NewEvent("e3", "", []Resource{res_2}) e3, _ := NewEvent("e3", "", []Resource{res_2})
e3_l := e3.UpdateChannel() e3_l := e3.UpdateChannel()
e3_r := e3.DoneResource() e3_r := e3.DoneResource()
e3_info := NewEventQueueInfo(3) e3_info := NewEventQueueInfo(3)
err = manager.AddEvent(root_event, e3, e3_info) err = LinkEvent(root_event, e3, e3_info)
if err != nil { if err != nil {
t.Fatal("Failed to add e3 to manager") t.Fatal("Failed to add e3 to root_event")
} }
(*GraphTester)(t).WaitForValue(rel, "child_added", root_event, time.Second, "No update on root_event after adding e3") (*GraphTester)(t).WaitForValue(rel, "child_added", root_event, time.Second, "No update on root_event after adding e3")
@ -386,7 +387,7 @@ func TestStartEventQueue(t * testing.T) {
} }
}() }()
// Now that an event manager is constructed with a queue and 3 basic events // Now that a root_event is constructed with a queue and 3 basic events
// start the queue and check that all the events are executed // start the queue and check that all the events are executed
go func() { go func() {
(*GraphTester)(t).WaitForValue(e1_l, "event_done", e1, time.Second, "No event_done for e3") (*GraphTester)(t).WaitForValue(e1_l, "event_done", e1, time.Second, "No event_done for e3")
@ -396,7 +397,7 @@ func TestStartEventQueue(t * testing.T) {
SendUpdate(root_event, signal) SendUpdate(root_event, signal)
}() }()
err = manager.Run() err = StartRootEvent(root_event)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

@ -12,8 +12,8 @@ func (resource * BaseResource) PropagateUpdate(signal GraphSignal) {
if signal.Downwards() == false { if signal.Downwards() == false {
// Child->Parent, resource updates parent resources // Child->Parent, resource updates parent resources
resource.parents_lock.Lock() resource.connection_lock.Lock()
defer resource.parents_lock.Unlock() defer resource.connection_lock.Unlock()
for _, parent := range resource.Parents() { for _, parent := range resource.Parents() {
SendUpdate(parent, signal) SendUpdate(parent, signal)
} }
@ -25,8 +25,8 @@ func (resource * BaseResource) PropagateUpdate(signal GraphSignal) {
SendUpdate(resource.lock_holder, signal) SendUpdate(resource.lock_holder, signal)
} }
resource.children_lock.Lock() resource.connection_lock.Lock()
defer resource.children_lock.Unlock() defer resource.connection_lock.Unlock()
for _, child := range(resource.children) { for _, child := range(resource.children) {
SendUpdate(child, signal) SendUpdate(child, signal)
} }
@ -43,9 +43,10 @@ type Resource interface {
Children() []Resource Children() []Resource
Parents() []Resource Parents() []Resource
AddParent(parent Resource) error AddParent(parent Resource)
LockParents() AddChild(child Resource)
UnlockParents() LockConnections()
UnlockConnections()
SetOwner(owner GraphNode) SetOwner(owner GraphNode)
LockState() LockState()
@ -56,24 +57,46 @@ type Resource interface {
unlock(node GraphNode) error unlock(node GraphNode) error
} }
func AddParent(resource Resource, parent Resource) error { // Recurse up cur's parents to ensure r is not present
if parent.ID() == resource.ID() { func checkIfParent(r Resource, cur Resource) bool {
error_str := fmt.Sprintf("Will not add %s as parent of itself", parent.Name()) if r == nil || cur == nil {
return errors.New(error_str) panic("Cannot recurse DAG with nil")
} }
resource.LockParents() if r.ID() == cur.ID() {
for _, p := range resource.Parents() { return true
if p.ID() == parent.ID() { }
error_str := fmt.Sprintf("%s is already a parent of %s, will not double-bond", p.Name(), resource.Name())
return errors.New(error_str) cur.LockConnections()
defer cur.UnlockConnections()
for _, p := range(cur.Parents()) {
if checkIfParent(r, p) == true {
return true
} }
} }
err := resource.AddParent(parent) return false
resource.UnlockParents() }
return err // Recurse doen cur's children to ensure r is not present
func checkIfChild(r Resource, cur Resource) bool {
if r == nil || cur == nil {
panic("Cannot recurse DAG with nil")
}
if r.ID() == cur.ID() {
return true
}
cur.LockConnections()
defer cur.UnlockConnections()
for _, c := range(cur.Children()) {
if checkIfChild(r, c) == true {
return true
}
}
return false
} }
func UnlockResource(resource Resource, event Event) error { func UnlockResource(resource Resource, event Event) error {
@ -149,9 +172,8 @@ func LockResource(resource Resource, node GraphNode) error {
type BaseResource struct { type BaseResource struct {
BaseNode BaseNode
parents []Resource parents []Resource
parents_lock sync.Mutex
children []Resource children []Resource
children_lock sync.Mutex connection_lock sync.Mutex
lock_holder GraphNode lock_holder GraphNode
lock_holder_lock sync.Mutex lock_holder_lock sync.Mutex
state_lock sync.Mutex state_lock sync.Mutex
@ -196,30 +218,72 @@ func (resource * BaseResource) Parents() []Resource {
return resource.parents return resource.parents
} }
func (resource * BaseResource) LockParents() { func (resource * BaseResource) LockConnections() {
resource.parents_lock.Lock() resource.connection_lock.Lock()
} }
func (resource * BaseResource) UnlockParents() { func (resource * BaseResource) UnlockConnections() {
resource.parents_lock.Unlock() resource.connection_lock.Unlock()
} }
func (resource * BaseResource) AddParent(parent Resource) error { func (resource * BaseResource) AddParent(parent Resource) {
resource.parents = append(resource.parents, parent) resource.parents = append(resource.parents, parent)
return nil
} }
func NewBaseResource(name string, description string, children []Resource) BaseResource { func (resource * BaseResource) AddChild(child Resource) {
resource.children = append(resource.children, child)
}
func NewBaseResource(name string, description string) BaseResource {
resource := BaseResource{ resource := BaseResource{
BaseNode: NewBaseNode(name, description, randid()), BaseNode: NewBaseNode(name, description, randid()),
parents: []Resource{}, parents: []Resource{},
children: children, children: []Resource{},
} }
return resource return resource
} }
func NewResource(name string, description string, children []Resource) * BaseResource { func LinkResource(resource Resource, child Resource) error {
resource := NewBaseResource(name, description, children) if child == nil || resource == nil {
return &resource return fmt.Errorf("Will not connect nil to resource DAG")
} else if child.ID() == resource.ID() {
return fmt.Errorf("Will not connect resource to itself")
}
if checkIfChild(resource, child) {
return fmt.Errorf("%s is a child of %s, cannot add as parent", resource.Name(), child.Name())
}
for _, p := range(resource.Parents()) {
if checkIfParent(child, p) {
return fmt.Errorf("Will not add %s as a parent of itself", child.Name())
}
}
child.AddParent(resource)
resource.AddChild(child)
return nil
}
func LinkResources(resource Resource, children []Resource) error {
for _, c := range(children) {
err := LinkResource(resource, c)
if err != nil {
return err
}
}
return nil
}
func NewResource(name string, description string, children []Resource) (* BaseResource, error) {
resource := NewBaseResource(name, description)
resource_ptr := &resource
err := LinkResources(resource_ptr, children)
if err != nil {
return nil, err
}
return resource_ptr, nil
} }