diff --git a/src/radix.h b/src/radix.h --- a/src/radix.h +++ b/src/radix.h @@ -56,6 +56,7 @@ public: RadixTree() : root(RadixElement()) {} + ~RadixTree() { root.load().release(); } /** * Insert a value into the tree. @@ -179,6 +180,9 @@ RadixElement(newChild.get()))) { // We have a subtree, resume normal operations from there. newChild.release(); + } else { + // We failed to insert our subtree, clean it before it is freed. + newChild->get(level, leafKey)->store(RadixElement()); } } } @@ -199,6 +203,20 @@ explicit RadixElement(RadixNode *nodeIn) : node(nodeIn) {} explicit RadixElement(T *leafIn) : leaf(leafIn) { raw |= DISCRIMINANT; } + /** + * RadixElement is designed to be a dumb wrapper. This allows any + * container to release what is held by the RadixElement. + */ + void release() { + if (isNode()) { + RadixNode *ptr = getNode(); + RCUPtr::acquire(ptr); + } else { + T *ptr = getLeaf(); + RCUPtr::acquire(ptr); + } + } + /** * Node features. */ @@ -230,7 +248,9 @@ } }; - struct RadixNode { + struct RadixNode : public boost::noncopyable { + IMPLEMENT_RCU_REFCOUNT(uint64_t); + private: union { std::array, CHILD_PER_LEVEL> childs; @@ -244,6 +264,12 @@ get(level, key)->store(e); } + ~RadixNode() { + for (RadixElement e : non_atomic_childs_DO_NOT_USE) { + e.release(); + } + } + std::atomic *get(uint32_t level, const K &key) { return &childs[(key >> (level * BITS)) & MASK]; }