Refactor component/extras into snapshotting
This commit is contained in:
parent
6d9c83c842
commit
6f409be8b2
9 changed files with 81 additions and 79 deletions
|
|
@ -1,2 +0,0 @@
|
||||||
// Package extras implements additional components to be used for backups and snapshots
|
|
||||||
package extras
|
|
||||||
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package extras
|
package snapshots
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package extras
|
package snapshots
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
@ -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"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package extras
|
package snapshots
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Package dis provides the main distillery
|
||||||
package dis
|
package dis
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -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()
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue