commit 4bd7742672fc8f9f0bfb75cbf5528098ee7998d9
parent f968d80d5e87723702e9d64777f735747b4ba95e
Author: lash <dev@holbrook.no>
Date: Mon, 2 Sep 2024 02:15:09 +0100
Complete engine refactor
Diffstat:
9 files changed, 86 insertions(+), 394 deletions(-)
diff --git a/engine/db.go b/engine/db.go
@@ -15,7 +15,7 @@ import (
"git.defalsify.org/vise.git/vm"
)
-type DbEngine struct {
+type dbEngine struct {
st *state.State
ca cache.Memory
vm *vm.Vm
@@ -28,11 +28,11 @@ type DbEngine struct {
exit string
}
-func NewDbEngine(cfg Config, rs resource.Resource) *DbEngine {
+func NewEngine(cfg Config, rs resource.Resource) *dbEngine {
if rs == nil {
panic("resource cannot be nil")
}
- en := &DbEngine{
+ en := &dbEngine{
rs: rs,
cfg: cfg,
}
@@ -42,7 +42,7 @@ func NewDbEngine(cfg Config, rs resource.Resource) *DbEngine {
return en
}
-func(en *DbEngine) WithState(st *state.State) *DbEngine {
+func(en *dbEngine) WithState(st *state.State) *dbEngine {
if en.st != nil {
panic("state already set")
}
@@ -53,7 +53,7 @@ func(en *DbEngine) WithState(st *state.State) *DbEngine {
return en
}
-func(en *DbEngine) WithCache(ca cache.Memory) *DbEngine {
+func(en *dbEngine) WithMemory(ca cache.Memory) *dbEngine {
if en.ca != nil {
panic("cache already set")
}
@@ -64,7 +64,7 @@ func(en *DbEngine) WithCache(ca cache.Memory) *DbEngine {
return en
}
-func(en *DbEngine) WithResource(rs resource.Resource) *DbEngine {
+func(en *dbEngine) WithResource(rs resource.Resource) *dbEngine {
if en.rs != nil {
panic("resource already set")
}
@@ -75,7 +75,7 @@ func(en *DbEngine) WithResource(rs resource.Resource) *DbEngine {
return en
}
-func(en *DbEngine) WithPersister(pe *persist.Persister) *DbEngine {
+func(en *dbEngine) WithPersister(pe *persist.Persister) *dbEngine {
if en.pe != nil {
panic("persister already set")
}
@@ -86,7 +86,7 @@ func(en *DbEngine) WithPersister(pe *persist.Persister) *DbEngine {
return en
}
-func(en *DbEngine) WithDebug(dbg Debug) *DbEngine {
+func(en *dbEngine) WithDebug(dbg Debug) *dbEngine {
if en.dbg != nil {
panic("debugger already set")
}
@@ -98,7 +98,7 @@ func(en *DbEngine) WithDebug(dbg Debug) *DbEngine {
return en
}
-func(en *DbEngine) WithFirst(fn resource.EntryFunc) *DbEngine {
+func(en *dbEngine) WithFirst(fn resource.EntryFunc) *dbEngine {
if en.first != nil {
panic("firstfunc already set")
}
@@ -109,7 +109,7 @@ func(en *DbEngine) WithFirst(fn resource.EntryFunc) *DbEngine {
return en
}
-func(en *DbEngine) ensureState() {
+func(en *dbEngine) ensureState() {
if en.st == nil {
st := state.NewState(en.cfg.FlagCount)
en.st = &st
@@ -130,7 +130,7 @@ func(en *DbEngine) ensureState() {
}
}
-func(en *DbEngine) ensureMemory() error {
+func(en *dbEngine) ensureMemory() error {
cac, ok := en.ca.(*cache.Cache)
if cac == nil {
ca := cache.NewCache()
@@ -146,7 +146,7 @@ func(en *DbEngine) ensureMemory() error {
return nil
}
-func(en *DbEngine) preparePersist() error {
+func(en *dbEngine) preparePersist() error {
if en.pe == nil {
return nil
}
@@ -185,7 +185,7 @@ func(en *DbEngine) preparePersist() error {
return nil
}
-func(en *DbEngine) ensurePersist() error {
+func(en *dbEngine) ensurePersist() error {
if en.pe == nil {
return nil
}
@@ -208,7 +208,7 @@ func(en *DbEngine) ensurePersist() error {
return nil
}
-func(en *DbEngine) setupVm() {
+func(en *dbEngine) setupVm() {
var szr *render.Sizer
if en.cfg.OutputSize > 0 {
szr = render.NewSizer(en.cfg.OutputSize)
@@ -216,7 +216,7 @@ func(en *DbEngine) setupVm() {
en.vm = vm.NewVm(en.st, en.rs, en.ca, szr)
}
-func(en *DbEngine) prepare() error {
+func(en *dbEngine) prepare() error {
err := en.preparePersist()
if err != nil {
return err
@@ -235,7 +235,7 @@ func(en *DbEngine) prepare() error {
}
// execute the first function, if set
-func(en *DbEngine) runFirst(ctx context.Context) (bool, error) {
+func(en *dbEngine) runFirst(ctx context.Context) (bool, error) {
var err error
var r bool
if en.first == nil {
@@ -274,7 +274,7 @@ func(en *DbEngine) runFirst(ctx context.Context) (bool, error) {
}
// Finish implements EngineIsh interface
-func(en *DbEngine) Finish() error {
+func(en *dbEngine) Finish() error {
var perr error
if en.pe != nil {
perr = en.pe.Save(en.cfg.SessionId)
@@ -294,7 +294,7 @@ func(en *DbEngine) Finish() error {
}
// change root to current state location if non-empty.
-func(en *DbEngine) restore() {
+func(en *dbEngine) restore() {
location, _ := en.st.Where()
if len(location) == 0 {
return
@@ -308,7 +308,7 @@ func(en *DbEngine) restore() {
// Init must be explicitly called before using the Engine instance.
//
// It loads and executes code for the start node.
-func(en *DbEngine) Init(ctx context.Context) (bool, error) {
+func(en *dbEngine) Init(ctx context.Context) (bool, error) {
err := en.prepare()
if err != nil {
return false, err
@@ -364,7 +364,7 @@ func(en *DbEngine) Init(ctx context.Context) (bool, error) {
// - input is formally invalid (too long etc)
// - no current bytecode is available
// - input processing against bytcode failed
-func (en *DbEngine) Exec(ctx context.Context, input []byte) (bool, error) {
+func (en *dbEngine) Exec(ctx context.Context, input []byte) (bool, error) {
var err error
if en.st.Language != nil {
ctx = context.WithValue(ctx, "Language", *en.st.Language)
@@ -388,7 +388,7 @@ func (en *DbEngine) Exec(ctx context.Context, input []byte) (bool, error) {
}
// backend for Exec, after the input validity check
-func(en *DbEngine) exec(ctx context.Context, input []byte) (bool, error) {
+func(en *dbEngine) exec(ctx context.Context, input []byte) (bool, error) {
logg.InfoCtxf(ctx, "new VM execution with input", "input", string(input))
code, err := en.st.GetCode()
if err != nil {
@@ -436,7 +436,7 @@ func(en *DbEngine) exec(ctx context.Context, input []byte) (bool, error) {
// - required data inputs to the template are not available.
// - the template for the given node point is note available for retrieval using the resource.Resource implementer.
// - the supplied writer fails to process the writes.
-func(en *DbEngine) WriteResult(ctx context.Context, w io.Writer) (int, error) {
+func(en *dbEngine) WriteResult(ctx context.Context, w io.Writer) (int, error) {
var l int
if en.st.Language != nil {
ctx = context.WithValue(ctx, "Language", *en.st.Language)
@@ -464,7 +464,7 @@ func(en *DbEngine) WriteResult(ctx context.Context, w io.Writer) (int, error) {
}
// start execution over at top node while keeping current state of client error flags.
-func(en *DbEngine) reset(ctx context.Context) (bool, error) {
+func(en *dbEngine) reset(ctx context.Context) (bool, error) {
var err error
var isTop bool
for !isTop {
diff --git a/engine/db_test.go b/engine/db_test.go
@@ -46,7 +46,7 @@ func TestDbEngineMinimal(t *testing.T) {
ctx := context.Background()
cfg := Config{}
rs := resource.NewMenuResource()
- en := NewDbEngine(cfg, rs)
+ en := NewEngine(cfg, rs)
cont, err := en.Init(ctx)
if err != nil {
t.Fatal(err)
@@ -67,7 +67,7 @@ func TestDbEngineRoot(t *testing.T) {
cfg := Config{}
rs := resource.NewMenuResource()
rs.WithCodeGetter(codeGet)
- en := NewDbEngine(cfg, rs)
+ en := NewEngine(cfg, rs)
cont, err := en.Init(ctx)
if err != nil {
t.Fatal(err)
@@ -110,7 +110,7 @@ func TestDbEnginePersist(t *testing.T) {
rs := resource.NewMenuResource()
rs.WithCodeGetter(codeGet)
rs.AddLocalFunc("foo", flagSet)
- en := NewDbEngine(cfg, rs)
+ en := NewEngine(cfg, rs)
en = en.WithPersister(pe)
cont, err := en.Init(ctx)
if err != nil {
diff --git a/engine/default.go b/engine/default.go
@@ -1,94 +0,0 @@
-package engine
-
-import (
- "context"
- "fmt"
-
- "git.defalsify.org/vise.git/cache"
- "git.defalsify.org/vise.git/persist"
- "git.defalsify.org/vise.git/resource"
- "git.defalsify.org/vise.git/state"
- "git.defalsify.org/vise.git/db"
- fsdb "git.defalsify.org/vise.git/db/fs"
-)
-
-// NewDefaultEngine is a convenience function to instantiate a filesystem-backed engine with no output constraints.
-func NewDefaultEngine(dir string, persistDb db.Db, session *string) (EngineIsh, error) {
- st := state.NewState(0)
- ctx := context.Background()
- store := fsdb.NewFsDb()
- err := store.Connect(ctx, dir)
- if err != nil {
- return nil, err
- }
- rs := resource.NewDbResource(store)
- rs.With(db.DATATYPE_STATICLOAD)
- ca := cache.NewCache()
- cfg := Config{
- Root: "root",
- }
- if session != nil {
- cfg.SessionId = *session
- } else if persistDb != nil {
- return nil, fmt.Errorf("session must be set if persist is used")
- }
- var en EngineIsh
- if persistDb != nil {
- pr := persist.NewPersister(persistDb)
- en, err = NewPersistedEngine(ctx, cfg, pr, rs)
- if err != nil {
- logg.Infof("persisted engine create error. trying again with persisting empty state first...")
- pr = pr.WithContent(&st, ca)
- err = pr.Save(cfg.SessionId)
- if err != nil {
- return nil, err
- }
- en, err = NewPersistedEngine(ctx, cfg, pr, rs)
- }
- } else {
- enb := NewEngine(ctx, cfg, &st, rs, ca)
- en = &enb
- }
- return en, err
-}
-
-// NewSizedEngine is a convenience function to instantiate a filesystem-backed engine with a specified output constraint.
-func NewSizedEngine(dir string, size uint32, persistDb db.Db, session *string) (EngineIsh, error) {
- st := state.NewState(0)
- ca := cache.NewCache()
- ctx := context.Background()
- store := fsdb.NewFsDb()
- err := store.Connect(ctx, dir)
- if err != nil {
- return nil, err
- }
- rs := resource.NewDbResource(store)
- rs.With(db.DATATYPE_STATICLOAD)
- cfg := Config{
- OutputSize: size,
- Root: "root",
- }
- if session != nil {
- cfg.SessionId = *session
- } else if persistDb != nil {
- return nil, fmt.Errorf("session must be set if persist is used")
- }
- var en EngineIsh
- if persistDb != nil {
- pr := persist.NewPersister(persistDb)
- en, err = NewPersistedEngine(ctx, cfg, pr, rs)
- if err != nil {
- logg.Infof("persisted engine create error. trying again with persisting empty state first...")
- pr = pr.WithContent(&st, ca)
- err = pr.Save(cfg.SessionId)
- if err != nil {
- return nil, err
- }
- en, err = NewPersistedEngine(ctx, cfg, pr, rs)
- }
- } else {
- enb := NewEngine(ctx, cfg, &st, rs, ca)
- en = &enb
- }
- return en, err
-}
diff --git a/engine/engine.go b/engine/engine.go
@@ -13,15 +13,15 @@ import (
)
// EngineIsh defines the interface for execution engines that handle vm initialization and execution, and rendering outputs.
-type EngineIsh interface {
+type Engine interface {
Init(ctx context.Context) (bool, error)
Exec(ctx context.Context, input []byte) (bool, error)
WriteResult(ctx context.Context, w io.Writer) (int, error)
Finish() error
}
-// Engine is an execution engine that handles top-level errors when running client inputs against code in the bytecode buffer.
-type Engine struct {
+// LegacyEngine is an execution engine that handles top-level errors when running client inputs against code in the bytecode buffer.
+type LegacyEngine struct {
st *state.State
rs resource.Resource
ca cache.Memory
@@ -34,14 +34,14 @@ type Engine struct {
exit string
}
-// NewEngine creates a new Engine
-func NewEngine(ctx context.Context, cfg Config, st *state.State, rs resource.Resource, ca cache.Memory) Engine {
+// NewLegacyEngine creates a new LegacyEngine
+func NewLegacyEngine(ctx context.Context, cfg Config, st *state.State, rs resource.Resource, ca cache.Memory) LegacyEngine {
var szr *render.Sizer
if cfg.OutputSize > 0 {
szr = render.NewSizer(cfg.OutputSize)
}
ctx = context.WithValue(ctx, "sessionId", cfg.SessionId)
- engine := Engine{
+ engine := LegacyEngine{
st: st,
rs: rs,
ca: ca,
@@ -70,23 +70,23 @@ func NewEngine(ctx context.Context, cfg Config, st *state.State, rs resource.Res
// SetDebugger sets a debugger to use.
//
// No debugger is set by default.
-func (en *Engine) SetDebugger(debugger Debug) {
+func (en *LegacyEngine) SetDebugger(debugger Debug) {
en.dbg = debugger
}
// SetFirst sets a function which will be executed before bytecode
-func(en *Engine) SetFirst(fn resource.EntryFunc) {
+func(en *LegacyEngine) SetFirst(fn resource.EntryFunc) {
en.first = fn
}
-// Finish implements EngineIsh interface
-func(en *Engine) Finish() error {
+// Finish implements LegacyEngineIsh interface
+func(en *LegacyEngine) Finish() error {
logg.Tracef("that's a wrap", "engine", en)
return nil
}
// change root to current state location if non-empty.
-func(en *Engine) restore() {
+func(en *LegacyEngine) restore() {
location, _ := en.st.Where()
if len(location) == 0 {
return
@@ -98,7 +98,7 @@ func(en *Engine) restore() {
}
// execute the first function, if set
-func(en *Engine) runFirst(ctx context.Context) (bool, error) {
+func(en *LegacyEngine) runFirst(ctx context.Context) (bool, error) {
var err error
var r bool
if en.first == nil {
@@ -136,10 +136,10 @@ func(en *Engine) runFirst(ctx context.Context) (bool, error) {
return r, err
}
-// Init must be explicitly called before using the Engine instance.
+// Init must be explicitly called before using the LegacyEngine instance.
//
// It loads and executes code for the start node.
-func(en *Engine) Init(ctx context.Context) (bool, error) {
+func(en *LegacyEngine) Init(ctx context.Context) (bool, error) {
en.restore()
if en.initd {
logg.DebugCtxf(ctx, "already initialized")
@@ -191,7 +191,7 @@ func(en *Engine) Init(ctx context.Context) (bool, error) {
// - input is formally invalid (too long etc)
// - no current bytecode is available
// - input processing against bytcode failed
-func (en *Engine) Exec(ctx context.Context, input []byte) (bool, error) {
+func (en *LegacyEngine) Exec(ctx context.Context, input []byte) (bool, error) {
var err error
if en.st.Language != nil {
ctx = context.WithValue(ctx, "Language", *en.st.Language)
@@ -215,7 +215,7 @@ func (en *Engine) Exec(ctx context.Context, input []byte) (bool, error) {
}
// backend for Exec, after the input validity check
-func(en *Engine) exec(ctx context.Context, input []byte) (bool, error) {
+func(en *LegacyEngine) exec(ctx context.Context, input []byte) (bool, error) {
logg.InfoCtxf(ctx, "new VM execution with input", "input", string(input))
code, err := en.st.GetCode()
if err != nil {
@@ -263,7 +263,7 @@ func(en *Engine) exec(ctx context.Context, input []byte) (bool, error) {
// - required data inputs to the template are not available.
// - the template for the given node point is note available for retrieval using the resource.Resource implementer.
// - the supplied writer fails to process the writes.
-func(en *Engine) WriteResult(ctx context.Context, w io.Writer) (int, error) {
+func(en *LegacyEngine) WriteResult(ctx context.Context, w io.Writer) (int, error) {
var l int
if en.st.Language != nil {
ctx = context.WithValue(ctx, "Language", *en.st.Language)
@@ -291,7 +291,7 @@ func(en *Engine) WriteResult(ctx context.Context, w io.Writer) (int, error) {
}
// start execution over at top node while keeping current state of client error flags.
-func(en *Engine) reset(ctx context.Context) (bool, error) {
+func(en *LegacyEngine) reset(ctx context.Context) (bool, error) {
var err error
var isTop bool
for !isTop {
diff --git a/engine/engine_test.go b/engine/engine_test.go
@@ -125,7 +125,9 @@ func TestEngineInit(t *testing.T) {
cfg := Config{
Root: "root",
}
- en := NewEngine(ctx, cfg, &st, &rs, ca)
+ en := NewEngine(cfg, &rs)
+ en = en.WithState(&st)
+ en = en.WithMemory(ca)
_, err = en.Init(ctx)
if err != nil {
@@ -183,7 +185,9 @@ func TestEngineExecInvalidInput(t *testing.T) {
cfg := Config{
Root: "root",
}
- en := NewEngine(ctx, cfg, &st, &rs, ca)
+ en := NewEngine(cfg, &rs)
+ en = en.WithState(&st)
+ en = en.WithMemory(ca)
var err error
_, err = en.Init(ctx)
if err != nil {
@@ -205,7 +209,9 @@ func TestEngineResumeTerminated(t *testing.T) {
cfg := Config{
Root: "root",
}
- en := NewEngine(ctx, cfg, &st, &rs, ca)
+ en := NewEngine(cfg, &rs)
+ en = en.WithState(&st)
+ en = en.WithMemory(ca)
var err error
_, err = en.Init(ctx)
if err != nil {
@@ -241,7 +247,9 @@ func TestLanguageSet(t *testing.T) {
cfg := Config{
Root: "root",
}
- en := NewEngine(ctx, cfg, &st, &rs, ca)
+ en := NewEngine(cfg, &rs)
+ en = en.WithState(&st)
+ en = en.WithMemory(ca)
var err error
_, err = en.Init(ctx)
@@ -294,7 +302,9 @@ func TestLanguageRender(t *testing.T) {
cfg := Config{
Root: "root",
}
- en := NewEngine(ctx, cfg, &st, &rs, ca)
+ en := NewEngine(cfg, &rs)
+ en = en.WithState(&st)
+ en = en.WithMemory(ca)
var err error
_, err = en.Init(ctx)
@@ -335,7 +345,9 @@ func TestConfigLanguageRender(t *testing.T) {
Root: "root",
Language: "nor",
}
- en := NewEngine(ctx, cfg, &st, &rs, ca)
+ en := NewEngine(cfg, &rs)
+ en = en.WithState(&st)
+ en = en.WithMemory(ca)
var err error
_, err = en.Init(ctx)
@@ -391,8 +403,10 @@ func TestPreVm(t *testing.T) {
cfg := Config{
Root: "root",
}
- en := NewEngine(ctx, cfg, &st, &rs, ca)
- en.SetFirst(preBlock)
+ en := NewEngine(cfg, &rs)
+ en = en.WithState(&st)
+ en = en.WithMemory(ca)
+ en = en.WithFirst(preBlock)
r, err := en.Init(ctx)
if err != nil {
t.Fatal(err)
@@ -411,8 +425,10 @@ func TestPreVm(t *testing.T) {
st = state.NewState(0)
ca = cache.NewCache()
- en = NewEngine(ctx, cfg, &st, &rs, ca)
- en.SetFirst(preAllow)
+ en = NewEngine(cfg, &rs)
+ en = en.WithState(&st)
+ en = en.WithMemory(ca)
+ en = en.WithFirst(preAllow)
r, err = en.Init(ctx)
if err != nil {
t.Fatal(err)
diff --git a/engine/loop.go b/engine/loop.go
@@ -17,7 +17,7 @@ import (
// Any error not handled by the engine will terminate the oop and return an error.
//
// Rendered output is written to the provided writer.
-func Loop(ctx context.Context, en EngineIsh, reader io.Reader, writer io.Writer) error {
+func Loop(ctx context.Context, en Engine, reader io.Reader, writer io.Writer) error {
defer en.Finish()
l, err := en.WriteResult(ctx, writer)
if err != nil {
diff --git a/engine/loop_test.go b/engine/loop_test.go
@@ -23,7 +23,10 @@ func TestLoopTop(t *testing.T) {
cfg := Config{
Root: "root",
}
- en := NewEngine(ctx, cfg, &st, rs, ca)
+ en := NewEngine(cfg, rs)
+ en = en.WithState(&st)
+ en = en.WithMemory(ca)
+
_, err = en.Init(ctx)
if err != nil {
t.Fatal(err)
@@ -39,7 +42,7 @@ func TestLoopTop(t *testing.T) {
outputBuf := bytes.NewBuffer(nil)
log.Printf("running with input: %s", inputBuf.Bytes())
- err = Loop(ctx, &en, inputBuf, outputBuf)
+ err = Loop(ctx, en, inputBuf, outputBuf)
if err != nil {
t.Fatal(err)
}
@@ -60,7 +63,10 @@ func TestLoopBackForth(t *testing.T) {
cfg := Config{
Root: "root",
}
- en := NewEngine(ctx, cfg, &st, rs, ca)
+ en := NewEngine(cfg, rs)
+ en = en.WithState(&st)
+ en = en.WithMemory(ca)
+
_, err = en.Init(ctx)
if err != nil {
t.Fatal(err)
@@ -77,7 +83,7 @@ func TestLoopBackForth(t *testing.T) {
outputBuf := bytes.NewBuffer(nil)
log.Printf("running with input: %s", inputBuf.Bytes())
- err = Loop(ctx, &en, inputBuf, outputBuf)
+ err = Loop(ctx, en, inputBuf, outputBuf)
if err != nil {
t.Fatal(err)
}
@@ -95,7 +101,10 @@ func TestLoopBrowse(t *testing.T) {
OutputSize: 68,
Root: "root",
}
- en := NewEngine(ctx, cfg, &st, rs, ca)
+ en := NewEngine(cfg, rs)
+ en = en.WithState(&st)
+ en = en.WithMemory(ca)
+
_, err = en.Init(ctx)
if err != nil {
t.Fatal(err)
@@ -113,7 +122,7 @@ func TestLoopBrowse(t *testing.T) {
outputBuf := bytes.NewBuffer(nil)
log.Printf("running with input: %s", inputBuf.Bytes())
- err = Loop(ctx, &en, inputBuf, outputBuf)
+ err = Loop(ctx, en, inputBuf, outputBuf)
if err != nil {
t.Fatal(err)
}
diff --git a/engine/persist.go b/engine/persist.go
@@ -1,93 +0,0 @@
-package engine
-
-import (
- "context"
- "io"
-
- "git.defalsify.org/vise.git/persist"
- "git.defalsify.org/vise.git/resource"
-)
-
-// PersistedEngine adds persisted state to the Engine object. It provides a persisted state option for synchronous/interactive clients.
-type PersistedEngine struct {
- *Engine
- pr *persist.Persister
-}
-
-
-// NewPersistedEngine creates a new PersistedEngine
-func NewPersistedEngine(ctx context.Context, cfg Config, pr *persist.Persister, rs resource.Resource) (PersistedEngine, error) {
- err := pr.Load(cfg.SessionId)
- if err != nil {
- return PersistedEngine{}, err
- }
- st := pr.GetState()
- ca := pr.GetMemory()
-
- enb := NewEngine(ctx, cfg, st, rs, ca)
- en := PersistedEngine{
- &enb,
- pr,
- }
- return en, err
-}
-
-// Exec executes the parent method Engine.Exec, and afterwards persists the new state.
-func(pe PersistedEngine) Exec(ctx context.Context, input []byte) (bool, error) {
- v, err := pe.Engine.Exec(ctx, input)
- if err != nil {
- return v, err
- }
- err = pe.pr.Save(pe.Engine.session)
- return v, err
-}
-
-// Finish implements EngineIsh interface
-func(pe PersistedEngine) Finish() error {
- logg.Tracef("that's a wrap", "engine", pe)
- return pe.pr.Save(pe.Engine.session)
-}
-
-// RunPersisted performs a single vm execution from client input using a persisted state.
-//
-// State is first loaded from storage. The vm is initialized with the state and executed. The new state is then saved to storage.
-//
-// The resulting output of the execution will be written to the provided writer.
-//
-// The state is identified by the SessionId member of the Config. Before first execution, the caller must ensure that an
-// initialized state actually is available for the identifier, otherwise the method will fail.
-//
-// It will also fail if execution by the underlying Engine fails.
-func RunPersisted(cfg Config, rs resource.Resource, pr *persist.Persister, input []byte, w io.Writer, ctx context.Context) error {
- err := pr.Load(cfg.SessionId)
- if err != nil {
- return err
- }
-
- st := pr.GetState()
- ca := pr.GetMemory()
- en := NewEngine(ctx, cfg, st, rs, ca)
-
- c, err := en.WriteResult(ctx, w)
- if err != nil {
- return err
- }
- err = pr.Save(cfg.SessionId)
- if err != nil {
- return err
- }
- if c > 0 {
- return err
- }
-
- _, err = en.Exec(ctx, input)
- if err != nil {
- return err
- }
- _, err = en.WriteResult(ctx, w)
- if err != nil {
- return err
- }
- en.Finish()
- return pr.Save(cfg.SessionId)
-}
diff --git a/engine/persist_test.go b/engine/persist_test.go
@@ -1,146 +0,0 @@
-package engine
-
-import (
- "context"
- "os"
- "testing"
-
- "git.defalsify.org/vise.git/cache"
- "git.defalsify.org/vise.git/persist"
- "git.defalsify.org/vise.git/state"
- memdb "git.defalsify.org/vise.git/db/mem"
-)
-
-func TestRunPersist(t *testing.T) {
- generateTestData(t)
- ctx := context.Background()
- cfg := Config{
- OutputSize: 83,
- SessionId: "xyzzy",
- Root: "root",
- }
- rs := newTestWrapper(dataDir, nil)
-
- st := state.NewState(3)
- ca := cache.NewCache().WithCacheSize(1024)
- store := memdb.NewMemDb()
- store.Connect(ctx, "")
- pr := persist.NewPersister(store).WithContent(&st, ca)
-
- w := os.Stdout
- ctx = context.Background()
-
- st = state.NewState(cfg.FlagCount)
- ca = cache.NewCache()
- ca = ca.WithCacheSize(cfg.CacheSize)
- pr = persist.NewPersister(store).WithContent(&st, ca)
- err := pr.Save(cfg.SessionId)
- if err != nil {
- t.Fatal(err)
- }
-
- pr = persist.NewPersister(store)
- inputs := []string{
- "", // trigger init, will not exec
- "1",
- "2",
- "00",
- }
- for _, v := range inputs {
- err = RunPersisted(cfg, rs, pr, []byte(v), w, ctx)
- if err != nil {
- t.Fatal(err)
- }
- }
-
- pr = persist.NewPersister(store)
- err = pr.Load(cfg.SessionId)
- if err != nil {
- t.Fatal(err)
- }
-
- stAfter := pr.GetState()
- location, idx := stAfter.Where()
- if location != "long" {
- t.Fatalf("expected 'long', got %s", location)
- }
- if idx != 1 {
- t.Fatalf("expected '1', got %v", idx)
- }
-}
-
-func TestEnginePersist(t *testing.T) {
- generateTestData(t)
- ctx := context.Background()
- cfg := Config{
- OutputSize: 83,
- SessionId: "xyzzy",
- Root: "root",
- }
- rs := newTestWrapper(dataDir, nil)
-
- st := state.NewState(3)
- ca := cache.NewCache().WithCacheSize(1024)
- store := memdb.NewMemDb()
- store.Connect(ctx, "")
- pr := persist.NewPersister(store).WithContent(&st, ca)
-
- st = state.NewState(cfg.FlagCount)
- ca = cache.NewCache()
- ca = ca.WithCacheSize(cfg.CacheSize)
- pr = persist.NewPersister(store).WithContent(&st, ca)
- err := pr.Save(cfg.SessionId)
- if err != nil {
- t.Fatal(err)
- }
-
- en, err := NewPersistedEngine(ctx, cfg, pr, rs)
- if err != nil {
- t.Fatal(err)
- }
-
- _, err = en.Init(ctx)
- if err != nil {
- t.Fatal(err)
- }
-
- _, err = en.Exec(ctx, []byte("1"))
- if err != nil {
- t.Fatal(err)
- }
-
- _, err = en.Exec(ctx, []byte("2"))
- if err != nil {
- t.Fatal(err)
- }
- _, err = en.Exec(ctx, []byte("00"))
- if err != nil {
- t.Fatal(err)
- }
- location, idx := st.Where()
- if location != "long" {
- t.Fatalf("expected location 'long', got %s", location)
- }
- if idx != 1 {
- t.Fatalf("expected index '1', got %v", idx)
- }
-
- pr = persist.NewPersister(store)
- en, err = NewPersistedEngine(ctx, cfg, pr, rs)
- if err != nil {
- t.Fatal(err)
- }
- st_loaded := pr.GetState()
- location, _ = st_loaded.Where()
- if location != "long" {
- t.Fatalf("expected location 'long', got %s", location)
- }
- if idx != 1 {
- t.Fatalf("expected index '1', got %v", idx)
- }
-
- _, err = en.Exec(ctx, []byte("11"))
- if err != nil {
- t.Fatal(err)
- }
-}