def action_add(self, id, stack_const, stack_exec, **kwargs): if id is None: id = uuid4().hex print(f'Generated ID {id}') def check_in_stack(k): if k in stack: raise KeyError(f'{k} defined twice') stack = {} for k, v in stack_const: check_in_stack(k) stack[k] = v for k, v in stack_exec: check_in_stack(k) try: v = eval(compile(v, filename='<string>', mode='eval')) stack[k] = v except: print(f'While evaluating {k}={v}') raise a, b = StackFrame.new(id, stack).create(self.db) return [a], [b]
def initiate(cls, db: Etcd3Client, frz: FrozenThreadContext, r: 'Request', stack): # we need: # - create a new stack frame in the context of the http request sf = StackFrame.new( uuid4().hex, { **stack, 'req_id': r.id } ) a1, b1 = frz.call(db, sf) a2, b2 = sf.create(db) ok, _ = db.transaction( compare=[ a1, a2 ], success=[ b1, b2, ], failure=[ ] ) return ok, r
def test_ok(self): db, lease = self._db_lease() opcodes = load_opcodes(tfci_core.opcodes, tfci_std.opcodes) eng = ExecutionEngine( TEST_IDENT, lease, opcodes, TestProgramPages('dasm_ep_2_plus_2.txt', db, opcodes), db) sf1 = StackFrame.new('sf1', {'x': 1}) t1 = ThreadContext.new('t1', 'ep_2_plus_2', [sf1.id]) ok, _, _ = sf1.create().merge(t1.create()).exec(db) self.assertTrue(ok, "Transaction must execute successfully") ok, upd = eng.step(t1) self.assertTrue(ok, "Step must execute succ I") ok, upd = eng.step(t1) self.assertTrue(ok, "Step must execute succ II") ok, upd = eng.step(t1) self.assertTrue(ok, "Step must execute succ III") tx1 = StackFrame.load_exists('sf1') sf: StackFrame ok, (sf, ), _ = tx1.exec(db) self.assertTrue(ok, "StackFrame must exist") self.assertEqual(sf.vals['x'], 3, "Return value must be equal") tx2 = ThreadContext.load_exists('t1') ok, (tctx, ), _ = tx2.exec(db) self.assertFalse(ok, "ThreadContext must not exist")
def fn(self, ctx: ExecutionContext) -> FollowUp: # how do we know which stacks have been changed ? csf = StackFrame.load_exists(ctx.singleton.db, ctx.resolve_arg(0)) push_pop(csf, ctx, ctx.args[1:]) return FollowUp.new(create_threads=[ ctx.thread.update(ip=ctx.nip, sp=[csf.id] + ctx.thread.sp) ], create_stacks=[csf])
def fn(self, ctx: ExecutionContext) -> FollowUp: # how do we know which stacks have been changed ? csf = StackFrame.new(uuid4().hex) push_pop(csf, ctx) return FollowUp.new(create_threads=[ ctx.thread.update(ip=ctx.nip, sp=[csf.id] + ctx.thread.sp) ], create_stacks=[csf])
def push_pop(csf: StackFrame, ctx: ExecutionContext, args=None): if args is None: args = ctx.args for arg in args: if isinstance(arg, Identifier): csf.set(arg.name, ctx.stack_get(arg.name, arg.level)) elif isinstance(arg, Constant): raise ExecutionError( f'(push) `{ctx.thread.id}:{ctx.thread.ip}` constant push requires an identifier' ) elif isinstance(arg, Map): if isinstance(arg.to, Constant): val = arg.to.value elif isinstance(arg.to, Identifier): val = ctx.stack_get(arg.to.name, arg.to.level) else: raise NotImplementedError(f'{repr(arg)}') csf.set(arg.identifier.name, val) else: raise NotImplementedError(f'{repr(arg)}')
def test_multi_proc(self): db, lease = self._db_lease() opcodes = load_opcodes(tfci_core.opcodes, tfci_std.opcodes) returns = [] def callback(*args, **kwargs): returns.append((args, kwargs)) cb_fix = callback_fixture('callback_fix', callback) opcodes[cb_fix.name] = cb_fix eng = ExecutionEngine( TEST_IDENT, lease, opcodes, TestProgramPages('dasm_multi_proc.txt', db, opcodes), db) PAYLOAD = list(range(5)) sf1 = StackFrame.new('sf1', { 'v': PAYLOAD, 'x': 'callback_fn', '_ret': 'ret_fn', }) t1 = ThreadContext.new('t1', 'fork_loop', [sf1.id]) ok, _, _ = sf1.create().merge(t1.create()).exec(db) tcxs = [t1] while len(tcxs): for t in tcxs: ok, upd = eng.step(t) self.assertTrue(ok, 'Must be OK') tcxs = ThreadContext.load_all(db).values() self.assertEqual(sorted([y['v'] for _, y in returns]), PAYLOAD)
def test_nonexistent_stack_arg(self): db, lease = self._db_lease() opcodes = load_opcodes(tfci_core.opcodes, tfci_std.opcodes) eng = ExecutionEngine( TEST_IDENT, lease, opcodes, TestProgramPages('dasm_ep_2_plus_2.txt', db, opcodes), db) sf1 = StackFrame.new('sf1') t1 = ThreadContext.new('t1', 'ep_2_plus_2', [sf1.id]) tx = sf1.create().merge(t1.create()) ok, _, _ = tx.exec(db) self.assertTrue(ok, "Transaction must execute successfully") ok, upd = eng.step(t1) self.assertTrue(ok, "Step must execute succ I") ok, upd = eng.step(t1) self.assertFalse(ok, "Step must execute succ II")
def action_add(self, id, stacks, ep, **kwargs): a, b = self.model.new(id, ep, stacks).create(self.db) return [a] + [StackFrame.exists(self.db, s) for s in stacks], [b]