From f71b8b0790943ee1d62464e054d5781f40f1b102 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Tue, 7 Sep 2021 14:35:40 +0200 Subject: [PATCH] Make it possible to retract handles from other facets within one's actor --- syndicate/actor.py | 54 ++++++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/syndicate/actor.py b/syndicate/actor.py index 4bf6348..04c9697 100644 --- a/syndicate/actor.py +++ b/syndicate/actor.py @@ -53,11 +53,11 @@ class Actor: if not daemon: adjust_engine_inhabitant_count(1) self.root = Facet(self, None) + self.outbound = initial_assertions or {} self.exit_reason = None # None -> running, True -> terminated OK, exn -> error self.exit_hooks = [] self._log = None - Turn.run(Facet(self, self.root, initial_assertions = initial_assertions), - stop_if_inert_after(boot_proc)) + Turn.run(Facet(self, self.root, set(self.outbound.keys())), stop_if_inert_after(boot_proc)) def __repr__(self): return '' % (self.name,) @@ -104,15 +104,24 @@ class Actor: adjust_engine_inhabitant_count(-1) queue_task(finish_termination) + def _pop_outbound(self, handle, clear_from_source_facet): + e = self.outbound.pop(handle) + if e and clear_from_source_facet: + try: + e.source_facet.handles.remove(handle) + except KeyError: + pass + return e + class Facet: - def __init__(self, actor, parent, initial_assertions = None): + def __init__(self, actor, parent, initial_handles=None): self.id = next(_next_facet_id) self.actor = actor self.parent = parent if parent: parent.children.add(self) self.children = set() - self.outbound = initial_assertions or {} + self.handles = initial_handles or set() self.shutdown_actions = [] self.linked_tasks = [] self.alive = True @@ -144,7 +153,7 @@ class Facet: def isinert(self): return \ len(self.children) == 0 and \ - len(self.outbound) == 0 and \ + len(self.handles) == 0 and \ len(self.linked_tasks) == 0 and \ self.inert_check_preventers == 0 @@ -193,9 +202,11 @@ class Facet: if orderly: for h in self.shutdown_actions: h(turn) - for e in self.outbound.values(): - turn._retract(e) - self.outbound.clear() + for h in self.handles: + # Optimization: don't clear from source facet, the source facet is us and we're + # about to clear our handles in one fell swoop. + turn._retract(self.actor._pop_outbound(h, clear_from_source_facet=False)) + self.handles.clear() if orderly: if parent: @@ -298,12 +309,13 @@ class Turn: def on_stop(self, a): self._facet.on_stop(a) - def spawn(self, boot_proc, name = None, initial_assertions = None, daemon = False): + def spawn(self, boot_proc, name = None, initial_handles = None, daemon = False): def action(turn): new_outbound = {} - if initial_assertions is not None: - for handle in initial_assertions: - new_outbound[handle] = self._facet.outbound.pop(handle) + if initial_handles is not None: + for handle in initial_handles: + new_outbound[handle] = \ + self._facet.actor._pop_outbound(handle, clear_from_source_facet=True) queue_task(lambda: Actor(boot_proc, name = name, initial_assertions = new_outbound, @@ -324,8 +336,10 @@ class Turn: def _publish(self, ref, assertion, handle): # TODO: attenuation assertion = preserve(assertion) - e = OutboundAssertion(handle, ref) - self._facet.outbound[handle] = e + facet = self._facet + e = OutboundAssertion(facet, handle, ref) + facet.actor.outbound[handle] = e + facet.handles.add(handle) def action(turn): e.established = True self.log.debug('%r <-- publish %r handle %r', ref, assertion, handle) @@ -334,7 +348,7 @@ class Turn: def retract(self, handle): if handle is not None: - e = self._facet.outbound.pop(handle, None) + e = self._facet.actor._pop_outbound(handle, clear_from_source_facet=True) if e is not None: self._retract(e) @@ -344,7 +358,8 @@ class Turn: return new_handle def _retract(self, e): - # Assumes e has already been removed from self._facet.outbound + # Assumes e has already been removed from self._facet.actor.outbound and the + # appropriate set of handles def action(turn): if e.established: e.established = False @@ -408,14 +423,15 @@ class Ref: return '' % (self.facet._repr_labels(), self.entity) class OutboundAssertion: - def __init__(self, handle, ref): + def __init__(self, source_facet, handle, ref): + self.source_facet = source_facet self.handle = handle self.ref = ref self.established = False def __repr__(self): - return '' % \ - (self.handle, self.ref, ' established' if self.established else '') + return '' % \ + (self.source_facet, self.handle, self.ref, ' established' if self.established else '') # Can act as a mixin class Entity: