spaces to tabs

Our Java bindings were in a state where we had a handful of files that were indented with spaces, while the rest were indented with tabs. In the interest of (1) fixing all of the indentation without (2) blowing all history, it seemed expedient to use tabs everywhere. So, here we are.
This commit is contained in:
Alec Grieser 2018-04-09 19:03:47 -07:00
parent b625114b1c
commit 1efb007648
No known key found for this signature in database
GPG Key ID: CAF63551C60D3462
20 changed files with 1065 additions and 1075 deletions

View File

@ -30,11 +30,6 @@
<property name="option" value="eol"/>
<property name="ignoreEnums" value="false"/>
</module>
<!-- We have about 76 errors with value = "alone" and 27 with value = "same". We should pick one.
<module name="RightCurly">
<property name="option" value="same"/>
</module>
-->
<!-- Design -->
<!-- We might get some helpful errors if we turned this on, but not right now.

View File

@ -42,12 +42,12 @@ class JNIUtil {
OSX("osx", "x86_64", true);
private final String name;
private final String arch;
private final String arch;
private final boolean canDeleteEager;
OS(String name, String arch, boolean canDeleteEager) {
this.name = name;
this.arch = arch;
this.arch = arch;
this.canDeleteEager = canDeleteEager;
}
@ -55,9 +55,9 @@ class JNIUtil {
return this.name;
}
public String getArch() {
return this.arch;
}
public String getArch() {
return this.arch;
}
}
/**
@ -89,18 +89,18 @@ class JNIUtil {
OS os = getRunningOS();
String path = getPath(os, libName);
if ((os.getName().equals("linux") && !path.endsWith(".so")) || (os.getName().equals("windows") && !path.endsWith(".dll")) || (os.getName().equals("osx") && !path.endsWith(".jnilib") && !path.endsWith(".dylib"))) {
throw new IllegalStateException("OS sanity check failed. System property os.name reports " + os.getName()+" but System.mapLibraryName is looking for " + getLibName(libName));
}
if ((os.getName().equals("linux") && !path.endsWith(".so")) || (os.getName().equals("windows") && !path.endsWith(".dll")) || (os.getName().equals("osx") && !path.endsWith(".jnilib") && !path.endsWith(".dylib"))) {
throw new IllegalStateException("OS sanity check failed. System property os.name reports " + os.getName()+" but System.mapLibraryName is looking for " + getLibName(libName));
}
File exported;
File exported;
try {
exported = exportResource(path);
}
catch (IOException e) {
throw new UnsatisfiedLinkError(e.getMessage());
}
try {
exported = exportResource(path);
}
catch (IOException e) {
throw new UnsatisfiedLinkError(e.getMessage());
}
String filename = exported.getAbsolutePath();
System.load(filename);

View File

@ -21,17 +21,17 @@
package com.apple.foundationdb;
class RangeResultInfo {
RangeResultSummary getSummary() {
return f.getSummary();
}
RangeResultSummary getSummary() {
return f.getSummary();
}
RangeResult get() {
return f.getResults();
}
RangeResult get() {
return f.getResults();
}
RangeResultInfo(FutureResults f) {
this.f = f;
}
RangeResultInfo(FutureResults f) {
this.f = f;
}
private FutureResults f;
private FutureResults f;
}

View File

@ -526,7 +526,7 @@ public class DirectoryLayer implements Directory {
return AsyncUtil.collect(
AsyncUtil.mapIterable(tr.getRange(subdir.range()),
kv -> subdir.unpack(kv.getKey()).getString(0)
kv -> subdir.unpack(kv.getKey()).getString(0)
),
tr.getExecutor()
);

View File

@ -46,231 +46,231 @@ import com.apple.foundationdb.tuple.Versionstamp;
* </p>
*/
public class Subspace {
static final Tuple EMPTY_TUPLE = Tuple.from();
static final byte[] EMPTY_BYTES = new byte[0];
static final Tuple EMPTY_TUPLE = Tuple.from();
static final byte[] EMPTY_BYTES = new byte[0];
private final byte[] rawPrefix;
private final byte[] rawPrefix;
/**
* Constructor for a subspace formed with an empty prefix {@link Tuple}.
*/
public Subspace() {
this(EMPTY_TUPLE, EMPTY_BYTES);
}
/**
* Constructor for a subspace formed with an empty prefix {@link Tuple}.
*/
public Subspace() {
this(EMPTY_TUPLE, EMPTY_BYTES);
}
/**
* Constructor for a subspace formed with the specified prefix {@link Tuple}.
* Note that the {@link Tuple} {@code prefix} should not contain any incomplete
* {@link Versionstamp}s as any of its entries.
*
* @param prefix a {@link Tuple} used to form the subspace
* @throws IllegalArgumentException if {@code prefix} contains any incomplete {@link Versionstamp}s
*/
public Subspace(Tuple prefix) {
this(prefix, EMPTY_BYTES);
}
/**
* Constructor for a subspace formed with the specified prefix {@link Tuple}.
* Note that the {@link Tuple} {@code prefix} should not contain any incomplete
* {@link Versionstamp}s as any of its entries.
*
* @param prefix a {@link Tuple} used to form the subspace
* @throws IllegalArgumentException if {@code prefix} contains any incomplete {@link Versionstamp}s
*/
public Subspace(Tuple prefix) {
this(prefix, EMPTY_BYTES);
}
/**
* Constructor for a subspace formed with the specified byte string, which will
* be prepended to all packed keys.
*
* @param rawPrefix a byte array used as the prefix for all packed keys
*/
public Subspace(byte[] rawPrefix) {
this(EMPTY_TUPLE, rawPrefix);
}
/**
* Constructor for a subspace formed with the specified byte string, which will
* be prepended to all packed keys.
*
* @param rawPrefix a byte array used as the prefix for all packed keys
*/
public Subspace(byte[] rawPrefix) {
this(EMPTY_TUPLE, rawPrefix);
}
/**
* Constructor for a subspace formed with both a prefix {@link Tuple} and a
* prefix byte string. The prefix {@code Tuple} will be prepended to all
* {@code Tuples} packed by the {@code Subspace}, and the byte string prefix
* will be prepended to the packed result. Note that the {@link Tuple} {@code prefix}
* should not contain any incomplete {@link Versionstamp}s as any of its entries.
*
* @param prefix a {@code Tuple} used to form the subspace
* @param rawPrefix a byte array used as the prefix for all packed keys
* @throws IllegalArgumentException if {@code prefix} contains any incomplete {@link Versionstamp}s
*/
public Subspace(Tuple prefix, byte[] rawPrefix) {
this.rawPrefix = join(rawPrefix, prefix.pack());
}
/**
* Constructor for a subspace formed with both a prefix {@link Tuple} and a
* prefix byte string. The prefix {@code Tuple} will be prepended to all
* {@code Tuples} packed by the {@code Subspace}, and the byte string prefix
* will be prepended to the packed result. Note that the {@link Tuple} {@code prefix}
* should not contain any incomplete {@link Versionstamp}s as any of its entries.
*
* @param prefix a {@code Tuple} used to form the subspace
* @param rawPrefix a byte array used as the prefix for all packed keys
* @throws IllegalArgumentException if {@code prefix} contains any incomplete {@link Versionstamp}s
*/
public Subspace(Tuple prefix, byte[] rawPrefix) {
this.rawPrefix = join(rawPrefix, prefix.pack());
}
/**
* Returns true if this {@code Subspace} is equal to {@code rhs}.
* Two {@code Subspace}s are equal if they have the same prefix.
*
* @param rhs the object to check for equality
* @return {@code true} if this {@code Subspace} and {@code rhs} have equal prefixes
*/
@Override
public boolean equals(Object rhs) {
if(this == rhs) {
return true;
}
if(rhs == null || getClass() != rhs.getClass()) {
return false;
}
Subspace other = (Subspace)rhs;
return Arrays.equals(rawPrefix, other.rawPrefix);
}
/**
* Returns true if this {@code Subspace} is equal to {@code rhs}.
* Two {@code Subspace}s are equal if they have the same prefix.
*
* @param rhs the object to check for equality
* @return {@code true} if this {@code Subspace} and {@code rhs} have equal prefixes
*/
@Override
public boolean equals(Object rhs) {
if(this == rhs) {
return true;
}
if(rhs == null || getClass() != rhs.getClass()) {
return false;
}
Subspace other = (Subspace)rhs;
return Arrays.equals(rawPrefix, other.rawPrefix);
}
/**
* Create a human-readable string representation of this subspace. This is
* really only useful for debugging purposes, but it includes information
* on what raw prefix the subspace is using.
* @return a printable representation of the subspace
*/
@Override
public String toString() {
return "Subspace(rawPrefix=" + printable(rawPrefix) + ")";
}
/**
* Create a human-readable string representation of this subspace. This is
* really only useful for debugging purposes, but it includes information
* on what raw prefix the subspace is using.
* @return a printable representation of the subspace
*/
@Override
public String toString() {
return "Subspace(rawPrefix=" + printable(rawPrefix) + ")";
}
/**
* Returns a hash-table compatible hash of this subspace. This is based off
* of the hash of the underlying byte-array prefix.
* @return a hash of this subspace
*/
@Override
public int hashCode() {
return Arrays.hashCode(rawPrefix);
}
/**
* Returns a hash-table compatible hash of this subspace. This is based off
* of the hash of the underlying byte-array prefix.
* @return a hash of this subspace
*/
@Override
public int hashCode() {
return Arrays.hashCode(rawPrefix);
}
/**
* Gets a new subspace which is equivalent to this subspace with its prefix {@link Tuple} extended by
* the specified {@code Object}. The object will be inserted into a {@link Tuple} and passed to {@link #get(Tuple)}.
*
* @param obj an {@code Object} compatible with {@code Tuple}s
* @return a new subspace formed by joining this {@code Subspace}'s prefix to {@code obj}
*/
public Subspace get(Object obj) {
return get(Tuple.from(obj));
}
/**
* Gets a new subspace which is equivalent to this subspace with its prefix {@link Tuple} extended by
* the specified {@code Object}. The object will be inserted into a {@link Tuple} and passed to {@link #get(Tuple)}.
*
* @param obj an {@code Object} compatible with {@code Tuple}s
* @return a new subspace formed by joining this {@code Subspace}'s prefix to {@code obj}
*/
public Subspace get(Object obj) {
return get(Tuple.from(obj));
}
/**
* Gets a new subspace which is equivalent to this subspace with its prefix {@link Tuple} extended by
* the specified {@link Tuple}.
*
* @param tuple the {@link Tuple} used to form the new {@code Subspace}
* @return a new subspace formed by joining this {@code Subspace}'s prefix to {@code tuple}
*/
public Subspace get(Tuple tuple) {
return subspace(tuple);
}
/**
* Gets a new subspace which is equivalent to this subspace with its prefix {@link Tuple} extended by
* the specified {@link Tuple}.
*
* @param tuple the {@link Tuple} used to form the new {@code Subspace}
* @return a new subspace formed by joining this {@code Subspace}'s prefix to {@code tuple}
*/
public Subspace get(Tuple tuple) {
return subspace(tuple);
}
/**
* Gets the key encoding the prefix used for this {@code Subspace}. This is equivalent to
* {@link #pack}ing the empty {@link Tuple}.
*
* @return the key encoding the prefix used for this {@code Subspace}
*/
public byte[] getKey() {
return pack();
}
/**
* Gets the key encoding the prefix used for this {@code Subspace}. This is equivalent to
* {@link #pack}ing the empty {@link Tuple}.
*
* @return the key encoding the prefix used for this {@code Subspace}
*/
public byte[] getKey() {
return pack();
}
/**
* Gets the key encoding the prefix used for this {@code Subspace}.
*
* @return the key encoding the prefix used for this {@code Subspace}
*/
public byte[] pack() {
return Arrays.copyOf(rawPrefix, rawPrefix.length);
}
/**
* Gets the key encoding the prefix used for this {@code Subspace}.
*
* @return the key encoding the prefix used for this {@code Subspace}
*/
public byte[] pack() {
return Arrays.copyOf(rawPrefix, rawPrefix.length);
}
/**
* Gets the key encoding the specified {@code Object} in this {@code Subspace}. {@code obj} is
* inserted into a {@link Tuple} and packed with {@link #pack(Tuple)}.
*
* @param obj an {@code Object} to be packed that is compatible with {@link Tuple}s
* @return the key encoding the tuple derived from {@code obj}
*/
public byte[] pack(Object obj) {
return pack(Tuple.from(obj));
}
/**
* Gets the key encoding the specified {@code Object} in this {@code Subspace}. {@code obj} is
* inserted into a {@link Tuple} and packed with {@link #pack(Tuple)}.
*
* @param obj an {@code Object} to be packed that is compatible with {@link Tuple}s
* @return the key encoding the tuple derived from {@code obj}
*/
public byte[] pack(Object obj) {
return pack(Tuple.from(obj));
}
/**
* Gets the key encoding the specified tuple in this {@code Subspace}. For example, if you have a {@code Subspace}
* with prefix {@link Tuple} {@code ("users")} and you use it to pack the {@link Tuple} {@code ("Smith")},
* the result is the same as if you packed the {@link Tuple} {@code ("users", "Smith")}.
*
* @param tuple the {@code Tuple} to be packed
* @return the key encoding the specified tuple in this {@code Subspace}
*/
public byte[] pack(Tuple tuple) {
return tuple.pack(rawPrefix);
}
/**
* Gets the key encoding the specified tuple in this {@code Subspace}. For example, if you have a {@code Subspace}
* with prefix {@link Tuple} {@code ("users")} and you use it to pack the {@link Tuple} {@code ("Smith")},
* the result is the same as if you packed the {@link Tuple} {@code ("users", "Smith")}.
*
* @param tuple the {@code Tuple} to be packed
* @return the key encoding the specified tuple in this {@code Subspace}
*/
public byte[] pack(Tuple tuple) {
return tuple.pack(rawPrefix);
}
/**
* Gets the key encoding the specified tuple in this {@code Subspace} for use with
* {@link com.apple.foundationdb.MutationType#SET_VERSIONSTAMPED_KEY MutationType.SET_VERSIONSTAMPED_KEY}.
* There must be exactly one incomplete {@link Versionstamp} included in the given {@link Tuple}. It will
* create a key that is within this {@code Subspace} that can be provided as the {@code key} argument to
* {@link com.apple.foundationdb.Transaction#mutate(com.apple.foundationdb.MutationType, byte[], byte[]) Transaction.mutate()}
* with the {@link com.apple.foundationdb.MutationType#SET_VERSIONSTAMPED_KEY SET_VERSIONSTAMPED_KEY}
* mutation. This will throw an {@link IllegalArgumentException} if the {@link Tuple} does not
* contain an incomplete {@link Versionstamp} or if it contains multiple.
*
* @param tuple the {@code Tuple} to be packed
* @return the key encoding the specified tuple in this {@code Subspace}
* @throws IllegalArgumentException if {@code tuple} does not contain exactly one incomplete {@link Versionstamp}
*/
public byte[] packWithVersionstamp(Tuple tuple) {
return tuple.packWithVersionstamp(rawPrefix);
}
/**
* Gets the key encoding the specified tuple in this {@code Subspace} for use with
* {@link com.apple.foundationdb.MutationType#SET_VERSIONSTAMPED_KEY MutationType.SET_VERSIONSTAMPED_KEY}.
* There must be exactly one incomplete {@link Versionstamp} included in the given {@link Tuple}. It will
* create a key that is within this {@code Subspace} that can be provided as the {@code key} argument to
* {@link com.apple.foundationdb.Transaction#mutate(com.apple.foundationdb.MutationType, byte[], byte[]) Transaction.mutate()}
* with the {@link com.apple.foundationdb.MutationType#SET_VERSIONSTAMPED_KEY SET_VERSIONSTAMPED_KEY}
* mutation. This will throw an {@link IllegalArgumentException} if the {@link Tuple} does not
* contain an incomplete {@link Versionstamp} or if it contains multiple.
*
* @param tuple the {@code Tuple} to be packed
* @return the key encoding the specified tuple in this {@code Subspace}
* @throws IllegalArgumentException if {@code tuple} does not contain exactly one incomplete {@link Versionstamp}
*/
public byte[] packWithVersionstamp(Tuple tuple) {
return tuple.packWithVersionstamp(rawPrefix);
}
/**
* Gets the {@link Tuple} encoded by the given key, with this {@code Subspace}'s prefix {@link Tuple} and
* {@code raw prefix} removed.
*
* @param key The key being decoded
* @return the {@link Tuple} encoded by {@code key} with the prefix removed
*/
public Tuple unpack(byte[] key) {
if(!contains(key))
throw new IllegalArgumentException("Cannot unpack key that is not contained in subspace.");
/**
* Gets the {@link Tuple} encoded by the given key, with this {@code Subspace}'s prefix {@link Tuple} and
* {@code raw prefix} removed.
*
* @param key The key being decoded
* @return the {@link Tuple} encoded by {@code key} with the prefix removed
*/
public Tuple unpack(byte[] key) {
if(!contains(key))
throw new IllegalArgumentException("Cannot unpack key that is not contained in subspace.");
return Tuple.fromBytes(Arrays.copyOfRange(key, rawPrefix.length, key.length));
}
return Tuple.fromBytes(Arrays.copyOfRange(key, rawPrefix.length, key.length));
}
/**
* Gets a {@link Range} respresenting all keys strictly in the {@code Subspace}.
*
* @return the {@link Range} of keyspace corresponding to this {@code Subspace}
*/
public Range range() {
return range(EMPTY_TUPLE);
}
/**
* Gets a {@link Range} respresenting all keys strictly in the {@code Subspace}.
*
* @return the {@link Range} of keyspace corresponding to this {@code Subspace}
*/
public Range range() {
return range(EMPTY_TUPLE);
}
/**
* Gets a {@link Range} representing all keys in the {@code Subspace} strictly starting with
* the specified {@link Tuple}.
*
* @param tuple the {@code Tuple} whose sub-keys we are searching for
* @return the {@link Range} of keyspace corresponding to {@code tuple}
*/
public Range range(Tuple tuple) {
Range p = tuple.range();
return new Range(join(rawPrefix, p.begin), join(rawPrefix, p.end));
}
/**
* Gets a {@link Range} representing all keys in the {@code Subspace} strictly starting with
* the specified {@link Tuple}.
*
* @param tuple the {@code Tuple} whose sub-keys we are searching for
* @return the {@link Range} of keyspace corresponding to {@code tuple}
*/
public Range range(Tuple tuple) {
Range p = tuple.range();
return new Range(join(rawPrefix, p.begin), join(rawPrefix, p.end));
}
/**
* Tests whether the specified key starts with this {@code Subspace}'s prefix, indicating that
* the {@code Subspace} logically contains key.
*
* @param key the key to be tested
* @return {@code true} if {@code key} starts with {@code Subspace.key()}
*/
public boolean contains(byte[] key) {
return ByteArrayUtil.startsWith(key, rawPrefix);
}
/**
* Tests whether the specified key starts with this {@code Subspace}'s prefix, indicating that
* the {@code Subspace} logically contains key.
*
* @param key the key to be tested
* @return {@code true} if {@code key} starts with {@code Subspace.key()}
*/
public boolean contains(byte[] key) {
return ByteArrayUtil.startsWith(key, rawPrefix);
}
/**
* Gets a new subspace which is equivalent to this subspace with its prefix {@link Tuple} extended by
* the specified {@link Tuple}.
*
* @param tuple the {@link Tuple} used to form the new {@code Subspace}
* @return a new subspace formed by joining this {@code Subspace}'s prefix to {@code tuple}
*/
public Subspace subspace(Tuple tuple) {
return new Subspace(tuple, rawPrefix);
}
/**
* Gets a new subspace which is equivalent to this subspace with its prefix {@link Tuple} extended by
* the specified {@link Tuple}.
*
* @param tuple the {@link Tuple} used to form the new {@code Subspace}
* @return a new subspace formed by joining this {@code Subspace}'s prefix to {@code tuple}
*/
public Subspace subspace(Tuple tuple) {
return new Subspace(tuple, rawPrefix);
}
}

View File

@ -63,45 +63,45 @@ import java.util.Iterator;
* </ul>
*/
public class IterableComparator implements Comparator<Iterable<?>> {
/**
* Creates a new {@code IterableComparator}. This {@link Comparator} has
* no internal state.
*/
public IterableComparator() {}
/**
* Creates a new {@code IterableComparator}. This {@link Comparator} has
* no internal state.
*/
public IterableComparator() {}
/**
* Compare two {@link Iterable}s in a way consistent with their
* byte representation. This is done element-wise and is consistent
* with a number of other ways of sorting {@link Tuple}s. This will
* raise an {@link IllegalArgumentException} if any of the items
* of either {@link Iterable} cannot be serialized by a {@link Tuple}.
*
* @param iterable1 the first {@link Iterable} of items
* @param iterable2 the second {@link Iterable} of items
* @return a negative number if the first iterable would sort before the second
* when serialized, a positive number if the opposite is true, and zero
* if the two are equal
*/
@Override
public int compare(Iterable<?> iterable1, Iterable<?> iterable2) {
Iterator<?> i1 = iterable1.iterator();
Iterator<?> i2 = iterable2.iterator();
/**
* Compare two {@link Iterable}s in a way consistent with their
* byte representation. This is done element-wise and is consistent
* with a number of other ways of sorting {@link Tuple}s. This will
* raise an {@link IllegalArgumentException} if any of the items
* of either {@link Iterable} cannot be serialized by a {@link Tuple}.
*
* @param iterable1 the first {@link Iterable} of items
* @param iterable2 the second {@link Iterable} of items
* @return a negative number if the first iterable would sort before the second
* when serialized, a positive number if the opposite is true, and zero
* if the two are equal
*/
@Override
public int compare(Iterable<?> iterable1, Iterable<?> iterable2) {
Iterator<?> i1 = iterable1.iterator();
Iterator<?> i2 = iterable2.iterator();
while(i1.hasNext() && i2.hasNext()) {
int itemComp = TupleUtil.compareItems(i1.next(), i2.next());
if(itemComp != 0) {
return itemComp;
}
}
while(i1.hasNext() && i2.hasNext()) {
int itemComp = TupleUtil.compareItems(i1.next(), i2.next());
if(itemComp != 0) {
return itemComp;
}
}
if(i1.hasNext()) {
// iterable2 is a prefix of iterable1.
return 1;
}
if(i2.hasNext()) {
// iterable1 is a prefix of iterable2.
return -1;
}
return 0;
}
if(i1.hasNext()) {
// iterable2 is a prefix of iterable1.
return 1;
}
if(i2.hasNext()) {
// iterable1 is a prefix of iterable2.
return -1;
}
return 0;
}
}

View File

@ -27,89 +27,89 @@ import com.apple.foundationdb.Database;
import com.apple.foundationdb.FDB;
public abstract class AbstractTester {
public static final int API_VERSION = 510;
protected static final int NUM_RUNS = 25;
protected static final Charset ASCII = Charset.forName("ASCII");
public static final int API_VERSION = 510;
protected static final int NUM_RUNS = 25;
protected static final Charset ASCII = Charset.forName("ASCII");
protected TesterArgs args;
protected Random random;
protected TestResult result;
protected FDB fdb;
protected TesterArgs args;
protected Random random;
protected TestResult result;
protected FDB fdb;
public AbstractTester() {
args = null;
random = new Random();
result = new TestResult(random);
}
public AbstractTester() {
args = null;
random = new Random();
result = new TestResult(random);
}
public void runTest() {
try(Database db = fdb.open()) {
try {
testPerformance(db);
}
catch (Exception e) {
result.addError(wrapAndPrintError(e, "Failed to complete all tests"));
}
}
catch (Exception e) {
result.addError(wrapAndPrintError(e, "fdb.open failed"));
return;
}
}
public void runTest() {
try(Database db = fdb.open()) {
try {
testPerformance(db);
}
catch (Exception e) {
result.addError(wrapAndPrintError(e, "Failed to complete all tests"));
}
}
catch (Exception e) {
result.addError(wrapAndPrintError(e, "fdb.open failed"));
return;
}
}
public abstract void testPerformance(Database db);
public abstract void testPerformance(Database db);
public String multiVersionDescription() {
if (args == null) return "";
public String multiVersionDescription() {
if (args == null) return "";
if (!args.useMultiversionApi()) {
return "multi-version API disabled";
} else if (args.useExternalClient()) {
if (args.putCallbacksOnExternalThread()) {
return "external client on external thread";
} else {
return "external client on main thread";
}
} else {
return "local client";
}
}
if (!args.useMultiversionApi()) {
return "multi-version API disabled";
} else if (args.useExternalClient()) {
if (args.putCallbacksOnExternalThread()) {
return "external client on external thread";
} else {
return "external client on main thread";
}
} else {
return "local client";
}
}
public void run(String[] argStrings) {
args = TesterArgs.parseArgs(argStrings);
if (args == null) return;
public void run(String[] argStrings) {
args = TesterArgs.parseArgs(argStrings);
if (args == null) return;
fdb = FDB.selectAPIVersion(API_VERSION);
fdb = FDB.selectAPIVersion(API_VERSION);
// Validate argument combinations and set options.
if (!args.useMultiversionApi()) {
if (args.putCallbacksOnExternalThread() || args.useExternalClient()) {
throw new IllegalArgumentException("Invalid multi-version API argument combination");
}
fdb.options().setDisableMultiVersionClientApi();
}
if (args.putCallbacksOnExternalThread()) {
if (!args.useExternalClient()) {
throw new IllegalArgumentException("Cannot enable callbacks on external thread without using external client");
}
fdb.options().setCallbacksOnExternalThreads();
}
if (args.useExternalClient()) {
fdb.options().setDisableLocalClient();
}
// Validate argument combinations and set options.
if (!args.useMultiversionApi()) {
if (args.putCallbacksOnExternalThread() || args.useExternalClient()) {
throw new IllegalArgumentException("Invalid multi-version API argument combination");
}
fdb.options().setDisableMultiVersionClientApi();
}
if (args.putCallbacksOnExternalThread()) {
if (!args.useExternalClient()) {
throw new IllegalArgumentException("Cannot enable callbacks on external thread without using external client");
}
fdb.options().setCallbacksOnExternalThreads();
}
if (args.useExternalClient()) {
fdb.options().setDisableLocalClient();
}
try {
runTest();
} catch (Exception e) {
result.addError(e);
}
try {
runTest();
} catch (Exception e) {
result.addError(e);
}
result.save(args.getOutputDirectory());
}
result.save(args.getOutputDirectory());
}
public RuntimeException wrapAndPrintError(Throwable t, String message) {
String errorMessage = message + ": " + t.getClass() + ": " + t.getMessage() + "\n";
t.printStackTrace();
return new RuntimeException(errorMessage, t);
}
public RuntimeException wrapAndPrintError(Throwable t, String message) {
String errorMessage = message + ": " + t.getClass() + ": " + t.getMessage() + "\n";
t.printStackTrace();
return new RuntimeException(errorMessage, t);
}
}

View File

@ -24,7 +24,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.apple.foundationdb.Cluster;
import com.apple.foundationdb.Database;
import com.apple.foundationdb.FDB;
import com.apple.foundationdb.TransactionContext;

View File

@ -22,7 +22,6 @@ package com.apple.foundationdb.test;
import java.util.concurrent.atomic.AtomicInteger;
import com.apple.foundationdb.Cluster;
import com.apple.foundationdb.Database;
import com.apple.foundationdb.FDB;
import com.apple.foundationdb.KeyValue;

View File

@ -53,15 +53,14 @@ public class ParallelRandomScan {
}
private static void runTest(Database database,
int parallelism, int rows, int duration) throws InterruptedException
{
int parallelism, int rows, int duration) throws InterruptedException {
final Random r = new Random();
final AtomicInteger readsCompleted = new AtomicInteger(0);
final AtomicInteger errors = new AtomicInteger(0);
final Semaphore coordinator = new Semaphore(parallelism);
final ContinuousSample<Long> latencies = new ContinuousSample<>(1000);
try(final Transaction tr = database.createTransaction()) {
try(Transaction tr = database.createTransaction()) {
tr.options().setReadYourWritesDisable();
// Clearing the whole database before starting means all reads are local

View File

@ -41,370 +41,370 @@ import com.apple.foundationdb.async.AsyncUtil;
import com.apple.foundationdb.tuple.ByteArrayUtil;
public class PerformanceTester extends AbstractTester {
private final int keyCount;
private final int keySize;
private final int valueSize;
private final String keyFormat;
private final byte[] valueBytes;
public static final int DEFAULT_KEY_COUNT = 10_000;
public static final int DEFAULT_KEY_SIZE = 16;
public static final int DEFAULT_VALUE_SIZE = 100;
private enum Tests {
FUTURE_LATENCY("Java Completable API future throughput"),
SET("Java Completable API set throughput"),
CLEAR("Java Completable API clear throughput"),
CLEAR_RANGE("Java Completable API clear_range throughput"),
PARALLEL_GET("Java Completable API parallel get throughput"),
SERIAL_GET("Java Completable API serial get throughput"),
GET_RANGE("Java Completable API get_range throughput"),
GET_KEY("Java Completable API get_key throughput"),
GET_SINGLE_KEY_RANGE("Java Completable API get_single_key_range throughput"),
ALTERNATING_GET_SET("Java Completable API alternating get and set throughput"),
WRITE_TRANSACTION("Java Completable API single-key transaction throughput");
private String kpi;
private Function<? super Database, ? extends Double> function;
Tests(String kpi) {
this.kpi = kpi;
}
public void setFunction(Function<?super Database, ? extends Double> function) {
this.function = function;
}
public Function<? super Database, ? extends Double> getFunction() {
return function;
}
public String getKpi() {
return kpi;
}
}
public PerformanceTester() {
this(DEFAULT_KEY_COUNT, DEFAULT_KEY_SIZE, DEFAULT_VALUE_SIZE);
}
public PerformanceTester(int keyCount, int keySize, int valueSize) {
super();
this.keyCount = keyCount;
this.keySize = keySize;
this.valueSize = valueSize;
keyFormat = "%0" + keySize + "d";
valueBytes = new byte[valueSize];
Arrays.fill(valueBytes, (byte)'x');
// Initialize tests.
Tests.FUTURE_LATENCY.setFunction(db -> futureLatency(db, 100_000));
Tests.SET.setFunction(db -> set(db, 100_000));
Tests.CLEAR.setFunction(db -> clear(db, 100_000));
Tests.CLEAR_RANGE.setFunction(db -> clearRange(db, 100_000));
Tests.PARALLEL_GET.setFunction(db -> parallelGet(db, 10_000));
Tests.SERIAL_GET.setFunction(db -> serialGet(db, 2_000));
Tests.GET_RANGE.setFunction(db -> getRange(db, 1_000));
Tests.GET_KEY.setFunction(db -> getKey(db, 2_000));
Tests.GET_SINGLE_KEY_RANGE.setFunction(db -> getSingleKeyRange(db, 2_000));
Tests.ALTERNATING_GET_SET.setFunction(db -> alternatingGetSet(db, 2_000));
Tests.WRITE_TRANSACTION.setFunction(db -> writeTransaction(db, 1_000));
}
@Override
public void testPerformance(Database db) {
insertData(db);
List<String> testsToRun;
if (args.getTestsToRun().isEmpty()) {
testsToRun = Arrays.stream(Tests.values()).map(Tests::name).map(String::toLowerCase).sorted().collect(Collectors.toList());
} else {
testsToRun = args.getTestsToRun();
}
for (String test : testsToRun) {
Tests testObj;
try {
testObj = Tests.valueOf(test.toUpperCase());
} catch (IllegalArgumentException e) {
result.addError(new IllegalArgumentException("Test " + test + " not implemented"));
continue;
}
Function<? super Database, ? extends Double> function = testObj.getFunction();
try {
Thread.sleep(5_000);
} catch (InterruptedException e) {
result.addError(wrapAndPrintError(e, "Interrupted while sleeping"));
}
System.out.println("Running test " + test);
List<Double> results = new ArrayList<>(NUM_RUNS);
for (int i = 0; i < NUM_RUNS; i++) {
try {
results.add(function.apply(db));
} catch (Exception e) {
result.addError(wrapAndPrintError(e, "Performance test failed: " + test));
break;
}
}
if (results.size() == NUM_RUNS) {
Collections.sort(results);
result.addKpi(String.format("%s (%s)", testObj.getKpi(), multiVersionDescription()), results.get(results.size()/2).intValue(), "keys/s");
}
}
}
public void insertData(Database db) {
System.out.println("Loading database");
db.run(tr -> {
byte[] subspacePrefix = args.getSubspace().pack();
if (subspacePrefix.length == 0) {
// Clear user space.
tr.clear(new byte[0], new byte[]{(byte)0xff});
} else {
tr.clear(args.getSubspace().range());
}
return null;
});
int keysPerActor = 100_000 / (keySize + valueSize);
int numActors = (int)Math.ceil(keyCount*1.0/keysPerActor);
List<CompletableFuture<Void>> futures = IntStream.range(0, numActors).mapToObj(i -> {
int startKey = keysPerActor * i;
int endKey = (i + 1 == numActors) ? (keyCount) : (keysPerActor * (i+1));
return db.runAsync(tr -> {
IntStream.range(startKey, endKey).forEach(keyIndex -> tr.set(key(keyIndex), value(keyIndex)));
return CompletableFuture.completedFuture((Void)null);
});
}).collect(Collectors.toList());
try {
AsyncUtil.whenAll(futures).get();
} catch (InterruptedException | ExecutionException e) {
result.addError(wrapAndPrintError(e, "Data insertion failed"));
}
// Give the database time to re-balance
try {
Thread.sleep(15_000);
} catch (InterruptedException e) {
result.addError(wrapAndPrintError(e, "Interrupted while waiting for quiescence"));
}
}
public Double futureLatency(Database db, int count) {
return db.run(tr -> {
tr.options().setRetryLimit(5);
tr.getReadVersion().join();
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
tr.getReadVersion().join();
}
long end = System.nanoTime();
return count*1_000_000_000.0/(end - start);
});
}
public Double clear(Database db, int count) {
try(Transaction tr = db.createTransaction()) {
long start = System.nanoTime();
for(int i = 0; i < count; i++) {
tr.clear(randomKey());
}
long end = System.nanoTime();
tr.cancel();
return count * 1_000_000_000.0 / (end - start);
}
}
public Double clearRange(Database db, int count) {
try(Transaction tr = db.createTransaction()) {
long start = System.nanoTime();
for(int i = 0; i < count; i++) {
int keyIndex = randomKeyIndex();
tr.clear(key(keyIndex), key(keyIndex + 1));
}
long end = System.nanoTime();
tr.cancel();
return count * 1_000_000_000.0 / (end - start);
}
}
public Double set(Database db, int count) {
try(Transaction tr = db.createTransaction()) {
long start = System.nanoTime();
for(int i = 0; i < count; i++) {
int keyIndex = randomKeyIndex();
tr.set(key(keyIndex), value(keyIndex));
}
long end = System.nanoTime();
tr.cancel();
return count * 1_000_000_000.0 / (end - start);
}
}
public Double parallelGet(TransactionContext tcx, int count) {
return tcx.run(tr -> {
tr.options().setRetryLimit(5);
long start = System.nanoTime();
List<CompletableFuture<byte[]>> futures = IntStream.range(0, count)
.mapToObj(ignore -> tr.get(randomKey()))
.collect(Collectors.toList());
AsyncUtil.whenAll(futures).join();
long end = System.nanoTime();
return count*1_000_000_000.0/(end - start);
});
}
public Double alternatingGetSet(TransactionContext tcx, int count) {
return tcx.run(tr -> {
tr.options().setRetryLimit(5);
long start = System.nanoTime();
List<CompletableFuture<byte[]>> futures = IntStream.range(0, count)
.mapToObj(ignore -> {
int keyIndex = randomKeyIndex();
byte[] keyBytes = key(keyIndex);
byte[] valBytes = value(keyIndex);
tr.set(keyBytes, valBytes);
return tr.get(keyBytes);
}).collect(Collectors.toList());
AsyncUtil.whenAll(futures).join();
long end = System.nanoTime();
return count*1_000_000_000.0/(end - start);
});
}
public Double serialGet(TransactionContext tcx, int count) {
return tcx.run(tr -> {
tr.options().setRetryLimit(5);
List<byte[]> keys;
if (count > keyCount/2) {
keys = Stream.generate(this::randomKey).limit(count).collect(Collectors.toList());
} else {
Set<Integer> keySet = new HashSet<>();
while (keySet.size() < count) {
keySet.add(randomKeyIndex());
}
keys = keySet.stream().map(this::key).collect(Collectors.toList());
}
long start = System.nanoTime();
for (byte[] key : keys) {
tr.get(key).join();
}
long end = System.nanoTime();
return count*1_000_000_000.0/(end - start);
});
}
public Double getRange(TransactionContext tcx, int count) {
return tcx.run(tr -> {
tr.options().setRetryLimit(5);
int startIndex = random.nextInt(keyCount - count);
long start = System.nanoTime();
tr.getRange(key(startIndex), key(startIndex+count)).asList().join();
long end = System.nanoTime();
return count*1_000_000_000.0/(end - start);
});
}
public Double getKey(TransactionContext tcx, int count) {
return tcx.run(tr -> {
tr.options().setRetryLimit(5);
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
tr.getKey(new KeySelector(randomKey(), true, random.nextInt(20) - 10)).join();
}
long end = System.nanoTime();
return count*1_000_000_000.0/(end - start);
});
}
public Double getSingleKeyRange(TransactionContext tcx, int count) {
return tcx.run(tr -> {
tr.options().setRetryLimit(5);
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
int keyIndex = randomKeyIndex();
tr.getRange(key(keyIndex), key(keyIndex + 1), 2).asList().join();
}
long end = System.nanoTime();
return count*1_000_000_000.0/(end - start);
});
}
public Double writeTransaction(TransactionContext tcx, int count) {
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
tcx.run(tr -> {
int keyIndex = randomKeyIndex();
tr.set(key(keyIndex), value(keyIndex));
return null;
});
}
long end = System.nanoTime();
return count*1_000_000_000.0/(end - start);
}
public byte[] key(int i) {
return ByteArrayUtil.join(args.getSubspace().pack(), String.format(keyFormat, i).getBytes(ASCII));
}
public int randomKeyIndex() {
return random.nextInt(keyCount);
}
public byte[] randomKey() {
return key(randomKeyIndex());
}
public byte[] value(int key) {
return valueBytes;
}
public static void main(String[] args) {
System.out.println("Running Java performance test on Java version " + System.getProperty("java.version"));
try {
new PerformanceTester().run(args);
} catch (IllegalArgumentException e) {
System.out.println("Could not run test due to malformed arguments.");
System.out.println(e.getMessage());
System.exit(1);
} catch (Exception e) {
System.out.println("Fatal error encountered during run: " + e);
e.printStackTrace();
System.exit(2);
}
}
private final int keyCount;
private final int keySize;
private final int valueSize;
private final String keyFormat;
private final byte[] valueBytes;
public static final int DEFAULT_KEY_COUNT = 10_000;
public static final int DEFAULT_KEY_SIZE = 16;
public static final int DEFAULT_VALUE_SIZE = 100;
private enum Tests {
FUTURE_LATENCY("Java Completable API future throughput"),
SET("Java Completable API set throughput"),
CLEAR("Java Completable API clear throughput"),
CLEAR_RANGE("Java Completable API clear_range throughput"),
PARALLEL_GET("Java Completable API parallel get throughput"),
SERIAL_GET("Java Completable API serial get throughput"),
GET_RANGE("Java Completable API get_range throughput"),
GET_KEY("Java Completable API get_key throughput"),
GET_SINGLE_KEY_RANGE("Java Completable API get_single_key_range throughput"),
ALTERNATING_GET_SET("Java Completable API alternating get and set throughput"),
WRITE_TRANSACTION("Java Completable API single-key transaction throughput");
private String kpi;
private Function<? super Database, ? extends Double> function;
Tests(String kpi) {
this.kpi = kpi;
}
public void setFunction(Function<?super Database, ? extends Double> function) {
this.function = function;
}
public Function<? super Database, ? extends Double> getFunction() {
return function;
}
public String getKpi() {
return kpi;
}
}
public PerformanceTester() {
this(DEFAULT_KEY_COUNT, DEFAULT_KEY_SIZE, DEFAULT_VALUE_SIZE);
}
public PerformanceTester(int keyCount, int keySize, int valueSize) {
super();
this.keyCount = keyCount;
this.keySize = keySize;
this.valueSize = valueSize;
keyFormat = "%0" + keySize + "d";
valueBytes = new byte[valueSize];
Arrays.fill(valueBytes, (byte)'x');
// Initialize tests.
Tests.FUTURE_LATENCY.setFunction(db -> futureLatency(db, 100_000));
Tests.SET.setFunction(db -> set(db, 100_000));
Tests.CLEAR.setFunction(db -> clear(db, 100_000));
Tests.CLEAR_RANGE.setFunction(db -> clearRange(db, 100_000));
Tests.PARALLEL_GET.setFunction(db -> parallelGet(db, 10_000));
Tests.SERIAL_GET.setFunction(db -> serialGet(db, 2_000));
Tests.GET_RANGE.setFunction(db -> getRange(db, 1_000));
Tests.GET_KEY.setFunction(db -> getKey(db, 2_000));
Tests.GET_SINGLE_KEY_RANGE.setFunction(db -> getSingleKeyRange(db, 2_000));
Tests.ALTERNATING_GET_SET.setFunction(db -> alternatingGetSet(db, 2_000));
Tests.WRITE_TRANSACTION.setFunction(db -> writeTransaction(db, 1_000));
}
@Override
public void testPerformance(Database db) {
insertData(db);
List<String> testsToRun;
if (args.getTestsToRun().isEmpty()) {
testsToRun = Arrays.stream(Tests.values()).map(Tests::name).map(String::toLowerCase).sorted().collect(Collectors.toList());
} else {
testsToRun = args.getTestsToRun();
}
for (String test : testsToRun) {
Tests testObj;
try {
testObj = Tests.valueOf(test.toUpperCase());
} catch (IllegalArgumentException e) {
result.addError(new IllegalArgumentException("Test " + test + " not implemented"));
continue;
}
Function<? super Database, ? extends Double> function = testObj.getFunction();
try {
Thread.sleep(5_000);
} catch (InterruptedException e) {
result.addError(wrapAndPrintError(e, "Interrupted while sleeping"));
}
System.out.println("Running test " + test);
List<Double> results = new ArrayList<>(NUM_RUNS);
for (int i = 0; i < NUM_RUNS; i++) {
try {
results.add(function.apply(db));
} catch (Exception e) {
result.addError(wrapAndPrintError(e, "Performance test failed: " + test));
break;
}
}
if (results.size() == NUM_RUNS) {
Collections.sort(results);
result.addKpi(String.format("%s (%s)", testObj.getKpi(), multiVersionDescription()), results.get(results.size()/2).intValue(), "keys/s");
}
}
}
public void insertData(Database db) {
System.out.println("Loading database");
db.run(tr -> {
byte[] subspacePrefix = args.getSubspace().pack();
if (subspacePrefix.length == 0) {
// Clear user space.
tr.clear(new byte[0], new byte[]{(byte)0xff});
} else {
tr.clear(args.getSubspace().range());
}
return null;
});
int keysPerActor = 100_000 / (keySize + valueSize);
int numActors = (int)Math.ceil(keyCount*1.0/keysPerActor);
List<CompletableFuture<Void>> futures = IntStream.range(0, numActors).mapToObj(i -> {
int startKey = keysPerActor * i;
int endKey = (i + 1 == numActors) ? (keyCount) : (keysPerActor * (i+1));
return db.runAsync(tr -> {
IntStream.range(startKey, endKey).forEach(keyIndex -> tr.set(key(keyIndex), value(keyIndex)));
return CompletableFuture.completedFuture((Void)null);
});
}).collect(Collectors.toList());
try {
AsyncUtil.whenAll(futures).get();
} catch (InterruptedException | ExecutionException e) {
result.addError(wrapAndPrintError(e, "Data insertion failed"));
}
// Give the database time to re-balance
try {
Thread.sleep(15_000);
} catch (InterruptedException e) {
result.addError(wrapAndPrintError(e, "Interrupted while waiting for quiescence"));
}
}
public Double futureLatency(Database db, int count) {
return db.run(tr -> {
tr.options().setRetryLimit(5);
tr.getReadVersion().join();
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
tr.getReadVersion().join();
}
long end = System.nanoTime();
return count*1_000_000_000.0/(end - start);
});
}
public Double clear(Database db, int count) {
try(Transaction tr = db.createTransaction()) {
long start = System.nanoTime();
for(int i = 0; i < count; i++) {
tr.clear(randomKey());
}
long end = System.nanoTime();
tr.cancel();
return count * 1_000_000_000.0 / (end - start);
}
}
public Double clearRange(Database db, int count) {
try(Transaction tr = db.createTransaction()) {
long start = System.nanoTime();
for(int i = 0; i < count; i++) {
int keyIndex = randomKeyIndex();
tr.clear(key(keyIndex), key(keyIndex + 1));
}
long end = System.nanoTime();
tr.cancel();
return count * 1_000_000_000.0 / (end - start);
}
}
public Double set(Database db, int count) {
try(Transaction tr = db.createTransaction()) {
long start = System.nanoTime();
for(int i = 0; i < count; i++) {
int keyIndex = randomKeyIndex();
tr.set(key(keyIndex), value(keyIndex));
}
long end = System.nanoTime();
tr.cancel();
return count * 1_000_000_000.0 / (end - start);
}
}
public Double parallelGet(TransactionContext tcx, int count) {
return tcx.run(tr -> {
tr.options().setRetryLimit(5);
long start = System.nanoTime();
List<CompletableFuture<byte[]>> futures = IntStream.range(0, count)
.mapToObj(ignore -> tr.get(randomKey()))
.collect(Collectors.toList());
AsyncUtil.whenAll(futures).join();
long end = System.nanoTime();
return count*1_000_000_000.0/(end - start);
});
}
public Double alternatingGetSet(TransactionContext tcx, int count) {
return tcx.run(tr -> {
tr.options().setRetryLimit(5);
long start = System.nanoTime();
List<CompletableFuture<byte[]>> futures = IntStream.range(0, count)
.mapToObj(ignore -> {
int keyIndex = randomKeyIndex();
byte[] keyBytes = key(keyIndex);
byte[] valBytes = value(keyIndex);
tr.set(keyBytes, valBytes);
return tr.get(keyBytes);
}).collect(Collectors.toList());
AsyncUtil.whenAll(futures).join();
long end = System.nanoTime();
return count*1_000_000_000.0/(end - start);
});
}
public Double serialGet(TransactionContext tcx, int count) {
return tcx.run(tr -> {
tr.options().setRetryLimit(5);
List<byte[]> keys;
if (count > keyCount/2) {
keys = Stream.generate(this::randomKey).limit(count).collect(Collectors.toList());
} else {
Set<Integer> keySet = new HashSet<>();
while (keySet.size() < count) {
keySet.add(randomKeyIndex());
}
keys = keySet.stream().map(this::key).collect(Collectors.toList());
}
long start = System.nanoTime();
for (byte[] key : keys) {
tr.get(key).join();
}
long end = System.nanoTime();
return count*1_000_000_000.0/(end - start);
});
}
public Double getRange(TransactionContext tcx, int count) {
return tcx.run(tr -> {
tr.options().setRetryLimit(5);
int startIndex = random.nextInt(keyCount - count);
long start = System.nanoTime();
tr.getRange(key(startIndex), key(startIndex+count)).asList().join();
long end = System.nanoTime();
return count*1_000_000_000.0/(end - start);
});
}
public Double getKey(TransactionContext tcx, int count) {
return tcx.run(tr -> {
tr.options().setRetryLimit(5);
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
tr.getKey(new KeySelector(randomKey(), true, random.nextInt(20) - 10)).join();
}
long end = System.nanoTime();
return count*1_000_000_000.0/(end - start);
});
}
public Double getSingleKeyRange(TransactionContext tcx, int count) {
return tcx.run(tr -> {
tr.options().setRetryLimit(5);
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
int keyIndex = randomKeyIndex();
tr.getRange(key(keyIndex), key(keyIndex + 1), 2).asList().join();
}
long end = System.nanoTime();
return count*1_000_000_000.0/(end - start);
});
}
public Double writeTransaction(TransactionContext tcx, int count) {
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
tcx.run(tr -> {
int keyIndex = randomKeyIndex();
tr.set(key(keyIndex), value(keyIndex));
return null;
});
}
long end = System.nanoTime();
return count*1_000_000_000.0/(end - start);
}
public byte[] key(int i) {
return ByteArrayUtil.join(args.getSubspace().pack(), String.format(keyFormat, i).getBytes(ASCII));
}
public int randomKeyIndex() {
return random.nextInt(keyCount);
}
public byte[] randomKey() {
return key(randomKeyIndex());
}
public byte[] value(int key) {
return valueBytes;
}
public static void main(String[] args) {
System.out.println("Running Java performance test on Java version " + System.getProperty("java.version"));
try {
new PerformanceTester().run(args);
} catch (IllegalArgumentException e) {
System.out.println("Could not run test due to malformed arguments.");
System.out.println(e.getMessage());
System.exit(1);
} catch (Exception e) {
System.out.println("Fatal error encountered during run: " + e);
e.printStackTrace();
System.exit(2);
}
}
}

View File

@ -32,62 +32,62 @@ import com.apple.foundationdb.Transaction;
import com.apple.foundationdb.tuple.ByteArrayUtil;
public class RYWBenchmark extends AbstractTester {
private int keyCount;
private int keyCount;
public static final int DEFAULT_KEY_COUNT = 10_000;
public static final int DEFAULT_KEY_SIZE = 16;
public static final int DEFAULT_KEY_COUNT = 10_000;
public static final int DEFAULT_KEY_SIZE = 16;
private final String keyFormat;
private final String keyFormat;
private enum Tests {
GET_SINGLE("RYW Java Completable: get single cached value throughput"),
GET_MANY_SEQUENTIAL("RYW Java Completable: get sequential cached value throughput"),
GET_RANGE_BASIC("RYW Java Completable: get range cached values throughput"),
SINGLE_CLEAR_GET_RANGE("RYW Java Completable: get range cached values with clears throughput"),
CLEAR_RANGE_GET_RANGE("RYW Java Completable: get range cached values with clear ranges throughput"),
INTERLEAVED_SETS_GETS("RYW Java Completable: interleaved sets and gets on a single key throughput");
private enum Tests {
GET_SINGLE("RYW Java Completable: get single cached value throughput"),
GET_MANY_SEQUENTIAL("RYW Java Completable: get sequential cached value throughput"),
GET_RANGE_BASIC("RYW Java Completable: get range cached values throughput"),
SINGLE_CLEAR_GET_RANGE("RYW Java Completable: get range cached values with clears throughput"),
CLEAR_RANGE_GET_RANGE("RYW Java Completable: get range cached values with clear ranges throughput"),
INTERLEAVED_SETS_GETS("RYW Java Completable: interleaved sets and gets on a single key throughput");
private String kpi;
private Function<? super Transaction, ? extends Double> function;
private String kpi;
private Function<? super Transaction, ? extends Double> function;
Tests(String kpi) {
this.kpi = kpi;
}
Tests(String kpi) {
this.kpi = kpi;
}
public void setFunction(Function<?super Transaction, ? extends Double> function) {
this.function = function;
}
public void setFunction(Function<?super Transaction, ? extends Double> function) {
this.function = function;
}
public Function<? super Transaction, ? extends Double> getFunction() {
return function;
}
public Function<? super Transaction, ? extends Double> getFunction() {
return function;
}
public String getKpi() {
return kpi;
}
}
public String getKpi() {
return kpi;
}
}
public RYWBenchmark() {
this(DEFAULT_KEY_COUNT, DEFAULT_KEY_SIZE);
}
public RYWBenchmark() {
this(DEFAULT_KEY_COUNT, DEFAULT_KEY_SIZE);
}
public RYWBenchmark(int keyCount, int keySize) {
super();
this.keyCount = keyCount;
public RYWBenchmark(int keyCount, int keySize) {
super();
this.keyCount = keyCount;
keyFormat = "%0" + keySize + "d";
keyFormat = "%0" + keySize + "d";
Tests.GET_SINGLE.setFunction(tr -> getSingle(tr, 10_000));
Tests.GET_MANY_SEQUENTIAL.setFunction(tr -> getManySequential(tr, 10_000));
Tests.GET_RANGE_BASIC.setFunction(tr -> getRangeBasic(tr, 1_000));
Tests.SINGLE_CLEAR_GET_RANGE.setFunction(tr -> singleClearGetRange(tr, 1_000));
Tests.CLEAR_RANGE_GET_RANGE.setFunction(tr -> clearRangeGetRange(tr, 1_000));
Tests.INTERLEAVED_SETS_GETS.setFunction(tr -> interleavedSetsGets(tr, 10_000));
}
Tests.GET_SINGLE.setFunction(tr -> getSingle(tr, 10_000));
Tests.GET_MANY_SEQUENTIAL.setFunction(tr -> getManySequential(tr, 10_000));
Tests.GET_RANGE_BASIC.setFunction(tr -> getRangeBasic(tr, 1_000));
Tests.SINGLE_CLEAR_GET_RANGE.setFunction(tr -> singleClearGetRange(tr, 1_000));
Tests.CLEAR_RANGE_GET_RANGE.setFunction(tr -> clearRangeGetRange(tr, 1_000));
Tests.INTERLEAVED_SETS_GETS.setFunction(tr -> interleavedSetsGets(tr, 10_000));
}
@Override
public void testPerformance(Database db) {
try(Transaction tr = db.createTransaction()) {
@Override
public void testPerformance(Database db) {
try(Transaction tr = db.createTransaction()) {
insertData(tr);
List<String> testsToRun;
@ -139,103 +139,103 @@ public class RYWBenchmark extends AbstractTester {
tr.cancel();
}
}
}
public Double getSingle(Transaction tr, int count) {
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
tr.get(key(5001)).join();
}
long end = System.nanoTime();
public Double getSingle(Transaction tr, int count) {
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
tr.get(key(5001)).join();
}
long end = System.nanoTime();
return count*1_000_000_000.0/(end - start);
}
return count*1_000_000_000.0/(end - start);
}
public Double getManySequential(Transaction tr, int count) {
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
tr.get(key(i)).join();
}
long end = System.nanoTime();
public Double getManySequential(Transaction tr, int count) {
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
tr.get(key(i)).join();
}
long end = System.nanoTime();
return count*1_000_000_000.0/(end - start);
}
return count*1_000_000_000.0/(end - start);
}
public Double getRangeBasic(Transaction tr, int count) {
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
tr.getRange(key(0), key(keyCount)).asList().join();
}
long end = System.nanoTime();
public Double getRangeBasic(Transaction tr, int count) {
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
tr.getRange(key(0), key(keyCount)).asList().join();
}
long end = System.nanoTime();
return count * 1_000_000_000.0 * keyCount/(end - start);
}
return count * 1_000_000_000.0 * keyCount/(end - start);
}
public Double singleClearGetRange(Transaction tr, int count) {
for (int i = 0; i < keyCount; i += 2) {
tr.clear(("" + i).getBytes(ASCII));
}
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
tr.getRange(key(0), key(keyCount)).asList().join();
}
long end = System.nanoTime();
public Double singleClearGetRange(Transaction tr, int count) {
for (int i = 0; i < keyCount; i += 2) {
tr.clear(("" + i).getBytes(ASCII));
}
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
tr.getRange(key(0), key(keyCount)).asList().join();
}
long end = System.nanoTime();
Double kpi = count * 1_000_000_000.0 * keyCount / 2 / (end - start);
insertData(tr);
return kpi;
}
Double kpi = count * 1_000_000_000.0 * keyCount / 2 / (end - start);
insertData(tr);
return kpi;
}
public Double clearRangeGetRange(Transaction tr, int count) {
for (int i = 0; i < keyCount; i += 4) {
tr.clear(key(i), key(i+1));
}
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
tr.getRange(key(0), key(keyCount)).asList().join();
}
long end = System.nanoTime();
public Double clearRangeGetRange(Transaction tr, int count) {
for (int i = 0; i < keyCount; i += 4) {
tr.clear(key(i), key(i+1));
}
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
tr.getRange(key(0), key(keyCount)).asList().join();
}
long end = System.nanoTime();
Double kpi = count * 1_000_000_000.0 * keyCount * 3 / 4 / (end - start);
insertData(tr);
return kpi;
}
Double kpi = count * 1_000_000_000.0 * keyCount * 3 / 4 / (end - start);
insertData(tr);
return kpi;
}
public Double interleavedSetsGets(Transaction tr, int count) {
long start = System.nanoTime();
byte[] keyBytes = "foo".getBytes(ASCII);
tr.set(keyBytes, "1".getBytes(ASCII));
for (int i = 0; i < count; i++) {
int old = Integer.parseInt(new String(tr.get(keyBytes).join(), ASCII));
tr.set(keyBytes, ("" + (old + 1)).getBytes(ASCII));
}
long end = System.nanoTime();
public Double interleavedSetsGets(Transaction tr, int count) {
long start = System.nanoTime();
byte[] keyBytes = "foo".getBytes(ASCII);
tr.set(keyBytes, "1".getBytes(ASCII));
for (int i = 0; i < count; i++) {
int old = Integer.parseInt(new String(tr.get(keyBytes).join(), ASCII));
tr.set(keyBytes, ("" + (old + 1)).getBytes(ASCII));
}
long end = System.nanoTime();
return count * 1_000_000_000.0/(end - start);
}
return count * 1_000_000_000.0/(end - start);
}
public void insertData(Transaction tr) {
tr.clear(new byte[0], new byte[]{(byte)0xff}); // Clear user space.
for (int i = 0; i < keyCount; i++) {
tr.set(key(i), "foo".getBytes(ASCII));
}
}
public void insertData(Transaction tr) {
tr.clear(new byte[0], new byte[]{(byte)0xff}); // Clear user space.
for (int i = 0; i < keyCount; i++) {
tr.set(key(i), "foo".getBytes(ASCII));
}
}
public byte[] key(int i) {
return ByteArrayUtil.join(args.getSubspace().pack(), String.format(keyFormat, i).getBytes(ASCII));
}
public byte[] key(int i) {
return ByteArrayUtil.join(args.getSubspace().pack(), String.format(keyFormat, i).getBytes(ASCII));
}
public static void main(String[] args) {
System.out.println("Running Java RYW benchmark on Java version " + System.getProperty("java.version"));
try {
new RYWBenchmark().run(args);
} catch (IllegalArgumentException e) {
System.out.println("Could not run test due to malformed arguments.");
System.exit(1);
} catch (Exception e) {
System.out.println("Fatal error encountered during run: " + e);
e.printStackTrace();
System.exit(2);
}
}
public static void main(String[] args) {
System.out.println("Running Java RYW benchmark on Java version " + System.getProperty("java.version"));
try {
new RYWBenchmark().run(args);
} catch (IllegalArgumentException e) {
System.out.println("Could not run test due to malformed arguments.");
System.exit(1);
} catch (Exception e) {
System.out.println("Fatal error encountered during run: " + e);
e.printStackTrace();
System.exit(2);
}
}
}

View File

@ -22,7 +22,6 @@ package com.apple.foundationdb.test;
import java.util.concurrent.atomic.AtomicInteger;
import com.apple.foundationdb.Cluster;
import com.apple.foundationdb.Database;
import com.apple.foundationdb.FDB;
import com.apple.foundationdb.TransactionContext;

View File

@ -439,15 +439,15 @@ public class StackTester {
byte[] prefix = (byte[]) params.get(0);
Map<Integer, StackEntry> entries = new HashMap<>();
while(inst.size() > 0) {
while(inst.size() > 0) {
entries.put(inst.size()-1, inst.pop());
if(entries.size() == 100) {
logStack(inst.context.db, entries, prefix);
entries.clear();
}
}
}
logStack(inst.context.db, entries, prefix);
logStack(inst.context.db, entries, prefix);
}
else {
throw new IllegalArgumentException("Unrecognized (or unimplemented) operation");
@ -576,7 +576,7 @@ public class StackTester {
}
private static void logStack(Database db, Map<Integer, StackEntry> entries, byte[] prefix) {
db.run(tr -> {
db.run(tr -> {
for(Map.Entry<Integer, StackEntry> it : entries.entrySet()) {
byte[] pk = Tuple.from(it.getKey(), it.getValue().idx).pack(prefix);
byte[] pv = Tuple.from(StackUtils.serializeFuture(it.getValue().value)).pack();
@ -588,7 +588,7 @@ public class StackTester {
}
private static boolean checkWatches(List<CompletableFuture<Void>> watches, Database db, boolean expected) {
for(CompletableFuture<Void> w : watches) {
for(CompletableFuture<Void> w : watches) {
if(w.isDone() || expected) {
try {
w.join();
@ -647,8 +647,8 @@ public class StackTester {
return null;
});
if(checkWatches(watches, db, true)) {
return;
if(checkWatches(watches, db, true)) {
return;
}
}
}

View File

@ -62,7 +62,7 @@ public class StackUtils {
throw e;
}
item = getErrorBytes(ex);
item = getErrorBytes(ex);
}
return item;
}

View File

@ -30,119 +30,119 @@ import java.util.Random;
import java.util.TreeMap;
public class TestResult {
private long id;
private Map<String,Map<String,Object>> kpis;
private List<Throwable> errors;
private long id;
private Map<String,Map<String,Object>> kpis;
private List<Throwable> errors;
public TestResult(Random r) {
id = Math.abs(r.nextLong());
kpis = new TreeMap<String,Map<String,Object>>(); // Tree map because we will have to print this out.
errors = new ArrayList<Throwable>();
}
public TestResult(Random r) {
id = Math.abs(r.nextLong());
kpis = new TreeMap<String,Map<String,Object>>(); // Tree map because we will have to print this out.
errors = new ArrayList<Throwable>();
}
public void addKpi(String name, Number value, String units) {
TreeMap<String,Object> kpi = new TreeMap<String,Object>();
kpi.put("value", value);
kpi.put("units", units);
kpis.put(name, kpi);
}
public void addKpi(String name, Number value, String units) {
TreeMap<String,Object> kpi = new TreeMap<String,Object>();
kpi.put("value", value);
kpi.put("units", units);
kpis.put(name, kpi);
}
public void addError(Throwable t) {
errors.add(t);
}
public void addError(Throwable t) {
errors.add(t);
}
public void save(String directory) {
String file = "javaresult-" + id + ".json";
if(directory.length() > 0) {
file = directory + "/" + file;
}
public void save(String directory) {
String file = "javaresult-" + id + ".json";
if(directory.length() > 0) {
file = directory + "/" + file;
}
// TODO: Should we use a really JSON library?
// TODO: Should we use a really JSON library?
StringBuilder outputBuilder = new StringBuilder();
outputBuilder.append('{');
StringBuilder outputBuilder = new StringBuilder();
outputBuilder.append('{');
// Add KPIs:
outputBuilder.append("\"kpis\": {");
boolean firstKpi = true;
for (Map.Entry<String,Map<String,Object>> kpi : kpis.entrySet()) {
if (firstKpi) {
firstKpi = false;
} else {
outputBuilder.append(", ");
}
// Add KPIs:
outputBuilder.append("\"kpis\": {");
boolean firstKpi = true;
for (Map.Entry<String,Map<String,Object>> kpi : kpis.entrySet()) {
if (firstKpi) {
firstKpi = false;
} else {
outputBuilder.append(", ");
}
outputBuilder.append("\"");
outputBuilder.append(kpi.getKey());
outputBuilder.append("\": {");
outputBuilder.append("\"");
outputBuilder.append(kpi.getKey());
outputBuilder.append("\": {");
boolean firstEntry = true;
boolean firstEntry = true;
for (Map.Entry<String,Object> entry : kpi.getValue().entrySet()) {
if (firstEntry) {
firstEntry = false;
} else {
outputBuilder.append(", ");
}
for (Map.Entry<String,Object> entry : kpi.getValue().entrySet()) {
if (firstEntry) {
firstEntry = false;
} else {
outputBuilder.append(", ");
}
outputBuilder.append("\"");
outputBuilder.append(entry.getKey());
outputBuilder.append("\": ");
outputBuilder.append("\"");
outputBuilder.append(entry.getKey());
outputBuilder.append("\": ");
Object value = entry.getValue();
if (value instanceof String) {
outputBuilder.append("\"");
outputBuilder.append((String)value);
outputBuilder.append("\"");
} else {
outputBuilder.append(value.toString());
}
}
Object value = entry.getValue();
if (value instanceof String) {
outputBuilder.append("\"");
outputBuilder.append((String)value);
outputBuilder.append("\"");
} else {
outputBuilder.append(value.toString());
}
}
outputBuilder.append("}");
}
outputBuilder.append("}, ");
outputBuilder.append("}");
}
outputBuilder.append("}, ");
// Add errors:
outputBuilder.append("\"errors\":[");
boolean firstError = true;
for (Throwable t : errors) {
if (firstError) {
firstError = false;
} else {
outputBuilder.append(", ");
}
// Add errors:
outputBuilder.append("\"errors\":[");
boolean firstError = true;
for (Throwable t : errors) {
if (firstError) {
firstError = false;
} else {
outputBuilder.append(", ");
}
StringBuilder msgBuilder = new StringBuilder();
msgBuilder.append(t.getClass().toString());
msgBuilder.append(": ");
msgBuilder.append(t.getMessage()); // Escaping quotes. Yeah, this won't work in the general case....
StackTraceElement[] stackTraceElements = t.getStackTrace();
for (StackTraceElement element : stackTraceElements) {
msgBuilder.append("\n ");
msgBuilder.append(element.toString());
}
outputBuilder.append('"');
outputBuilder.append(msgBuilder.toString()
.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\t", "\\t")
.replace("\r", "\\r")
.replace("\n", "\\n")
.replace("\f", "\\f")
.replace("\b", "\\b")
);
outputBuilder.append('"');
}
outputBuilder.append("]");
StringBuilder msgBuilder = new StringBuilder();
msgBuilder.append(t.getClass().toString());
msgBuilder.append(": ");
msgBuilder.append(t.getMessage()); // Escaping quotes. Yeah, this won't work in the general case....
StackTraceElement[] stackTraceElements = t.getStackTrace();
for (StackTraceElement element : stackTraceElements) {
msgBuilder.append("\n ");
msgBuilder.append(element.toString());
}
outputBuilder.append('"');
outputBuilder.append(msgBuilder.toString()
.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\t", "\\t")
.replace("\r", "\\r")
.replace("\n", "\\n")
.replace("\f", "\\f")
.replace("\b", "\\b")
);
outputBuilder.append('"');
}
outputBuilder.append("]");
outputBuilder.append('}');
outputBuilder.append('}');
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
writer.write(outputBuilder.toString());
} catch (IOException e) {
System.out.println("Could not write results to file " + file);
throw new RuntimeException("Could not save results: " + e.getMessage(), e);
}
}
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
writer.write(outputBuilder.toString());
} catch (IOException e) {
System.out.println("Could not write results to file " + file);
throw new RuntimeException("Could not save results: " + e.getMessage(), e);
}
}
}

View File

@ -27,126 +27,126 @@ import com.apple.foundationdb.subspace.Subspace;
import com.apple.foundationdb.tuple.Tuple;
public class TesterArgs {
private String outputDirectory;
private boolean multiversionApi;
private boolean callbacksOnExternalThread;
private boolean externalClient;
private Subspace subspace;
private List<String> testsToRun;
private String outputDirectory;
private boolean multiversionApi;
private boolean callbacksOnExternalThread;
private boolean externalClient;
private Subspace subspace;
private List<String> testsToRun;
private TesterArgs(String outputDirectory, boolean multiversionApi, boolean callbacksOnExternalThread, boolean externalClient, Subspace subspace, List<String> testsToRun) {
this.outputDirectory = outputDirectory;
this.multiversionApi = multiversionApi;
this.callbacksOnExternalThread = callbacksOnExternalThread;
this.externalClient = externalClient;
this.subspace = subspace;
this.testsToRun = testsToRun;
}
private TesterArgs(String outputDirectory, boolean multiversionApi, boolean callbacksOnExternalThread, boolean externalClient, Subspace subspace, List<String> testsToRun) {
this.outputDirectory = outputDirectory;
this.multiversionApi = multiversionApi;
this.callbacksOnExternalThread = callbacksOnExternalThread;
this.externalClient = externalClient;
this.subspace = subspace;
this.testsToRun = testsToRun;
}
public static void printUsage() {
String usage = "Arguments: [-o/--output-directory DIR] [--disable-multiversion-api] [--enable-callbacks-on-external-threads] [--use-external-client] [--tests-to-run TEST [TEST ...]] [-h/--help]\n" +
"\n" +
"Arguments:\n" +
" -o/--output-directory DIR Directory to store JSON output. If not set, the current directory is used.\n" +
" --disable-multiversion-api Disables the multi-version client API\n" +
" --enable-callbacks-on-external-threads Allows callbacks to be called on threads created by the client library.\n" +
" --use-external-client Connect to the server using an external client.\n" +
" --tests-to-run TEST [TEST ...] List of test names to run.\n" +
" -h/--help Print this help message and then quit.\n";
public static void printUsage() {
String usage = "Arguments: [-o/--output-directory DIR] [--disable-multiversion-api] [--enable-callbacks-on-external-threads] [--use-external-client] [--tests-to-run TEST [TEST ...]] [-h/--help]\n" +
"\n" +
"Arguments:\n" +
" -o/--output-directory DIR Directory to store JSON output. If not set, the current directory is used.\n" +
" --disable-multiversion-api Disables the multi-version client API\n" +
" --enable-callbacks-on-external-threads Allows callbacks to be called on threads created by the client library.\n" +
" --use-external-client Connect to the server using an external client.\n" +
" --tests-to-run TEST [TEST ...] List of test names to run.\n" +
" -h/--help Print this help message and then quit.\n";
System.out.print(usage);
}
System.out.print(usage);
}
/**
* Parses the argument strings into a <code>TesterArgs</code> instance.
* This will return <code>null</code> if the args include an argument telling
* it to print the help message and it will throw an {@link IllegalArgumentException}
* if it can't parse the arguments.
*
* @param args command-line args
* @return built instance or <code>null</code>
* @throws IllegalArgumentException if the arguments can't be parsed
*/
public static TesterArgs parseArgs(String[] args) {
String outputDirectory = "";
boolean multiversionApi = true;
boolean callbacksOnExternalThread = false;
boolean externalClient = false;
Subspace subspace = new Subspace();
List<String> testsToRun = new ArrayList<String>();
/**
* Parses the argument strings into a <code>TesterArgs</code> instance.
* This will return <code>null</code> if the args include an argument telling
* it to print the help message and it will throw an {@link IllegalArgumentException}
* if it can't parse the arguments.
*
* @param args command-line args
* @return built instance or <code>null</code>
* @throws IllegalArgumentException if the arguments can't be parsed
*/
public static TesterArgs parseArgs(String[] args) {
String outputDirectory = "";
boolean multiversionApi = true;
boolean callbacksOnExternalThread = false;
boolean externalClient = false;
Subspace subspace = new Subspace();
List<String> testsToRun = new ArrayList<String>();
for (int i = 0; i < args.length; i++) {
String arg = args[i];
if (arg.equals("-o") || arg.equals("--output-directory")) {
if (i + 1 < args.length) {
outputDirectory = args[++i];
} else {
System.out.println("No output directory specified for argument " + arg + "\n");
printUsage();
throw new IllegalArgumentException("No output directory specified for argument " + arg);
}
} else if (arg.equals("--subspace")) {
if (i + 1 < args.length) {
subspace = new Subspace(Tuple.from(args[++i]));
} else {
System.out.println("No subspace specified for argument " + arg + "\n");
printUsage();
throw new IllegalArgumentException("Not subspace specified for argument " + arg);
}
} else if (arg.equals("--disable-multiversion-api")) {
multiversionApi = false;
} else if (arg.equals("--enable-callbacks-on-external-threads")) {
callbacksOnExternalThread = true;
} else if (arg.equals("--use-external-client")) {
externalClient = true;
} else if (arg.equals("--tests-to-run")) {
if (i + 1 < args.length && args[i + 1].charAt(0) != '-') {
int j;
for (j = i + 1; j < args.length && args[j].charAt(0) != '-'; j++) {
testsToRun.add(args[j]);
}
i = j - 1;
} else {
System.out.println("No tests specified with argument " + arg + "\n");
printUsage();
throw new IllegalArgumentException("No tests specified with argument " + arg);
}
} else if (arg.equals("-h") || arg.equals("--help")) {
printUsage();
return null;
} else {
System.out.println("Unknown argument " + arg + "\n");
printUsage();
throw new IllegalArgumentException("Unknown argument " + arg);
}
}
for (int i = 0; i < args.length; i++) {
String arg = args[i];
if (arg.equals("-o") || arg.equals("--output-directory")) {
if (i + 1 < args.length) {
outputDirectory = args[++i];
} else {
System.out.println("No output directory specified for argument " + arg + "\n");
printUsage();
throw new IllegalArgumentException("No output directory specified for argument " + arg);
}
} else if (arg.equals("--subspace")) {
if (i + 1 < args.length) {
subspace = new Subspace(Tuple.from(args[++i]));
} else {
System.out.println("No subspace specified for argument " + arg + "\n");
printUsage();
throw new IllegalArgumentException("Not subspace specified for argument " + arg);
}
} else if (arg.equals("--disable-multiversion-api")) {
multiversionApi = false;
} else if (arg.equals("--enable-callbacks-on-external-threads")) {
callbacksOnExternalThread = true;
} else if (arg.equals("--use-external-client")) {
externalClient = true;
} else if (arg.equals("--tests-to-run")) {
if (i + 1 < args.length && args[i + 1].charAt(0) != '-') {
int j;
for (j = i + 1; j < args.length && args[j].charAt(0) != '-'; j++) {
testsToRun.add(args[j]);
}
i = j - 1;
} else {
System.out.println("No tests specified with argument " + arg + "\n");
printUsage();
throw new IllegalArgumentException("No tests specified with argument " + arg);
}
} else if (arg.equals("-h") || arg.equals("--help")) {
printUsage();
return null;
} else {
System.out.println("Unknown argument " + arg + "\n");
printUsage();
throw new IllegalArgumentException("Unknown argument " + arg);
}
}
return new TesterArgs(outputDirectory, multiversionApi, callbacksOnExternalThread, externalClient, subspace, testsToRun);
}
return new TesterArgs(outputDirectory, multiversionApi, callbacksOnExternalThread, externalClient, subspace, testsToRun);
}
// Accessors.
// Accessors.
public String getOutputDirectory() {
return outputDirectory;
}
public String getOutputDirectory() {
return outputDirectory;
}
public boolean useMultiversionApi() {
return multiversionApi;
}
public boolean useMultiversionApi() {
return multiversionApi;
}
public boolean putCallbacksOnExternalThread() {
return callbacksOnExternalThread;
}
public boolean putCallbacksOnExternalThread() {
return callbacksOnExternalThread;
}
public boolean useExternalClient() {
return externalClient;
}
public boolean useExternalClient() {
return externalClient;
}
public Subspace getSubspace() {
return subspace;
}
public Subspace getSubspace() {
return subspace;
}
public List<String> getTestsToRun() {
return testsToRun;
}
public List<String> getTestsToRun() {
return testsToRun;
}
}

View File

@ -20,7 +20,6 @@
package com.apple.foundationdb.test;
import com.apple.foundationdb.Cluster;
import com.apple.foundationdb.Database;
import com.apple.foundationdb.FDB;
import com.apple.foundationdb.TransactionContext;

View File

@ -31,9 +31,9 @@ import com.apple.foundationdb.tuple.Tuple;
import com.apple.foundationdb.tuple.Versionstamp;
public class VersionstampSmokeTest {
public static void main(String[] args) {
FDB fdb = FDB.selectAPIVersion(510);
try(Database db = fdb.open()) {
public static void main(String[] args) {
FDB fdb = FDB.selectAPIVersion(510);
try(Database db = fdb.open()) {
db.run(tr -> {
tr.clear(Tuple.from("prefix").range());
return null;
@ -59,7 +59,7 @@ public class VersionstampSmokeTest {
System.out.println(Versionstamp.complete(trVersion));
assert v.equals(Versionstamp.complete(trVersion));
}
}
}
private VersionstampSmokeTest() {}
private VersionstampSmokeTest() {}
}

View File

@ -26,13 +26,13 @@ import java.util.concurrent.atomic.AtomicInteger;
import com.apple.foundationdb.async.AsyncUtil;
public class WhileTrueTest {
public static void main(String[] args) {
// This should cause memory issues using the old implementation but not the new one.
// Pro tip: Run with options -Xms16m -Xmx16m -XX:+HeadDumpOnOutOfMemoryError
AtomicInteger count = new AtomicInteger(1000000);
AsyncUtil.whileTrue(() -> CompletableFuture.completedFuture(count.decrementAndGet()).thenApplyAsync(c -> c > 0)).join();
System.out.println("Final value: " + count.get());
}
public static void main(String[] args) {
// This should cause memory issues using the old implementation but not the new one.
// Pro tip: Run with options -Xms16m -Xmx16m -XX:+HeadDumpOnOutOfMemoryError
AtomicInteger count = new AtomicInteger(1000000);
AsyncUtil.whileTrue(() -> CompletableFuture.completedFuture(count.decrementAndGet()).thenApplyAsync(c -> c > 0)).join();
System.out.println("Final value: " + count.get());
}
private WhileTrueTest() {}
private WhileTrueTest() {}
}