1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.archive.util;
24
25 import java.io.File;
26 import java.util.HashMap;
27 import java.util.concurrent.atomic.AtomicInteger;
28 import java.util.logging.Handler;
29 import java.util.logging.Level;
30 import java.util.logging.Logger;
31
32 import org.apache.commons.lang.math.RandomUtils;
33
34 /***
35 * @author stack
36 * @version $Date: 2011-06-09 23:34:44 +0000 (Thu, 09 Jun 2011) $, $Revision: 7175 $
37 */
38 @SuppressWarnings("deprecation")
39 public class CachedBdbMapTest extends TmpDirTestCase {
40 File envDir;
41 private CachedBdbMap<String,HashMap<String,String>> cache;
42
43 @SuppressWarnings("unchecked")
44 protected void setUp() throws Exception {
45 super.setUp();
46 this.envDir = new File(getTmpDir(),"CachedBdbMapTest");
47 this.envDir.mkdirs();
48 this.cache = new CachedBdbMap(this.envDir,
49 this.getClass().getName(), String.class, HashMap.class);
50 }
51
52 protected void tearDown() throws Exception {
53 this.cache.close();
54 FileUtils.deleteDir(this.envDir);
55 super.tearDown();
56 }
57
58 @SuppressWarnings("unchecked")
59 public void xestReadConsistencyUnderLoad() throws Exception {
60 final CachedBdbMap<String,AtomicInteger> cbdbmap =
61 new CachedBdbMap(
62 this.envDir,
63 this.getClass().getName(),
64 Integer.class,
65 AtomicInteger.class);
66 try {
67 final AtomicInteger level = new AtomicInteger(0);
68 final int keyCount = 128 * 1024;
69 final int maxLevel = 64;
70
71 for(int i=0; i < keyCount; i++) {
72 AtomicInteger prevVal = cbdbmap.putIfAbsent(""+i, new AtomicInteger(level.get()));
73 assertNull("unexpected prior value", prevVal);
74 }
75
76 new Thread() {
77 public void run() {
78 untilmax: while(true) {
79 for(int j=keyCount-1; j >= 0; j--) {
80 int targetValue = level.get();
81 if(targetValue>=maxLevel) {
82 break untilmax;
83 }
84 assertTrue("stale value revseq key "+j,cbdbmap.get(j).get()>=targetValue);
85 Thread.yield();
86 }
87 }
88 }
89 }.start();
90
91 new Thread() {
92 public void run() {
93 untilmax: while(true) {
94 int j = RandomUtils.nextInt(keyCount);
95 int targetValue = level.get();
96 if(targetValue>=maxLevel) {
97 break untilmax;
98 }
99 assertTrue("stale value random key "+j,
100 cbdbmap.get(""+j).get()>=targetValue);
101 Thread.yield();
102 }
103 }
104 }.start();
105
106 for(; level.get() < maxLevel; level.incrementAndGet()) {
107 for(int k = 0; k < keyCount; k++) {
108 int foundValue = cbdbmap.get(""+k).getAndIncrement();
109 assertEquals("stale value preinc key "+k, level.get(), foundValue);
110 }
111 if(level.get() % 10 == 0) {
112 System.out.println("level to "+level.get());
113 }
114 Thread.yield();
115 }
116 } finally {
117 cbdbmap.close();
118 }
119
120 }
121
122 public void testBackingDbGetsUpdated() {
123
124
125 Handler [] handlers = Logger.getLogger("").getHandlers();
126 for (int index = 0; index < handlers.length; index++) {
127 handlers[index].setLevel(Level.FINEST);
128 }
129 Logger.getLogger(CachedBdbMap.class.getName()).
130 setLevel(Level.FINEST);
131
132 final String value = "value";
133 final String key = "key";
134 final int upperbound = 3;
135
136 for (int i = 0; i < upperbound; i++) {
137 HashMap<String,String> prevVal = this.cache.putIfAbsent(key + Integer.toString(i), new HashMap<String,String>());
138 assertNull("unexpected previous value", prevVal);
139 }
140
141 for (int i = 0; i < upperbound; i++) {
142 HashMap<String,String> m = this.cache.get(key + Integer.toString(i));
143 m.put(key, value);
144 }
145 this.cache.sync();
146 for (int i = 0; i < upperbound; i++) {
147 HashMap<String,String> m = this.cache.get(key + Integer.toString(i));
148 String v = m.get(key);
149 if (v == null || !v.equals(value)) {
150 Logger.getLogger(CachedBdbMap.class.getName()).
151 warning("Wrong value " + i);
152 }
153 }
154 }
155
156 /***
157 * Test that in scarce memory conditions, the memory map is
158 * expunged of otherwise unreferenced entries as expected.
159 *
160 * NOTE: this test may be especially fragile with regard to
161 * GC/timing issues; relies on timely finalization, which is
162 * never guaranteed by JVM/GC. For example, it is so sensitive
163 * to CPU speed that a Thread.sleep(1000) succeeds when my
164 * laptop is plugged in, but fails when it is on battery!
165 *
166 * @throws InterruptedException
167 */
168 public void testMemMapCleared() throws InterruptedException {
169 System.gc();
170 assertEquals(cache.memMap.size(), 0);
171 for(int i=0; i < 10000; i++) {
172 cache.putIfAbsent(""+i, new HashMap<String,String>());
173 }
174 assertEquals(cache.memMap.size(), 10000);
175 assertEquals(cache.size(), 10000);
176 TestUtils.forceScarceMemory();
177 System.gc();
178 System.runFinalization();
179 Thread.sleep(2000);
180 System.gc();
181 System.runFinalization();
182 Thread.sleep(2000);
183
184
185
186 System.out.println(cache.size()+","+cache.memMap.size());
187 assertEquals(0, cache.memMap.size());
188 }
189
190
191 public static void main(String [] args) {
192 junit.textui.TestRunner.run(CachedBdbMapTest.class);
193 }
194 }