/** * Copyright 2005-2012 Akiban Technologies, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.persistit.stress.unit; import java.util.Arrays; import java.util.BitSet; import java.util.concurrent.atomic.AtomicLong; import com.persistit.Exchange; import com.persistit.Key; import com.persistit.Transaction; import com.persistit.Value; import com.persistit.exception.RollbackException; import com.persistit.util.ArgParser; public class Stress3txn extends StressBase { private final static String DEFAULT_DATA_FILE_NAME = "src/test/resources/test3_data.txt"; private final static String[] ARGS_TEMPLATE = { "op|String:wrd|Operations to perform", "repeat|int:1:0:1000000000|Repetitions", "count|int:10000:0:1000000000|Number of nodes to populate", "seed|int:1:1:20000|Random seed", "size|int:3000:1:20000|Maximum record size", "splay|int:1:1:1000|Splay", "datafile|String:" + DEFAULT_DATA_FILE_NAME, }; static String[] _fileNames = null; static boolean _filesLoaded; final static AtomicLong _counter = new AtomicLong(0); int _splay; int _seed; int _size; String _opflags; public Stress3txn(final String argsString) { super(argsString); } @Override public void setUp() throws Exception { super.setUp(); _ap = new ArgParser("com.persistit.Stress3txn", _args, ARGS_TEMPLATE).strict(); _splay = _ap.getIntValue("splay"); _opflags = _ap.getStringValue("op"); _seed = _ap.getIntValue("seed"); _size = _ap.getIntValue("size"); _repeatTotal = _ap.getIntValue("repeat"); _total = _ap.getIntValue("count"); try { // Exchange with Thread-private Tree _ex = getPersistit().getExchange("persistit", _rootName + _threadIndex, true); } catch (final Exception ex) { handleThrowable(ex); } initialize(_ap.getStringValue("datafile")); } /** * Performed by only one thread. */ public synchronized static void initialize(final String fileName) { if (_filesLoaded) { return; } Stress3.initialize(fileName); _fileNames = Stress3._fileNames; _filesLoaded = Stress3._filesLoaded; } /** * Performed once by each newly started thread. */ @Override public void executeTest() { final int[] sizeArray = new int[_total * 100]; final int[] randomSeq = new int[_total]; final int[] randomUniqueSeq = new int[_total]; _random.setSeed(_seed); BitSet bs = new BitSet(); for (int counter = 0; counter < _total; counter++) { final int keyInteger = random(0, _fileNames.length); randomSeq[counter] = keyInteger; final boolean unique = !bs.get(keyInteger); if (unique) { bs.set(keyInteger); } randomUniqueSeq[counter] = unique ? keyInteger : -1; } bs = null; setPhase("@"); try { _ex.clear().remove(Key.GTEQ); } catch (final Exception e) { handleThrowable(e); } final Exchange ex1 = new Exchange(_ex); final Exchange ex2 = new Exchange(_ex); final Exchange ex3 = new Exchange(_ex); for (_repeat = 0; (_repeat < _repeatTotal || isUntilStopped()) && !isStopped(); _repeat++) { final Transaction txn = ex1.getTransaction(); if (_opflags.indexOf('w') >= 0) { setPhase("w"); for (_count = 0; (_count < _total) && !isStopped(); _count++) { try { final int keyInteger = randomSeq[_count]; final String s = _fileNames[keyInteger]; long atomic; int retries = 100; for (;;) { txn.begin(); try { ex1.clear().append("byName").append(s).fetch(); if (!ex1.getValue().isDefined() || ex1.getValue().isNull()) { atomic = _counter.incrementAndGet(); ex1.getValue().put(atomic); ex1.store(); addWork(1); } else { atomic = ex1.getValue().getLong(); } setupTestValue(ex2, _count, random(30, _size)); if (atomic < sizeArray.length) { sizeArray[(int) atomic] = ex2.getValue().getEncodedSize(); } ex2.clear().append("byCounter").append(atomic).store(); addWork(1); _sb1.setLength(0); _sb1.append(s); _sb1.reverse(); ex3.getValue().put(atomic); ex3.clear().append("byReversedName").append(_sb1).store(); addWork(1); txn.commit(); break; } catch (final RollbackException rbe) { if (--retries <= 0) { throw rbe; } } finally { txn.end(); } } } catch (final Throwable t) { handleThrowable(t); } } } if (_opflags.indexOf('r') >= 0) { setPhase("r"); final Value value2 = new Value(getPersistit()); for (_count = 0; (_count < _total) && !isStopped(); _count++) { try { final int keyInteger = randomSeq[_count]; if (keyInteger < 0) { continue; } final String s = _fileNames[keyInteger]; ex1.clear().append("byName").append(s).fetch(); addWork(1); if (!ex1.getValue().isDefined() || ex1.getValue().isNull()) { throw new RuntimeException("Expected filename <" + s + "> was not found - key=" + ex1.getKey()); } final long atomic = ex1.getValue().getLong(); setupTestValue(ex2, _count, random(30, _size)); ex2.clear().append("byCounter").append(atomic).fetch(value2); addWork(1); if (!value2.isDefined() || value2.isNull()) { throw new RuntimeException("Expected value for byCounter " + atomic + " was not found - key=" + ex2.getKey()); } final int size2 = value2.getEncodedSize(); if (atomic < sizeArray.length) { final int size1 = sizeArray[(int) atomic]; if (size1 != size2) { throw new RuntimeException("Value is size " + size2 + ", should be " + size1 + " key=" + ex2.getKey()); } } _sb1.setLength(0); _sb1.append(s); _sb1.reverse(); ex3.clear().append("byReversedName").append(_sb1).fetch(); addWork(1); if (!ex3.getValue().isDefined() || ex3.getValue().isNull() || (ex3.getValue().getLong() != atomic)) { throw new RuntimeException("Missing or incorrect value " + ex3.getValue() + " should be " + atomic + " key=" + ex3.getKey()); } } catch (final Throwable t) { handleThrowable(t); } } } if ((_opflags.indexOf('D') >= 0) && !isStopped()) { if (random(0, 4) == 0) { setPhase("D"); try { ex1.clear().append("byName").remove(Key.GTEQ); ex2.clear().append("byCounter").remove(Key.GTEQ); ex3.clear().append("byReversedName").remove(Key.GTEQ); ex1.clear().append("counter").remove(); addWork(4); Arrays.fill(sizeArray, 0); // We've deleted everything, so we might as well restart continue; } catch (final Throwable t) { handleThrowable(t); } } } if (_opflags.indexOf('d') >= 0) { if (random(0, 4) == 0) { setPhase("d"); for (_count = 0; (_count < _total) && !isStopped(); _count++) { try { final int keyInteger = randomUniqueSeq[_count]; if (keyInteger < 0) { continue; } int retries = 100; for (;;) { txn.begin(); try { final String s = _fileNames[keyInteger]; ex1.clear().append("byName").append(s).fetch(); addWork(1); if (!ex1.getValue().isDefined() || ex1.getValue().isNull()) { fail("Expected filename <" + s + "> was not found - key=" + ex1.getKey() + " keyInteger=" + keyInteger + " at counter=" + _count); break; } final long atomic = ex1.getValue().getLong(); ex1.remove(); ex2.clear().append("byCounter").append(atomic).remove(); addWork(1); if (atomic < sizeArray.length) { sizeArray[(int) atomic] = 0; } _sb1.setLength(0); _sb1.append(s); _sb1.reverse(); ex3.clear().append("byReversedName").append(_sb1).remove(); addWork(1); txn.commit(); break; } catch (final RollbackException rbe) { if (--retries <= 0) { throw rbe; } } finally { txn.end(); } } } catch (final Throwable t) { handleThrowable(t); } } } } } } }