Added constructor for EventManger that requires a single event with no children and a list of Resources ordered by dependency. Updated main and tests to match.

graph-rework
noah metz 2023-04-08 16:51:34 -06:00
parent d4da75d6a1
commit 81b3ab65bf
3 changed files with 96 additions and 67 deletions

@ -2,6 +2,7 @@ package main
import (
"fmt"
"log"
"errors"
"sync"
graphql "github.com/graph-gophers/graphql-go"
@ -112,6 +113,10 @@ func (resource * BaseResource) Update() error {
}
}
if resource.lock_holder != nil {
resource.lock_holder.Update()
}
return nil
}
@ -133,7 +138,7 @@ type Resource interface {
AddParent(parent Resource) error
Children() []Resource
Parents() []Resource
Lock() error
Lock(event Event) error
Unlock() error
}
@ -141,30 +146,30 @@ type BaseResource struct {
BaseNode
parents []Resource
children []Resource
locked bool
lock_holder Event
state_lock sync.Mutex
}
// Grab the state mutex and check the state, if unlocked continue to hold the mutex while doing the same for children
// When the bottom of a tree is reached(no more children) go back up and set the lock state
func (resource * BaseResource) Lock() error {
func (resource * BaseResource) Lock(event Event) error {
var err error = nil
locked := false
resource.state_lock.Lock()
if resource.locked == true {
if resource.lock_holder != nil {
err = errors.New("Resource already locked")
} else {
all_children_locked := true
for _, child := range resource.Children() {
err = child.Lock()
err = child.Lock(event)
if err != nil {
all_children_locked = false
break
}
}
if all_children_locked == true {
resource.locked = true
resource.lock_holder = event
locked = true
}
}
@ -183,7 +188,7 @@ func (resource * BaseResource) Unlock() error {
unlocked := false
resource.state_lock.Lock()
if resource.locked == false {
if resource.lock_holder == nil {
err = errors.New("Resource already unlocked")
} else {
all_children_unlocked := true
@ -195,7 +200,7 @@ func (resource * BaseResource) Unlock() error {
}
}
if all_children_unlocked == true{
resource.locked = false
resource.lock_holder = nil
unlocked = true
}
}
@ -348,12 +353,26 @@ type EventManager struct {
root_event Event
}
func NewEventManager() * EventManager {
state := &EventManager{
// root_event's requirements must be in dag_nodes, and dag_nodes must be ordered by dependency(no children first)
func NewEventManager(root_event Event, dag_nodes []Resource) * EventManager {
manager := &EventManager{
dag_nodes: map[graphql.ID]Resource{},
root_event: nil,
}
return state;
// Construct the DAG
for _, resource := range dag_nodes {
err := manager.AddResource(resource)
if err != nil {
log.Printf("Failed to add %s to EventManager: %s", resource.ID(), err)
return nil
}
}
manager.AddEvent(nil, root_event)
return manager;
}
func (manager * EventManager) FindResource(id graphql.ID) Resource {
@ -399,14 +418,10 @@ func (manager * EventManager) AddResource(resource Resource) error {
// Add resources created by the event to the DAG
// Add child to parent
func (manager * EventManager) AddEvent(parent Event, child Event) error {
if manager.root_event.FindChild(child.ID()) != nil {
error_str := fmt.Sprintf("Event %s already exists in the event tree, can not add again", child.ID())
return errors.New(error_str)
}
if manager.root_event.FindChild(parent.ID()) == nil {
error_str := fmt.Sprintf("Event %s is not present in the event tree, cannot add %s as child", parent.ID(), child.ID())
return errors.New(error_str)
if child == nil {
return errors.New("Cannot add nil Event to EventManager")
} else if len(child.Children()) != 0 {
return errors.New("Adding events recursively not implemented")
}
for _, resource := range child.RequiredResources() {
@ -425,7 +440,28 @@ func (manager * EventManager) AddEvent(parent Event, child Event) error {
}
}
parent.AddChild(child)
if manager.root_event == nil && parent != nil {
error_str := fmt.Sprintf("EventManager has no root, so can't add event to parent")
return errors.New(error_str)
} else if manager.root_event != nil && parent == nil {
// TODO
return errors.New("Replacing root event not implemented")
} else if manager.root_event == nil && parent == nil {
manager.root_event = child
} else {
if manager.root_event.FindChild(parent.ID()) == nil {
error_str := fmt.Sprintf("Event %s is not present in the event tree, cannot add %s as child", parent.ID(), child.ID())
return errors.New(error_str)
}
if manager.root_event.FindChild(child.ID()) != nil {
error_str := fmt.Sprintf("Event %s already exists in the event tree, can not add again", child.ID())
return errors.New(error_str)
}
parent.AddChild(child)
}
return nil
}

@ -50,9 +50,9 @@ func TestNewResourceAdd(t *testing.T) {
description := "A resource for testing"
children := []Resource{}
root_event := NewEvent("", "", []Resource{})
test_resource := NewResource(name, description, children)
event_manager := NewEventManager()
event_manager.AddResource(test_resource)
event_manager := NewEventManager(root_event, []Resource{test_resource})
res := event_manager.FindResource(test_resource.ID())
if res == nil {
@ -65,56 +65,48 @@ func TestNewResourceAdd(t *testing.T) {
}
func TestDoubleResourceAdd(t * testing.T) {
root_event := NewEvent("", "", []Resource{})
test_resource := NewResource("", "", []Resource{})
event_manager := NewEventManager()
err_1 := event_manager.AddResource(test_resource)
err_2 := event_manager.AddResource(test_resource)
event_manager := NewEventManager(root_event, []Resource{test_resource})
err := event_manager.AddResource(test_resource)
if err_1 != nil {
t.Fatalf("First AddResource returned error %s", err_1)
}
if err_2 == nil {
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()
event_manager := NewEventManager(root_event, []Resource{})
err := event_manager.AddResource(r2)
if err == nil {
t.Fatal("AddResource with missing child returned nil")
}
}
func TestTieredResourceAdd(t * testing.T) {
func TestTieredResource(t * testing.T) {
root_event := NewEvent("", "", []Resource{})
r1 := NewResource("r1", "", []Resource{})
r2 := NewResource("r2", "", []Resource{r1})
event_manager := NewEventManager()
err_1 := event_manager.AddResource(r1)
err_2 := event_manager.AddResource(r2)
if err_1 != nil || err_2 != nil {
t.Fatal("Failed adding tiered resource")
event_manager := NewEventManager(root_event, []Resource{r1, r2})
if event_manager == nil {
t.Fatal("Failed to create event manager with tiered resources")
}
}
func TestResourceUpdate(t * testing.T) {
root_event := NewEvent("", "", []Resource{})
r1 := NewResource("r1", "", []Resource{})
r2 := NewResource("r2", "", []Resource{})
r3 := NewResource("r3", "", []Resource{r1, r2})
r4 := NewResource("r4", "", []Resource{r3})
event_manager := NewEventManager()
err_1 := event_manager.AddResource(r1)
err_2 := event_manager.AddResource(r2)
err_3 := event_manager.AddResource(r3)
err_4 := event_manager.AddResource(r4)
if err_1 != nil || err_2 != nil || err_3 != nil || err_4 != nil {
event_manager := NewEventManager(root_event, []Resource{r1, r2, r3, r4})
if event_manager == nil {
t.Fatal("Failed to add initial tiered resources for test")
}
@ -145,41 +137,44 @@ func TestResourceUpdate(t * testing.T) {
(*graph_tester)(t).CheckForNil(r4_l)
}
func TestAddEvent(t * testing.T) {
}
func TestLockResource(t * testing.T) {
root_event := NewEvent("", "", []Resource{})
r1 := NewResource("r1", "", []Resource{})
r2 := NewResource("r2", "", []Resource{})
r3 := NewResource("r3", "", []Resource{r1, r2})
r4 := NewResource("r3", "", []Resource{r1, r2})
event_manager := NewEventManager()
err_1 := event_manager.AddResource(r1)
err_2 := event_manager.AddResource(r2)
err_3 := event_manager.AddResource(r3)
err_4 := event_manager.AddResource(r4)
event_manager := NewEventManager(root_event, []Resource{r1, r2, r3, r4})
if err_1 != nil || err_2 != nil || err_3 != nil || err_4 != nil {
if event_manager == nil {
t.Fatal("Failed to add initial tiered resources for test")
}
r1_l := r1.UpdateChannel()
rel := root_event.UpdateChannel()
err := r3.Lock()
err := r3.Lock(root_event)
if err != nil {
t.Fatal("Failed to lock r3")
}
(*graph_tester)(t).CheckForNil(r1_l)
(*graph_tester)(t).CheckForNil(rel)
err = r3.Lock()
err = r3.Lock(root_event)
if err == nil {
t.Fatal("Locked r3 after locking r3")
}
err = r4.Lock()
err = r4.Lock(root_event)
if err == nil {
t.Fatal("Locked r4 after locking r3")
}
err = r1.Lock()
err = r1.Lock(root_event)
if err == nil {
t.Fatal("Locked r1 after locking r3")
}
@ -189,16 +184,19 @@ func TestLockResource(t * testing.T) {
t.Fatal("Failed to unlock r3")
}
(*graph_tester)(t).CheckForNil(r1_l)
(*graph_tester)(t).CheckForNil(rel)
err = r4.Lock()
err = r4.Lock(root_event)
if err != nil {
t.Fatal("Failed to lock r4 after unlocking r3")
}
(*graph_tester)(t).CheckForNil(r1_l)
(*graph_tester)(t).CheckForNil(rel)
err = r4.Unlock()
if err != nil {
t.Fatal("Failed to unlock r4")
}
(*graph_tester)(t).CheckForNil(r1_l)
(*graph_tester)(t).CheckForNil(rel)
}

@ -5,7 +5,7 @@ import (
)
func fake_data() * EventManager {
event_manager := NewEventManager()
resources := []Resource{}
teams := []*Team{}
teams = append(teams, NewTeam("6659", "A", []string{"jimmy"}))
@ -22,25 +22,20 @@ func fake_data() * EventManager {
teams = append(teams, NewTeam("315", "Z", []string{"emily"}))
for _, team := range teams {
err := event_manager.AddResource(team)
if err != nil {
log.Print(err)
}
resources = append(resources, team)
}
alliances := []Resource{}
for i, team := range teams[:len(teams)-1] {
for _, team2 := range teams[i+1:] {
alliance := NewAlliance(team, team2)
alliances = append(alliances, alliance)
err := event_manager.AddResource(alliance)
if err != nil {
log.Print(err)
}
resources = append(resources, alliance)
}
}
root_event := NewEvent("root_event", "", []Resource{})
event_manager := NewEventManager(root_event, resources)
return event_manager
}