Skip to content

Commit 48b3767

Browse files
committed
MNEMONIC-305: Implement Remove operation for Durable Trees
1 parent 3d5465c commit 48b3767

File tree

3 files changed

+190
-3
lines changed

3 files changed

+190
-3
lines changed

mnemonic-collections/src/main/java/org/apache/mnemonic/collections/DurableTree.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,19 @@ public void setupGenericInfo(EntityFactoryProxy[] efproxies, DurableType[] gftyp
104104
*/
105105
public abstract void insert(E item);
106106

107+
/**
108+
* removes a specific element from the tree
109+
*
110+
* @param item
111+
* the item to be removed
112+
*
113+
* @param destroy
114+
* destroy the item to be removed
115+
*
116+
* @return true if element is removed
117+
*/
118+
public abstract boolean remove(E item, boolean destroy);
119+
107120
/**
108121
* print tree
109122
*

mnemonic-collections/src/main/java/org/apache/mnemonic/collections/DurableTreeImpl.java

Lines changed: 120 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,14 +183,133 @@ protected void rotateRight(TreeNode<E> currentNode) {
183183
}
184184
}
185185

186+
/**
187+
* removes a specific element from the tree
188+
*
189+
* @param item
190+
* the item to be removed
191+
*
192+
* @return true if element is removed
193+
*/
194+
public boolean remove(E item, boolean destroy) {
195+
TreeNode<E> currentNode = findNode(item);
196+
if (null == currentNode) {
197+
return false;
198+
}
199+
TreeNode<E> tmp, ref = currentNode;
200+
boolean col = ref.getColor();
201+
if (null == currentNode.getLeft()) {
202+
tmp = currentNode.getRight();
203+
replace(currentNode, currentNode.getRight());
204+
} else if (null == currentNode.getRight()) {
205+
tmp = currentNode.getLeft();
206+
replace(currentNode, currentNode.getLeft());
207+
} else {
208+
ref = findMinimum(currentNode.getRight());
209+
col = ref.getColor();
210+
tmp = ref.getRight();
211+
if (ref.getParent().equals(currentNode)) {
212+
tmp.setParent(ref, false);
213+
} else {
214+
replace(ref, ref.getRight());
215+
ref.setRight(currentNode.getRight(), false);
216+
ref.getRight().setParent(ref, false);
217+
}
218+
replace(currentNode, ref);
219+
ref.setLeft(currentNode.getLeft(), false);
220+
ref.getLeft().setParent(ref, false);
221+
ref.setColor(currentNode.getColor());
222+
}
223+
if (col == BLACK && tmp != null) {
224+
fixDelete(tmp);
225+
}
226+
if (destroy) {
227+
currentNode.setLeft(null, false);
228+
currentNode.setRight(null, false);
229+
currentNode.setParent(null, false);
230+
currentNode.destroy();
231+
}
232+
return true;
233+
}
234+
235+
protected void fixDelete(TreeNode<E> currentNode) {
236+
while (!currentNode.equals(root) && currentNode.getColor() == BLACK) {
237+
if (currentNode.equals(currentNode.getParent().getLeft())) {
238+
TreeNode<E> other = currentNode.getParent().getRight();
239+
if (other.getColor() == RED) {
240+
other.setColor(BLACK);
241+
currentNode.getParent().setColor(RED);
242+
rotateLeft(currentNode.getParent());
243+
other = currentNode.getParent().getRight();
244+
}
245+
if (other.getLeft().getColor() == BLACK && other.getRight().getColor() == BLACK) {
246+
other.setColor(RED);
247+
currentNode = currentNode.getParent();
248+
continue;
249+
} else if (other.getRight().getColor() == BLACK) {
250+
other.getLeft().setColor(BLACK);
251+
other.setColor(RED);
252+
rotateRight(other);
253+
other = currentNode.getParent().getRight();
254+
}
255+
if (other.getRight().getColor() == RED) {
256+
other.setColor(currentNode.getParent().getColor());
257+
currentNode.getParent().setColor(BLACK);
258+
other.getRight().setColor(BLACK);
259+
rotateLeft(currentNode.getParent());
260+
currentNode = root;
261+
}
262+
} else {
263+
TreeNode other = currentNode.getParent().getLeft();
264+
if (other.getColor() == RED) {
265+
other.setColor(BLACK);
266+
currentNode.getParent().setColor(RED);
267+
rotateRight(currentNode.getParent());
268+
other = currentNode.getParent().getLeft();
269+
}
270+
if (other.getRight().getColor() == BLACK && other.getLeft().getColor() == BLACK) {
271+
other.setColor(RED);
272+
currentNode = currentNode.getParent();
273+
continue;
274+
} else if (other.getLeft().getColor() == BLACK) {
275+
other.getRight().setColor(BLACK);
276+
other.setColor(RED);
277+
rotateLeft(other);
278+
other = currentNode.getParent().getLeft();
279+
}
280+
if (other.getLeft().getColor() == RED) {
281+
other.setColor(currentNode.getParent().getColor());
282+
currentNode.getParent().setColor(BLACK);
283+
other.getLeft().setColor(BLACK);
284+
rotateRight(currentNode.getParent());
285+
currentNode = root;
286+
}
287+
}
288+
}
289+
currentNode.setColor(BLACK);
290+
}
291+
292+
protected void replace(TreeNode<E> first, TreeNode<E> second) {
293+
if (null == first.getParent()) {
294+
root = second;
295+
unsafe.putLong(holder.get(), root.getHandler());
296+
} else if (first.equals(first.getParent().getLeft())) {
297+
first.getParent().setLeft(second, false);
298+
} else {
299+
first.getParent().setRight(second, false);
300+
}
301+
if (second != null) {
302+
second.setParent(first.getParent(), false);
303+
}
304+
}
186305

187306
/**
188307
* checks if tree contains the specified element
189308
*
190309
* @param item
191310
* the item to be set
192311
*
193-
* @return tree if set contains the element
312+
* @return true if tree contains the element
194313
*/
195314
public boolean contains(E item) {
196315
return findNode(item) == null ? false : true;

mnemonic-collections/src/test/java/org/apache/mnemonic/collections/DurableTreeNGTest.java

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,20 @@ public void testInsertIntegers() {
114114
AssertJUnit.assertEquals(tree.predecessor(7).intValue(), 6);
115115
AssertJUnit.assertNull(tree.successor(7));
116116

117+
AssertJUnit.assertTrue(tree.contains(3));
118+
tree.remove(3, true);
119+
AssertJUnit.assertFalse(tree.contains(3));
120+
AssertJUnit.assertEquals(tree.successor(1).intValue(), 4);
121+
AssertJUnit.assertEquals(tree.predecessor(4).intValue(), 1);
122+
AssertJUnit.assertTrue(tree.isValidTree());
123+
tree.remove(7, true);
124+
AssertJUnit.assertFalse(tree.contains(7));
125+
AssertJUnit.assertNull(tree.successor(6));
126+
AssertJUnit.assertTrue(tree.isValidTree());
127+
128+
tree.insert(3);
129+
tree.insert(7);
130+
117131
DurableTree<Integer> restoredTree = DurableTreeFactory.restore(m_act, null, gtypes, handler, false);
118132

119133
AssertJUnit.assertTrue(restoredTree.isValidTree());
@@ -131,8 +145,7 @@ public void testInsertIntegers() {
131145
AssertJUnit.assertNull(restoredTree.successor(7));
132146

133147
restoredTree.insert(10);
134-
restoredTree.insert(2);
135-
AssertJUnit.assertEquals(restoredTree.successor(1).intValue(), 2);
148+
AssertJUnit.assertEquals(restoredTree.successor(1).intValue(), 3);
136149
AssertJUnit.assertEquals(restoredTree.predecessor(10).intValue(), 7);
137150

138151
restoredTree.destroy();
@@ -166,6 +179,13 @@ public void testInsertString() {
166179
AssertJUnit.assertEquals(tree.predecessor("Fun"), "Ele");
167180
AssertJUnit.assertNull(tree.successor("bob"));
168181

182+
tree.remove("Cat", true);
183+
AssertJUnit.assertEquals(tree.predecessor("Dog"), "Alice");
184+
AssertJUnit.assertEquals(tree.successor("Alice"), "Dog");
185+
AssertJUnit.assertTrue(tree.isValidTree());
186+
tree.remove("Alice", true);
187+
AssertJUnit.assertNull(tree.predecessor("Dog"));
188+
169189
tree.destroy();
170190
}
171191

@@ -184,6 +204,41 @@ public void testInsertRandomBigTrees() {
184204
tree.destroy();
185205
}
186206

207+
@Test(enabled = true)
208+
public void testInsertRemoveBigTrees() {
209+
DurableType gtypes[] = {DurableType.INTEGER};
210+
DurableTree<Integer> tree = DurableTreeFactory.create(m_act, null, gtypes, false);
211+
212+
Long handler = tree.getHandler();
213+
for (int i = 0; i < 10 * 1024; i++) {
214+
tree.insert(i);
215+
AssertJUnit.assertTrue(tree.contains(i));
216+
}
217+
218+
AssertJUnit.assertTrue(tree.isValidTree());
219+
220+
for (int i = 0; i < 5 * 1024; i++) {
221+
AssertJUnit.assertTrue(tree.remove(i, true));
222+
}
223+
AssertJUnit.assertTrue(tree.isValidTree());
224+
225+
for (int i = 0; i < 10 * 1024; i++) {
226+
if (i < 5 * 1024) {
227+
AssertJUnit.assertFalse(tree.contains(i));
228+
tree.insert(i);
229+
} else {
230+
AssertJUnit.assertTrue(tree.contains(i));
231+
}
232+
}
233+
234+
for (int i = 0; i < 10 * 1024; i++) {
235+
AssertJUnit.assertTrue(tree.contains(i));
236+
}
237+
AssertJUnit.assertTrue(tree.isValidTree());
238+
239+
tree.destroy();
240+
}
241+
187242
@Test(enabled = true)
188243
public void testInsertDurable() {
189244
DurableType gtypes[] = {DurableType.DURABLE};

0 commit comments

Comments
 (0)