Refactor component/extras into snapshotting

This commit is contained in:
Tom Wiesing 2022-10-04 10:25:51 +02:00
parent 6d9c83c842
commit 6f409be8b2
No known key found for this signature in database
9 changed files with 81 additions and 79 deletions

View file

@ -1,2 +0,0 @@
// Package extras implements additional components to be used for backups and snapshots
package extras

View file

@ -31,29 +31,7 @@ func (p *Pool) init() {
}) })
} }
// ComponentDescription describes a component // Find finds all components of the specific subtype
type ComponentDescription struct {
Type reflect.Type
Elem reflect.Type
Name string
}
// New creates a new ComponentDescription
func (cd ComponentDescription) New() any {
return reflect.New(cd.Elem).Interface()
}
// GetDescription gets the description of a component type
func GetDescription[C Component]() (desc ComponentDescription) {
desc.Type = reflectx.TypeOf[C]()
if desc.Type.Kind() != reflect.Pointer {
panic("GetDescription: C must be backed by a pointer")
}
desc.Elem = desc.Type.Elem()
desc.Name = desc.Elem.PkgPath() + "." + desc.Elem.Name()
return
}
func Find[C Component](components []Component) C { func Find[C Component](components []Component) C {
for _, c := range components { for _, c := range components {
if cc, ok := c.(C); ok { if cc, ok := c.(C); ok {
@ -63,17 +41,20 @@ func Find[C Component](components []Component) C {
panic("FindComponent: Invalid arguments") panic("FindComponent: Invalid arguments")
} }
// Put initializes a single component in the pool. // InitComponent initializes a specific component and caches it within the given pool.
//
// Concurrent calls of InitComponent must use a distinct thread parameter.
// Nested calls of InitComponent should use the same thread parameter.
// //
// Init may initialize components, but not call functions on them! // Init may initialize components, but not call functions on them!
func PutComponent[C Component](p *Pool, thread int32, core Core, init func(component C, thread int32)) C { func InitComponent[C Component](p *Pool, thread int32, core Core, init func(component C, thread int32)) C {
p.init() p.init()
p.rLock.Lock(int(thread)) p.rLock.Lock(int(thread))
defer p.rLock.Unlock() defer p.rLock.Unlock()
// get a description of the type // get a description of the type
cd := GetDescription[C]() cd := getComponent[C]()
// find a field to put the component into // find a field to put the component into
instance, created := func() (C, bool) { instance, created := func() (C, bool) {
@ -129,3 +110,26 @@ func PutComponent[C Component](p *Pool, thread int32, core Core, init func(compo
// and return the instance // and return the instance
return instance return instance
} }
// getComponent gets the component belonging to a component type
func getComponent[C Component]() (desc component) {
tp := reflectx.TypeOf[C]()
if tp.Kind() != reflect.Pointer {
panic("getComponent: C must be backed by a pointer")
// should never be reached!
}
desc.Elem = tp.Elem()
desc.Name = desc.Elem.PkgPath() + "." + desc.Elem.Name()
return
}
// component represents a component
type component struct {
Elem reflect.Type // the element type of the component
Name string // the name of the component
}
// New creates a new ComponentDescription
func (cd component) New() any {
return reflect.New(cd.Elem).Interface()
}

View file

@ -1,4 +1,4 @@
package extras package snapshots
import ( import (
"fmt" "fmt"

View file

@ -1,4 +1,4 @@
package extras package snapshots
import ( import (
"path/filepath" "path/filepath"

View file

@ -1,4 +1,4 @@
package extras package snapshots
import ( import (
"github.com/FAU-CDI/wisski-distillery/internal/component" "github.com/FAU-CDI/wisski-distillery/internal/component"

View file

@ -1,4 +1,4 @@
package extras package snapshots
import ( import (
"io" "io"

View file

@ -6,7 +6,6 @@ import (
"github.com/FAU-CDI/wisski-distillery/internal/component" "github.com/FAU-CDI/wisski-distillery/internal/component"
"github.com/FAU-CDI/wisski-distillery/internal/component/control" "github.com/FAU-CDI/wisski-distillery/internal/component/control"
"github.com/FAU-CDI/wisski-distillery/internal/component/extras"
"github.com/FAU-CDI/wisski-distillery/internal/component/instances" "github.com/FAU-CDI/wisski-distillery/internal/component/instances"
"github.com/FAU-CDI/wisski-distillery/internal/component/snapshots" "github.com/FAU-CDI/wisski-distillery/internal/component/snapshots"
"github.com/FAU-CDI/wisski-distillery/internal/component/sql" "github.com/FAU-CDI/wisski-distillery/internal/component/sql"
@ -25,6 +24,16 @@ type components struct {
pool component.Pool pool component.Pool
} }
// c initializes a component of the provided type
func c[C component.Component](dis *Distillery, thread int32, init func(component C, thread int32)) C {
return component.InitComponent(&dis.pool, thread, dis.Core, init)
}
// cc is like c, but with init set to nil
func cc[C component.Component](dis *Distillery, thread int32) C {
return c[C](dis, thread, nil)
}
// //
// Individual Components // Individual Components
// //
@ -34,22 +43,22 @@ func (c *components) thread() int32 {
} }
func (dis *Distillery) cWeb(thread int32) *web.Web { func (dis *Distillery) cWeb(thread int32) *web.Web {
return component.PutComponent[*web.Web](&dis.pool, thread, dis.Core, nil) return component.InitComponent[*web.Web](&dis.pool, thread, dis.Core, nil)
} }
func (dis *Distillery) cControl(thread int32) *control.Control { func (dis *Distillery) cControl(thread int32) *control.Control {
return component.PutComponent(&dis.pool, thread, dis.Core, func(control *control.Control, thread int32) { return component.InitComponent(&dis.pool, thread, dis.Core, func(control *control.Control, thread int32) {
control.ResolverFile = core.PrefixConfig control.ResolverFile = core.PrefixConfig
control.Instances = dis.cInstances(thread) control.Instances = dis.cInstances(thread)
}) })
} }
func (dis *Distillery) cSSH(thread int32) *ssh.SSH { func (dis *Distillery) cSSH(thread int32) *ssh.SSH {
return component.PutComponent[*ssh.SSH](&dis.pool, thread, dis.Core, nil) return component.InitComponent[*ssh.SSH](&dis.pool, thread, dis.Core, nil)
} }
func (dis *Distillery) cSQL(thread int32) *sql.SQL { func (dis *Distillery) cSQL(thread int32) *sql.SQL {
return component.PutComponent(&dis.pool, thread, dis.Core, func(sql *sql.SQL, thread int32) { return component.InitComponent(&dis.pool, thread, dis.Core, func(sql *sql.SQL, thread int32) {
sql.ServerURL = dis.Upstream.SQL sql.ServerURL = dis.Upstream.SQL
sql.PollContext = dis.Context() sql.PollContext = dis.Context()
sql.PollInterval = time.Second sql.PollInterval = time.Second
@ -57,7 +66,7 @@ func (dis *Distillery) cSQL(thread int32) *sql.SQL {
} }
func (dis *Distillery) cTriplestore(thread int32) *triplestore.Triplestore { func (dis *Distillery) cTriplestore(thread int32) *triplestore.Triplestore {
return component.PutComponent(&dis.pool, thread, dis.Core, func(ts *triplestore.Triplestore, thread int32) { return component.InitComponent(&dis.pool, thread, dis.Core, func(ts *triplestore.Triplestore, thread int32) {
ts.BaseURL = "http://" + dis.Upstream.Triplestore ts.BaseURL = "http://" + dis.Upstream.Triplestore
ts.PollContext = dis.Context() ts.PollContext = dis.Context()
ts.PollInterval = time.Second ts.PollInterval = time.Second
@ -65,14 +74,14 @@ func (dis *Distillery) cTriplestore(thread int32) *triplestore.Triplestore {
} }
func (dis *Distillery) cInstances(thread int32) *instances.Instances { func (dis *Distillery) cInstances(thread int32) *instances.Instances {
return component.PutComponent(&dis.pool, thread, dis.Core, func(instances *instances.Instances, thread int32) { return component.InitComponent(&dis.pool, thread, dis.Core, func(instances *instances.Instances, thread int32) {
instances.SQL = dis.cSQL(thread) instances.SQL = dis.cSQL(thread)
instances.TS = dis.cTriplestore(thread) instances.TS = dis.cTriplestore(thread)
}) })
} }
func (dis *Distillery) cSnapshotManager(thread int32) *snapshots.Manager { func (dis *Distillery) cSnapshotManager(thread int32) *snapshots.Manager {
return component.PutComponent(&dis.pool, thread, dis.Core, func(snapshots *snapshots.Manager, thread int32) { return component.InitComponent(&dis.pool, thread, dis.Core, func(snapshots *snapshots.Manager, thread int32) {
snapshots.SQL = dis.cSQL(thread) snapshots.SQL = dis.cSQL(thread)
snapshots.Instances = dis.cInstances(thread) snapshots.Instances = dis.cInstances(thread)
snapshots.Snapshotable = dis.cSnapshotable(thread) snapshots.Snapshotable = dis.cSnapshotable(thread)
@ -80,28 +89,6 @@ func (dis *Distillery) cSnapshotManager(thread int32) *snapshots.Manager {
}) })
} }
//
// EXTRAS COMPONENTS
//
func (dis *Distillery) cExtrasConfig(thread int32) *extras.Config {
return component.PutComponent[*extras.Config](&dis.pool, thread, dis.Core, nil)
}
func (dis *Distillery) cExtrasBookkeeping(thread int32) *extras.Bookkeeping {
return component.PutComponent[*extras.Bookkeeping](&dis.pool, thread, dis.Core, nil)
}
func (dis *Distillery) cExtrasFilesystem(thread int32) *extras.Filesystem {
return component.PutComponent[*extras.Filesystem](&dis.pool, thread, dis.Core, nil)
}
func (dis *Distillery) cExtrasPathbuilders(thread int32) *extras.Pathbuilders {
return component.PutComponent(&dis.pool, thread, dis.Core, func(pbs *extras.Pathbuilders, thread int32) {
pbs.Instances = dis.cInstances(thread)
})
}
// //
// ALL COMPONENTS // ALL COMPONENTS
// //
@ -114,12 +101,15 @@ func (dis *Distillery) cComponents(thread int32) []component.Component {
dis.cTriplestore(thread), dis.cTriplestore(thread),
dis.cSQL(thread), dis.cSQL(thread),
dis.cInstances(thread), dis.cInstances(thread),
dis.cSnapshotManager(thread),
dis.cExtrasConfig(thread), // Snapshots
dis.cExtrasBookkeeping(thread), dis.cSnapshotManager(thread),
dis.cExtrasFilesystem(thread), cc[*snapshots.Config](dis, thread),
dis.cExtrasPathbuilders(thread), cc[*snapshots.Bookkeeping](dis, thread),
cc[*snapshots.Filesystem](dis, thread),
c(dis, thread, func(pbs *snapshots.Pathbuilders, thread int32) {
pbs.Instances = dis.cInstances(thread)
}),
} }
} }
@ -147,12 +137,12 @@ func (dis *Distillery) cSnapshotable(thread int32) []component.Snapshotable {
return getComponentSubtype[component.Snapshotable](dis, thread) return getComponentSubtype[component.Snapshotable](dis, thread)
} }
func getComponentSubtype[T component.Component](dis *Distillery, thread int32) (components []T) { func getComponentSubtype[C component.Component](dis *Distillery, thread int32) (components []C) {
all := dis.cComponents(thread) all := dis.cComponents(thread)
components = make([]T, 0, len(all)) components = make([]C, 0, len(all))
for _, c := range all { for _, c := range all {
sc, ok := c.(T) sc, ok := c.(C)
if !ok { if !ok {
continue continue
} }

View file

@ -1,3 +1,4 @@
// Package dis provides the main distillery
package dis package dis
import ( import (

View file

@ -5,6 +5,7 @@ import (
"time" "time"
) )
// RLock is like [sync.Mutex], but permits recursive locking.
type RLock struct { type RLock struct {
m sync.Mutex // m is held internally m sync.Mutex // m is held internally
@ -13,32 +14,40 @@ type RLock struct {
counter uint64 counter uint64
} }
// Lock acquires this lock with the given id, and blocks until it can be aquired.
// Concurrent locks with the same ids do not block; however each should be unlocked with a call to unlock.
func (rm *RLock) Lock(id int) { func (rm *RLock) Lock(id int) {
loop:
for { for {
rm.m.Lock() rm.m.Lock()
if !rm.held { switch {
case !rm.held:
rm.held = true rm.held = true
rm.holder = id rm.holder = id
break break loop
} else if rm.held && rm.holder == id { case rm.held && rm.holder == id:
break break loop
} else {
rm.m.Unlock()
time.Sleep(time.Millisecond)
continue
} }
rm.m.Unlock()
time.Sleep(time.Millisecond) // spinning!
} }
rm.counter++ rm.counter++
rm.m.Unlock() rm.m.Unlock()
} }
// Unlock releases the lock
func (rm *RLock) Unlock() { func (rm *RLock) Unlock() {
rm.m.Lock() rm.m.Lock()
defer rm.m.Unlock()
if !rm.held || rm.counter <= 0 {
panic("RLock: Unlock() without Lock()")
}
rm.counter-- rm.counter--
if rm.counter == 0 { if rm.counter == 0 {
rm.held = false rm.held = false
rm.holder = 0 rm.holder = 0
} }
rm.m.Unlock()
} }