From e4621cb68814cd55044ab8ec2d232e2ba8a7d4a2 Mon Sep 17 00:00:00 2001 From: blackout Date: Mon, 22 Jan 2024 19:29:50 -0500 Subject: [PATCH] SYN-6652: --deledges option to delnode (#3503) --- synapse/lib/storm.py | 21 ++++++++++++++ synapse/tests/test_lib_node.py | 53 ++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/synapse/lib/storm.py b/synapse/lib/storm.py index b9f5d4bec5..a1cd30944f 100644 --- a/synapse/lib/storm.py +++ b/synapse/lib/storm.py @@ -4567,12 +4567,15 @@ def getArgParser(self): pars.add_argument('--delbytes', default=False, action='store_true', help='For file:bytes nodes, remove the bytes associated with the ' 'sha256 property from the axon as well if present.') + pars.add_argument('--deledges', default=False, action='store_true', + help='Delete N2 light edges before deleting the node.') return pars async def execStormCmd(self, runt, genr): force = await s_stormtypes.tobool(self.opts.force) delbytes = await s_stormtypes.tobool(self.opts.delbytes) + deledges = await s_stormtypes.tobool(self.opts.deledges) if force: if runt.user is not None and not runt.isAdmin(): @@ -4592,6 +4595,24 @@ async def execStormCmd(self, runt, genr): runt.layerConfirm(('node', 'del', node.form.name)) + if deledges: + async with await s_spooled.Set.anit(dirn=self.runt.snap.core.dirn) as edges: + seenverbs = set() + + async for (verb, n2iden) in node.iterEdgesN2(): + if verb not in seenverbs: + runt.layerConfirm(('node', 'edge', 'del', verb)) + seenverbs.add(verb) + await edges.add((verb, n2iden)) + + async with self.runt.snap.getEditor() as editor: + async for (verb, n2iden) in edges: + n2 = await editor.getNodeByBuid(s_common.uhex(n2iden)) + if n2 is not None: + if await n2.delEdge(verb, node.iden()) and len(editor.protonodes) >= 1000: + await self.runt.snap.applyNodeEdits(editor.getNodeEdits()) + editor.protonodes.clear() + if delbytes and node.form.name == 'file:bytes': sha256 = node.props.get('sha256') if sha256: diff --git a/synapse/tests/test_lib_node.py b/synapse/tests/test_lib_node.py index 88f4d28c9d..aa99d15903 100644 --- a/synapse/tests/test_lib_node.py +++ b/synapse/tests/test_lib_node.py @@ -454,6 +454,59 @@ async def test_node_delete(self): msgs = await core.stormlist(edgeq) self.len(1, [m for m in msgs if m[0] == 'print']) + q = ''' + [test:str=delfoo test:str=delbar] + { test:str=delfoo [ +(bar)> { test:str=delbar } ] } + { test:str=delbar [ +(foo)> { test:str=delfoo } ] } + ''' + nodes = await core.nodes(q) + self.len(2, nodes) + + foo, bar = nodes + fooedges = [edge async for edge in foo.iterEdgesN1()] + baredges = [edge async for edge in bar.iterEdgesN1()] + + self.len(2, fooedges) + self.len(2, baredges) + + msgs = await core.stormlist('test:str=delfoo | delnode') + self.stormIsInErr('Other nodes still have light edges to this node.', msgs) + + nodes = await core.nodes('test:str=delfoo') + self.len(1, nodes) + + msgs = await core.stormlist('test:str=delfoo | delnode --deledges') + self.stormHasNoWarnErr(msgs) + + nodes = await core.nodes('test:str=delfoo') + self.len(0, nodes) + + msgs = await core.stormlist('test:str=delbar | delnode') + self.stormHasNoWarnErr(msgs) + + nodes = await core.nodes('[test:str=delfoo]') + self.len(1, nodes) + foo = nodes[0] + + q = ''' + for $ii in $lib.range(1200) { + $valu = `bar{$ii}` + [ test:str=$valu +(foo)> { test:str=delfoo } ] + } + ''' + msgs = await core.stormlist(q) + self.stormHasNoWarnErr(msgs) + + fooedges = [edge async for edge in foo.iterEdgesN2()] + + self.len(1200, fooedges) + + msgs = await core.stormlist('test:str=delfoo | delnode --deledges') + self.stormHasNoWarnErr(msgs) + + nodes = await core.nodes('test:str=delfoo') + self.len(0, nodes) + async def test_node_remove_missing_basetag(self): async with self.getTestCore() as core: