1 /*
   2  * Copyright (c) 2011, 2018, 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 /*
  25  * @test
  26  * @key stress gc randomness
  27  *
  28  * @summary converted from VM Testbase gc/gctests/StringInternSync.
  29  * VM Testbase keywords: [gc, stress, stressopt, feature_perm_removal_jdk7, nonconcurrent]
  30  * VM Testbase readme:
  31  * The test verifies that String.intern is correctly synchronized.
  32  * Test interns same strings in different threads and verifies that all interned equal
  33  * strings are same objects.
  34  * This test interns a few large strings.
  35  *
  36  * @library /vmTestbase
  37  *          /test/lib
  38  * @run driver jdk.test.lib.FileInstaller . .
  39  * @run main/othervm
  40  *      -XX:+UnlockDiagnosticVMOptions
  41  *      -XX:+VerifyStringTableAtExit
  42  *      gc.gctests.StringInternSync.StringInternSync
  43  *      -ms low
  44  */
  45 
  46 package gc.gctests.StringInternSync;
  47 
  48 import java.util.*;
  49 import java.util.ArrayList;
  50 import java.util.concurrent.locks.ReadWriteLock;
  51 import java.util.concurrent.locks.ReentrantReadWriteLock;
  52 import nsk.share.TestBug;
  53 import nsk.share.TestFailure;
  54 import nsk.share.gc.*;
  55 import nsk.share.gc.gp.MemoryStrategy;
  56 import nsk.share.gc.gp.MemoryStrategyAware;
  57 import nsk.share.gc.gp.string.RandomStringProducer;
  58 
  59 public class StringInternSync extends ThreadedGCTest implements MemoryStrategyAware {
  60 
  61     // The list of strings which will be interned
  62     static final List<String> stringsToIntern = new ArrayList();
  63     // The global container for references to internded strings
  64     static final List<List<String>> internedStrings = new ArrayList<List<String>>();
  65     // Approximate size occupied by all interned strings
  66     long sizeOfAllInteredStrings = 0;
  67     // maximum size of one string
  68     int maxStringSize;
  69     RandomStringProducer gp = new RandomStringProducer();
  70     MemoryStrategy memoryStrategy;
  71     ReadWriteLock rwlock = new ReentrantReadWriteLock();
  72 
  73     @Override
  74     public void setMemoryStrategy(MemoryStrategy memoryStrategy) {
  75         this.memoryStrategy = memoryStrategy;
  76     }
  77 
  78     private class StringGenerator implements Runnable {
  79 
  80         List<String> internedLocal;
  81 
  82         public StringGenerator(List<String> internedLocal) {
  83             this.internedLocal = internedLocal;
  84         }
  85 
  86         public void run() {
  87             try {
  88                 rwlock.readLock().lock();
  89                 internedLocal.clear();
  90                 for (String str : stringsToIntern) {
  91                     // Intern copy of string
  92                     // and save reference to it
  93                     internedLocal.add(new String(str).intern());
  94                 }
  95             } finally {
  96                 rwlock.readLock().unlock();
  97             }
  98 
  99             // after each iteration 0 thread
 100             // lock our main resource and verify String.intern
 101             if (internedLocal == internedStrings.get(0)) {
 102                 try {
 103                     rwlock.writeLock().lock();
 104                     // We select first list and compare all other with it
 105                     // if 2 strings are equal they should be the same "=="
 106                     List<String> interned = internedStrings.get(0);
 107 
 108                     for (List<String> list : internedStrings) {
 109                         if (list == interned) {
 110                             continue;
 111                         }
 112                         if (list.size() == 0) {
 113                             continue; // this thread haven't got lock
 114                         }
 115 
 116                         if (list.size() != interned.size()) {
 117                             throw new TestFailure("Size of interned string list differ from origial."
 118                                     + " interned " + list.size() + " original " + interned.size());
 119                         }
 120                         for (int i = 0; i < interned.size(); i++) {
 121                             String str = interned.get(i);
 122                             if (!str.equals(list.get(i))) {
 123                                 throw new TestFailure("The interned strings are not the equals.");
 124                             }
 125                             if (str != list.get(i)) {
 126                                 throw new TestFailure("The equal interned strings are not the same.");
 127                             }
 128                         }
 129                         list.clear();
 130 
 131                     }
 132                     interned.clear();
 133                     stringsToIntern.clear();
 134                     for (long currentSize = 0; currentSize <= sizeOfAllInteredStrings; currentSize++) {
 135                         stringsToIntern.add(gp.create(maxStringSize));
 136                         currentSize += maxStringSize;
 137                     }
 138                 } finally {
 139                     rwlock.writeLock().unlock();
 140                 }
 141             }
 142         }
 143     }
 144 
 145     @Override
 146     public void run() {
 147         sizeOfAllInteredStrings = 10 * 1024 * 1024; // let use 100 * strings of size 10000
 148         maxStringSize = (int) (sizeOfAllInteredStrings / memoryStrategy.getSize(sizeOfAllInteredStrings));
 149         log.debug("The overall size of interned strings  : " + sizeOfAllInteredStrings / (1024 * 1024) + "M");
 150         log.debug("The count of interned strings : " + sizeOfAllInteredStrings / maxStringSize);
 151         for (long currentSize = 0; currentSize <= sizeOfAllInteredStrings; currentSize++) {
 152             stringsToIntern.add(gp.create(maxStringSize));
 153             currentSize += maxStringSize;
 154         }
 155         super.run();
 156     }
 157 
 158     @Override
 159     protected Runnable createRunnable(int i) {
 160         ArrayList list = new ArrayList();
 161         internedStrings.add(list);
 162         return new StringGenerator(list);
 163     }
 164 
 165     public static void main(String[] args) {
 166         GC.runTest(new StringInternSync(), args);
 167     }
 168 }