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 }