|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- package exec
-
- import (
- "context"
- "fmt"
- "sync"
-
- "gitlink.org.cn/cloudream/common/pkgs/future"
- "gitlink.org.cn/cloudream/common/utils/lo2"
- "gitlink.org.cn/cloudream/common/utils/sync2"
- )
-
- type binding struct {
- ID VarID
- Callback *future.SetValueFuture[VarValue]
- }
-
- type freeVar struct {
- ID VarID
- Value VarValue
- }
-
- type Executor struct {
- plan Plan
- vars map[VarID]freeVar
- bindings []*binding
- lock sync.Mutex
- store map[string]VarValue
- }
-
- func NewExecutor(plan Plan) *Executor {
- planning := Executor{
- plan: plan,
- vars: make(map[VarID]freeVar),
- store: make(map[string]VarValue),
- }
-
- return &planning
- }
-
- func (s *Executor) Plan() *Plan {
- return &s.plan
- }
-
- func (s *Executor) Run(ctx *ExecContext) (map[string]VarValue, error) {
- c, cancel := context.WithCancel(ctx.Context)
- ctx.Context = c
-
- defer cancel()
-
- err := sync2.ParallelDo(s.plan.Ops, func(o Op, idx int) error {
- err := o.Execute(ctx, s)
-
- s.lock.Lock()
- defer s.lock.Unlock()
-
- if err != nil {
- cancel()
- return fmt.Errorf("%T: %w", o, err)
- }
-
- return nil
- })
- if err != nil {
- return nil, err
- }
-
- return s.store, nil
- }
-
- func (s *Executor) BindVar(ctx context.Context, id VarID) (VarValue, error) {
- s.lock.Lock()
-
- gv, ok := s.vars[id]
- if ok {
- delete(s.vars, id)
- s.lock.Unlock()
- return gv.Value, nil
- }
-
- callback := future.NewSetValue[VarValue]()
- s.bindings = append(s.bindings, &binding{
- ID: id,
- Callback: callback,
- })
-
- s.lock.Unlock()
- return callback.Wait(ctx)
- }
-
- func (s *Executor) PutVar(id VarID, value VarValue) *Executor {
- s.lock.Lock()
- defer s.lock.Unlock()
-
- for ib, b := range s.bindings {
- if b.ID != id {
- continue
- }
-
- b.Callback.SetValue(value)
- s.bindings = lo2.RemoveAt(s.bindings, ib)
-
- return s
- }
-
- // 如果没有绑定,则直接放入变量表中
- s.vars[id] = freeVar{ID: id, Value: value}
- return s
- }
-
- func (s *Executor) Store(key string, val VarValue) {
- s.lock.Lock()
- defer s.lock.Unlock()
-
- s.store[key] = val
- }
-
- func BindVar[T VarValue](e *Executor, ctx context.Context, id VarID) (T, error) {
- v, err := e.BindVar(ctx, id)
- if err != nil {
- var def T
- return def, err
- }
-
- ret, ok := v.(T)
- if !ok {
- var def T
- return def, fmt.Errorf("binded var %v is %T, not %T", id, v, def)
- }
-
- return ret, nil
- }
-
- func BindArray[T VarValue](e *Executor, ctx context.Context, ids []VarID) ([]T, error) {
- ret := make([]T, len(ids))
- for i := range ids {
- v, err := e.BindVar(ctx, ids[i])
- if err != nil {
- return nil, err
- }
-
- v2, ok := v.(T)
- if !ok {
- var def T
- return nil, fmt.Errorf("binded var %v is %T, not %T", ids[i], v, def)
- }
-
- ret[i] = v2
- }
- return ret, nil
- }
-
- func PutArray[T VarValue](e *Executor, ids []VarID, values []T) {
- for i := range ids {
- e.PutVar(ids[i], values[i])
- }
- }
|