Skip to content

Commit

Permalink
feat: add links and unlinks
Browse files Browse the repository at this point in the history
  • Loading branch information
siyul-park committed Oct 3, 2024
1 parent decce40 commit 5911ca9
Show file tree
Hide file tree
Showing 2 changed files with 258 additions and 0 deletions.
175 changes: 175 additions & 0 deletions pkg/chart/table.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
package chart

import (
"slices"
"sync"

"github.com/gofrs/uuid"
)

type Table struct {
charts map[uuid.UUID]*Chart
namespaces map[string]map[string]uuid.UUID
refences map[uuid.UUID][]uuid.UUID
mu sync.RWMutex
}

func NewTable() *Table {
return &Table{
charts: make(map[uuid.UUID]*Chart),
namespaces: make(map[string]map[string]uuid.UUID),
refences: make(map[uuid.UUID][]uuid.UUID),
}
}

func (t *Table) Insert(chrt *Chart) error {
t.mu.Lock()
defer t.mu.Unlock()

if _, err := t.free(chrt.GetID()); err != nil {
return err
}
return t.insert(chrt)
}

func (t *Table) Free(id uuid.UUID) (bool, error) {
t.mu.Lock()
defer t.mu.Unlock()

chrt, err := t.free(id)
if err != nil {
return false, err
}
return chrt != nil, nil
}

func (t *Table) Lookup(id uuid.UUID) *Chart {
t.mu.RLock()
defer t.mu.RUnlock()

return t.charts[id]
}

func (t *Table) Close() error {
t.mu.Lock()
defer t.mu.Unlock()

for id := range t.charts {
if _, err := t.free(id); err != nil {
return err
}
}
return nil
}

func (t *Table) insert(chrt *Chart) error {
t.charts[chrt.GetID()] = chrt

ns, ok := t.namespaces[chrt.GetNamespace()]
if !ok {
ns = make(map[string]uuid.UUID)
t.namespaces[chrt.GetNamespace()] = ns
}
ns[chrt.GetName()] = chrt.GetID()

t.links(chrt)
return nil
}

func (t *Table) free(id uuid.UUID) (*Chart, error) {
chrt, ok := t.charts[id]
if !ok {
return nil, nil
}

t.unlinks(chrt)

if ns, ok := t.namespaces[chrt.GetNamespace()]; ok {
delete(ns, chrt.GetName())
if len(ns) == 0 {
delete(t.namespaces, chrt.GetNamespace())
}
}

delete(t.charts, id)

return chrt, nil
}

func (t *Table) links(chrt *Chart) {
for _, spec := range chrt.GetSpecs() {
id := t.lookup(chrt.GetNamespace(), spec.GetKind())
if !slices.Contains(t.refences[id], chrt.GetID()) {
t.refences[id] = append(t.refences[id], chrt.GetID())
}
}

for _, ref := range t.charts {
for _, spec := range ref.GetSpecs() {
id := t.lookup(ref.GetNamespace(), spec.GetKind())
if id == chrt.GetID() {
if !slices.Contains(t.refences[id], ref.GetID()) {
t.refences[id] = append(t.refences[id], ref.GetID())
}
}
}
}
}

func (t *Table) unlinks(chrt *Chart) {
for _, spec := range chrt.GetSpecs() {
id := t.lookup(chrt.GetNamespace(), spec.GetKind())

refences := t.refences[id]
for i := 0; i < len(refences); i++ {
if refences[i] == chrt.GetID() {
refences = append(refences[:i], refences[i+1:]...)
i--
}
}

if len(refences) > 0 {
t.refences[id] = refences
} else {
delete(t.refences, id)
}
}

delete(t.refences, chrt.GetID())
}

func (t *Table) active(chrt *Chart) bool {

Check failure on line 141 in pkg/chart/table.go

View workflow job for this annotation

GitHub Actions / Check ubuntu-22.04 @ Go 1.23

func (*Table).active is unused (U1000)
var linked []*Chart

nexts := []*Chart{chrt}
for len(nexts) > 0 {
chrt := nexts[len(nexts)-1]
ok := true
for _, sp := range chrt.Specs {
id := t.lookup(chrt.GetNamespace(), sp.GetKind())
next := t.charts[id]

if next == nil || slices.Contains(nexts, next) {
return false
}

ok = slices.Contains(linked, next)
if !ok {
nexts = append(nexts, next)
break
}
}
if ok {
nexts = nexts[0 : len(nexts)-1]
linked = append(linked, chrt)
}
}
return true
}

func (t *Table) lookup(namespace, name string) uuid.UUID {
if ns, ok := t.namespaces[namespace]; ok {
return ns[name]
}
return uuid.Nil
}
83 changes: 83 additions & 0 deletions pkg/chart/table_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package chart

import (
"testing"

"github.com/go-faker/faker/v4"
"github.com/gofrs/uuid"
"github.com/siyul-park/uniflow/pkg/resource"
"github.com/siyul-park/uniflow/pkg/spec"
"github.com/stretchr/testify/assert"
)

func TestTable_Insert(t *testing.T) {
tb := NewTable()
defer tb.Close()

chrt := &Chart{
ID: uuid.Must(uuid.NewV7()),
Namespace: resource.DefaultNamespace,
Name: faker.UUIDHyphenated(),
Specs: []spec.Spec{
&spec.Meta{
ID: uuid.Must(uuid.NewV7()),
Kind: faker.UUIDHyphenated(),
Namespace: resource.DefaultNamespace,
Name: faker.UUIDHyphenated(),
},
},
}

err := tb.Insert(chrt)
assert.NoError(t, err)
assert.NotNil(t, tb.Lookup(chrt.GetID()))
}

func TestTable_Free(t *testing.T) {
tb := NewTable()
defer tb.Close()

chrt := &Chart{
ID: uuid.Must(uuid.NewV7()),
Namespace: resource.DefaultNamespace,
Name: faker.UUIDHyphenated(),
Specs: []spec.Spec{
&spec.Meta{
ID: uuid.Must(uuid.NewV7()),
Kind: faker.UUIDHyphenated(),
Namespace: resource.DefaultNamespace,
Name: faker.UUIDHyphenated(),
},
},
}

err := tb.Insert(chrt)
assert.NoError(t, err)

ok, err := tb.Free(chrt.GetID())
assert.NoError(t, err)
assert.True(t, ok)
}

func TestTable_Lookup(t *testing.T) {
tb := NewTable()
defer tb.Close()

chrt := &Chart{
ID: uuid.Must(uuid.NewV7()),
Namespace: resource.DefaultNamespace,
Name: faker.UUIDHyphenated(),
Specs: []spec.Spec{
&spec.Meta{
ID: uuid.Must(uuid.NewV7()),
Kind: faker.UUIDHyphenated(),
Namespace: resource.DefaultNamespace,
Name: faker.UUIDHyphenated(),
},
},
}

err := tb.Insert(chrt)
assert.NoError(t, err)
assert.Equal(t, chrt, tb.Lookup(chrt.GetID()))
}

0 comments on commit 5911ca9

Please sign in to comment.