Skip to content

Commit 1559100

Browse files
author
Johnu George
committed
MNEMONIC-209: Implementing iterators for Maps
1 parent 7e19791 commit 1559100

File tree

4 files changed

+205
-2
lines changed

4 files changed

+205
-2
lines changed

build-tools/test.conf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ mvn -Dtest=DurableSinglyLinkedListNGTest test -pl mnemonic-collections -DskipTe
3333
# a testcase for module "mnemonic-collection" that requires 'pmalloc' memory service to pass
3434
mvn -Dtest=DurablePersonNGTest test -pl mnemonic-collections -DskipTests=false
3535

36+
# a testcase for module "mnemonic-collection" that requires 'pmalloc' memory service to pass
37+
mvn -Dtest=DurableHashMapNGTest test -pl mnemonic-collections -DskipTests=false
38+
3639
# a testcase for module "mnemonic-computing-services/mnemonic-utilities-service" that requires 'pmalloc' memory service to pass
3740
mvn -Dtest=DurableSinglyLinkedListNGPrintTest test -pl mnemonic-computing-services/mnemonic-utilities-service -DskipTests=false
3841

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
import org.apache.mnemonic.EntityFactoryProxy;
2222
import org.apache.mnemonic.DurableType;
2323

24-
public abstract class DurableHashMap<K, V> implements Durable {
24+
import java.util.Iterator;
25+
26+
public abstract class DurableHashMap<K, V> implements Durable, Iterable<MapEntry<K, V>> {
2527
protected transient EntityFactoryProxy[] m_node_efproxies;
2628
protected transient DurableType[] m_node_gftypes;
2729
protected long threshold;
@@ -96,6 +98,13 @@ public void setupGenericInfo(EntityFactoryProxy[] efproxies, DurableType[] gftyp
9698
*/
9799
public abstract V remove(K key);
98100

101+
/**
102+
* Retrieve a iterator
103+
*
104+
* @return iterator to the hash map
105+
*/
106+
107+
public abstract Iterator<MapEntry<K, V>> iterator();
99108
/**
100109
* Apply hash function to given hash code
101110
*

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

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,12 @@
2626
import org.apache.mnemonic.RestoreDurableEntityError;
2727
import org.apache.mnemonic.RetrieveDurableEntityError;
2828
import org.apache.mnemonic.Utils;
29+
2930
import org.apache.commons.lang3.tuple.Pair;
3031
import org.apache.commons.lang3.ArrayUtils;
3132
import sun.misc.Unsafe;
33+
import java.util.Iterator;
34+
import java.util.NoSuchElementException;
3235

3336
@SuppressWarnings("restriction")
3437
public class DurableHashMapImpl<A extends RestorableAllocator<A>, K, V>
@@ -443,5 +446,85 @@ public void createDurableEntity(A allocator, EntityFactoryProxy[] factoryProxy,
443446
}
444447
initializeAfterCreate();
445448
}
449+
450+
@Override
451+
public Iterator<MapEntry<K, V>> iterator() {
452+
return new HashMapItr(this);
453+
}
454+
455+
private class HashMapItr implements Iterator<MapEntry<K, V>> {
456+
long currentBucketAddr = 0;
457+
long prevBucketAddr = 0;
458+
long maxBucketAddr = 0;
459+
DurableHashMapImpl<A, K, V> map;
460+
DurableSinglyLinkedList<MapEntry<K, V>> currentNode = null;
461+
DurableSinglyLinkedList<MapEntry<K, V>> prevNode = null;
462+
DurableSinglyLinkedList<MapEntry<K, V>> prevPrevNode = null;
463+
464+
HashMapItr(DurableHashMapImpl<A, K, V> map) {
465+
this.map = map;
466+
currentBucketAddr = map.holder.get();
467+
maxBucketAddr = currentBucketAddr + MAX_OBJECT_SIZE * map.totalCapacity;
468+
nextValidBucket();
469+
}
470+
471+
@Override
472+
public boolean hasNext() {
473+
return (null != currentNode);
474+
}
475+
476+
public void nextValidBucket() {
477+
while ((null == currentNode) && (currentBucketAddr < maxBucketAddr)) {
478+
long handler = unsafe.getAddress(currentBucketAddr);
479+
if (0L != handler) {
480+
currentNode = DurableSinglyLinkedListFactory.restore(allocator,
481+
listefproxies, listgftypes, handler, false);
482+
break;
483+
}
484+
currentBucketAddr += MAX_OBJECT_SIZE;
485+
}
486+
}
487+
488+
@Override
489+
public MapEntry<K, V> next() {
490+
if (null != currentNode) {
491+
MapEntry<K, V> entry = currentNode.getItem();
492+
if (prevBucketAddr != currentBucketAddr) {
493+
prevPrevNode = null;
494+
prevBucketAddr = currentBucketAddr;
495+
} else {
496+
prevPrevNode = prevNode;
497+
}
498+
prevNode = currentNode;
499+
currentNode = currentNode.getNext();
500+
if (null == currentNode) {
501+
currentBucketAddr += MAX_OBJECT_SIZE;
502+
nextValidBucket();
503+
}
504+
return entry;
505+
} else {
506+
throw new NoSuchElementException();
507+
}
508+
}
509+
510+
@Override
511+
public void remove() {
512+
if (null == prevPrevNode) {
513+
if (null == prevNode.getNext()) {
514+
unsafe.putAddress(prevBucketAddr, 0L);
515+
prevNode.destroy();
516+
} else {
517+
unsafe.putAddress(prevBucketAddr, prevNode.getNext().getHandler());
518+
prevNode.setNext(null, false);
519+
prevNode.destroy(); // #TODO: better way to delete one node
520+
}
521+
} else {
522+
prevPrevNode.setNext(prevNode.getNext(), false);
523+
prevNode.setNext(null, false);
524+
prevNode.destroy(); // #TODO: better way to delete one node
525+
}
526+
map.mapSize--;
527+
}
528+
}
446529
}
447530

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

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package org.apache.mnemonic.collections;
1919

20+
import java.util.Iterator;
2021
import java.nio.ByteBuffer;
2122

2223
import org.apache.mnemonic.Utils;
@@ -31,6 +32,7 @@
3132
import org.testng.annotations.BeforeClass;
3233
import org.testng.annotations.Test;
3334
import org.testng.AssertJUnit;
35+
3436
/**
3537
*
3638
*
@@ -109,6 +111,16 @@ public void testGetPutRemovePrimitives() {
109111
val = map.remove("world");
110112
AssertJUnit.assertEquals(2, val.intValue());
111113

114+
Iterator<MapEntry<String, Integer>> iter = map.iterator();
115+
MapEntry<String, Integer> entry = null;
116+
int count = 0;
117+
while (iter.hasNext()) {
118+
entry = iter.next();
119+
count++;
120+
}
121+
AssertJUnit.assertEquals(count, 1);
122+
AssertJUnit.assertEquals(entry.getKey(), "hello");
123+
AssertJUnit.assertEquals(entry.getValue().intValue(), 3);
112124

113125
DurableHashMap<String, Integer> restoredMap = DurableHashMapFactory.restore(m_act, null, gtypes, handler,
114126
false);
@@ -336,11 +348,21 @@ public void testAutoResizeMaps() {
336348
DurableType gtypes[] = {DurableType.STRING, DurableType.INTEGER};
337349
DurableHashMap<String, Integer> map = DurableHashMapFactory.create(m_act, null, gtypes, mInitialCapacity, false);
338350
Long handler = map.getHandler();
351+
Iterator<MapEntry<String, Integer>> iter = null;
352+
MapEntry<String, Integer> entry = null;
353+
int count = 0;
339354
Integer val = 0;
340355
for (int i = 0; i < 200; i++) {
341356
val = map.put("str" + i, i);
342357
AssertJUnit.assertNull(val);
343358
}
359+
360+
iter = map.iterator();
361+
while (iter.hasNext()) {
362+
entry = iter.next();
363+
count++;
364+
}
365+
AssertJUnit.assertEquals(count, 200);
344366
AssertJUnit.assertEquals(map.getSize(), 200);
345367
for (int i = 0; i < 200; i++) {
346368
AssertJUnit.assertEquals(map.get("str" + i).intValue(), i);
@@ -350,7 +372,16 @@ public void testAutoResizeMaps() {
350372
AssertJUnit.assertEquals(restoredMap.getSize(), 200);
351373
for (int i = 0; i < 200; i++) {
352374
AssertJUnit.assertEquals(restoredMap.get("str" + i).intValue(), i);
353-
}
375+
}
376+
377+
iter = restoredMap.iterator();
378+
count = 0;
379+
while (iter.hasNext()) {
380+
entry = iter.next();
381+
count++;
382+
}
383+
AssertJUnit.assertEquals(count, 200);
384+
354385
for (int i = 0; i < 100; i++) {
355386
AssertJUnit.assertEquals(restoredMap.remove("str" + i).intValue(), i);
356387
}
@@ -362,5 +393,82 @@ public void testAutoResizeMaps() {
362393
AssertJUnit.assertEquals(restoredMap.get("str" + i).intValue(), i);
363394
}
364395
}
396+
397+
iter = restoredMap.iterator();
398+
count = 0;
399+
while (iter.hasNext()) {
400+
entry = iter.next();
401+
count++;
402+
}
403+
AssertJUnit.assertEquals(count, 100);
404+
405+
iter = restoredMap.iterator();
406+
count = 0;
407+
while (iter.hasNext()) {
408+
entry = iter.next();
409+
count++;
410+
if (count > 50) {
411+
iter.remove();
412+
}
413+
}
414+
AssertJUnit.assertEquals(restoredMap.getSize(), 50);
415+
416+
iter = restoredMap.iterator();
417+
count = 0;
418+
while (iter.hasNext()) {
419+
entry = iter.next();
420+
count++;
421+
}
422+
AssertJUnit.assertEquals(count, 50);
423+
424+
425+
}
426+
427+
@Test(enabled = true)
428+
public void testMapIterator() {
429+
DurableType gtypes[] = {DurableType.STRING, DurableType.INTEGER};
430+
DurableHashMap<String, Integer> map = DurableHashMapFactory.create(m_act, null, gtypes, mInitialCapacity, false);
431+
432+
Long handler = map.getHandler();
433+
map.put("hello", 1);
434+
map.put("world", 2);
435+
AssertJUnit.assertEquals(map.getSize(), 2);
436+
437+
Iterator<MapEntry<String, Integer>> iter = map.iterator();
438+
MapEntry<String, Integer> entry = null;
439+
int count = 0;
440+
while (iter.hasNext()) {
441+
entry = iter.next();
442+
count++;
443+
if (entry.getKey().equals("world")) {
444+
iter.remove();
445+
}
446+
}
447+
AssertJUnit.assertEquals(count, 2);
448+
AssertJUnit.assertEquals(map.getSize(), 1);
449+
iter = map.iterator();
450+
count = 0;
451+
while (iter.hasNext()) {
452+
entry = iter.next();
453+
iter.remove();
454+
count++;
455+
}
456+
AssertJUnit.assertEquals(count, 1);
457+
AssertJUnit.assertEquals(map.getSize(), 0);
458+
AssertJUnit.assertEquals(entry.getKey(), "hello");
459+
AssertJUnit.assertEquals(entry.getValue().intValue(), 1);
460+
461+
iter = map.iterator();
462+
count = 0;
463+
while (iter.hasNext()) {
464+
entry = iter.next();
465+
count++;
466+
}
467+
AssertJUnit.assertEquals(count, 0);
468+
map.put("hello", 1);
469+
map.put("world", 2);
470+
AssertJUnit.assertEquals(map.get("hello").intValue(), 1);
471+
AssertJUnit.assertEquals(map.get("world").intValue(), 2);
472+
AssertJUnit.assertEquals(map.getSize(), 2);
365473
}
366474
}

0 commit comments

Comments
 (0)