Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Right node inaccessible after deleting parent #52

Open
jsandbrook opened this issue Oct 28, 2020 · 1 comment
Open

Right node inaccessible after deleting parent #52

jsandbrook opened this issue Oct 28, 2020 · 1 comment

Comments

@jsandbrook
Copy link

Apologies if I'm stating that incorrectly. I don't have the best handle on the inner workings of this library.

When a covering node has 'right' and 'left' nodes, deleting it makes the right prefix inaccessible. It's fairly easy to reproduce. [1]

This specifically happens with version 0.10.0 installed explicitly without the C extension. With the C-extension, it works as expected [2].

[1] No c-extension

# Setup
>>> import radix._radix
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named 'radix._radix'

>>> import radix
>>> radix.__version__
'0.10.0'
>>> rt = radix.Radix()
>>> rt.add('1.2.2.0/23')
<1.2.2.0/23>
>>> rt.add('1.2.2.0/24')
<1.2.2.0/24>
>>> rt.add('1.2.3.0/24')
<1.2.3.0/24>

# Check that the covering node has a right and left
>>> node = rt.search_exact('1.2.2.0/23')
>>> node.right
<1.2.3.0/24>
>>> node.left
<1.2.2.0/24>

# Delete the covering node
>>> rt.delete('1.2.2.0/23')

# The right node is no longer accessible despite still existing within nodes()
>>> rt.nodes()
[<1.2.2.0/24>, <1.2.3.0/24>]
>>> rt.search_exact('1.2.3.0/24')
>>> rt.delete('1.2.3.0/24')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/var/www/netarch-rest/ab-www/app/radix/radix.py", line 446, in delete
    raise KeyError('match not found')
KeyError: 'match not found'

[2] C-Extension exists this time

>>> import radix._radix
>>> rt = radix.Radix()
>>> rt.add('1.2.2.0/23')
<_radix.RadixNode object at 0x7fb361bda390>
>>> rt.add('1.2.2.0/24')
<_radix.RadixNode object at 0x7fb361bda420>
>>> rt.add('1.2.3.0/24')
<_radix.RadixNode object at 0x7fb361bda468>
>>> node = rt.search_exact('1.2.2.0/23')
>>> node.right
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: '_radix.RadixNode' object has no attribute 'right'
>>> node.left
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: '_radix.RadixNode' object has no attribute 'left'
>>> rt.delete(node.prefix)
>>> rt.search_exact('1.2.3.0/24')
<_radix.RadixNode object at 0x7fb361bda468>
>>> rt.delete('1.2.3.0/24')
>>>
@ljluestc
Copy link

import radix

class CustomRadix(radix.Radix):
    def delete(self, prefix):
        node = self.search_exact(prefix)
        if node is None:
            raise KeyError('match not found')
        
        # Check if the node to delete has children
        left_child = node.left
        right_child = node.right
        
        super().delete(prefix)
        
        if left_child:
            self._rehash_node(left_child)
        if right_child:
            self._rehash_node(right_child)

    def _rehash_node(self, node):
        # Re-add the node to fix the tree structure
        self.add(node.prefix)

# Example usage
if __name__ == "__main__":
    rt = CustomRadix()
    rt.add('1.2.2.0/23')
    rt.add('1.2.2.0/24')
    rt.add('1.2.3.0/24')

    print("Nodes before deletion:")
    for node in rt.nodes():
        print(node)

    # Delete the covering node
    rt.delete('1.2.2.0/23')

    print("\nNodes after deletion:")
    for node in rt.nodes():
        print(node)

    # Check if the right node is accessible
    right_node = rt.search_exact('1.2.3.0/24')
    print("\nRight node after deletion:")
    print(right_node)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants