def remove_node(self, node: StorageNode) -> int:
"""remove_node removes the node and returns the key
from the hash space on which the node was placed.
"""
# handling error when space is empty
if len(self._keys) == 0:
raise Exception("hash space is empty")
key = hash_fn(node.host, self.total_slots)
# we find the index where the key would reside in the keys
index = bisect_left(self._keys, key)
# if key does not exist in the array we raise Exception
if index >= len(self._keys) or self._keys[index] != key:
raise Exception("node does not exist")
# Perform data migration
# now that all sanity checks are done we popping the
# keys and nodes at the index and thus removing the presence of the node.
self._keys.pop(index)
self.nodes.pop(index)
return key