1 /*
2 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /* @test
25 * @run main Basher
26 * @run main Basher -noshare
27 * @summary Tests multiple readers for PersistentTreeMap
28 */
29
30 import java.io.File;
31 import java.io.IOException;
32 import java.util.concurrent.Phaser;
33 import org.openjdk.jigsaw.PersistentTreeMap;
34 import org.openjdk.jigsaw.PersistentTreeMap.StringAndInt;
35
36 public class Basher implements Runnable
37 {
38 // Small values so that the test can be run in constrained
39 // test environments. Increase when running manually.
40 static final int NUM_THREADS = 50;
41 static final int NUM_ENTRIES = 10000;
42
43 static final boolean debug = false;
44 static final String FILENAME = "Basher_db.db";
45 static volatile int fail;
46
47 static enum Mode {
48 /** Share the PersistentTreeMap instance across multiple threads */
49 SHARE_INSTANCE,
50 /** Create a per thread PersistentTreeMap instance */
51 NOSHARE_INSTANCE
52 };
53 static Mode mode;
54
55 final PersistentTreeMap pmap;
56
57 public static void main(String[] args) throws Exception {
58 if (args.length >= 1 && args[0].equals("-noshare")) {
59 mode = Mode.NOSHARE_INSTANCE;
60 System.out.println("Using NO share mode");
61 } else {
62 mode = Mode.SHARE_INSTANCE;
63 System.out.println("Using share mode");
64 }
65 test();
66 }
67
68 Basher(PersistentTreeMap pmap) {
69 this.pmap = pmap;
70 }
71
72 static Basher createBasher(PersistentTreeMap ptm) throws Exception {
73 if (mode.equals(Mode.NOSHARE_INSTANCE))
74 return new Basher(PersistentTreeMap.open(new File(FILENAME)));
75 else if (mode.equals(Mode.SHARE_INSTANCE))
76 return new Basher(ptm);
77 else
78 throw new Error("Unknown run mode");
79 }
80
81 static void test() throws Exception {
82 System.out.print("Using " + NUM_THREADS + " threads, and " +
83 NUM_ENTRIES + " entries\n");
84 debug("Using database: " + FILENAME + "\n");
85 File dbFile = new File(FILENAME);
86
87 System.out.print("creating db...");
88 createdb(dbFile);
89 System.out.print("completed\n");
90
91 PersistentTreeMap pmap = PersistentTreeMap.open(dbFile);
92 try {
93 Thread[] threads = new Thread[NUM_THREADS];
94 for (int i=0; i<NUM_THREADS; i++) {
95 threads[i] = new Thread(createBasher(pmap));
96 }
97 for (int i=0; i<NUM_THREADS; i++) {
98 threads[i].start();
99 }
100 for (int i=0; i<NUM_THREADS; i++) {
101 threads[i].join();
102 }
103
104 } finally {
105 pmap.close();
106 dbFile.delete();
107 }
108
109 if (fail > 0)
110 throw new RuntimeException("Failed: " + fail + " tests failed. " +
111 "Check output");
112 }
113
114 static void createdb(File dbFile) throws IOException {
115 String tn = Thread.currentThread().getName();
116
117 try (PersistentTreeMap cpmap = PersistentTreeMap.create(dbFile)) {
118 for (int i=0; i<NUM_ENTRIES; i++) {
119 put("Key" + i, "Value" + i, cpmap, tn);
120 put("Int.Key" + i, i, cpmap, tn);
121 put("S.A.I.Key" + i, "S.A.I.Value" + i, i, cpmap, tn );
122 }
123 }
124 }
125
126 @Override
127 public void run() {
128 String tn = Thread.currentThread().getName();
129
130 toTheStartingGate();
131 try {
132 for (int i=0; i< NUM_ENTRIES; i++) {
133 check("Key" + i, "Value" + i, pmap, tn);
134 check("Int.Key" + i, i, pmap, tn);
135 check("S.A.I.Key" + i, "S.A.I.Value" + i, i, pmap, tn);
136 if (i % 1000 == 0)
137 System.out.print(".");
138 }
139 } catch (IOException e) {
140 fail(e.getMessage());
141 } finally {
142 if (mode.equals(Mode.NOSHARE_INSTANCE))
143 try {pmap.close(); } catch (IOException e) { fail(e.getMessage()); }
144 }
145 }
146
147 // Mechanism to get all test threads into "running" mode.
148 static Phaser atTheStartingGate = new Phaser(NUM_THREADS);
149 static void toTheStartingGate() {
150 atTheStartingGate.arriveAndAwaitAdvance();
151 }
152
153 static void put(String key, String value, PersistentTreeMap pmap, String tn)
154 throws IOException
155 {
156 debug(tn + ": putting: " + key + ", " + value + "\n");
157 pmap.put(key, value);
158 }
159
160 static void put(String key, int value, PersistentTreeMap pmap, String tn)
161 throws IOException
162 {
163 debug(tn + ": putting: " + key + ", " + value + "\n");
164 pmap.put(key, value);
165 }
166
167 static void put(String key, String sval, int ival,
168 PersistentTreeMap pmap, String tn)
169 throws IOException
170 {
171 debug(tn + ": putting: " + key + ", [" + sval + "," + ival + "]" + "\n");
172 pmap.put(key, sval, ival);
173 }
174
175 static String get(String key, PersistentTreeMap pmap, String tn)
176 throws IOException
177 {
178 debug(tn + ": getting: " + key + ", ");
179 String value = pmap.get(key);
180 debug(value + "\n");
181 return value;
182 }
183
184 static int getInt(String key, PersistentTreeMap pmap, String tn)
185 throws IOException
186 {
187 debug(tn + ": getting: " + key + ", ");
188 int value = pmap.getInt(key);
189 debug(value + "\n");
190 return value;
191 }
192
193 static StringAndInt getStringAndInt(String key, PersistentTreeMap pmap,
194 String tn)
195 throws IOException
196 {
197 debug(tn + ": getting: " + key + ", ");
198 StringAndInt value = pmap.getStringAndInt(key);
199 debug("[" + value.s + "," + value.i + "]" + "\n");
200 return value;
201 }
202
203 static void check(String key, String expected, PersistentTreeMap pmap,
204 String tn)
205 throws IOException
206 {
207 String value = get(key, pmap, tn);
208 if (!expected.equals(value))
209 fail(tn + ": Failed: key:" + key + ", expected: " +
210 expected + ", got:" + value);
211 }
212
213 static void check(String key, int expected, PersistentTreeMap pmap,
214 String tn)
215 throws IOException
216 {
217 int value = getInt(key, pmap, tn);
218 if (expected != value)
219 fail(tn + ": Failed: key:" + key + ", expected: " +
220 expected + ", got:" + value);
221 }
222
223 static void check(String key, String expectedString,
224 int expectedInt, PersistentTreeMap pmap, String tn)
225 throws IOException
226 {
227 StringAndInt value = getStringAndInt(key, pmap, tn);
228 if (!expectedString.equals(value.s) || expectedInt != value.i) {
229 fail(tn + ": Failed: key:" + key + ", expected: " +
230 "[" + expectedString + "," + expectedInt + "]" + ", got:" +
231 "[" + value.s + "," + value.i + "]");
232 }
233 }
234
235 static void debug(String message) {
236 if (debug)
237 System.out.print(message);
238 }
239
240 static void fail(String message) {
241 System.err.println(message);
242 fail++;
243 //Thread.dumpStack();
244 }
245 }