fix: Invalidate cache of removed input sockets.

This was a nasty (interesting?) one - usually, input sockets are not attempted used
after the socket no longer exists.
Various checks in ex. `events` tend to help that process along.

Unfortunately (fortunately?), `Extract` uses a `_compute_input` query with
`optional=True`, which results in a direct attempt to hit the cache
without any other checks.
Because old input socket caches were never deleted, it would
**continue to get cached data from sockets that no longer exist**.

While on the surface this could be considered a case of "the
private method (`_compute_input`) is private for a reason", or
alternatively, "don't hijack the graph flow", I'm more convinced that
the usage is actually quite clean, being read-only and generally
well-conceived. It's reasonable to presume that asking for a thing that
doesn't exist won't produce output!

Moreover, I wouldn't be surprised if several other mysterious bugs were
caused by this. Not to mention the memory leak of endless caching! (Well,
until the node is deleted). It's a good things we noticed!
main
Sofus Albert Høgsbro Rose 2024-04-24 18:41:06 +02:00
parent c82862dde9
commit 785995117e
Signed by: so-rose
GPG Key ID: AD901CB0F3701434
2 changed files with 10 additions and 26 deletions

View File

@ -69,10 +69,8 @@ class ExtractDataNode(base.MaxwellSimNode):
'Sim Data', kind=ct.FlowKind.Value, optional=True 'Sim Data', kind=ct.FlowKind.Value, optional=True
) )
if not ct.FlowSignal.check(sim_data): if not ct.FlowSignal.check(sim_data):
log.critical('Sim Data was Not FlowSignal')
return sim_data return sim_data
log.critical('Sim Data was FlowSignal: %s', str(sim_data))
return None return None
@bl_cache.cached_bl_property() @bl_cache.cached_bl_property()
@ -190,9 +188,6 @@ class ExtractDataNode(base.MaxwellSimNode):
Returns: Returns:
Valid `self.extract_filter` in a format compatible with dynamic `EnumProperty`. Valid `self.extract_filter` in a format compatible with dynamic `EnumProperty`.
""" """
log.critical('Searching Extract Filters')
log.critical(self.sim_data_monitor_nametype)
log.critical(self.monitor_data_components)
if self.sim_data_monitor_nametype is not None: if self.sim_data_monitor_nametype is not None:
return [ return [
(monitor_name, monitor_name, monitor_type.removesuffix('Data'), '', i) (monitor_name, monitor_name, monitor_type.removesuffix('Data'), '', i)

View File

@ -430,6 +430,11 @@ class MaxwellSimNode(bpy.types.Node):
# Remove Sockets # Remove Sockets
for bl_socket in bl_sockets_to_remove: for bl_socket in bl_sockets_to_remove:
node_tree.on_node_socket_removed(bl_socket) node_tree.on_node_socket_removed(bl_socket)
self._compute_input.invalidate(
input_socket_name=bl_socket.name,
kind=...,
unit_system=...,
)
all_bl_sockets.remove(bl_socket) all_bl_sockets.remove(bl_socket)
def _add_new_active_sockets(self): def _add_new_active_sockets(self):
@ -771,12 +776,6 @@ class MaxwellSimNode(bpy.types.Node):
# Invalidate Input Socket Cache # Invalidate Input Socket Cache
if input_socket_name is not None: if input_socket_name is not None:
if socket_kinds is None: if socket_kinds is None:
log.critical(
'[%s] Invalidating: (%s, %s)',
self.sim_node_name,
input_socket_name,
str(socket_kinds),
)
self._compute_input.invalidate( self._compute_input.invalidate(
input_socket_name=input_socket_name, input_socket_name=input_socket_name,
kind=..., kind=...,
@ -784,12 +783,6 @@ class MaxwellSimNode(bpy.types.Node):
) )
else: else:
for socket_kind in socket_kinds: for socket_kind in socket_kinds:
log.critical(
'[%s] Invalidating: (%s, %s)',
self.sim_node_name,
input_socket_name,
str(socket_kind),
)
self._compute_input.invalidate( self._compute_input.invalidate(
input_socket_name=input_socket_name, input_socket_name=input_socket_name,
kind=socket_kind, kind=socket_kind,
@ -844,15 +837,11 @@ class MaxwellSimNode(bpy.types.Node):
) )
for event_method in triggered_event_methods: for event_method in triggered_event_methods:
stop_propagation |= event_method.stop_propagation stop_propagation |= event_method.stop_propagation
log.critical( # log.critical(
'$[%s] [%s %s %s %s] Running: (%s)', # '$[%s] [%s %s %s %s] Running: (%s)',
self.sim_node_name, # self.sim_node_name,
event, # event_method.callback_info,
socket_name, # )
socket_kinds,
prop_name,
event_method.callback_info,
)
event_method(self) event_method(self)
# Propagate Event to All Sockets in "Trigger Direction" # Propagate Event to All Sockets in "Trigger Direction"