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()); } } } @@ -201,6 +205,20 @@ 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. */ @@ -232,7 +250,9 @@ } }; - struct RadixNode { + struct RadixNode : public boost::noncopyable { + IMPLEMENT_RCU_REFCOUNT(uint64_t); + private: union { std::array, CHILD_PER_LEVEL> childs; @@ -246,6 +266,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]; }