Merge pull request #223 from cie/java-future-cleanup

Java cleanup
This commit is contained in:
A.J. Beamon 2017-12-14 13:37:33 -08:00 committed by GitHub Enterprise
commit 7102e4f97a
62 changed files with 1684 additions and 2060 deletions

View File

@ -0,0 +1,146 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
The style for code written within the FDB Java bindings.
Note that this style guide grew up somewhat organically from
the idiosyncracies of the committers involved. It aims to
be at least a little idiomatically Java while at the same time
trying not to look too incongruous when compared to the style
of our core products (e.g., fdbserver). It also isn't
borrowed from some other style guide, because that would
be too easy.
-->
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<module name="Checker">
<module name="SuppressionFilter">
<property name="file" value="suppressions.xml"/>
</module>
<module name="TreeWalker">
<property name="tabWidth" value="4"/>
<!-- Blocks -->
<module name="AvoidNestedBlocks"/>
<module name="EmptyBlock"/>
<module name="EmptyCatchBlock"/>
<module name="LeftCurly">
<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.
<module name="DesignForExtension"/>
-->
<!-- We have some classes violating this. It seems like a reasonable thing to add, but it is technically API breaking.
<module name="FinalClass"/>
-->
<module name="HideUtilityClassConstructor"/>
<module name="MutableException"/>
<module name="OneTopLevelClass"/>
<!-- Coding -->
<module name="CovariantEquals"/>
<module name="DefaultComesLast"/>
<module name="EmptyStatement"/>
<module name="EqualsHashCode"/>
<module name="FallThrough"/>
<!-- We should probably clean these up at some point, but not today.
<module name="MagicNumber">
<property name="ignoreNumbers" value="-1, 0, 1, 2, 255, 65535"/>
<property name="ignoreHashCodeMethod" value="true"/>
</module>
-->
<module name="MissingSwitchDefault"/>
<module name="NoClone"/>
<module name="PackageDeclaration"/>
<module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/>
<module name="StringLiteralEquality"/>
<module name="SuperClone"/>
<module name="SuperFinalize"/>
<!-- Imports -->
<module name="CustomImportOrder">
<property name="customImportOrderRules" value="STATIC###STANDARD_JAVA_PACKAGE###SAME_PACKAGE(3)"/>
</module>
<module name="AvoidStarImport"/>
<module name="UnusedImports"/>
<module name="RedundantImport"/>
<!-- Javadoc -->
<!-- TODO -->
<!-- Miscellaneous -->
<module name="ArrayTypeStyle"/>
<module name="CommentsIndentation"/>
<module name="Indentation"/>
<module name="OuterTypeFilename"/>
<module name="UpperEll"/>
<!-- Modifiers -->
<module name="ModifierOrder"/>
<module name="RedundantModifier"/>
<!-- Naming conventions -->
<module name="CatchParameterName">
<property name="format" value="^(e\d*|t\d*|ex\d*|err\d*)$"/>
</module>
<module name="ClassTypeParameterName"/>
<module name="InterfaceTypeParameterName"/>
<module name="LocalFinalVariableName"/>
<module name="LocalVariableName"/>
<module name="MemberName"/>
<module name="MethodName">
<property name="applyToProtected" value="false"/>
<property name="applyToPackage" value="false"/>
<property name="applyToPrivate" value="false"/>
</module>
<module name="MethodTypeParameterName"/>
<module name="PackageName"/>
<module name="ParameterName"/>
<module name="StaticVariableName"/>
<module name="TypeName"/>
<!-- Whitespace -->
<module name="EmptyForInitializerPad"/>
<module name="EmptyForIteratorPad"/>
<module name="GenericWhitespace"/>
<module name="MethodParamPad"/>
<module name="NoLineWrap"/>
<module name="NoWhitespaceAfter">
<property name="tokens" value="AT, INC, DEC, UNARY_MINUS, UNARY_PLUS, BNOT, LNOT, DOT, ARRAY_DECLARATOR, INDEX_OP, METHOD_REF"/>
</module>
<module name="NoWhitespaceBefore">
<property name="allowLineBreaks" value="true"/>
<property name="tokens" value="COMMA, SEMI, POST_INC, POST_DEC, DOT, ELLIPSIS, METHOD_REF"/>
</module>
<module name="OperatorWrap">
<property name="option" value="eol"/>
</module>
<module name="ParenPad"/>
<module name="SeparatorWrap">
<property name="option" value="eol"/>
<property name="tokens" value="COMMA"/>
</module>
<module name="SeparatorWrap">
<property name="option" value="nl"/>
<property name="tokens" value="DOT"/>
</module>
<module name="TypecastParenPad">
<property name="option" value="nospace"/>
</module>
<module name="WhitespaceAfter">
<property name="tokens" value="SEMI"/>
</module>
</module>
</module>

View File

@ -29,7 +29,6 @@ import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.List;
import com.apple.foundationdb.tuple.ByteArrayUtil;
import org.junit.Test;
/**

View File

@ -55,7 +55,9 @@ public class Cluster extends NativeObjectWrapper {
*
* @return a set of cluster-specific options affecting this {@code Cluster}
*/
public ClusterOptions options() { return options; }
public ClusterOptions options() {
return options;
}
@Override
protected void finalize() throws Throwable {

View File

@ -116,7 +116,7 @@ public interface Database extends AutoCloseable, TransactionContext {
*/
@Override
default <T> CompletableFuture<T> readAsync(
Function<? super ReadTransaction, CompletableFuture<T>> retryable) {
Function<? super ReadTransaction, ? extends CompletableFuture<T>> retryable) {
return readAsync(retryable, getExecutor());
}
@ -132,7 +132,7 @@ public interface Database extends AutoCloseable, TransactionContext {
* @see #readAsync(Function)
*/
<T> CompletableFuture<T> readAsync(
Function<? super ReadTransaction, CompletableFuture<T>> retryable, Executor e);
Function<? super ReadTransaction, ? extends CompletableFuture<T>> retryable, Executor e);
/**
* Runs a transactional function against this {@code Database} with retry logic.
@ -194,7 +194,7 @@ public interface Database extends AutoCloseable, TransactionContext {
*/
@Override
default <T> CompletableFuture<T> runAsync(
Function<? super Transaction, CompletableFuture<T>> retryable) {
Function<? super Transaction, ? extends CompletableFuture<T>> retryable) {
return runAsync(retryable, getExecutor());
}
@ -210,7 +210,7 @@ public interface Database extends AutoCloseable, TransactionContext {
* @see #run(Function)
*/
<T> CompletableFuture<T> runAsync(
Function<? super Transaction, CompletableFuture<T>> retryable, Executor e);
Function<? super Transaction, ? extends CompletableFuture<T>> retryable, Executor e);
/**
* Close the {@code Database} object and release any associated resources. This must be called at

View File

@ -64,7 +64,7 @@ public class FDB {
static class DaemonThreadFactory implements ThreadFactory {
private final ThreadFactory factory;
public DaemonThreadFactory(ThreadFactory factory) {
DaemonThreadFactory(ThreadFactory factory) {
this.factory = factory;
}
@ -82,7 +82,7 @@ public class FDB {
private volatile boolean netStarted = false;
private volatile boolean netStopped = false;
volatile boolean warnOnUnclosed = true;
final private Semaphore netRunning = new Semaphore(1);
private final Semaphore netRunning = new Semaphore(1);
private final NetworkOptions options;
static {
@ -103,21 +103,8 @@ public class FDB {
private FDB(int apiVersion) {
this.apiVersion = apiVersion;
options = new NetworkOptions(new OptionConsumer() {
@Override
public void setOption(int code, byte[] parameter) {
Network_setOption(code, parameter);
}
});
Runtime.getRuntime().addShutdownHook(new Thread(
new Runnable(){
@Override
public void run() {
FDB.this.stopNetwork();
}
}
));
options = new NetworkOptions(this::Network_setOption);
Runtime.getRuntime().addShutdownHook(new Thread(this::stopNetwork));
}
/**
@ -129,7 +116,9 @@ public class FDB {
*
* @return a set of options affecting this instance of the FoundationDB API
*/
public NetworkOptions options() { return options; }
public NetworkOptions options() {
return options;
}
/**
* Select the version for the client API. An exception will be thrown if the
@ -148,7 +137,7 @@ public class FDB {
*
* @return the FoundationDB API object
*/
public synchronized static FDB selectAPIVersion(final int version) throws FDBException {
public static synchronized FDB selectAPIVersion(final int version) throws FDBException {
if(singleton != null) {
if(version != singleton.apiVersion) {
throw new IllegalArgumentException(
@ -347,38 +336,37 @@ public class FDB {
Network_setup();
netStarted = true;
e.execute(new Runnable() {
@Override
public void run() {
boolean acquired = false;
try {
while(!acquired) {
try {
// make attempt to avoid a needless deadlock
synchronized (FDB.this) {
if(netStopped) {
return;
}
}
netRunning.acquire();
acquired = true;
} catch(InterruptedException e) {}
}
e.execute(() -> {
boolean acquired = false;
try {
while(!acquired) {
try {
Network_run();
} catch (Throwable t) {
System.err.println("Unhandled error in FoundationDB network thread: " + t.getMessage());
// eat this error. we have nowhere to send it.
}
} finally {
if(acquired) {
netRunning.release();
}
synchronized (FDB.this) {
netStopped = true;
// make attempt to avoid a needless deadlock
synchronized (FDB.this) {
if(netStopped) {
return;
}
}
netRunning.acquire();
acquired = true;
} catch(InterruptedException err) {
// Swallow thread interruption
}
}
try {
Network_run();
} catch (Throwable t) {
System.err.println("Unhandled error in FoundationDB network thread: " + t.getMessage());
// eat this error. we have nowhere to send it.
}
} finally {
if(acquired) {
netRunning.release();
}
synchronized (FDB.this) {
netStopped = true;
}
}
});
}
@ -414,7 +402,10 @@ public class FDB {
// that we will never again be able to call runNetwork()
netRunning.acquire();
return;
} catch (InterruptedException e) {}
} catch (InterruptedException e) {
// If the thread is interrupted while trying to acquire
// the semaphore, we just want to try again.
}
}
}

View File

@ -67,27 +67,27 @@ class FDBDatabase extends NativeObjectWrapper implements Database, OptionConsume
}
@Override
public <T> CompletableFuture<T> runAsync(final Function<? super Transaction, CompletableFuture<T>> retryable, Executor e) {
public <T> CompletableFuture<T> runAsync(final Function<? super Transaction, ? extends CompletableFuture<T>> retryable, Executor e) {
final AtomicReference<Transaction> trRef = new AtomicReference<>(createTransaction(e));
final AtomicReference<T> returnValue = new AtomicReference<>();
return AsyncUtil.whileTrue(() -> {
CompletableFuture<T> process = AsyncUtil.applySafely(retryable, trRef.get());
return process.thenComposeAsync(returnVal ->
return AsyncUtil.composeHandleAsync(process.thenComposeAsync(returnVal ->
trRef.get().commit().thenApply(o -> {
returnValue.set(returnVal);
return false;
})
, e).handleAsync((value, t) -> {
if(t == null)
return CompletableFuture.completedFuture(value);
if(!(t instanceof RuntimeException))
throw new CompletionException(t);
return trRef.get().onError(t).thenApply(newTr -> {
trRef.set(newTr);
return true;
});
}, e).thenCompose(x -> x);
}), e),
(value, t) -> {
if(t == null)
return CompletableFuture.completedFuture(value);
if(!(t instanceof RuntimeException))
throw new CompletionException(t);
return trRef.get().onError(t).thenApply(newTr -> {
trRef.set(newTr);
return true;
});
}, e);
}, e)
.thenApply(o -> returnValue.get())
.whenComplete((v, t) -> trRef.get().close());
@ -95,7 +95,7 @@ class FDBDatabase extends NativeObjectWrapper implements Database, OptionConsume
@Override
public <T> CompletableFuture<T> readAsync(
Function<? super ReadTransaction, CompletableFuture<T>> retryable, Executor e) {
Function<? super ReadTransaction, ? extends CompletableFuture<T>> retryable, Executor e) {
return this.runAsync(retryable, e);
}

View File

@ -26,7 +26,8 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.function.Function;
import com.apple.foundationdb.async.*;
import com.apple.foundationdb.async.AsyncIterable;
import com.apple.foundationdb.async.AsyncUtil;
import com.apple.foundationdb.tuple.ByteArrayUtil;
class FDBTransaction extends NativeObjectWrapper implements Transaction, OptionConsumer {
@ -137,7 +138,7 @@ class FDBTransaction extends NativeObjectWrapper implements Transaction, OptionC
@Override
public <T> CompletableFuture<T> readAsync(
Function<? super ReadTransaction, CompletableFuture<T>> retryable) {
Function<? super ReadTransaction, ? extends CompletableFuture<T>> retryable) {
return AsyncUtil.applySafely(retryable, this);
}
@ -183,7 +184,7 @@ class FDBTransaction extends NativeObjectWrapper implements Transaction, OptionC
public CompletableFuture<Long> getReadVersion() {
pointerReadLock.lock();
try {
return new FutureVersion( Transaction_getReadVersion(getPtr()), executor);
return new FutureVersion(Transaction_getReadVersion(getPtr()), executor);
} finally {
pointerReadLock.unlock();
}
@ -200,7 +201,7 @@ class FDBTransaction extends NativeObjectWrapper implements Transaction, OptionC
private CompletableFuture<byte[]> get_internal(byte[] key, boolean isSnapshot) {
pointerReadLock.lock();
try {
return new FutureResult( Transaction_get(getPtr(), key, isSnapshot), executor);
return new FutureResult(Transaction_get(getPtr(), key, isSnapshot), executor);
} finally {
pointerReadLock.unlock();
}
@ -217,7 +218,7 @@ class FDBTransaction extends NativeObjectWrapper implements Transaction, OptionC
private CompletableFuture<byte[]> getKey_internal(KeySelector selector, boolean isSnapshot) {
pointerReadLock.lock();
try {
return new FutureKey( Transaction_getKey(getPtr(),
return new FutureKey(Transaction_getKey(getPtr(),
selector.getKey(), selector.orEqual(), selector.getOffset(), isSnapshot), executor);
} finally {
pointerReadLock.unlock();
@ -357,7 +358,7 @@ class FDBTransaction extends NativeObjectWrapper implements Transaction, OptionC
@Override
public <T> CompletableFuture<T> runAsync(
Function<? super Transaction, CompletableFuture<T>> retryable) {
Function<? super Transaction, ? extends CompletableFuture<T>> retryable) {
return AsyncUtil.applySafely(retryable, this);
}
@ -368,7 +369,7 @@ class FDBTransaction extends NativeObjectWrapper implements Transaction, OptionC
@Override
public <T> CompletableFuture<T> readAsync(
Function<? super ReadTransaction, CompletableFuture<T>> retryable) {
Function<? super ReadTransaction, ? extends CompletableFuture<T>> retryable) {
return AsyncUtil.applySafely(retryable, this);
}

View File

@ -179,4 +179,6 @@ class JNIUtil {
return OS.OSX;
throw new IllegalStateException("Unknown or unsupported OS: " + osname);
}
private JNIUtil() {}
}

View File

@ -71,8 +71,8 @@ public class KeySelector {
*
* @return a newly created {@code KeySelector}
*/
public static KeySelector lastLessThan( byte[] key ) {
return new KeySelector( key, false, 0 );
public static KeySelector lastLessThan(byte[] key) {
return new KeySelector(key, false, 0);
}
/**
@ -82,8 +82,8 @@ public class KeySelector {
*
* @return a newly created {@code KeySelector}
*/
public static KeySelector lastLessOrEqual( byte[] key ) {
return new KeySelector( key, true, 0 );
public static KeySelector lastLessOrEqual(byte[] key) {
return new KeySelector(key, true, 0);
}
/**
@ -93,8 +93,8 @@ public class KeySelector {
*
* @return a newly created {@code KeySelector}
*/
public static KeySelector firstGreaterThan( byte[] key ) {
return new KeySelector( key, true, +1 );
public static KeySelector firstGreaterThan(byte[] key) {
return new KeySelector(key, true, +1);
}
/**
@ -104,8 +104,8 @@ public class KeySelector {
*
* @return a newly created {@code KeySelector}
*/
public static KeySelector firstGreaterOrEqual( byte[] key ) {
return new KeySelector( key, false, +1 );
public static KeySelector firstGreaterOrEqual(byte[] key) {
return new KeySelector(key, false, +1);
}
/**
@ -126,8 +126,8 @@ public class KeySelector {
*
* @return a newly created {@code KeySelector} that is offset by a number of keys.
*/
public KeySelector add( int offset ) {
return new KeySelector( getKey(), orEqual(), getOffset() + offset );
public KeySelector add(int offset) {
return new KeySelector(getKey(), orEqual(), getOffset() + offset);
}
/**

View File

@ -24,10 +24,12 @@ import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.Executor;
import java.util.function.BiFunction;
import com.apple.foundationdb.async.AsyncIterable;
import com.apple.foundationdb.async.AsyncIterator;
import com.apple.foundationdb.async.AsyncUtil;
import com.apple.foundationdb.async.CloseableAsyncIterator;
import com.apple.foundationdb.tuple.ByteArrayUtil;
@ -80,7 +82,7 @@ public class LocalityUtil {
* @return an sequence of keys denoting the start of single-server ranges
*/
public static CloseableAsyncIterator<byte[]> getBoundaryKeys(Transaction tr, byte[] begin, byte[] end) {
Transaction local = tr.getDatabase().createTransaction();
Transaction local = tr.getDatabase().createTransaction(tr.getExecutor());
CompletableFuture<Long> readVersion = tr.getReadVersion();
if(readVersion.isDone() && !readVersion.isCompletedExceptionally()) {
local.setReadVersion(readVersion.getNow(null));
@ -137,7 +139,7 @@ public class LocalityUtil {
firstGet = tr.getRange(keyServersForKey(begin), keyServersForKey(end));
block = firstGet.iterator();
nextFuture = block.onHasNext().handleAsync(handler, tr.getExecutor()).thenCompose(x -> x);
nextFuture = AsyncUtil.composeHandleAsync(block.onHasNext(), handler, tr.getExecutor());
closed = false;
}
@ -154,14 +156,14 @@ public class LocalityUtil {
CompletableFuture<Boolean> restartGet() {
if(ByteArrayUtil.compareUnsigned(begin, end) >= 0) {
return CompletableFuture.completedFuture(false);
return AsyncUtil.READY_FALSE;
}
lastBegin = begin;
tr.options().setReadSystemKeys();
block = tr.getRange(
keyServersForKey(begin),
keyServersForKey(end)).iterator();
nextFuture = block.onHasNext().handleAsync(handler, tr.getExecutor()).thenCompose(x -> x);
nextFuture = AsyncUtil.composeHandleAsync(block.onHasNext(), handler, tr.getExecutor());
return nextFuture;
}
@ -174,8 +176,9 @@ public class LocalityUtil {
if(o instanceof FDBException) {
FDBException err = (FDBException) o;
if(err.getCode() == 1007 && !Arrays.equals(begin, lastBegin)) {
Executor executor = BoundaryIterator.this.tr.getExecutor();
BoundaryIterator.this.tr.close();
BoundaryIterator.this.tr = BoundaryIterator.this.tr.getDatabase().createTransaction();
BoundaryIterator.this.tr = BoundaryIterator.this.tr.getDatabase().createTransaction(executor);
return restartGet();
}
}
@ -200,14 +203,14 @@ public class LocalityUtil {
byte[] key = o.getKey();
byte[] suffix = Arrays.copyOfRange(key, 13, key.length);
BoundaryIterator.this.begin = ByteArrayUtil.join(suffix, new byte[] { (byte)0 });
nextFuture = block.onHasNext().handleAsync(handler, tr.getExecutor()).thenCompose(x -> x);
nextFuture = AsyncUtil.composeHandleAsync(block.onHasNext(), handler, tr.getExecutor());
return suffix;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Boundary keys are read-only");
}
throw new UnsupportedOperationException("Boundary keys are read-only");
}
@Override
public void close() {
@ -231,7 +234,7 @@ public class LocalityUtil {
}
}
private static Charset ASCII = Charset.forName("US-ASCII");
private static final Charset ASCII = Charset.forName("US-ASCII");
static byte[] keyServersForKey(byte[] key) {
return ByteArrayUtil.join(new byte[] { (byte)255 },
"/keyServers/".getBytes(ASCII),

View File

@ -82,7 +82,7 @@ abstract class NativeFuture<T> extends CompletableFuture<T> implements AutoClose
close();
}
abstract protected T getIfDone_internal(long cPtr) throws FDBException;
protected abstract T getIfDone_internal(long cPtr) throws FDBException;
@Override
public void close() {
@ -122,7 +122,7 @@ abstract class NativeFuture<T> extends CompletableFuture<T> implements AutoClose
// we must have a read lock for this function to make sense, however it
// does not make sense to take the lock here, since the code that uses
// the result must inherently have the read lock itself.
assert( rwl.getReadHoldCount() > 0 );
assert(rwl.getReadHoldCount() > 0);
if(cPtr == 0)
throw new IllegalStateException("Cannot access closed object");

View File

@ -30,7 +30,7 @@ abstract class NativeObjectWrapper implements AutoCloseable {
private boolean closed = false;
private long cPtr;
public NativeObjectWrapper(long cPtr) {
NativeObjectWrapper(long cPtr) {
this.cPtr = cPtr;
if(this.cPtr == 0)
this.closed = true;
@ -40,7 +40,7 @@ abstract class NativeObjectWrapper implements AutoCloseable {
// we must have a read lock for this function to make sense, however it
// does not make sense to take the lock here, since the code that uses
// the result must inherently have the read lock itself.
assert( rwl.getReadHoldCount() > 0 );
assert(rwl.getReadHoldCount() > 0);
return closed;
}
@ -51,7 +51,10 @@ abstract class NativeObjectWrapper implements AutoCloseable {
System.err.println(context + " not closed");
}
}
catch(Exception e) {}
catch(Exception e) {
// Eat this error. This is called from the finalizer,
// so there isn't much we can do.
}
}
@Override
@ -76,7 +79,7 @@ abstract class NativeObjectWrapper implements AutoCloseable {
// we must have a read lock for this function to make sense, however it
// does not make sense to take the lock here, since the code that uses
// the result must inherently have the read lock itself.
assert( rwl.getReadHoldCount() > 0 );
assert(rwl.getReadHoldCount() > 0);
if(this.closed)
throw new IllegalStateException("Cannot access closed object");

View File

@ -25,10 +25,10 @@ import java.nio.ByteOrder;
import java.nio.charset.Charset;
abstract class OptionsSet {
private final static Charset CHARSET_UTF8 = Charset.forName("UTF-8");
private static final Charset CHARSET_UTF8 = Charset.forName("UTF-8");
OptionConsumer consumer;
public OptionsSet(OptionConsumer provider) {
OptionsSet(OptionConsumer provider) {
this.consumer = provider;
}
@ -39,7 +39,9 @@ abstract class OptionsSet {
*
* @return target of option set calls
*/
public OptionConsumer getOptionConsumer() { return consumer; }
public OptionConsumer getOptionConsumer() {
return consumer;
}
protected void setOption(int code) {
consumer.setOption(code, null);
@ -57,6 +59,6 @@ abstract class OptionsSet {
ByteBuffer b = ByteBuffer.allocate(8);
b.order(ByteOrder.LITTLE_ENDIAN);
b.putLong(param);
consumer.setOption(code, b.array() );
consumer.setOption(code, b.array());
}
}

View File

@ -64,7 +64,7 @@ public class Range {
public static Range startsWith(byte[] prefix) {
if(prefix == null)
throw new NullPointerException("prefix cannot be null");
return new Range( prefix, ByteArrayUtil.strinc(prefix) );
return new Range(prefix, ByteArrayUtil.strinc(prefix));
}
/**
@ -113,7 +113,7 @@ public class Range {
*/
@Override
public String toString() {
return "Range(" + (begin == null ? "null" : "\"" + ByteArrayUtil.printable(begin) + "\"")
+ ", " + (end == null ? "null" : "\"" + ByteArrayUtil.printable(end) + "\"") + ")";
return "Range(" + (begin == null ? "null" : "\"" + ByteArrayUtil.printable(begin) + "\"") +
", " + (end == null ? "null" : "\"" + ByteArrayUtil.printable(end) + "\"") + ")";
}
}

View File

@ -234,14 +234,14 @@ class RangeQuery implements AsyncIterable<KeyValue>, Iterable<KeyValue> {
// We have a chunk and are still working though it
if(index < chunk.values.size()) {
return CompletableFuture.completedFuture(true);
return AsyncUtil.READY_TRUE;
}
// If we are at the end of the current chunk there is either:
// - no more data -or-
// - we are already fetching the next block
return mainChunkIsTheLast() ?
CompletableFuture.completedFuture(false) :
AsyncUtil.READY_FALSE :
nextFuture;
}

View File

@ -21,7 +21,6 @@
package com.apple.foundationdb;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.function.Function;
@ -62,7 +61,7 @@ public interface ReadTransactionContext {
* to {@code retryable}
*/
<T> CompletableFuture<T> readAsync(
Function<? super ReadTransaction, CompletableFuture<T>> retryable);
Function<? super ReadTransaction, ? extends CompletableFuture<T>> retryable);
/**
* Retrieves the {@link Executor} used by this {@code TransactionContext} when running

View File

@ -22,6 +22,7 @@ package com.apple.foundationdb;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import com.apple.foundationdb.tuple.Tuple;
/**
@ -367,7 +368,7 @@ public interface Transaction extends AutoCloseable, ReadTransaction, Transaction
*/
@Override
<T> CompletableFuture<T> runAsync(
Function<? super Transaction, CompletableFuture<T>> retryable);
Function<? super Transaction, ? extends CompletableFuture<T>> retryable);
/**
* Close the {@code Transaction} object and release any associated resources. This must be called at

View File

@ -59,5 +59,5 @@ public interface TransactionContext extends ReadTransactionContext {
* @return a {@code CompletableFuture} that will be set to the value returned by the last call
* to {@code retryable}
*/
<T> CompletableFuture<T> runAsync(Function<? super Transaction, CompletableFuture<T>> retryable);
<T> CompletableFuture<T> runAsync(Function<? super Transaction, ? extends CompletableFuture<T>> retryable);
}

View File

@ -29,6 +29,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
@ -36,6 +37,26 @@ import java.util.function.Supplier;
* Provided utilities for using and manipulating {@link CompletableFuture}s.
*/
public class AsyncUtil {
/**
* A completed future of type {@link Void}. In particular, it is completed to {@code null},
* but that shouldn't really matter for the {@link Void} type. This can be used instead
* of creating a new future if one wants to signal that some asynchronous task has
* already been completed.
*/
public static final CompletableFuture<Void> DONE = CompletableFuture.completedFuture(null);
/**
* A completed future of type {@link Boolean} that is set to {@code true}. This can be
* used instead of creating a new future if one wants to signal that some task has
* already been completed with a {@code true} result.
*/
public static final CompletableFuture<Boolean> READY_TRUE = CompletableFuture.completedFuture(Boolean.TRUE);
/**
* A completed future of type {@link Boolean} that is set to {@code false}. This can be
* used instead of creating a new future if one wants to signal that some task has
* already been completed with a {@code false} result.
*/
public static final CompletableFuture<Boolean> READY_FALSE = CompletableFuture.completedFuture(Boolean.FALSE);
/**
* Run {@code Function} {@code func}, returning all caught exceptions as a
* {@code CompletableFuture} in an error state.
@ -46,7 +67,7 @@ public class AsyncUtil {
* @return the output of {@code func}, or a {@code CompletableFuture} carrying any exception
* caught in the process.
*/
public static <I,O> CompletableFuture<O> applySafely( Function<I, CompletableFuture<O>> func, I value ) {
public static <I,O> CompletableFuture<O> applySafely(Function<I, ? extends CompletableFuture<O>> func, I value) {
try {
return func.apply(value);
} catch (RuntimeException e) {
@ -56,6 +77,87 @@ public class AsyncUtil {
}
}
/**
* Run the {@code consumer} on each element of the iterable in order. The future will
* complete with either the first error encountered by either the iterable itself
* or by the consumer provided or with {@code null} if the future completes
* successfully. Items are processed in order from the iterable, and each item
* will be processed only after the item before it has finished processing.
*
* @param iterable the source of data over from which to consume
* @param consumer operation to apply to each item
* @param <V> type of the items returned by the iterable
*
* @return a future that is ready once the asynchronous operation completes
*/
public static <V> CompletableFuture<Void> forEach(final AsyncIterable<V> iterable, final Consumer<? super V> consumer) {
return forEachRemaining(iterable.iterator(), consumer);
}
/**
* Run the {@code consumer} on each element of the iterable in order. The future will
* complete with either the first error encountered by either the iterable itself
* or by the consumer provided or with {@code null} if the future completes
* successfully. Items are processed in order from the iterable, and each item
* will be processed only after the item before it has finished processing. Asynchronous
* tasks needed to complete this operation are scheduled on the provided executor.
*
* @param iterable the source of data over from which to consume
* @param consumer operation to apply to each item
* @param executor executor on which to schedule asynchronous tasks
* @param <V> type of the items returned by the iterable
*
* @return a future that is ready once the asynchronous operation completes
*/
public static <V> CompletableFuture<Void> forEach(final AsyncIterable<V> iterable, final Consumer<? super V> consumer, final Executor executor) {
return forEachRemaining(iterable.iterator(), consumer, executor);
}
/**
* Run the {@code consumer} on each element remaining in the iterator in order. The future will
* complete with either the first error encountered by either the iterator itself
* or by the consumer provided or with {@code null} if the future completes
* successfully. Items are processed in order from the iterator, and each item
* will be processed only after the item before it has finished processing.
*
* @param iterator the source of data over from which to consume
* @param consumer operation to apply to each item
* @param <V> type of the items returned by the iterator
*
* @return a future that is ready once the asynchronous operation completes
*/
public static <V> CompletableFuture<Void> forEachRemaining(final AsyncIterator<V> iterator, final Consumer<? super V> consumer) {
return forEachRemaining(iterator, consumer, DEFAULT_EXECUTOR);
}
/**
* Run the {@code consumer} on each element remaining if the iterator in order. The future will
* complete with either the first error encountered by either the iterator itself
* or by the consumer provided or with {@code null} if the future completes
* successfully. Items are processed in order from the iterator, and each item
* will be processed only after the item before it has finished processing. Asynchronous
* tasks needed to complete this operation are scheduled on the provided executor.
*
* @param iterator the source of data over from which to consume
* @param consumer operation to apply to each item
* @param executor executor on which to schedule asynchronous tasks
* @param <V> type of the items returned by the iterator
*
* @return a future that is ready once the asynchronous operation completes
*/
public static <V> CompletableFuture<Void> forEachRemaining(final AsyncIterator<V> iterator, final Consumer<? super V> consumer, final Executor executor) {
return iterator.onHasNext().thenComposeAsync(hasAny -> {
if (hasAny) {
return whileTrue(() -> {
consumer.accept(iterator.next());
return iterator.onHasNext();
}, executor);
} else {
return DONE;
}
}, executor);
}
/**
* Iterates over a set of items and returns the result as a list.
*
@ -69,15 +171,15 @@ public class AsyncUtil {
}
/**
* Iterates over a set of items and returns the result as a list.
* Iterates over a set of items and returns the remaining results as a list.
*
* @param iterator the source of data over which to iterate. This function will exhaust the iterator.
*
* @return a {@code CompletableFuture} which will be set to the amalgamation of results
* from iteration.
*/
public static <V> CompletableFuture<List<V>> collect(final AsyncIterator<V> iterator) {
return collect(iterator, DEFAULT_EXECUTOR);
public static <V> CompletableFuture<List<V>> collectRemaining(final AsyncIterator<V> iterator) {
return collectRemaining(iterator, DEFAULT_EXECUTOR);
}
/**
@ -90,11 +192,11 @@ public class AsyncUtil {
* from iteration.
*/
public static <V> CompletableFuture<List<V>> collect(final AsyncIterable<V> iterable, final Executor executor) {
return collect(iterable.iterator(), executor);
return collectRemaining(iterable.iterator(), executor);
}
/**
* Iterates over a set of items and returns the result as a list.
* Iterates over a set of items and returns the remaining results as a list.
*
* @param iterator the source of data over which to iterate. This function will exhaust the iterator.
* @param executor the {@link Executor} to use for asynchronous operations
@ -102,20 +204,9 @@ public class AsyncUtil {
* @return a {@code CompletableFuture} which will be set to the amalgamation of results
* from iteration.
*/
public static <V> CompletableFuture<List<V>> collect(final AsyncIterator<V> iterator, final Executor executor) {
public static <V> CompletableFuture<List<V>> collectRemaining(final AsyncIterator<V> iterator, final Executor executor) {
final List<V> accumulator = new LinkedList<>();
// The condition of the while loop is simply "onHasNext()" returning true
Supplier<CompletableFuture<Boolean>> condition = () ->
iterator.onHasNext().thenApply(hasNext -> {
if(hasNext) {
accumulator.add(iterator.next());
}
return hasNext;
});
CompletableFuture<Void> complete = whileTrue(condition, executor);
return tag(complete, accumulator);
return tag(forEachRemaining(iterator, accumulator::add, executor), accumulator);
}
/**
@ -136,12 +227,8 @@ public class AsyncUtil {
@Override
public CompletableFuture<List<T>> asList() {
return iterable.asList().thenApply(result -> {
ArrayList<T> out = new ArrayList<>(result.size());
for(V in : result)
out.add(func.apply(in));
return out;
});
final List<T> accumulator = new LinkedList<>();
return tag(AsyncUtil.forEach(iterable, value -> accumulator.add(func.apply(value))), accumulator);
}
};
}
@ -354,8 +441,7 @@ public class AsyncUtil {
* @return a new {@link CompletableFuture} that is set when {@code task} is ready.
*/
public static <V> CompletableFuture<Void> whenReady(CompletableFuture<V> task) {
return task.thenApply(o -> (Void)null)
.exceptionally(o -> null);
return task.handle((v, t) -> null);
}
public static <V> CompletableFuture<V> composeExceptionally(CompletableFuture<V> task, Function<Throwable, CompletableFuture<V>> fn) {
@ -369,6 +455,67 @@ public class AsyncUtil {
});
}
/**
* Compose a handler bi-function to the result of a future. Unlike the
* {@link CompletableFuture#handle(BiFunction) CompletableFuture.handle()}
* function, which requires that the handler return a regular value, this
* method requires that the handler return a {@link CompletableFuture}.
* The returned future will then be ready with the result of the
* handler's future (or an error if that future completes exceptionally).
*
* @param future future to compose the handler onto
* @param handler handler bi-function to compose onto the passed future
* @param <V> return type of original future
* @param <T> return type of final future
*
* @return future with same completion properties as the future returned by the handler
*/
public static <V, T> CompletableFuture<T> composeHandle(CompletableFuture<V> future, BiFunction<V,Throwable,? extends CompletableFuture<T>> handler) {
return future.handle(handler).thenCompose(Function.identity());
}
/**
* Compose a handler bi-function to the result of a future. Unlike the
* {@link CompletableFuture#handle(BiFunction) CompletableFuture.handle()}
* function, which requires that the handler return a regular value, this
* method requires that the handler return a {@link CompletableFuture}.
* The returned future will then be ready with the result of the
* handler's future (or an error if that future completes exceptionally).
* The handler will execute on the {@link com.apple.foundationdb.FDB#DEFAULT_EXECUTOR default executor}
* used for asychronous tasks.
*
* @param future future to compose the handler onto
* @param handler handler bi-function to compose onto the passed future
* @param <V> return type of original future
* @param <T> return type of final future
*
* @return future with same completion properties as the future returned by the handler
*/
public static <V, T> CompletableFuture<T> composeHandleAsync(CompletableFuture<V> future, BiFunction<V,Throwable,? extends CompletableFuture<T>> handler) {
return composeHandleAsync(future, handler, DEFAULT_EXECUTOR);
}
/**
* Compose a handler bi-function to the result of a future. Unlike the
* {@link CompletableFuture#handle(BiFunction) CompletableFuture.handle()}
* function, which requires that the handler return a regular value, this
* method requires that the handler return a {@link CompletableFuture}.
* The returned future will then be ready with the result of the
* handler's future (or an error if that future completes excpetionally).
* The handler will execute on the passed {@link Executor}.
*
* @param future future to compose the handler onto
* @param handler handler bi-function to compose onto the passed future
* @param executor executor on which to execute the handler function
* @param <V> return type of original future
* @param <T> return type of final future
*
* @return future with same completion properties as the future returned by the handler
*/
public static <V, T> CompletableFuture<T> composeHandleAsync(CompletableFuture<V> future, BiFunction<V,Throwable,? extends CompletableFuture<T>> handler, Executor executor) {
return future.handleAsync(handler, executor).thenCompose(Function.identity());
}
/**
* Collects the results of many asynchronous processes into one asynchronous output. If
* any of the tasks returns an error, the output is set to that error.
@ -379,7 +526,7 @@ public class AsyncUtil {
*/
public static <V> CompletableFuture<List<V>> getAll(final Collection<CompletableFuture<V>> tasks) {
return whenAll(tasks).thenApply(unused -> {
List<V> result = new ArrayList<>();
List<V> result = new ArrayList<>(tasks.size());
for(CompletableFuture<V> f : tasks) {
assert(f.isDone());
result.add(f.getNow(null));
@ -411,8 +558,7 @@ public class AsyncUtil {
* @return a signal that will be set when any of the {@code CompletableFuture}s are done
*/
public static <V> CompletableFuture<Void> whenAny(final Collection<? extends CompletableFuture<V>> input) {
@SuppressWarnings("unchecked")
CompletableFuture<V>[] array = (CompletableFuture<V>[]) input.toArray(new CompletableFuture<?>[input.size()]);
CompletableFuture<?>[] array = input.toArray(new CompletableFuture<?>[input.size()]);
CompletableFuture<Object> anyOf = CompletableFuture.anyOf(array);
return success(anyOf);
}
@ -427,8 +573,7 @@ public class AsyncUtil {
* @return a signal that will be set when all of the {@code CompletableFuture}s are done
*/
public static <V> CompletableFuture<Void> whenAll(final Collection<? extends CompletableFuture<V>> input) {
@SuppressWarnings("unchecked")
CompletableFuture<V>[] array = (CompletableFuture<V>[]) input.toArray(new CompletableFuture<?>[input.size()]);
CompletableFuture<?>[] array = input.toArray(new CompletableFuture<?>[input.size()]);
return CompletableFuture.allOf(array);
}

View File

@ -33,5 +33,5 @@ public interface Cancellable {
* is not an error to call this method on an operation that has already completed or
* already been cancelled. This method will not block or throw non-fatal exceptions.
*/
public abstract void cancel();
void cancel();
}

View File

@ -30,5 +30,5 @@ public interface CloneableException {
*
* @return a newly created {@code Exception}.
*/
public Exception retargetClone();
Exception retargetClone();
}

View File

@ -54,21 +54,21 @@ class DirectoryPartition extends DirectorySubspace {
this.parentDirectoryLayer = parentDirectoryLayer;
}
/**
* Raises an exception because DirectoryPartition cannot be used as a Subspace.
*
* @throws UnsupportedOperationException
*/
/**
* Raises an exception because DirectoryPartition cannot be used as a Subspace.
*
* @throws UnsupportedOperationException
*/
@Override
public Subspace get(Object o) {
throw new UnsupportedOperationException("Cannot open subspace in the root of a directory partition.");
}
/**
* Raises an exception because DirectoryPartition cannot be used as a Subspace.
*
* @throws UnsupportedOperationException
*/
/**
* Raises an exception because DirectoryPartition cannot be used as a Subspace.
*
* @throws UnsupportedOperationException
*/
@Override
public Subspace get(Tuple name) {
throw new UnsupportedOperationException("Cannot open subspace in the root of a directory partition.");
@ -84,61 +84,61 @@ class DirectoryPartition extends DirectorySubspace {
throw new UnsupportedOperationException("Cannot get key for the root of a directory partition.");
}
/**
* Raises an exception because DirectoryPartition cannot be used as a Subspace.
*
* @throws UnsupportedOperationException
*/
/**
* Raises an exception because DirectoryPartition cannot be used as a Subspace.
*
* @throws UnsupportedOperationException
*/
@Override
public byte[] pack() {
throw new UnsupportedOperationException("Cannot pack keys using the root of a directory partition.");
}
/**
* Raises an exception because DirectoryPartition cannot be used as a Subspace.
*
* @throws UnsupportedOperationException
*/
/**
* Raises an exception because DirectoryPartition cannot be used as a Subspace.
*
* @throws UnsupportedOperationException
*/
@Override
public byte[] pack(Object o) {
throw new UnsupportedOperationException("Cannot pack keys using the root of a directory partition.");
}
/**
* Raises an exception because DirectoryPartition cannot be used as a Subspace.
*
* @throws UnsupportedOperationException
*/
/**
* Raises an exception because DirectoryPartition cannot be used as a Subspace.
*
* @throws UnsupportedOperationException
*/
@Override
public byte[] pack(Tuple tuple) {
throw new UnsupportedOperationException("Cannot pack keys using the root of a directory partition.");
}
/**
* Raises an exception because DirectoryPartition cannot be used as a Subspace.
*
* @throws UnsupportedOperationException
*/
/**
* Raises an exception because DirectoryPartition cannot be used as a Subspace.
*
* @throws UnsupportedOperationException
*/
@Override
public Tuple unpack(byte[] key) {
throw new UnsupportedOperationException("Cannot unpack keys using the root of a directory partition.");
}
/**
* Raises an exception because DirectoryPartition cannot be used as a Subspace.
*
* @throws UnsupportedOperationException
*/
/**
* Raises an exception because DirectoryPartition cannot be used as a Subspace.
*
* @throws UnsupportedOperationException
*/
@Override
public Range range() {
throw new UnsupportedOperationException("Cannot get range for the root of a directory partition.");
}
/**
* Raises an exception because DirectoryPartition cannot be used as a Subspace.
*
* @throws UnsupportedOperationException
*/
/**
* Raises an exception because DirectoryPartition cannot be used as a Subspace.
*
* @throws UnsupportedOperationException
*/
@Override
public Range range(Tuple tuple) {
throw new UnsupportedOperationException("Cannot get range for the root of a directory partition.");
@ -154,11 +154,11 @@ class DirectoryPartition extends DirectorySubspace {
throw new UnsupportedOperationException("Cannot check whether a key belongs to the root of a directory partition.");
}
/**
* Raises an exception because DirectoryPartition cannot be used as a Subspace.
*
* @throws UnsupportedOperationException
*/
/**
* Raises an exception because DirectoryPartition cannot be used as a Subspace.
*
* @throws UnsupportedOperationException
*/
@Override
public Subspace subspace(Tuple tuple) {
throw new UnsupportedOperationException("Cannot open subspace in the root of a directory partition.");
@ -180,18 +180,33 @@ class DirectoryPartition extends DirectorySubspace {
* @param rhs the {@code} Object to test for equality
* @return true if this is equal to {@code rhs}
*/
@Override
public boolean equals(Object rhs) {
if(this == rhs) {
return true;
}
if(rhs == null || getClass() != rhs.getClass()) {
return false;
}
@Override
public boolean equals(Object rhs) {
if(this == rhs) {
return true;
}
if(rhs == null || getClass() != rhs.getClass()) {
return false;
}
DirectoryPartition other = (DirectoryPartition)rhs;
return (getPath() == other.getPath() || getPath() == other.getPath()) &&
DirectoryPartition other = (DirectoryPartition)rhs;
return (getPath() == other.getPath() || getPath().equals(other.getPath())) &&
parentDirectoryLayer.equals(other.parentDirectoryLayer) &&
super.equals(rhs);
}
}
/**
* Computes a hash code compatible with this class's {@link #equals(Object) equals()}
* method. In particular, it computes a hash that is based off of the
* hash of the parent {@link DirectoryLayer} and this partition's
* path, layer, and subspace prefix.
*
* @return a hash compatible with this class's {@code equals()} method
*/
@Override
public int hashCode() {
// The path, layer, and subspace prefix information comes from the super
// class's hash code method.
return parentDirectoryLayer.hashCode() ^ (super.hashCode() * 3209);
}
}

View File

@ -45,28 +45,28 @@ import com.apple.foundationdb.subspace.Subspace;
* </p>
*/
public class DirectorySubspace extends Subspace implements Directory {
private final List<String> path;
private final byte[] layer;
private final DirectoryLayer directoryLayer;
private final List<String> path;
private final byte[] layer;
private final DirectoryLayer directoryLayer;
DirectorySubspace(List<String> path, byte[] prefix, DirectoryLayer directoryLayer) {
this(path, prefix, directoryLayer, EMPTY_BYTES);
}
DirectorySubspace(List<String> path, byte[] prefix, DirectoryLayer directoryLayer) {
this(path, prefix, directoryLayer, EMPTY_BYTES);
}
DirectorySubspace(List<String> path, byte[] prefix, DirectoryLayer directoryLayer, byte[] layer) {
super(prefix);
this.path = path;
this.layer = layer;
this.directoryLayer = directoryLayer;
}
DirectorySubspace(List<String> path, byte[] prefix, DirectoryLayer directoryLayer, byte[] layer) {
super(prefix);
this.path = path;
this.layer = layer;
this.directoryLayer = directoryLayer;
}
/**
* @return a printable representation of this {@code DirectorySubspace}
*/
@Override
public String toString() {
return getClass().getSimpleName() + '(' + DirectoryUtil.pathStr(path) + ", " + printable(getKey()) + ')';
}
@Override
public String toString() {
return getClass().getSimpleName() + '(' + DirectoryUtil.pathStr(path) + ", " + printable(getKey()) + ')';
}
/**
* Returns whether this {@code DirectorySubspace} is equal to {@code rhs}.
@ -76,91 +76,103 @@ public class DirectorySubspace extends Subspace implements Directory {
* @param rhs the {@code} Object to test for equality
* @return true if this is equal to {@code rhs}
*/
@Override
public boolean equals(Object rhs) {
if(this == rhs) {
return true;
}
if(rhs == null || getClass() != rhs.getClass()) {
return false;
}
DirectorySubspace other = (DirectorySubspace)rhs;
return (path == other.path || path.equals(other.path)) &&
Arrays.equals(layer, other.layer) &&
@Override
public boolean equals(Object rhs) {
if(this == rhs) {
return true;
}
if(rhs == null || getClass() != rhs.getClass()) {
return false;
}
DirectorySubspace other = (DirectorySubspace)rhs;
return (path == other.path || path.equals(other.path)) &&
Arrays.equals(layer, other.layer) &&
directoryLayer.equals(other.directoryLayer) &&
super.equals(rhs);
}
}
@Override
public List<String> getPath() {
return Collections.unmodifiableList(path);
}
/**
* Computes a hash code compatible with the {@link #equals(Object) equals()} method of
* this class. In particular, it will produce a hash code that is based off of the hashes
* of its path, its layer, and its subspace prefix.
*
* @return a hash compatible with this class's {@code equals()} method
*/
@Override
public int hashCode() {
return path.hashCode() ^ (Arrays.hashCode(layer) * 1153) ^ (directoryLayer.hashCode() * 929) ^ (super.hashCode() * 419);
}
@Override
public byte[] getLayer() {
return Arrays.copyOf(layer, layer.length);
}
@Override
public List<String> getPath() {
return Collections.unmodifiableList(path);
}
@Override
public byte[] getLayer() {
return Arrays.copyOf(layer, layer.length);
}
@Override
public DirectoryLayer getDirectoryLayer() {
return directoryLayer;
}
@Override
public CompletableFuture<DirectorySubspace> createOrOpen(TransactionContext tcx, List<String> subpath, byte[] otherLayer) {
return directoryLayer.createOrOpen(tcx, getPartitionSubpath(subpath), otherLayer);
}
@Override
public CompletableFuture<DirectorySubspace> createOrOpen(TransactionContext tcx, List<String> subpath, byte[] otherLayer) {
return directoryLayer.createOrOpen(tcx, getPartitionSubpath(subpath), otherLayer);
}
@Override
public CompletableFuture<DirectorySubspace> open(ReadTransactionContext tcx, List<String> subpath, byte[] otherLayer) {
return directoryLayer.open(tcx, getPartitionSubpath(subpath), otherLayer);
}
@Override
public CompletableFuture<DirectorySubspace> open(ReadTransactionContext tcx, List<String> subpath, byte[] otherLayer) {
return directoryLayer.open(tcx, getPartitionSubpath(subpath), otherLayer);
}
@Override
public CompletableFuture<DirectorySubspace> create(TransactionContext tcx, List<String> subpath, byte[] otherLayer, byte[] prefix) {
return directoryLayer.create(tcx, getPartitionSubpath(subpath), otherLayer, prefix);
}
@Override
public CompletableFuture<DirectorySubspace> create(TransactionContext tcx, List<String> subpath, byte[] otherLayer, byte[] prefix) {
return directoryLayer.create(tcx, getPartitionSubpath(subpath), otherLayer, prefix);
}
@Override
public CompletableFuture<List<String>> list(ReadTransactionContext tcx, List<String> subpath) {
return directoryLayer.list(tcx, getPartitionSubpath(subpath));
}
@Override
public CompletableFuture<List<String>> list(ReadTransactionContext tcx, List<String> subpath) {
return directoryLayer.list(tcx, getPartitionSubpath(subpath));
}
@Override
public CompletableFuture<DirectorySubspace> move(TransactionContext tcx, List<String> oldSubpath, List<String> newSubpath) {
return directoryLayer.move(tcx, getPartitionSubpath(oldSubpath), getPartitionSubpath(newSubpath));
}
@Override
public CompletableFuture<DirectorySubspace> move(TransactionContext tcx, List<String> oldSubpath, List<String> newSubpath) {
return directoryLayer.move(tcx, getPartitionSubpath(oldSubpath), getPartitionSubpath(newSubpath));
}
@Override
public CompletableFuture<DirectorySubspace> moveTo(TransactionContext tcx, List<String> newAbsolutePath) {
@Override
public CompletableFuture<DirectorySubspace> moveTo(TransactionContext tcx, List<String> newAbsolutePath) {
DirectoryLayer dir = getLayerForPath(EMPTY_PATH);
int partitionLen = dir.getPath().size();
List<String> partitionPath = newAbsolutePath.subList(0, Math.min(newAbsolutePath.size(), partitionLen));
if(!partitionPath.equals(dir.getPath()))
throw new DirectoryMoveException("Cannot move between partitions", path, newAbsolutePath);
return dir.move(tcx,
return dir.move(tcx,
getPartitionSubpath(EMPTY_PATH, dir),
newAbsolutePath.subList(partitionLen, newAbsolutePath.size()));
}
}
@Override
public CompletableFuture<Void> remove(TransactionContext tcx, List<String> subpath) {
@Override
public CompletableFuture<Void> remove(TransactionContext tcx, List<String> subpath) {
DirectoryLayer dir = getLayerForPath(subpath);
return dir.remove(tcx, getPartitionSubpath(subpath, dir));
}
return dir.remove(tcx, getPartitionSubpath(subpath, dir));
}
@Override
public CompletableFuture<Boolean> removeIfExists(TransactionContext tcx, List<String> subpath) {
@Override
public CompletableFuture<Boolean> removeIfExists(TransactionContext tcx, List<String> subpath) {
DirectoryLayer dir = getLayerForPath(subpath);
return dir.removeIfExists(tcx, getPartitionSubpath(subpath, dir));
}
return dir.removeIfExists(tcx, getPartitionSubpath(subpath, dir));
}
@Override
public CompletableFuture<Boolean> exists(ReadTransactionContext tcx, List<String> subpath) {
@Override
public CompletableFuture<Boolean> exists(ReadTransactionContext tcx, List<String> subpath) {
DirectoryLayer dir = getLayerForPath(subpath);
return dir.exists(tcx, getPartitionSubpath(subpath, dir));
}
return dir.exists(tcx, getPartitionSubpath(subpath, dir));
}
private List<String> getPartitionSubpath(List<String> path) {
return getPartitionSubpath(path, directoryLayer);

View File

@ -42,4 +42,6 @@ class DirectoryUtil {
sb.append(')');
return sb.toString();
}
private DirectoryUtil() {}
}

View File

@ -20,10 +20,10 @@
package com.apple.foundationdb.directory;
import com.apple.foundationdb.tuple.ByteArrayUtil;
import java.util.List;
import com.apple.foundationdb.tuple.ByteArrayUtil;
/**
* A {@link DirectoryException} that is thrown when a directory is opened with an incompatible layer.
*/

View File

@ -92,4 +92,6 @@ public class PathUtil {
return new LinkedList<String>(path.subList(0, path.size() - 1));
}
private PathUtil() {}
}

View File

@ -45,8 +45,7 @@ import com.apple.foundationdb.tuple.Versionstamp;
* As a best practice, API clients should use at least one subspace for application data.
* </p>
*/
public class Subspace
{
public class Subspace {
static final Tuple EMPTY_TUPLE = Tuple.from();
static final byte[] EMPTY_BYTES = new byte[0];
@ -112,7 +111,7 @@ public class Subspace
return false;
}
Subspace other = (Subspace)rhs;
return Arrays.equals(rawPrefix, other.rawPrefix) ;
return Arrays.equals(rawPrefix, other.rawPrefix);
}
/**

View File

@ -59,29 +59,29 @@ public class ByteArrayUtil {
if(interlude == null)
interlude = new byte[0];
int element_totals = 0;
int elementTotals = 0;
int interludeSize = interlude.length;
for(byte[] e : parts) {
element_totals += e.length;
elementTotals += e.length;
}
byte[] dest = new byte[(interludeSize * (partCount - 1)) + element_totals];
byte[] dest = new byte[(interludeSize * (partCount - 1)) + elementTotals];
//System.out.println(" interlude -> " + ArrayUtils.printable(interlude));
int start_byte = 0;
int startByte = 0;
int index = 0;
for(byte[] part : parts) {
//System.out.println(" section -> " + ArrayUtils.printable(parts.get(i)));
int length = part.length;
if(length > 0) {
System.arraycopy(part, 0, dest, start_byte, length);
start_byte += length;
System.arraycopy(part, 0, dest, startByte, length);
startByte += length;
}
if(index < partCount - 1 && interludeSize > 0) {
// If this is not the last element, append the interlude
System.arraycopy(interlude, 0, dest, start_byte, interludeSize);
start_byte += interludeSize;
System.arraycopy(interlude, 0, dest, startByte, interludeSize);
startByte += interludeSize;
}
index++;
}
@ -97,7 +97,7 @@ public class ByteArrayUtil {
*
* @return a newly created concatenation of the input
*/
public static byte[] join(byte[] ... parts) {
public static byte[] join(byte[]... parts) {
return join(null, Arrays.asList(parts));
}

View File

@ -21,11 +21,8 @@
package com.apple.foundationdb.tuple;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
@ -852,12 +849,12 @@ public class Tuple implements Comparable<Tuple>, Iterable<Object> {
*
* @return a newly created {@code Tuple}
*/
public static Tuple from(Object ... items) {
public static Tuple from(Object... items) {
return fromList(Arrays.asList(items));
}
static void main(String[] args) {
for( int i : new int[] {10, 100, 1000, 10000, 100000, 1000000} ) {
for(int i : new int[] {10, 100, 1000, 10000, 100000, 1000000}) {
createTuple(i);
}

View File

@ -421,10 +421,10 @@ class TupleUtil {
// Convert to long if in range -- otherwise, leave as BigInteger.
if (val.compareTo(BigInteger.valueOf(Long.MIN_VALUE))<0||
val.compareTo(BigInteger.valueOf(Long.MAX_VALUE))>0) {
// This can occur if the thing can be represented with 8 bytes but not
// the right sign information.
return new DecodeResult(end, val);
val.compareTo(BigInteger.valueOf(Long.MAX_VALUE))>0) {
// This can occur if the thing can be represented with 8 bytes but not
// the right sign information.
return new DecodeResult(end, val);
}
return new DecodeResult(end, val.longValue());
}
@ -610,18 +610,18 @@ class TupleUtil {
public static void main(String[] args) {
try {
byte[] bytes = pack(Collections.singletonList(4), null );
assert 4 == (Integer)(decode( bytes, 0, bytes.length ).o);
byte[] bytes = pack(Collections.singletonList(4), null);
assert 4 == (Integer)(decode(bytes, 0, bytes.length).o);
} catch (Exception e) {
e.printStackTrace();
System.out.println("Error " + e.getMessage());
}
try {
byte[] bytes = pack( Collections.singletonList("\u021Aest \u0218tring"), null );
String string = (String)(decode( bytes, 0, bytes.length ).o);
byte[] bytes = pack(Collections.singletonList("\u021Aest \u0218tring"), null);
String string = (String)(decode(bytes, 0, bytes.length).o);
System.out.println("contents -> " + string);
assert "\u021Aest \u0218tring" == string;
assert "\u021Aest \u0218tring".equals(string);
} catch (Exception e) {
e.printStackTrace();
System.out.println("Error " + e.getMessage());

View File

@ -20,12 +20,12 @@
package com.apple.foundationdb.test;
import com.apple.foundationdb.Database;
import com.apple.foundationdb.FDB;
import java.nio.charset.Charset;
import java.util.Random;
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;

View File

@ -22,13 +22,11 @@ package com.apple.foundationdb.test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import com.apple.foundationdb.Range;
import com.apple.foundationdb.Transaction;
import com.apple.foundationdb.async.AsyncUtil;
import com.apple.foundationdb.directory.Directory;
import com.apple.foundationdb.directory.DirectoryLayer;
@ -37,11 +35,11 @@ import com.apple.foundationdb.subspace.Subspace;
import com.apple.foundationdb.tuple.Tuple;
class AsyncDirectoryExtension {
List<Object> dirList = new ArrayList<Object>();
List<Object> dirList = new ArrayList<>();
int dirIndex = 0;
int errorIndex = 0;
public AsyncDirectoryExtension() {
AsyncDirectoryExtension() {
dirList.add(DirectoryLayer.getDefault());
}
@ -54,13 +52,9 @@ class AsyncDirectoryExtension {
}
CompletableFuture<Void> processInstruction(final Instruction inst) {
return executeInstruction(inst)
.exceptionally(new Function<Throwable, Void>() {
@Override
public Void apply(Throwable e) {
DirectoryUtil.pushError(inst, e, dirList);
return null;
}
return executeInstruction(inst).exceptionally(e -> {
DirectoryUtil.pushError(inst, e, dirList);
return null;
});
}
@ -69,372 +63,184 @@ class AsyncDirectoryExtension {
if(op == DirectoryOperation.DIRECTORY_CREATE_SUBSPACE) {
return DirectoryUtil.popTuple(inst)
.thenComposeAsync(new Function<Tuple, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(final Tuple prefix) {
return inst.popParam()
.thenApplyAsync(new Function<Object, Void>() {
@Override
public Void apply(Object rawPrefix) {
dirList.add(new Subspace(prefix, (byte[])rawPrefix));
return null;
}
});
}
});
.thenComposeAsync(prefix -> inst.popParam()
.thenAccept(rawPrefix -> dirList.add(new Subspace(prefix, (byte[])rawPrefix))));
}
else if(op == DirectoryOperation.DIRECTORY_CREATE_LAYER) {
return inst.popParams(3)
.thenApplyAsync(new Function<List<Object>, Void>() {
@Override
public Void apply(List<Object> params) {
Subspace nodeSubspace = (Subspace)dirList.get(StackUtils.getInt(params.get(0)));
Subspace contentSubspace = (Subspace)dirList.get(StackUtils.getInt(params.get(1)));
boolean allowManualPrefixes = StackUtils.getInt(params.get(2)) == 1;
return inst.popParams(3).thenAcceptAsync(params -> {
Subspace nodeSubspace = (Subspace)dirList.get(StackUtils.getInt(params.get(0)));
Subspace contentSubspace = (Subspace)dirList.get(StackUtils.getInt(params.get(1)));
boolean allowManualPrefixes = StackUtils.getInt(params.get(2)) == 1;
if(nodeSubspace == null || contentSubspace == null)
dirList.add(null);
else
dirList.add(new DirectoryLayer(nodeSubspace, contentSubspace, allowManualPrefixes));
return null;
}
if(nodeSubspace == null || contentSubspace == null)
dirList.add(null);
else
dirList.add(new DirectoryLayer(nodeSubspace, contentSubspace, allowManualPrefixes));
});
}
else if(op == DirectoryOperation.DIRECTORY_CHANGE) {
return inst.popParam()
.thenApplyAsync(new Function<Object, Void>() {
@Override
public Void apply(Object index) {
dirIndex = StackUtils.getInt(index);
if(dirList.get(dirIndex) == null)
dirIndex = errorIndex;
return null;
}
return inst.popParam().thenAcceptAsync(index -> {
dirIndex = StackUtils.getInt(index);
if(dirList.get(dirIndex) == null)
dirIndex = errorIndex;
});
}
else if(op == DirectoryOperation.DIRECTORY_SET_ERROR_INDEX) {
return inst.popParam()
.thenApplyAsync(new Function<Object, Void>() {
@Override
public Void apply(Object index) {
errorIndex = StackUtils.getInt(index);
return null;
}
});
return inst.popParam().thenAcceptAsync(index -> errorIndex = StackUtils.getInt(index));
}
else if(op == DirectoryOperation.DIRECTORY_CREATE_OR_OPEN || op == DirectoryOperation.DIRECTORY_OPEN) {
return DirectoryUtil.popPath(inst)
.thenComposeAsync(new Function<List<String>, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(final List<String> path) {
return inst.popParam()
.thenComposeAsync(new Function<Object, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(Object layer) {
CompletableFuture<DirectorySubspace> dir;
if(layer == null) {
if(op == DirectoryOperation.DIRECTORY_CREATE_OR_OPEN)
dir = directory().createOrOpen(inst.tcx, path);
else
dir = directory().open(inst.readTcx, path);
}
else {
if(op == DirectoryOperation.DIRECTORY_CREATE_OR_OPEN)
dir = directory().createOrOpen(inst.tcx, path, (byte[])layer);
else
dir = directory().open(inst.readTcx, path, (byte[])layer);
}
return dir.thenApplyAsync(new Function<DirectorySubspace, Void>() {
@Override
public Void apply(DirectorySubspace dirSubspace) {
dirList.add(dirSubspace);
return null;
}
});
}
});
.thenComposeAsync(path -> inst.popParam().thenComposeAsync(layer -> {
CompletableFuture<DirectorySubspace> dir;
if(layer == null) {
if(op == DirectoryOperation.DIRECTORY_CREATE_OR_OPEN)
dir = directory().createOrOpen(inst.tcx, path);
else
dir = directory().open(inst.readTcx, path);
}
});
else {
if(op == DirectoryOperation.DIRECTORY_CREATE_OR_OPEN)
dir = directory().createOrOpen(inst.tcx, path, (byte[])layer);
else
dir = directory().open(inst.readTcx, path, (byte[])layer);
}
return dir.thenAccept(dirList::add);
}));
}
else if(op == DirectoryOperation.DIRECTORY_CREATE) {
return DirectoryUtil.popPath(inst)
.thenComposeAsync(new Function<List<String>, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(final List<String> path) {
return inst.popParams(2)
.thenComposeAsync(new Function<List<Object>, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(List<Object> params) {
byte[] layer = (byte[])params.get(0);
byte[] prefix = (byte[])params.get(1);
return DirectoryUtil.popPath(inst).thenComposeAsync(path -> inst.popParams(2).thenComposeAsync(params -> {
byte[] layer = (byte[])params.get(0);
byte[] prefix = (byte[])params.get(1);
CompletableFuture<DirectorySubspace> dir;
if(layer == null && prefix == null)
dir = directory().create(inst.tcx, path);
else if(prefix == null)
dir = directory().create(inst.tcx, path, layer);
else {
if(layer == null)
layer = new byte[0];
CompletableFuture<DirectorySubspace> dir;
if(layer == null && prefix == null)
dir = directory().create(inst.tcx, path);
else if(prefix == null)
dir = directory().create(inst.tcx, path, layer);
else {
if(layer == null)
layer = new byte[0];
dir = directory().create(inst.tcx, path, layer, prefix);
}
return dir.thenApplyAsync(new Function<DirectorySubspace, Void>() {
@Override
public Void apply(DirectorySubspace dirSubspace) {
dirList.add(dirSubspace);
return null;
}
});
}
});
dir = directory().create(inst.tcx, path, layer, prefix);
}
});
return dir.thenAccept(dirList::add);
}));
}
else if(op == DirectoryOperation.DIRECTORY_MOVE) {
return DirectoryUtil.popPaths(inst, 2)
.thenComposeAsync(new Function<List<List<String>>, CompletableFuture<DirectorySubspace>>() {
@Override
public CompletableFuture<DirectorySubspace> apply(List<List<String>> paths) {
return directory().move(inst.tcx, paths.get(0), paths.get(1));
}
})
.thenApplyAsync(new Function<DirectorySubspace, Void>() {
@Override
public Void apply(DirectorySubspace dirSubspace) {
dirList.add(dirSubspace);
return null;
}
});
.thenComposeAsync(paths -> directory().move(inst.tcx, paths.get(0), paths.get(1)))
.thenAccept(dirList::add);
}
else if(op == DirectoryOperation.DIRECTORY_MOVE_TO) {
return DirectoryUtil.popPath(inst)
.thenComposeAsync(new Function<List<String>, CompletableFuture<DirectorySubspace>>() {
@Override
public CompletableFuture<DirectorySubspace> apply(List<String> newAbsolutePath) {
return directory().moveTo(inst.tcx, newAbsolutePath);
}
})
.thenApplyAsync(new Function<DirectorySubspace, Void>() {
@Override
public Void apply(DirectorySubspace dirSubspace) {
dirList.add(dirSubspace);
return null;
}
});
.thenComposeAsync(newAbsolutePath -> directory().moveTo(inst.tcx, newAbsolutePath))
.thenAccept(dirList::add);
}
else if(op == DirectoryOperation.DIRECTORY_REMOVE) {
return inst.popParam()
.thenComposeAsync(new Function<Object, CompletableFuture<List<List<String>>>>() {
@Override
public CompletableFuture<List<List<String>>> apply(Object count) {
return DirectoryUtil.popPaths(inst, StackUtils.getInt(count));
}
})
.thenComposeAsync(new Function<List<List<String>>, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(List<List<String>> path) {
if(path.size() == 0)
return directory().remove(inst.tcx);
else
return directory().remove(inst.tcx, path.get(0));
}
.thenComposeAsync(count -> DirectoryUtil.popPaths(inst, StackUtils.getInt(count)))
.thenComposeAsync(path -> {
if(path.size() == 0)
return directory().remove(inst.tcx);
else
return directory().remove(inst.tcx, path.get(0));
});
}
else if(op == DirectoryOperation.DIRECTORY_REMOVE_IF_EXISTS) {
return inst.popParam()
.thenComposeAsync(new Function<Object, CompletableFuture<List<List<String>>>>() {
@Override
public CompletableFuture<List<List<String>>> apply(Object count) {
return DirectoryUtil.popPaths(inst, StackUtils.getInt(count));
}
})
.thenComposeAsync(new Function<List<List<String>>, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(List<List<String>> path) {
if(path.size() == 0)
return AsyncUtil.success(directory().removeIfExists(inst.tcx));
else
return AsyncUtil.success(directory().removeIfExists(inst.tcx, path.get(0)));
}
.thenComposeAsync(count -> DirectoryUtil.popPaths(inst, StackUtils.getInt(count)))
.thenComposeAsync(path -> {
if(path.size() == 0)
return AsyncUtil.success(directory().removeIfExists(inst.tcx));
else
return AsyncUtil.success(directory().removeIfExists(inst.tcx, path.get(0)));
});
}
else if(op == DirectoryOperation.DIRECTORY_LIST) {
return inst.popParam()
.thenComposeAsync(new Function<Object, CompletableFuture<List<List<String>>>>() {
@Override
public CompletableFuture<List<List<String>>> apply(Object count) {
return DirectoryUtil.popPaths(inst, StackUtils.getInt(count));
}
.thenComposeAsync(count -> DirectoryUtil.popPaths(inst, StackUtils.getInt(count)))
.thenComposeAsync(path -> {
if(path.size() == 0)
return directory().list(inst.readTcx);
else
return directory().list(inst.readTcx, path.get(0));
})
.thenComposeAsync(new Function<List<List<String>>, CompletableFuture<List<String>>>() {
@Override
public CompletableFuture<List<String>> apply(List<List<String>> path) {
if(path.size() == 0)
return directory().list(inst.readTcx);
else
return directory().list(inst.readTcx, path.get(0));
}
})
.thenApplyAsync(new Function<List<String>, Void>() {
@Override
public Void apply(List<String> children) {
inst.push(Tuple.fromItems(children).pack());
return null;
}
});
.thenAccept(children -> inst.push(Tuple.fromItems(children).pack()));
}
else if(op == DirectoryOperation.DIRECTORY_EXISTS) {
return inst.popParam()
.thenComposeAsync(new Function<Object, CompletableFuture<List<List<String>>>>() {
@Override
public CompletableFuture<List<List<String>>> apply(Object count) {
return DirectoryUtil.popPaths(inst, StackUtils.getInt(count));
}
.thenComposeAsync(count -> DirectoryUtil.popPaths(inst, StackUtils.getInt(count)))
.thenComposeAsync(path -> {
if(path.size() == 0)
return directory().exists(inst.readTcx);
else
return directory().exists(inst.readTcx, path.get(0));
})
.thenComposeAsync(new Function<List<List<String>>, CompletableFuture<Boolean>>() {
@Override
public CompletableFuture<Boolean> apply(List<List<String>> path) {
if(path.size() == 0)
return directory().exists(inst.readTcx);
else
return directory().exists(inst.readTcx, path.get(0));
}
})
.thenApplyAsync(new Function<Boolean, Void>() {
@Override
public Void apply(Boolean exists){
inst.push(exists ? 1 : 0);
return null;
}
});
.thenAccept(exists -> inst.push(exists ? 1 : 0));
}
else if(op == DirectoryOperation.DIRECTORY_PACK_KEY) {
return DirectoryUtil.popTuple(inst)
.thenApplyAsync(new Function<Tuple, Void>() {
@Override
public Void apply(Tuple keyTuple) {
inst.push(subspace().pack(keyTuple));
return null;
}
});
return DirectoryUtil.popTuple(inst).thenAccept(keyTuple -> inst.push(subspace().pack(keyTuple)));
}
else if(op == DirectoryOperation.DIRECTORY_UNPACK_KEY) {
return inst.popParam()
.thenApplyAsync(new Function<Object, Void>() {
@Override
public Void apply(Object key) {
Tuple tup = subspace().unpack((byte[])key);
for(Object o : tup)
inst.push(o);
return null;
}
return inst.popParam().thenAcceptAsync(key -> {
Tuple tup = subspace().unpack((byte[])key);
for(Object o : tup)
inst.push(o);
});
}
else if(op == DirectoryOperation.DIRECTORY_RANGE) {
return DirectoryUtil.popTuple(inst)
.thenApplyAsync(new Function<Tuple, Void>() {
@Override
public Void apply(Tuple tup) {
Range range = subspace().range(tup);
inst.push(range.begin);
inst.push(range.end);
return null;
}
return DirectoryUtil.popTuple(inst).thenAcceptAsync(tup -> {
Range range = subspace().range(tup);
inst.push(range.begin);
inst.push(range.end);
});
}
else if(op == DirectoryOperation.DIRECTORY_CONTAINS) {
return inst.popParam()
.thenApplyAsync(new Function<Object, Void>() {
@Override
public Void apply(Object key) {
inst.push(subspace().contains((byte[])key) ? 1 : 0);
return null;
}
});
return inst.popParam().thenAccept(key -> inst.push(subspace().contains((byte[])key) ? 1 : 0));
}
else if(op == DirectoryOperation.DIRECTORY_OPEN_SUBSPACE) {
return DirectoryUtil.popTuple(inst)
.thenApplyAsync(new Function<Tuple, Void>() {
@Override
public Void apply(Tuple prefix) {
dirList.add(subspace().subspace(prefix));
return null;
}
});
return DirectoryUtil.popTuple(inst).thenAcceptAsync(prefix -> dirList.add(subspace().subspace(prefix)));
}
else if(op == DirectoryOperation.DIRECTORY_LOG_SUBSPACE) {
return inst.popParam()
.thenComposeAsync(new Function<Object, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(final Object prefix) {
return inst.tcx.runAsync(new Function<Transaction, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(Transaction tr) {
tr.set(Tuple.from(dirIndex).pack((byte[])prefix), subspace().getKey());
return CompletableFuture.completedFuture(null);
}
});
}
});
return inst.popParam().thenComposeAsync(prefix ->
inst.tcx.runAsync(tr -> {
tr.set(Tuple.from(dirIndex).pack((byte[])prefix), subspace().getKey());
return AsyncUtil.DONE;
})
);
}
else if(op == DirectoryOperation.DIRECTORY_LOG_DIRECTORY) {
return inst.popParam()
.thenComposeAsync(new Function<Object, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(Object prefix) {
final Subspace logSubspace = new Subspace(new Tuple().add(dirIndex), (byte[])prefix);
return inst.tcx.runAsync(new Function<Transaction, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(final Transaction tr) {
return directory().exists(tr)
.thenComposeAsync(new Function<Boolean, CompletableFuture<List<String>>>() {
@Override
public CompletableFuture<List<String>> apply(Boolean exists) {
tr.set(logSubspace.pack("path"), Tuple.fromItems(directory().getPath()).pack());
tr.set(logSubspace.pack("layer"), new Tuple().add(directory().getLayer()).pack());
tr.set(logSubspace.pack("exists"), new Tuple().add(exists ? 1 : 0).pack());
if(exists)
return directory().list(tr);
else
return CompletableFuture.completedFuture(new ArrayList<String>());
}
})
.thenApplyAsync(new Function<List<String>, Void>() {
@Override
public Void apply(List<String> children) {
tr.set(logSubspace.pack("children"), Tuple.fromItems(children).pack());
return null;
}
});
}
});
}
return inst.popParam().thenComposeAsync(prefix -> {
final Subspace logSubspace = new Subspace(new Tuple().add(dirIndex), (byte[])prefix);
return inst.tcx.runAsync(tr -> directory().exists(tr)
.thenComposeAsync(exists -> {
tr.set(logSubspace.pack("path"), Tuple.fromItems(directory().getPath()).pack());
tr.set(logSubspace.pack("layer"), new Tuple().add(directory().getLayer()).pack());
tr.set(logSubspace.pack("exists"), new Tuple().add(exists ? 1 : 0).pack());
if(exists)
return directory().list(tr);
else
return CompletableFuture.completedFuture(Collections.emptyList());
})
.thenAcceptAsync(children -> tr.set(logSubspace.pack("children"), Tuple.fromItems(children).pack()))
);
});
}
else if(op == DirectoryOperation.DIRECTORY_STRIP_PREFIX) {
return inst.popParam()
.thenApplyAsync(new Function<Object, Void>() {
@Override
public Void apply(Object param) {
byte[] str = (byte[])param;
byte[] rawPrefix = subspace().getKey();
return inst.popParam().thenAcceptAsync(param -> {
byte[] str = (byte[])param;
byte[] rawPrefix = subspace().getKey();
if(str.length < rawPrefix.length)
if(str.length < rawPrefix.length)
throw new RuntimeException("String does not start with raw prefix");
for(int i = 0; i < rawPrefix.length; ++i)
if(str[i] != rawPrefix[i])
throw new RuntimeException("String does not start with raw prefix");
for(int i = 0; i < rawPrefix.length; ++i)
if(str[i] != rawPrefix[i])
throw new RuntimeException("String does not start with raw prefix");
inst.push(Arrays.copyOfRange(str, rawPrefix.length, str.length));
return null;
}
inst.push(Arrays.copyOfRange(str, rawPrefix.length, str.length));
});
}
else {

View File

@ -1,28 +0,0 @@
/*
* AsyncPerformanceTester.java
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
*
* 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.apple.foundationdb.test;
public class AsyncPerformanceTester {
public static void main(String[] args) {
System.out.println("Running Java async performance test on Java version " + System.getProperty("java.version"));
}
}

View File

@ -21,10 +21,15 @@
package com.apple.foundationdb.test;
import java.math.BigInteger;
import java.util.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
@ -53,16 +58,12 @@ public class AsyncStackTester {
@Override
public CompletableFuture<Void> apply(Transaction tr) {
return tr.getRange(Range.startsWith(prefix)).asList().thenApplyAsync(new Function<List<KeyValue>, Void>() {
@Override
public Void apply(List<KeyValue> list) {
if(list.size() > 0) {
//System.out.println(" - Throwing new fake commit error...");
throw new FDBException("ERROR: Fake commit conflict", 1020);
}
return null;
return tr.getRange(Range.startsWith(prefix)).asList().thenAcceptAsync(list -> {
if(list.size() > 0) {
//System.out.println(" - Throwing new fake commit error...");
throw new FDBException("ERROR: Fake commit conflict", 1020);
}
});
}, FDB.DEFAULT_EXECUTOR);
}
}
@ -81,11 +82,11 @@ public class AsyncStackTester {
System.out.println(inst.context.preStr + " - " + "Pushing null");
else
System.out.println(inst.context.preStr + " - " + "Pushing item of type " + item.getClass().getName());*/
return CompletableFuture.completedFuture(null);
return AsyncUtil.DONE;
}
else if(op == StackOperation.POP) {
inst.pop();
return CompletableFuture.completedFuture(null);
return AsyncUtil.DONE;
}
else if(op == StackOperation.DUP) {
if(inst.size() == 0)
@ -93,281 +94,183 @@ public class AsyncStackTester {
StackEntry e = inst.pop();
inst.push(e);
inst.push(e);
return CompletableFuture.completedFuture(null);
return AsyncUtil.DONE;
}
else if(op == StackOperation.EMPTY_STACK) {
inst.clear();
return CompletableFuture.completedFuture(null);
return AsyncUtil.DONE;
}
else if(op == StackOperation.SWAP) {
return inst.popParam()
.thenApplyAsync(new Function<Object, Void>() {
@Override
public Void apply(Object param) {
int index = StackUtils.getInt(param);
if(index >= inst.size())
throw new IllegalArgumentException("Stack index not valid");
return inst.popParam().thenAcceptAsync(param -> {
int index = StackUtils.getInt(param);
if(index >= inst.size())
throw new IllegalArgumentException("Stack index not valid");
inst.swap(index);
return null;
}
});
inst.swap(index);
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.WAIT_FUTURE) {
return popAndWait(inst)
.thenApplyAsync(new Function<StackEntry, Void>() {
@Override
public Void apply(StackEntry e) {
inst.push(e);
return null;
}
});
return popAndWait(inst).thenAccept(inst::push);
}
else if(op == StackOperation.WAIT_EMPTY) {
return inst.popParam()
.thenComposeAsync(new Function<Object, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(Object param) {
WaitEmpty retryable = new WaitEmpty((byte[])param);
return inst.context.db.runAsync(retryable).thenApply(new Function<Void, Void>() {
@Override
public Void apply(Void o) {
inst.push( "WAITED_FOR_EMPTY".getBytes());
return null;
}
});
}
});
return inst.popParam().thenComposeAsync(param -> {
WaitEmpty retryable = new WaitEmpty((byte[])param);
return inst.context.db.runAsync(retryable).thenRun(() -> inst.push("WAITED_FOR_EMPTY".getBytes()));
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.START_THREAD) {
return inst.popParam()
.thenApplyAsync(new Function<Object, Void>() {
@Override
public Void apply(Object param) {
//System.out.println(inst.context.preStr + " - " + "Starting new thread at prefix: " + ByteArrayUtil.printable((byte[]) params.get(0)));
inst.context.addContext((byte[])param);
return null;
}
});
return inst.popParam().thenAcceptAsync(param -> {
//System.out.println(inst.context.preStr + " - " + "Starting new thread at prefix: " + ByteArrayUtil.printable((byte[]) params.get(0)));
inst.context.addContext((byte[])param);
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.NEW_TRANSACTION) {
inst.context.newTransaction();
return CompletableFuture.completedFuture(null);
return AsyncUtil.DONE;
}
else if(op == StackOperation.USE_TRANSACTION) {
return inst.popParam()
.thenApplyAsync(new Function<Object, Void>() {
public Void apply(Object param) {
inst.context.switchTransaction((byte[])param);
return null;
}
});
return inst.popParam().thenAcceptAsync(param -> {
inst.context.switchTransaction((byte[])param);
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.SET) {
return inst.popParams(2).thenComposeAsync(new Function<List<Object>, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(final List<Object> params) {
/*System.out.println(inst.context.preStr + " - " + "Setting '" + ByteArrayUtil.printable((byte[]) params.get(0)) +
"' to '" + ByteArrayUtil.printable((byte[]) params.get(1)) + "'"); */
return executeMutation(inst, new Function<Transaction, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(Transaction tr) {
tr.set((byte[])params.get(0), (byte[])params.get(1));
return CompletableFuture.completedFuture(null);
}
});
}
});
return inst.popParams(2).thenComposeAsync(params -> {
/*System.out.println(inst.context.preStr + " - " + "Setting '" + ByteArrayUtil.printable((byte[]) params.get(0)) +
"' to '" + ByteArrayUtil.printable((byte[]) params.get(1)) + "'"); */
return executeMutation(inst, tr -> {
tr.set((byte[])params.get(0), (byte[])params.get(1));
return AsyncUtil.DONE;
});
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.CLEAR) {
return inst.popParam().thenComposeAsync(new Function<Object, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(final Object param) {
//System.out.println(inst.context.preStr + " - " + "Clearing: '" + ByteArrayUtil.printable((byte[])param) + "'");
return executeMutation(inst, new Function<Transaction, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(Transaction tr) {
tr.clear((byte[])param);
return CompletableFuture.completedFuture(null);
}
});
}
});
return inst.popParam().thenComposeAsync(param -> {
//System.out.println(inst.context.preStr + " - " + "Clearing: '" + ByteArrayUtil.printable((byte[])param) + "'");
return executeMutation(inst, tr -> {
tr.clear((byte[])param);
return AsyncUtil.DONE;
});
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.CLEAR_RANGE) {
return inst.popParams(2).thenComposeAsync(new Function<List<Object>, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(final List<Object> params) {
return executeMutation(inst, new Function<Transaction, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(Transaction tr) {
tr.clear((byte[])params.get(0), (byte[])params.get(1));
return CompletableFuture.completedFuture(null);
}
});
}
});
return inst.popParams(2).thenComposeAsync(params ->
executeMutation(inst, tr -> {
tr.clear((byte[])params.get(0), (byte[])params.get(1));
return AsyncUtil.DONE;
}),
FDB.DEFAULT_EXECUTOR
);
}
else if(op == StackOperation.CLEAR_RANGE_STARTS_WITH) {
return inst.popParam().thenComposeAsync(new Function<Object, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(final Object param) {
return executeMutation(inst, new Function<Transaction, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(Transaction tr) {
tr.clear(Range.startsWith((byte[])param));
return CompletableFuture.completedFuture(null);
}
});
}
});
return inst.popParam().thenComposeAsync(param ->
executeMutation(inst, tr -> {
tr.clear(Range.startsWith((byte[])param));
return AsyncUtil.DONE;
}),
FDB.DEFAULT_EXECUTOR
);
}
else if(op == StackOperation.ATOMIC_OP) {
return inst.popParams(3).thenComposeAsync(new Function<List<Object>, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(final List<Object> params) {
final MutationType optype = MutationType.valueOf((String)params.get(0));
return executeMutation(inst,
new Function<Transaction, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(Transaction tr) {
tr.mutate(optype, (byte[])params.get(1), (byte[])params.get(2));
return CompletableFuture.completedFuture(null);
}
}
);
}
});
return inst.popParams(3).thenComposeAsync(params -> {
final MutationType optype = MutationType.valueOf((String)params.get(0));
return executeMutation(inst, tr -> {
tr.mutate(optype, (byte[])params.get(1), (byte[])params.get(2));
return AsyncUtil.DONE;
});
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.COMMIT) {
inst.push(inst.tr.commit());
return CompletableFuture.completedFuture(null);
return AsyncUtil.DONE;
}
else if(op == StackOperation.RESET) {
inst.context.newTransaction();
return CompletableFuture.completedFuture(null);
return AsyncUtil.DONE;
}
else if(op == StackOperation.CANCEL) {
inst.tr.cancel();
return CompletableFuture.completedFuture(null);
return AsyncUtil.DONE;
}
else if(op == StackOperation.READ_CONFLICT_RANGE) {
return inst.popParams(2).thenApplyAsync(new Function<List<Object>, Void>() {
@Override
public Void apply(List<Object> params) {
inst.tr.addReadConflictRange((byte[])params.get(0), (byte[])params.get(1));
inst.push("SET_CONFLICT_RANGE".getBytes());
return null;
}
});
return inst.popParams(2).thenAcceptAsync(params -> {
inst.tr.addReadConflictRange((byte[])params.get(0), (byte[])params.get(1));
inst.push("SET_CONFLICT_RANGE".getBytes());
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.WRITE_CONFLICT_RANGE) {
return inst.popParams(2).thenApplyAsync(new Function<List<Object>, Void>() {
@Override
public Void apply(List<Object> params) {
inst.tr.addWriteConflictRange((byte[])params.get(0), (byte[])params.get(1));
inst.push("SET_CONFLICT_RANGE".getBytes());
return null;
}
});
return inst.popParams(2).thenAcceptAsync(params -> {
inst.tr.addWriteConflictRange((byte[])params.get(0), (byte[])params.get(1));
inst.push("SET_CONFLICT_RANGE".getBytes());
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.READ_CONFLICT_KEY) {
return inst.popParam().thenApplyAsync(new Function<Object, Void>() {
@Override
public Void apply(Object param) {
inst.tr.addReadConflictKey((byte[])param);
inst.push("SET_CONFLICT_KEY".getBytes());
return null;
}
});
return inst.popParam().thenAcceptAsync(param -> {
inst.tr.addReadConflictKey((byte[])param);
inst.push("SET_CONFLICT_KEY".getBytes());
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.WRITE_CONFLICT_KEY) {
return inst.popParam().thenApplyAsync(new Function<Object, Void>() {
@Override
public Void apply(Object param) {
inst.tr.addWriteConflictKey((byte[])param);
inst.push("SET_CONFLICT_KEY".getBytes());
return null;
}
return inst.popParam().thenAcceptAsync(param -> {
inst.tr.addWriteConflictKey((byte[])param);
inst.push("SET_CONFLICT_KEY".getBytes());
});
}
else if(op == StackOperation.DISABLE_WRITE_CONFLICT) {
inst.tr.options().setNextWriteNoWriteConflictRange();
return CompletableFuture.completedFuture(null);
return AsyncUtil.DONE;
}
else if(op == StackOperation.GET) {
return inst.popParam().thenApplyAsync(new Function<Object, Void>() {
@Override
public Void apply(Object param) {
inst.push(inst.readTcx.readAsync(readTr -> readTr.get((byte[]) param)));
return null;
}
return inst.popParam().thenAcceptAsync(param -> {
inst.push(inst.readTcx.readAsync(readTr -> readTr.get((byte[]) param)));
});
}
else if(op == StackOperation.GET_RANGE) {
return inst.popParams(5).thenComposeAsync(new Function<List<Object>, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(List<Object> params) {
int limit = StackUtils.getInt(params.get(2));
boolean reverse = StackUtils.getBoolean(params.get(3));
StreamingMode mode = inst.context.streamingModeFromCode(
StackUtils.getInt(params.get(4), StreamingMode.ITERATOR.code()));
return inst.popParams(5).thenComposeAsync(params -> {
int limit = StackUtils.getInt(params.get(2));
boolean reverse = StackUtils.getBoolean(params.get(3));
StreamingMode mode = inst.context.streamingModeFromCode(
StackUtils.getInt(params.get(4), StreamingMode.ITERATOR.code()));
CompletableFuture<List<KeyValue>> range = inst.readTcx.readAsync(readTr -> readTr.getRange((byte[])params.get(0), (byte[])params.get(1), limit, reverse, mode).asList());
return pushRange(inst, range);
}
});
CompletableFuture<List<KeyValue>> range = inst.readTcx.readAsync(readTr -> readTr.getRange((byte[])params.get(0), (byte[])params.get(1), limit, reverse, mode).asList());
return pushRange(inst, range);
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.GET_RANGE_SELECTOR) {
return inst.popParams(10).thenComposeAsync(new Function<List<Object>, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(List<Object> params) {
int limit = StackUtils.getInt(params.get(6));
boolean reverse = StackUtils.getBoolean(params.get(7));
StreamingMode mode = inst.context.streamingModeFromCode(
StackUtils.getInt(params.get(8), StreamingMode.ITERATOR.code()));
return inst.popParams(10).thenComposeAsync(params -> {
int limit = StackUtils.getInt(params.get(6));
boolean reverse = StackUtils.getBoolean(params.get(7));
StreamingMode mode = inst.context.streamingModeFromCode(
StackUtils.getInt(params.get(8), StreamingMode.ITERATOR.code()));
KeySelector start = StackUtils.createSelector(params.get(0),params.get(1), params.get(2));
KeySelector end = StackUtils.createSelector(params.get(3), params.get(4), params.get(5));
KeySelector start = StackUtils.createSelector(params.get(0),params.get(1), params.get(2));
KeySelector end = StackUtils.createSelector(params.get(3), params.get(4), params.get(5));
CompletableFuture<List<KeyValue>> range = inst.readTcx.readAsync(readTr -> readTr.getRange(start, end, limit, reverse, mode).asList());
return pushRange(inst, range, (byte[])params.get(9));
}
});
CompletableFuture<List<KeyValue>> range = inst.readTcx.readAsync(readTr -> readTr.getRange(start, end, limit, reverse, mode).asList());
return pushRange(inst, range, (byte[])params.get(9));
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.GET_RANGE_STARTS_WITH) {
return inst.popParams(4).thenComposeAsync(new Function<List<Object>, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(List<Object> params) {
int limit = StackUtils.getInt(params.get(1));
boolean reverse = StackUtils.getBoolean(params.get(2));
StreamingMode mode = inst.context.streamingModeFromCode(
StackUtils.getInt(params.get(3), StreamingMode.ITERATOR.code()));
return inst.popParams(4).thenComposeAsync(params -> {
int limit = StackUtils.getInt(params.get(1));
boolean reverse = StackUtils.getBoolean(params.get(2));
StreamingMode mode = inst.context.streamingModeFromCode(
StackUtils.getInt(params.get(3), StreamingMode.ITERATOR.code()));
CompletableFuture<List<KeyValue>> range = inst.readTcx.readAsync(readTr -> readTr.getRange(Range.startsWith((byte[])params.get(0)), limit, reverse, mode).asList());
return pushRange(inst, range);
}
CompletableFuture<List<KeyValue>> range = inst.readTcx.readAsync(readTr -> readTr.getRange(Range.startsWith((byte[])params.get(0)), limit, reverse, mode).asList());
return pushRange(inst, range);
});
}
else if(op == StackOperation.GET_KEY) {
return inst.popParams(4).thenApplyAsync(new Function<List<Object>, Void>() {
@Override
public Void apply(List<Object> params) {
KeySelector start = StackUtils.createSelector(params.get(0),params.get(1), params.get(2));
inst.push(inst.readTcx.readAsync(readTr -> executeGetKey(readTr.getKey(start), (byte[])params.get(3))));
return null;
}
});
return inst.popParams(4).thenAcceptAsync(params -> {
KeySelector start = StackUtils.createSelector(params.get(0),params.get(1), params.get(2));
inst.push(inst.readTcx.readAsync(readTr -> executeGetKey(readTr.getKey(start), (byte[])params.get(3))));
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.GET_READ_VERSION) {
return inst.readTr.getReadVersion().thenApplyAsync(new Function<Long, Void>() {
@Override
public Void apply(Long readVersion) {
inst.context.lastVersion = readVersion;
inst.push("GOT_READ_VERSION".getBytes());
return null;
}
});
return inst.readTr.getReadVersion().thenAcceptAsync(readVersion -> {
inst.context.lastVersion = readVersion;
inst.push("GOT_READ_VERSION".getBytes());
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.GET_COMMITTED_VERSION) {
try {
@ -378,7 +281,7 @@ public class AsyncStackTester {
StackUtils.pushError(inst, e);
}
return CompletableFuture.completedFuture(null);
return AsyncUtil.DONE;
}
else if(op == StackOperation.GET_VERSIONSTAMP) {
try {
@ -388,224 +291,162 @@ public class AsyncStackTester {
StackUtils.pushError(inst, e);
}
return CompletableFuture.completedFuture(null);
return AsyncUtil.DONE;
}
else if(op == StackOperation.SET_READ_VERSION) {
if(inst.context.lastVersion == null)
throw new IllegalArgumentException("Read version has not been read");
inst.tr.setReadVersion(inst.context.lastVersion);
return CompletableFuture.completedFuture(null);
return AsyncUtil.DONE;
}
else if(op == StackOperation.ON_ERROR) {
return inst.popParam().thenComposeAsync(new Function<Object, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(Object param) {
int errorCode = StackUtils.getInt(param);
return inst.popParam().thenComposeAsync(param -> {
int errorCode = StackUtils.getInt(param);
// 1102 (future_released) and 2015 (future_not_set) are not errors to Java.
// This is never encountered by user code, so we have to do something rather
// messy here to get compatibility with other languages.
//
// First, try on error with a retryable error. If it fails, then the transaction is in
// a failed state and we should rethrow the error. Otherwise, throw the original error.
boolean filteredError = errorCode == 1102 || errorCode == 2015;
// 1102 (future_released) and 2015 (future_not_set) are not errors to Java.
// This is never encountered by user code, so we have to do something rather
// messy here to get compatibility with other languages.
//
// First, try on error with a retryable error. If it fails, then the transaction is in
// a failed state and we should rethrow the error. Otherwise, throw the original error.
boolean filteredError = errorCode == 1102 || errorCode == 2015;
FDBException err = new FDBException("Fake testing error", filteredError ? 1020 : errorCode);
final Transaction oldTr = inst.tr;
CompletableFuture<Void> f = oldTr.onError(err)
.whenComplete((tr, t) -> {
if(t != null) {
inst.context.newTransaction(oldTr); // Other bindings allow reuse of non-retryable transactions, so we need to emulate that behavior.
}
else {
inst.setTransaction(oldTr, tr);
}
})
.thenApply(v -> null);
if(filteredError) {
f.join();
throw new FDBException("Fake testing error", errorCode);
FDBException err = new FDBException("Fake testing error", filteredError ? 1020 : errorCode);
final Transaction oldTr = inst.tr;
CompletableFuture<Void> f = oldTr.onError(err).whenComplete((tr, t) -> {
if(t != null) {
inst.context.newTransaction(oldTr); // Other bindings allow reuse of non-retryable transactions, so we need to emulate that behavior.
}
else {
inst.setTransaction(oldTr, tr);
}
}).thenApply(v -> null);
inst.push(f);
return CompletableFuture.completedFuture(null);
if(filteredError) {
f.join();
throw new FDBException("Fake testing error", errorCode);
}
});
inst.push(f);
return AsyncUtil.DONE;
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.SUB) {
return inst.popParams(2).thenApplyAsync(new Function<List<Object>, Void>() {
@Override
public Void apply(List<Object> params) {
BigInteger result = StackUtils.getBigInteger(params.get(0)).subtract(
StackUtils.getBigInteger(params.get(1))
);
inst.push(result);
return null;
}
return inst.popParams(2).thenAcceptAsync(params -> {
BigInteger result = StackUtils.getBigInteger(params.get(0)).subtract(
StackUtils.getBigInteger(params.get(1))
);
inst.push(result);
});
}
else if(op == StackOperation.CONCAT) {
return inst.popParams(2).thenApplyAsync(new Function<List<Object>, Void>() {
@Override
public Void apply(List<Object> params) {
if(params.get(0) instanceof String) {
inst.push((String)params.get(0) + (String)params.get(1));
}
else {
inst.push(ByteArrayUtil.join((byte[])params.get(0), (byte[])params.get(1)));
}
return null;
return inst.popParams(2).thenAcceptAsync(params -> {
if(params.get(0) instanceof String) {
inst.push((String)params.get(0) + (String)params.get(1));
}
});
else {
inst.push(ByteArrayUtil.join((byte[])params.get(0), (byte[])params.get(1)));
}
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.TUPLE_PACK) {
return inst.popParam().thenComposeAsync(new Function<Object, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(Object param) {
int tupleSize = StackUtils.getInt(param);
//System.out.println(inst.context.preStr + " - " + "Packing top " + tupleSize + " items from stack");
return inst.popParams(tupleSize).thenApplyAsync(new Function<List<Object>, Void>() {
@Override
public Void apply(List<Object> elements) {
byte[] coded = Tuple.fromItems(elements).pack();
//System.out.println(inst.context.preStr + " - " + " -> result '" + ByteArrayUtil.printable(coded) + "'");
inst.push(coded);
return null;
}
});
}
});
return inst.popParam().thenComposeAsync(param -> {
int tupleSize = StackUtils.getInt(param);
//System.out.println(inst.context.preStr + " - " + "Packing top " + tupleSize + " items from stack");
return inst.popParams(tupleSize).thenAcceptAsync(elements -> {
byte[] coded = Tuple.fromItems(elements).pack();
//System.out.println(inst.context.preStr + " - " + " -> result '" + ByteArrayUtil.printable(coded) + "'");
inst.push(coded);
}, FDB.DEFAULT_EXECUTOR);
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.TUPLE_PACK_WITH_VERSIONSTAMP) {
return inst.popParams(2).thenComposeAsync(new Function<List<Object>, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(List<Object> params) {
byte[] prefix = (byte[])params.get(0);
int tupleSize = StackUtils.getInt(params.get(1));
//System.out.println(inst.context.preStr + " - " + "Packing top " + tupleSize + " items from stack");
return inst.popParams(tupleSize).thenApplyAsync(new Function<List<Object>, Void>() {
@Override
public Void apply(List<Object> elements) {
Tuple tuple = Tuple.fromItems(elements);
if(!tuple.hasIncompleteVersionstamp() && Math.random() < 0.5) {
inst.push("ERROR: NONE".getBytes());
return null;
}
try {
byte[] coded = tuple.packWithVersionstamp(prefix);
inst.push("OK".getBytes());
inst.push(coded);
} catch(IllegalArgumentException e) {
if(e.getMessage().startsWith("No incomplete")) {
inst.push("ERROR: NONE".getBytes());
} else {
inst.push("ERROR: MULTIPLE".getBytes());
}
}
return null;
return inst.popParams(2).thenComposeAsync(params -> {
byte[] prefix = (byte[])params.get(0);
int tupleSize = StackUtils.getInt(params.get(1));
//System.out.println(inst.context.preStr + " - " + "Packing top " + tupleSize + " items from stack");
return inst.popParams(tupleSize).thenAcceptAsync(elements -> {
Tuple tuple = Tuple.fromItems(elements);
if(!tuple.hasIncompleteVersionstamp() && Math.random() < 0.5) {
inst.push("ERROR: NONE".getBytes());
return;
}
try {
byte[] coded = tuple.packWithVersionstamp(prefix);
inst.push("OK".getBytes());
inst.push(coded);
} catch(IllegalArgumentException e) {
if(e.getMessage().startsWith("No incomplete")) {
inst.push("ERROR: NONE".getBytes());
} else {
inst.push("ERROR: MULTIPLE".getBytes());
}
});
}
});
}
}, FDB.DEFAULT_EXECUTOR);
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.TUPLE_UNPACK) {
return inst.popParam().thenApplyAsync(new Function<Object, Void>() {
@Override
public Void apply(Object param) {
/*System.out.println(inst.context.preStr + " - " + "Unpacking tuple code: " +
ByteArrayUtil.printable((byte[]) param)); */
Tuple t = Tuple.fromBytes((byte[])param);
for(Object o : t.getItems()) {
byte[] itemBytes = Tuple.from(o).pack();
inst.push(itemBytes);
}
return null;
return inst.popParam().thenAcceptAsync(param -> {
/*System.out.println(inst.context.preStr + " - " + "Unpacking tuple code: " +
ByteArrayUtil.printable((byte[]) param)); */
Tuple t = Tuple.fromBytes((byte[])param);
for(Object o : t.getItems()) {
byte[] itemBytes = Tuple.from(o).pack();
inst.push(itemBytes);
}
});
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.TUPLE_RANGE) {
return inst.popParam().thenComposeAsync(new Function<Object, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(Object param) {
int tupleSize = StackUtils.getInt(param);
//System.out.println(inst.context.preStr + " - " + "Tuple range with top " + tupleSize + " items from stack");
return inst.popParams(tupleSize).thenApplyAsync(new Function<List<Object>, Void>() {
@Override
public Void apply(List<Object> elements) {
Range range = Tuple.fromItems(elements).range();
inst.push(range.begin);
inst.push(range.end);
return null;
}
});
}
});
return inst.popParam().thenComposeAsync(param -> {
int tupleSize = StackUtils.getInt(param);
//System.out.println(inst.context.preStr + " - " + "Tuple range with top " + tupleSize + " items from stack");
return inst.popParams(tupleSize).thenAcceptAsync(elements -> {
Range range = Tuple.fromItems(elements).range();
inst.push(range.begin);
inst.push(range.end);
}, FDB.DEFAULT_EXECUTOR);
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.TUPLE_SORT) {
return inst.popParam().thenComposeAsync(new Function<Object, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(Object param) {
final int listSize = StackUtils.getInt(param);
return inst.popParams(listSize).thenApply(new Function<List<Object>, Void>() {
@Override
public Void apply(List<Object> rawElements) {
List<Tuple> tuples = new ArrayList<Tuple>(listSize);
for(Object o : rawElements) {
tuples.add(Tuple.fromBytes((byte[])o));
}
Collections.sort(tuples);
for(Tuple t : tuples) {
inst.push(t.pack());
}
return null;
}
});
}
});
return inst.popParam().thenComposeAsync(param -> {
final int listSize = StackUtils.getInt(param);
return inst.popParams(listSize).thenAcceptAsync(rawElements -> {
List<Tuple> tuples = new ArrayList<>(listSize);
for(Object o : rawElements) {
tuples.add(Tuple.fromBytes((byte[])o));
}
Collections.sort(tuples);
for(Tuple t : tuples) {
inst.push(t.pack());
}
}, FDB.DEFAULT_EXECUTOR);
}, FDB.DEFAULT_EXECUTOR);
}
else if (op == StackOperation.ENCODE_FLOAT) {
return inst.popParam().thenApply(new Function<Object, Void>() {
@Override
public Void apply(Object param) {
byte[] fBytes = (byte[])param;
float value = ByteBuffer.wrap(fBytes).order(ByteOrder.BIG_ENDIAN).getFloat();
inst.push(value);
return null;
}
});
return inst.popParam().thenAcceptAsync(param -> {
byte[] fBytes = (byte[])param;
float value = ByteBuffer.wrap(fBytes).order(ByteOrder.BIG_ENDIAN).getFloat();
inst.push(value);
}, FDB.DEFAULT_EXECUTOR);
}
else if (op == StackOperation.ENCODE_DOUBLE) {
return inst.popParam().thenApply(new Function<Object, Void>() {
@Override
public Void apply(Object param) {
byte[] dBytes = (byte[])param;
double value = ByteBuffer.wrap(dBytes).order(ByteOrder.BIG_ENDIAN).getDouble();
inst.push(value);
return null;
}
});
return inst.popParam().thenAcceptAsync(param -> {
byte[] dBytes = (byte[])param;
double value = ByteBuffer.wrap(dBytes).order(ByteOrder.BIG_ENDIAN).getDouble();
inst.push(value);
}, FDB.DEFAULT_EXECUTOR);
}
else if (op == StackOperation.DECODE_FLOAT) {
return inst.popParam().thenApply(new Function<Object, Void>() {
@Override
public Void apply(Object param) {
float value = ((Number)param).floatValue();
inst.push(ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putFloat(value).array());
return null;
}
});
return inst.popParam().thenAcceptAsync(param -> {
float value = ((Number)param).floatValue();
inst.push(ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putFloat(value).array());
}, FDB.DEFAULT_EXECUTOR);
}
else if (op == StackOperation.DECODE_DOUBLE) {
return inst.popParam().thenApply(new Function<Object, Void>() {
@Override
public Void apply(Object param) {
double value = ((Number)param).doubleValue();
inst.push(ByteBuffer.allocate(8).order(ByteOrder.BIG_ENDIAN).putDouble(value).array());
return null;
}
});
return inst.popParam().thenAcceptAsync(param -> {
double value = ((Number)param).doubleValue();
inst.push(ByteBuffer.allocate(8).order(ByteOrder.BIG_ENDIAN).putDouble(value).array());
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.UNIT_TESTS) {
inst.context.db.options().setLocationCacheSize(100001);
@ -638,7 +479,7 @@ public class AsyncStackTester {
});
}
else if(op == StackOperation.LOG_STACK) {
return inst.popParam().thenComposeAsync(prefix -> doLogStack(inst, (byte[])prefix));
return inst.popParam().thenComposeAsync(prefix -> doLogStack(inst, (byte[])prefix), FDB.DEFAULT_EXECUTOR);
}
throw new IllegalArgumentException("Unrecognized (or unimplemented) operation");
@ -646,31 +487,24 @@ public class AsyncStackTester {
private static CompletableFuture<Void> executeMutation(final Instruction inst, Function<Transaction, CompletableFuture<Void>> r) {
// run this with a retry loop
return inst.tcx.runAsync(r).thenApplyAsync(new Function<Void, Void>() {
@Override
public Void apply(Void a) {
if(inst.isDatabase)
inst.push("RESULT_NOT_PRESENT".getBytes());
return null;
}
});
return inst.tcx.runAsync(r).thenRunAsync(() -> {
if(inst.isDatabase)
inst.push("RESULT_NOT_PRESENT".getBytes());
}, FDB.DEFAULT_EXECUTOR);
}
private static CompletableFuture<byte[]> executeGetKey(final CompletableFuture<byte[]> keyFuture, final byte[] prefixFilter) {
return keyFuture.thenApplyAsync(new Function<byte[], byte[]>() {
@Override
public byte[] apply(byte[] key) {
if(ByteArrayUtil.startsWith(key, prefixFilter)) {
return key;
}
else if(ByteArrayUtil.compareUnsigned(key, prefixFilter) < 0) {
return prefixFilter;
}
else {
return ByteArrayUtil.strinc(prefixFilter);
}
return keyFuture.thenApplyAsync(key -> {
if(ByteArrayUtil.startsWith(key, prefixFilter)) {
return key;
}
});
else if(ByteArrayUtil.compareUnsigned(key, prefixFilter) < 0) {
return prefixFilter;
}
else {
return ByteArrayUtil.strinc(prefixFilter);
}
}, FDB.DEFAULT_EXECUTOR);
}
private static CompletableFuture<Void> doLogStack(final Instruction inst, final byte[] prefix) {
@ -678,7 +512,7 @@ public class AsyncStackTester {
while(inst.size() > 0) {
entries.put(inst.size() - 1, inst.pop());
if(entries.size() == 100) {
return logStack(inst.context.db, entries, prefix).thenComposeAsync(v -> doLogStack(inst, prefix));
return logStack(inst.context.db, entries, prefix).thenComposeAsync(v -> doLogStack(inst, prefix), FDB.DEFAULT_EXECUTOR);
}
}
@ -693,7 +527,7 @@ public class AsyncStackTester {
tr.set(pk, pv.length < 40000 ? pv : Arrays.copyOfRange(pv, 0, 40000));
}
return CompletableFuture.completedFuture(null);
return AsyncUtil.DONE;
});
}
@ -719,7 +553,7 @@ public class AsyncStackTester {
}
@Override
public Void apply(List<KeyValue> list) {
List<byte[]> o = new LinkedList<byte[]>();
List<byte[]> o = new LinkedList<>();
for(KeyValue kv : list) {
if(prefixFilter == null || ByteArrayUtil.startsWith(kv.getKey(), prefixFilter)) {
o.add(kv.getKey());
@ -763,7 +597,7 @@ public class AsyncStackTester {
FDBException ex = StackUtils.getRootFDBException(e);
if(ex != null) {
StackUtils.pushError(inst, ex);
return CompletableFuture.completedFuture(null);
return AsyncUtil.DONE;
}
else {
CompletableFuture<Void> f = new CompletableFuture<>();
@ -780,12 +614,9 @@ public class AsyncStackTester {
}
CompletableFuture<Void> executeRemainingOperations() {
final Function<Void, CompletableFuture<Void>> processNext = new Function<Void, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(Void ignore) {
instructionIndex++;
return executeRemainingOperations();
}
final Function<Void, CompletableFuture<Void>> processNext = ignore -> {
instructionIndex++;
return executeRemainingOperations();
};
if(operations == null || ++currentOp == operations.size()) {
@ -793,24 +624,21 @@ public class AsyncStackTester {
return tr.getRange(nextKey, endKey, 1000).asList()
.whenComplete((x, t) -> tr.close())
.thenComposeAsync(new Function<List<KeyValue>, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(List<KeyValue> next) {
if(next.size() < 1) {
//System.out.println("No key found after: " + ByteArrayUtil.printable(nextKey.getKey()));
return CompletableFuture.completedFuture(null);
}
operations = next;
currentOp = 0;
nextKey = KeySelector.firstGreaterThan(next.get(next.size()-1).getKey());
return processOp(next.get(0).getValue()).thenComposeAsync(processNext);
.thenComposeAsync(next -> {
if(next.size() < 1) {
//System.out.println("No key found after: " + ByteArrayUtil.printable(nextKey.getKey()));
return AsyncUtil.DONE;
}
});
operations = next;
currentOp = 0;
nextKey = KeySelector.firstGreaterThan(next.get(next.size()-1).getKey());
return processOp(next.get(0).getValue()).thenComposeAsync(processNext);
}, FDB.DEFAULT_EXECUTOR);
}
return processOp(operations.get(currentOp).getValue()).thenComposeAsync(processNext);
return processOp(operations.get(currentOp).getValue()).thenComposeAsync(processNext, FDB.DEFAULT_EXECUTOR);
}
}
@ -822,44 +650,31 @@ public class AsyncStackTester {
}
final int idx = entry.idx;
@SuppressWarnings("unchecked")
final CompletableFuture<Object> future = (CompletableFuture<Object>)item;
final CompletableFuture<?> future = (CompletableFuture<?>)item;
CompletableFuture<Object> flattened = flatten(future);
return flattened.thenApplyAsync(new Function<Object, StackEntry>() {
@Override
public StackEntry apply(Object o) {
return new StackEntry(idx, o);
}
});
return flattened.thenApplyAsync(o -> new StackEntry(idx, o));
}
private static CompletableFuture<Object> flatten(final CompletableFuture<Object> future) {
CompletableFuture<Object> f = future.thenApplyAsync(new Function<Object, Object>() {
@Override
public Object apply(Object o) {
if(o == null)
return "RESULT_NOT_PRESENT".getBytes();
return o;
}
private static CompletableFuture<Object> flatten(final CompletableFuture<?> future) {
CompletableFuture<Object> f = future.thenApply(o -> {
if(o == null)
return "RESULT_NOT_PRESENT".getBytes();
return o;
});
return AsyncUtil.composeExceptionally(f, new Function<Throwable, CompletableFuture<Object>>() {
@Override
public CompletableFuture<Object> apply(Throwable t) {
FDBException e = StackUtils.getRootFDBException(t);
if(e != null) {
return CompletableFuture.completedFuture(StackUtils.getErrorBytes(e));
}
CompletableFuture<Object> error = new CompletableFuture<Object>();
error.completeExceptionally(t);
return error;
return AsyncUtil.composeExceptionally(f, t -> {
FDBException e = StackUtils.getRootFDBException(t);
if(e != null) {
return CompletableFuture.completedFuture(StackUtils.getErrorBytes(e));
}
CompletableFuture<Object> error = new CompletableFuture<>();
error.completeExceptionally(t);
return error;
});
}
/**
* Run a stack-machine based test.
*/
@ -893,4 +708,5 @@ public class AsyncStackTester {
executor.shutdown();*/
}
private AsyncStackTester() {}
}

View File

@ -44,78 +44,59 @@ public class BlockingBenchmark {
Transaction tr = database.createTransaction();
tr.setReadVersion(100000);
final Function<Long,Long> identity = new Function<Long, Long>() {
@Override
public Long apply(Long o) {
return o;
}
};
System.out.println("readVersion().join():");
runTests(tr, new Function<CompletableFuture<Long>, Void>() {
@Override
public Void apply(CompletableFuture<Long> o) {
try {
o.join();
} catch(Exception e) { }
return null;
runTests(tr, o -> {
try {
o.join();
} catch(Exception e) {
// Ignore
}
return null;
});
System.out.println("readVersion().get():");
runTests(tr, new Function<CompletableFuture<Long>, Void>() {
@Override
public Void apply(CompletableFuture<Long> o) {
try {
o.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch(Exception e) { }
return null;
runTests(tr, o -> {
try {
o.get();
} catch(Exception e) {
// Ignore
}
return null;
});
System.out.println("readVersion().thenApplyAsync(identity).get():");
runTests(tr, new Function<CompletableFuture<Long>, Void>() {
@Override
public Void apply(CompletableFuture<Long> o) {
try {
o.thenApplyAsync(identity).get();
} catch(Exception e) { }
return null;
runTests(tr, o -> {
try {
o.thenApplyAsync(Function.identity(), FDB.DEFAULT_EXECUTOR).get();
} catch(Exception e) {
// Ignore
}
return null;
});
System.out.println("readVersion().thenApplyAsync^10(identity).get():");
runTests(tr, new Function<CompletableFuture<Long>, Void>() {
@Override
public Void apply(CompletableFuture<Long> o) {
for(int i=0; i<10; i++)
o = o.thenApplyAsync(identity);
try {
o.get();
} catch(Exception e) { }
return null;
runTests(tr, o -> {
for(int i=0; i<10; i++)
o = o.thenApplyAsync(Function.identity(), FDB.DEFAULT_EXECUTOR);
try {
o.get();
} catch(Exception e) {
// Ignore
}
return null;
});
System.out.println("readVersion().get^100():");
runTests(tr, new Function<CompletableFuture<Long>, Void>() {
@Override
public Void apply(CompletableFuture<Long> o) {
for(int i=0; i<100; i++) {
try {
o.get();
} catch(Exception e) { }
runTests(tr, o -> {
for(int i=0; i<100; i++) {
try {
o.get();
} catch(Exception e) {
// Ignore
}
return null;
}
return null;
});
}
@ -124,7 +105,7 @@ public class BlockingBenchmark {
for(int r=0; r<4; r++) {
long start = System.currentTimeMillis();
for(int i = 0; i < REPS; i++) {
blockMethod.apply( tr.getReadVersion() );
blockMethod.apply(tr.getReadVersion());
}
long taken = System.currentTimeMillis() - start;
@ -145,4 +126,6 @@ public class BlockingBenchmark {
System.out.println(" " + REPS + " done in " + taken + "ms -> " + (REPS / (taken)) + " KHz");
}
}
private BlockingBenchmark() {}
}

View File

@ -23,14 +23,11 @@ package com.apple.foundationdb.test;
import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import com.apple.foundationdb.Database;
import com.apple.foundationdb.FDB;
import com.apple.foundationdb.Transaction;
public class ConcurrentGetSetGet {
public static final Charset UTF8 = Charset.forName("UTF-8");
@ -55,25 +52,22 @@ public class ConcurrentGetSetGet {
new ConcurrentGetSetGet().apply(database);
}
public void apply(Database d) {
new Thread(new Runnable() {
@Override
public void run() {
int loops = 0;
try {
Thread.sleep(5000);
System.out.println("Loop " + loops++ + ":");
System.out.println(" attempts: " + attemptCount.get());
System.out.println(" gets complete: " + getCompleteCount.get());
System.out.println(" errors: " + errorCount.get());
System.out.println(" sem: " + semaphore);
System.out.println();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
public void apply(Database db) {
new Thread(() -> {
int loops = 0;
try {
Thread.sleep(5000);
System.out.println("Loop " + loops++ + ":");
System.out.println(" attempts: " + attemptCount.get());
System.out.println(" gets complete: " + getCompleteCount.get());
System.out.println(" errors: " + errorCount.get());
System.out.println(" sem: " + semaphore);
System.out.println();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}).start();
final Random random = new SecureRandom();
try {
@ -86,50 +80,37 @@ public class ConcurrentGetSetGet {
System.out.println("Waited " + wait + "ms");
}
current = System.currentTimeMillis();
d.runAsync(new Function<Transaction, CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(final Transaction r) {
attemptCount.addAndGet(1);
final String key = "test:" + random.nextInt();
return r.get($(key)).thenComposeAsync(new Function<byte[], CompletableFuture<Void>>() {
@Override
public CompletableFuture<Void> apply(byte[] o) {
r.set($(key), $("value"));
return r.get($(key)).thenApplyAsync(new Function<byte[], Void>() {
@Override
public Void apply(byte[] o) {
getCompleteCount.addAndGet(1);
semaphore.release();
return null;
}
});
}
}).exceptionally(new Function<Throwable, Void>() {
@Override
public Void apply(Throwable o) {
errorCount.addAndGet(1);
System.err.println("Fail (" + o.getMessage() + ")");
semaphore.release();
return null;
}
});
}
db.runAsync(tr -> {
attemptCount.addAndGet(1);
final String key = "test:" + random.nextInt();
return tr.get($(key)).thenComposeAsync(ignore -> {
tr.set($(key), $("value"));
return tr.get($(key)).thenRunAsync(() -> {
getCompleteCount.addAndGet(1);
semaphore.release();
}, FDB.DEFAULT_EXECUTOR);
}, FDB.DEFAULT_EXECUTOR).exceptionally(t -> {
errorCount.addAndGet(1);
System.err.println("Fail (" + t.getMessage() + ")");
semaphore.release();
return null;
});
});
}
semaphore.acquire(CONCURRENCY);
long diff = System.currentTimeMillis() - start;
System.out.println("time taken (ms): " + diff);
System.out.println("tr/sec:" + COUNT * 1000l / diff);
System.out.println("tr/sec:" + COUNT * 1000L / diff);
System.out.println("attempts: " + attemptCount.get());
System.out.println("gets complete: " + getCompleteCount.get());
System.out.println("errors: " + errorCount.get());
System.out.println();
// Can be enabled in Database.java
//System.out.println("db success: " + d.commitSuccessCount.get());
//System.out.println("db errors: " + d.commitErrorCount.get());
//System.out.println("db success: " + db.commitSuccessCount.get());
//System.out.println("db errors: " + db.commitErrorCount.get());
System.exit(0);
} catch (Throwable throwable) {
throwable.printStackTrace();
} catch (Throwable t) {
t.printStackTrace();
System.exit(1);
}
}

View File

@ -20,6 +20,7 @@
package com.apple.foundationdb.test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@ -29,6 +30,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.CompletableFuture;
import com.apple.foundationdb.Database;
import com.apple.foundationdb.FDB;
import com.apple.foundationdb.FDBException;
import com.apple.foundationdb.KeySelector;
import com.apple.foundationdb.Range;
@ -47,8 +49,8 @@ abstract class Context implements Runnable, AutoCloseable {
private String trName;
private List<Thread> children = new LinkedList<>();
static private Map<String, Transaction> transactionMap = new HashMap<>();
static private Map<Transaction, AtomicInteger> transactionRefCounts = new HashMap<>();
private static Map<String, Transaction> transactionMap = new HashMap<>();
private static Map<Transaction, AtomicInteger> transactionRefCounts = new HashMap<>();
Context(Database db, byte[] prefix) {
this.db = db;
@ -171,8 +173,7 @@ abstract class Context implements Runnable, AutoCloseable {
while(num-- > 0) {
Object item = stack.pop().value;
if(item instanceof CompletableFuture) {
@SuppressWarnings("unchecked")
final CompletableFuture<Object> future = (CompletableFuture<Object>)item;
final CompletableFuture<?> future = (CompletableFuture<?>)item;
final int nextNum = num;
future.whenCompleteAsync((o, t) -> {
if(t != null) {
@ -193,7 +194,7 @@ abstract class Context implements Runnable, AutoCloseable {
popParams(nextNum, params, done);
}
});
}, FDB.DEFAULT_EXECUTOR);
return;
}
@ -205,11 +206,11 @@ abstract class Context implements Runnable, AutoCloseable {
}
CompletableFuture<List<Object>> popParams(int num) {
final List<Object> params = new LinkedList<>();
final List<Object> params = new ArrayList<>(num);
CompletableFuture<Void> done = new CompletableFuture<>();
popParams(num, params, done);
return done.thenApplyAsync((x) -> params);
return done.thenApply(x -> params);
}
@Override

View File

@ -25,54 +25,59 @@ import java.util.Collections;
import java.util.List;
import java.util.Random;
public class ContinuousSample <T extends Number & Comparable<T>> {
public ContinuousSample( int sampleSize ) {
public class ContinuousSample<T extends Number & Comparable<T>> {
public ContinuousSample(int sampleSize) {
this.sampleSize = sampleSize;
this.samples = new ArrayList<T>(sampleSize);
this.samples = new ArrayList<>(sampleSize);
this.populationSize = 0;
this.sorted = true;
}
public ContinuousSample<T> addSample(T sample) {
if(populationSize == 0)
_min = _max = sample;
min = max = sample;
populationSize++;
sorted = false;
if( populationSize <= sampleSize ) {
samples.add( sample );
} else if( random.nextDouble() < ( (double)sampleSize / populationSize ) ) {
if(populationSize <= sampleSize) {
samples.add(sample);
} else if(random.nextDouble() < ((double)sampleSize / populationSize)) {
samples.add(random.nextInt(sampleSize), sample);
}
_max = sample.compareTo(_max) > 0 ? sample : _max;
_min = sample.compareTo(_min) < 0 ? sample : _min;
max = sample.compareTo(max) > 0 ? sample : max;
min = sample.compareTo(min) < 0 ? sample : min;
return this;
}
public double mean() {
if (samples.size() == 0) return 0;
double sum = 0;
for( int c = 0; c < samples.size(); c++ ) {
for(int c = 0; c < samples.size(); c++) {
sum += samples.get(c).doubleValue();
}
return sum / samples.size();
}
public T median() {
return percentile( 0.5 );
return percentile(0.5);
}
public T percentile( double percentile ) {
if( samples.size() == 0 || percentile < 0.0 || percentile > 1.0 )
public T percentile(double percentile) {
if(samples.size() == 0 || percentile < 0.0 || percentile > 1.0)
return null;
sort();
int idx = (int)Math.floor( ( samples.size() - 1 ) * percentile );
int idx = (int)Math.floor((samples.size() - 1) * percentile);
return samples.get(idx);
}
public T min() { return _min; }
public T max() { return _max; }
public T min() {
return min;
}
public T max() {
return max;
}
@Override
public String toString() {
@ -85,10 +90,10 @@ public class ContinuousSample <T extends Number & Comparable<T>> {
private long populationSize;
private boolean sorted;
private List<T> samples;
private T _min, _max;
private T min, max;
private void sort() {
if( !sorted && samples.size() > 1 )
if(!sorted && samples.size() > 1)
Collections.sort(samples);
sorted = true;
}

View File

@ -38,7 +38,7 @@ class DirectoryExtension {
int dirIndex = 0;
int errorIndex = 0;
public DirectoryExtension() {
DirectoryExtension() {
dirList.add(DirectoryLayer.getDefault());
}

View File

@ -24,12 +24,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import com.apple.foundationdb.Cluster;
import com.apple.foundationdb.Database;
import com.apple.foundationdb.FDB;
import com.apple.foundationdb.Transaction;
import com.apple.foundationdb.TransactionContext;
import com.apple.foundationdb.directory.DirectoryLayer;
import com.apple.foundationdb.directory.DirectorySubspace;
@ -52,33 +49,30 @@ public class DirectoryTest {
final DirectoryLayer dir = new DirectoryLayer();
try {
db.run(new Function<Transaction, Void>() {
@Override
public Void apply(Transaction tr) {
List<String> path = new ArrayList<>();
path.add("foo");
DirectorySubspace foo = dir.create(tr, path).join();//, "partition".getBytes("UTF-8")).get();
System.out.println(foo.getPath());
path.add("bar");
DirectorySubspace bar = dir.create(tr, path).join();//, "partition".getBytes("UTF-8")).get();
System.out.println(foo.getPath());
path.add("baz");
DirectorySubspace baz = dir.create(tr, path).join();
System.out.println(foo.getPath());
System.out.println("Created foo: " + foo.exists(tr).join());
System.out.println("Created bar: " + bar.exists(tr).join());
System.out.println("Created baz: " + baz.exists(tr).join());
db.run(tr -> {
List<String> path = new ArrayList<>();
path.add("foo");
DirectorySubspace foo = dir.create(tr, path).join(); //, "partition".getBytes("UTF-8")).get();
System.out.println(foo.getPath());
path.add("bar");
DirectorySubspace bar = dir.create(tr, path).join(); //, "partition".getBytes("UTF-8")).get();
System.out.println(foo.getPath());
path.add("baz");
DirectorySubspace baz = dir.create(tr, path).join();
System.out.println(foo.getPath());
System.out.println("Created foo: " + foo.exists(tr).join());
System.out.println("Created bar: " + bar.exists(tr).join());
System.out.println("Created baz: " + baz.exists(tr).join());
DirectorySubspace bat = baz.moveTo(tr, Arrays.asList("foo", "bar", "bat")).join();
DirectorySubspace bat = baz.moveTo(tr, Arrays.asList("foo", "bar", "bat")).join();
System.out.println("Moved baz to bat: " + bat.exists(tr).join());
System.out.println("Moved baz to bat: " + bat.exists(tr).join());
foo.removeIfExists(tr).join();
foo.removeIfExists(tr).join();
System.out.println("Removed foo: " + foo.exists(tr).join());
System.out.println("Removed foo: " + foo.exists(tr).join());
return null;
}
return null;
});
} catch (Throwable e) {
e.printStackTrace();
@ -86,4 +80,6 @@ public class DirectoryTest {
System.exit(0);
}
private DirectoryTest() {}
}

View File

@ -23,9 +23,8 @@ package com.apple.foundationdb.test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.function.Supplier;
import com.apple.foundationdb.FDB;
import com.apple.foundationdb.async.AsyncUtil;
import com.apple.foundationdb.tuple.Tuple;
@ -41,34 +40,18 @@ class DirectoryUtil {
}
CompletableFuture<List<Tuple>> pop() {
return AsyncUtil.whileTrue(new Supplier<CompletableFuture<Boolean>>() {
@Override
public CompletableFuture<Boolean> get() {
if(num-- == 0) {
return CompletableFuture.completedFuture(false);
}
return inst.popParam()
.thenComposeAsync(new Function<Object, CompletableFuture<List<Object>>>() {
@Override
public CompletableFuture<List<Object>> apply(Object count) {
return inst.popParams(StackUtils.getInt(count));
}
})
.thenApplyAsync(new Function<List<Object>, Boolean>() {
@Override
public Boolean apply(List<Object> elements) {
return AsyncUtil.whileTrue(() -> {
if(num-- == 0) {
return AsyncUtil.READY_FALSE;
}
return inst.popParam()
.thenComposeAsync(count -> inst.popParams(StackUtils.getInt(count)), FDB.DEFAULT_EXECUTOR)
.thenApplyAsync(elements -> {
tuples.add(Tuple.fromItems(elements));
return num > 0;
}
});
}
}, FDB.DEFAULT_EXECUTOR);
})
.thenApplyAsync(new Function<Void, List<Tuple>>() {
@Override
public List<Tuple> apply(Void ignore) {
return tuples;
}
});
.thenApply(ignore -> tuples);
}
}
@ -77,42 +60,26 @@ class DirectoryUtil {
}
static CompletableFuture<Tuple> popTuple(Instruction inst) {
return popTuples(inst, 1)
.thenApplyAsync(new Function<List<Tuple>, Tuple>() {
@Override
public Tuple apply(List<Tuple> tuples) {
return tuples.get(0);
}
});
return popTuples(inst, 1).thenApply(tuples -> tuples.get(0));
}
static CompletableFuture<List<List<String>>> popPaths(Instruction inst, int num) {
return popTuples(inst, num)
.thenApplyAsync(new Function<List<Tuple>, List<List<String>>>() {
@Override
public List<List<String>> apply(List<Tuple> tuples) {
List<List<String>> paths = new ArrayList<List<String>>();
for(Tuple t : tuples) {
List<String> path = new ArrayList<String>();
for(int i = 0; i < t.size(); ++i)
path.add(t.getString(i));
return popTuples(inst, num).thenApplyAsync(tuples -> {
List<List<String>> paths = new ArrayList<>(tuples.size());
for(Tuple t : tuples) {
List<String> path = new ArrayList<>(t.size());
for(int i = 0; i < t.size(); ++i)
path.add(t.getString(i));
paths.add(path);
}
return paths;
paths.add(path);
}
});
return paths;
}, FDB.DEFAULT_EXECUTOR);
}
static CompletableFuture<List<String>> popPath(Instruction inst) {
return popPaths(inst, 1)
.thenApplyAsync(new Function<List<List<String>>, List<String>>() {
@Override
public List<String> apply(List<List<String>> paths) {
return paths.get(0);
}
});
return popPaths(inst, 1).thenApply(paths -> paths.get(0));
}
static void pushError(Instruction inst, Throwable t, List<Object> dirList) {
@ -123,4 +90,6 @@ class DirectoryUtil {
if(op.createsDirectory)
dirList.add(null);
}
private DirectoryUtil() {}
}

View File

@ -29,27 +29,23 @@ import com.apple.foundationdb.Transaction;
import com.apple.foundationdb.tuple.Tuple;
public class Example {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FDB fdb = FDB.selectAPIVersion(510);
Database db = fdb.open();
public static void main(String[] args) throws ExecutionException, InterruptedException {
FDB fdb = FDB.selectAPIVersion(510);
Database db = fdb.open();
// Run an operation on the database
db.run(new Function<Transaction, Void>() {
@Override
public Void apply(Transaction tr) {
tr.set(Tuple.from("hello").pack(), Tuple.from("world").pack());
return null;
}
});
// Run an operation on the database
db.run((Function<Transaction, Void>) tr -> {
tr.set(Tuple.from("hello").pack(), Tuple.from("world").pack());
return null;
});
// Get the value of 'hello' from the database
String hello = db.run(new Function<Transaction, String>() {
@Override
public String apply(Transaction tr) {
byte[] result = tr.get(Tuple.from("hello").pack()).join();
return Tuple.fromBytes(result).getString(0);
}
});
System.out.println("Hello " + hello);
}
// Get the value of 'hello' from the database
String hello = db.run(tr -> {
byte[] result = tr.get(Tuple.from("hello").pack()).join();
return Tuple.fromBytes(result).getString(0);
});
System.out.println("Hello " + hello);
}
private Example() {}
}

View File

@ -21,6 +21,7 @@
package com.apple.foundationdb.test;
import java.util.concurrent.CompletableFuture;
import java.util.List;
import com.apple.foundationdb.ReadTransaction;
import com.apple.foundationdb.ReadTransactionContext;
@ -28,11 +29,10 @@ import com.apple.foundationdb.Transaction;
import com.apple.foundationdb.TransactionContext;
import com.apple.foundationdb.tuple.Tuple;
import java.util.List;
class Instruction extends Stack {
private final static String SUFFIX_SNAPSHOT = "_SNAPSHOT";
private final static String SUFFIX_DATABASE = "_DATABASE";
private static final String SUFFIX_SNAPSHOT = "_SNAPSHOT";
private static final String SUFFIX_DATABASE = "_DATABASE";
final String op;
final Tuple tokens;
@ -44,7 +44,7 @@ class Instruction extends Stack {
final TransactionContext tcx;
final ReadTransactionContext readTcx;
public Instruction(Context context, Tuple tokens) {
Instruction(Context context, Tuple tokens) {
this.context = context;
this.tokens = tokens;

View File

@ -21,13 +21,11 @@
package com.apple.foundationdb.test;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import com.apple.foundationdb.Cluster;
import com.apple.foundationdb.Database;
import com.apple.foundationdb.FDB;
import com.apple.foundationdb.KeyValue;
import com.apple.foundationdb.Transaction;
import com.apple.foundationdb.TransactionContext;
public class IterableTest {
@ -49,14 +47,11 @@ public class IterableTest {
long start = System.currentTimeMillis();
final AtomicInteger lastcount = new AtomicInteger(0);
try {
db.run(new Function<Transaction, Void>() {
@Override
public Void apply(Transaction tr) {
for(KeyValue e : tr.getRange("vcount".getBytes(), "zz".getBytes())) {
System.out.println("K: " + new String(e.getKey()) + ", V: " + new String(e.getValue()));
}
return null;
db.run(tr -> {
for(KeyValue e : tr.getRange("vcount".getBytes(), "zz".getBytes())) {
System.out.println("K: " + new String(e.getKey()) + ", V: " + new String(e.getValue()));
}
return null;
});
} catch (Throwable e) {
e.printStackTrace();
@ -71,4 +66,6 @@ public class IterableTest {
System.exit(0);
}
private IterableTest() {}
}

View File

@ -36,18 +36,17 @@ public class LocalityTests {
public static void main(String[] args) {
FDB fdb = FDB.selectAPIVersion(510);
Database database = fdb.open(args[0]);
{
Transaction tr = database.createTransaction();
String[] keyAddresses = LocalityUtil.getAddressesForKey(tr, "a".getBytes()).join();
for(String s : keyAddresses) {
System.out.println(" @ " + s);
}
Transaction tr = database.createTransaction();
String[] keyAddresses = LocalityUtil.getAddressesForKey(tr, "a".getBytes()).join();
for(String s : keyAddresses) {
System.out.println(" @ " + s);
}
long start = System.currentTimeMillis();
CloseableAsyncIterator<byte[]> keys = LocalityUtil.getBoundaryKeys(database, new byte[0], new byte[] { (byte)255 } );
CompletableFuture<List<byte[]>> collection = AsyncUtil.collect(keys);
CloseableAsyncIterator<byte[]> keys = LocalityUtil.getBoundaryKeys(database, new byte[0], new byte[] { (byte)255 });
CompletableFuture<List<byte[]>> collection = AsyncUtil.collectRemaining(keys);
List<byte[]> list = collection.join();
System.out.println("Took " + (System.currentTimeMillis() - start) + "ms to get " +
list.size() + " items");
@ -59,4 +58,6 @@ public class LocalityTests {
System.out.println(i++ + ": " + ByteArrayUtil.printable(key));
}
}
private LocalityTests() {}
}

View File

@ -25,8 +25,6 @@ import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Function;
import com.apple.foundationdb.Database;
import com.apple.foundationdb.FDB;
@ -92,34 +90,26 @@ public class ParallelRandomScan {
final long launch = System.nanoTime();
final AsyncIterator<KeyValue> it = range.iterator();
final CompletableFuture<KeyValue> f = it.onHasNext().thenApplyAsync(
new Function<Boolean, KeyValue>() {
@Override
public KeyValue apply(Boolean o) {
if(!o) {
return null;
}
return it.next();
}
}
);
f.whenCompleteAsync(new BiConsumer<KeyValue, Throwable>() {
@Override
public void accept(KeyValue kv, Throwable t) {
if(kv != null) {
readsCompleted.incrementAndGet();
long timeTaken = System.nanoTime() - launch;
synchronized(latencies) {
latencies.addSample(timeTaken);
}
}
else if(t != null) {
errors.incrementAndGet();
}
coordinator.release();
final CompletableFuture<KeyValue> f = it.onHasNext().thenApplyAsync(hasFirst -> {
if(!hasFirst) {
return null;
}
});
return it.next();
}, FDB.DEFAULT_EXECUTOR);
f.whenCompleteAsync((kv, t) -> {
if(kv != null) {
readsCompleted.incrementAndGet();
long timeTaken = System.nanoTime() - launch;
synchronized(latencies) {
latencies.addSample(timeTaken);
}
}
else if(t != null) {
errors.incrementAndGet();
}
coordinator.release();
}, FDB.DEFAULT_EXECUTOR);
}
// Block for ALL tasks to end!
@ -133,4 +123,6 @@ public class ParallelRandomScan {
System.out.println(String.format(" Mean: %.2f, Median: %d, 98%%: %d",
latencies.mean(), latencies.median(), latencies.percentile(0.98)));
}
private ParallelRandomScan() {}
}

View File

@ -20,13 +20,6 @@
package com.apple.foundationdb.test;
import com.apple.foundationdb.Database;
import com.apple.foundationdb.KeySelector;
import com.apple.foundationdb.Transaction;
import com.apple.foundationdb.TransactionContext;
import com.apple.foundationdb.async.AsyncUtil;
import com.apple.foundationdb.tuple.ByteArrayUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -40,6 +33,13 @@ import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import com.apple.foundationdb.Database;
import com.apple.foundationdb.KeySelector;
import com.apple.foundationdb.Transaction;
import com.apple.foundationdb.TransactionContext;
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;

View File

@ -20,14 +20,17 @@
package com.apple.foundationdb.test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.apple.foundationdb.Database;
import com.apple.foundationdb.Transaction;
import com.apple.foundationdb.tuple.ByteArrayUtil;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class RYWBenchmark extends AbstractTester {
private int keyCount;
@ -156,7 +159,7 @@ public class RYWBenchmark extends AbstractTester {
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();
tr.getRange(key(0), key(keyCount)).asList().join();
}
long end = System.nanoTime();

View File

@ -55,22 +55,19 @@ public class RangeTest {
Database db = fdb.open();
try {
db.run(new Function<Transaction, Void>() {
@Override
public Void apply(Transaction tr) {
long version = tr.getReadVersion().join();
System.out.println("DB version: " + version);
tr.get("apple1".getBytes()).join();
tr.set("apple1".getBytes(), "crunchy1".getBytes());
tr.set("apple2".getBytes(), "crunchy2".getBytes());
tr.set("apple3".getBytes(), "crunchy3".getBytes());
tr.set("apple4".getBytes(), "crunchy4".getBytes());
tr.set("apple5".getBytes(), "crunchy5".getBytes());
tr.set("apple6".getBytes(), "crunchy6".getBytes());
System.out.println("Attempting to commit apple/crunchy pairs...");
db.run((Function<Transaction, Void>) tr -> {
long version = tr.getReadVersion().join();
System.out.println("DB version: " + version);
tr.get("apple1".getBytes()).join();
tr.set("apple1".getBytes(), "crunchy1".getBytes());
tr.set("apple2".getBytes(), "crunchy2".getBytes());
tr.set("apple3".getBytes(), "crunchy3".getBytes());
tr.set("apple4".getBytes(), "crunchy4".getBytes());
tr.set("apple5".getBytes(), "crunchy5".getBytes());
tr.set("apple6".getBytes(), "crunchy6".getBytes());
System.out.println("Attempting to commit apple/crunchy pairs...");
return null;
}
return null;
});
} catch (Throwable e){
e.printStackTrace();
@ -167,7 +164,7 @@ public class RangeTest {
System.out.println("Value is " +
(val != null ? new String(val) : "not present"));
AsyncIterable<KeyValue> entryList = tr.getRange(
AsyncIterable<KeyValue> entryList = tr.getRange(
KeySelector.firstGreaterOrEqual("apple".getBytes()),
KeySelector.firstGreaterOrEqual("banana".getBytes()),4);
List<KeyValue> entries = entryList.asList().join();
@ -187,4 +184,6 @@ public class RangeTest {
}
}
private RangeTest() {}
}

View File

@ -94,4 +94,5 @@ public class SerialInsertion {
}
}
private SerialInsertion() {}
}

View File

@ -133,4 +133,6 @@ public class SerialIteration {
}
return counter;
}
private SerialIteration() {}
}

View File

@ -21,12 +21,10 @@
package com.apple.foundationdb.test;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import com.apple.foundationdb.Cluster;
import com.apple.foundationdb.Database;
import com.apple.foundationdb.FDB;
import com.apple.foundationdb.Transaction;
import com.apple.foundationdb.TransactionContext;
public class SerialTest {
@ -56,17 +54,14 @@ public class SerialTest {
final AtomicInteger lastcount = new AtomicInteger(0);
for(int i = 0; i < reps; i++) {
try {
db.run(new Function<Transaction, Void>() {
@Override
public Void apply(Transaction tr) {
byte[] val = tr.get("count".getBytes()).join();
//System.out.println("Got value");
int count = Integer.parseInt(new String(val));
tr.set("count".getBytes(), Integer.toString(count + 1).getBytes());
lastcount.set(count);
db.run(tr -> {
byte[] val = tr.get("count".getBytes()).join();
//System.out.println("Got value");
int count = Integer.parseInt(new String(val));
tr.set("count".getBytes(), Integer.toString(count + 1).getBytes());
lastcount.set(count);
return null;
}
return null;
});
} catch (Throwable e) {
e.printStackTrace();
@ -83,4 +78,5 @@ public class SerialTest {
System.exit(0);
}
private SerialTest() {}
}

View File

@ -23,7 +23,7 @@ package com.apple.foundationdb.test;
class StackEntry {
int idx;
Object value;
public StackEntry(int idx, Object value) {
StackEntry(int idx, Object value) {
this.idx = idx;
this.value = value;
}

View File

@ -21,10 +21,15 @@
package com.apple.foundationdb.test;
import java.math.BigInteger;
import java.util.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.function.Function;
@ -110,7 +115,7 @@ public class StackTester {
}
else if(op == StackOperation.WAIT_EMPTY) {
List<Object> params = inst.popParams(1).join();
inst.context.db.run(new WaitEmpty((byte [])params.get(0)));
inst.context.db.run(new WaitEmpty((byte[])params.get(0)));
inst.push("WAITED_FOR_EMPTY".getBytes());
}
else if(op == StackOperation.START_THREAD) {
@ -129,62 +134,40 @@ public class StackTester {
final List<Object> params = inst.popParams(2).join();
//System.out.println(inst.context.preStr + " - " + "Setting '" + ArrayUtils.printable((byte[]) params.get(0)) +
// "' to '" + ArrayUtils.printable((byte[]) params.get(1)) + "'");
executeMutation(inst,
new Function<Transaction, Void>() {
@Override
public Void apply(Transaction tr) {
tr.set((byte[])params.get(0), (byte[])params.get(1));
return null;
}
});
executeMutation(inst, tr -> {
tr.set((byte[])params.get(0), (byte[])params.get(1));
return null;
});
}
else if(op == StackOperation.CLEAR) {
final List<Object> params = inst.popParams(1).join();
//System.out.println(inst.context.preStr + " - " + "Clearing: '" + ByteArrayUtil.printable((byte[]) params.get(0)) + "'");
executeMutation(inst,
new Function<Transaction, Void>() {
@Override
public Void apply(Transaction tr) {
tr.clear((byte[])params.get(0));
return null;
}
}
);
executeMutation(inst, tr -> {
tr.clear((byte[])params.get(0));
return null;
});
}
else if(op == StackOperation.CLEAR_RANGE) {
final List<Object> params = inst.popParams(2).join();
executeMutation(inst,
new Function<Transaction, Void>() {
@Override
public Void apply(Transaction tr) {
tr.clear((byte[])params.get(0), (byte[])params.get(1));
return null;
}
});
executeMutation(inst, tr -> {
tr.clear((byte[])params.get(0), (byte[])params.get(1));
return null;
});
}
else if(op == StackOperation.CLEAR_RANGE_STARTS_WITH) {
final List<Object> params = inst.popParams(1).join();
executeMutation(inst,
new Function<Transaction, Void>() {
@Override
public Void apply(Transaction tr) {
tr.clear(Range.startsWith((byte[])params.get(0)));
return null;
}
});
executeMutation(inst, tr -> {
tr.clear(Range.startsWith((byte[])params.get(0)));
return null;
});
}
else if(op == StackOperation.ATOMIC_OP) {
final List<Object> params = inst.popParams(3).join();
final MutationType optype = MutationType.valueOf((String)params.get(0));
executeMutation(inst,
new Function<Transaction, Void>() {
@Override
public Void apply(Transaction tr) {
tr.mutate(optype, (byte[])params.get(1), (byte[])params.get(2));
return null;
}
}
);
executeMutation(inst, tr -> {
tr.mutate(optype, (byte[])params.get(1), (byte[])params.get(2));
return null;
});
}
else if(op == StackOperation.COMMIT) {
inst.push(inst.tr.commit());
@ -678,7 +661,7 @@ public class StackTester {
CloseableAsyncIterator<byte[]> boundaryKeys = LocalityUtil.getBoundaryKeys(
tr, new byte[0], new byte[]{(byte) 255, (byte) 255});
try {
List<byte[]> keys = AsyncUtil.collect(boundaryKeys).join();
List<byte[]> keys = AsyncUtil.collectRemaining(boundaryKeys).join();
for(int i = 0; i < keys.size() - 1; i++) {
byte[] start = keys.get(i);
byte[] end = tr.getKey(KeySelector.lastLessThan(keys.get(i + 1))).join();
@ -723,5 +706,7 @@ public class StackTester {
db.close();
System.gc();
}
private StackTester() {}
}

View File

@ -27,7 +27,6 @@ import java.util.concurrent.CompletionException;
import com.apple.foundationdb.FDBException;
import com.apple.foundationdb.KeySelector;
import com.apple.foundationdb.async.AsyncUtil;
import com.apple.foundationdb.tuple.Tuple;
public class StackUtils {
@ -127,4 +126,6 @@ public class StackUtils {
return (t instanceof FDBException) ? (FDBException)t : null;
}
private StackUtils() {}
}

View File

@ -20,13 +20,12 @@
package com.apple.foundationdb.test;
import java.util.ArrayList;
import java.util.List;
import com.apple.foundationdb.subspace.Subspace;
import com.apple.foundationdb.tuple.Tuple;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TesterArgs {
private String outputDirectory;
private boolean multiversionApi;
@ -45,15 +44,15 @@ public class TesterArgs {
}
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";
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);
}

View File

@ -20,12 +20,9 @@
package com.apple.foundationdb.test;
import java.util.function.Function;
import com.apple.foundationdb.Cluster;
import com.apple.foundationdb.Database;
import com.apple.foundationdb.FDB;
import com.apple.foundationdb.Transaction;
import com.apple.foundationdb.TransactionContext;
import com.apple.foundationdb.tuple.Tuple;
@ -47,19 +44,16 @@ public class TupleTest {
System.out.println("Running tests...");
long start = System.currentTimeMillis();
try {
db.run(new Function<Transaction, Void>() {
@Override
public Void apply(Transaction tr) {
Tuple t = new Tuple();
t.add(100230045000L);
t.add("Hello!");
t.add("foo".getBytes());
db.run(tr -> {
Tuple t = new Tuple();
t.add(100230045000L);
t.add("Hello!");
t.add("foo".getBytes());
/*for(Map.Entry<byte[], byte[]> e : tr.getRange("vcount".getBytes(), "zz".getBytes())) {
System.out.println("K: " + new String(e.getKey()) + ", V: " + new String(e.getValue()));
}*/
return null;
}
/*for(Map.Entry<byte[], byte[]> e : tr.getRange("vcount".getBytes(), "zz".getBytes())) {
System.out.println("K: " + new String(e.getKey()) + ", V: " + new String(e.getValue()));
}*/
return null;
});
} catch (Throwable e) {
e.printStackTrace();
@ -73,4 +67,6 @@ public class TupleTest {
System.exit(0);
}
private TupleTest() {}
}

View File

@ -20,6 +20,8 @@
package com.apple.foundationdb.test;
import java.util.concurrent.CompletableFuture;
import com.apple.foundationdb.Database;
import com.apple.foundationdb.FDB;
import com.apple.foundationdb.MutationType;
@ -28,36 +30,36 @@ import com.apple.foundationdb.subspace.Subspace;
import com.apple.foundationdb.tuple.Tuple;
import com.apple.foundationdb.tuple.Versionstamp;
import java.util.concurrent.CompletableFuture;
public class VersionstampSmokeTest {
public static void main(String[] args) {
FDB fdb = FDB.selectAPIVersion(510);
Database db = fdb.open();
db.run(tr -> {
tr.clear(Tuple.from("prefix").range());
return null;
tr.clear(Tuple.from("prefix").range());
return null;
});
CompletableFuture<byte[]> trVersionFuture = db.run((Transaction tr) -> {
// The incomplete Versionstamp will have tr's version information when committed.
Tuple t = Tuple.from("prefix", Versionstamp.incomplete());
tr.mutate(MutationType.SET_VERSIONSTAMPED_KEY, t.packWithVersionstamp(), new byte[0]);
return tr.getVersionstamp();
// The incomplete Versionstamp will have tr's version information when committed.
Tuple t = Tuple.from("prefix", Versionstamp.incomplete());
tr.mutate(MutationType.SET_VERSIONSTAMPED_KEY, t.packWithVersionstamp(), new byte[0]);
return tr.getVersionstamp();
});
byte[] trVersion = trVersionFuture.join();
Versionstamp v = db.run((Transaction tr) -> {
Subspace subspace = new Subspace(Tuple.from("prefix"));
byte[] serialized = tr.getRange(subspace.range(), 1).iterator().next().getKey();
Tuple t = subspace.unpack(serialized);
return t.getVersionstamp(0);
Subspace subspace = new Subspace(Tuple.from("prefix"));
byte[] serialized = tr.getRange(subspace.range(), 1).iterator().next().getKey();
Tuple t = subspace.unpack(serialized);
return t.getVersionstamp(0);
});
System.out.println(v);
System.out.println(Versionstamp.complete(trVersion));
assert v.equals(Versionstamp.complete(trVersion));
}
private VersionstampSmokeTest() {}
}

View File

@ -75,20 +75,17 @@ public class WatchTest {
a.incrementAndGet();
}
};
Runnable get = new Runnable() {
@Override
public void run() {
try {
System.err.println("`f' get()...");
f.join();
System.err.println("`f' changed");
} catch(FDBException e) {
System.err.println("`f' watch error -> " + e.getMessage());
if(e.getCode() != 1101)
throw e;
} finally {
a.incrementAndGet();
}
Runnable get = () -> {
try {
System.err.println("`f' get()...");
f.join();
System.err.println("`f' changed");
} catch(FDBException e12) {
System.err.println("`f' watch error -> " + e12.getMessage());
if(e12.getCode() != 1101)
throw e12;
} finally {
a.incrementAndGet();
}
};
if(r.nextBoolean()) {
@ -109,8 +106,10 @@ public class WatchTest {
}
//if(i % 1000 == 0) {
System.out.println("Done with " + i);
System.out.println("Done with " + i);
//}
}
}
private WatchTest() {}
}

View File

@ -20,10 +20,11 @@
package com.apple.foundationdb.test;
import com.apple.foundationdb.async.AsyncUtil;
import java.util.concurrent.CompletableFuture;
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.
@ -32,4 +33,6 @@ public class WhileTrueTest {
AsyncUtil.whileTrue(() -> CompletableFuture.completedFuture(count.decrementAndGet()).thenApplyAsync(c -> c > 0)).join();
System.out.println("Final value: " + count.get());
}
private WhileTrueTest() {}
}

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suppressions PUBLIC
"-//Puppy Crawl//DTD Suppressions 1.1//EN"
"http://checkstyle.sourceforge.net/dtds/suppressions_1_1.dtd">
<suppressions>
<!-- These files are auto generated. Ignore those files for style checks. -->
<suppress files=".+Options\.java" checks=".*"/>
<suppress files=".+ConflictRangeType\.java" checks=".*"/>
<suppress files=".+FDBException\.java" checks=".*"/>
<suppress files=".+MutationType\.java" checks=".*"/>
<suppress files=".+StreamingMode\.java" checks=".*"/>
</suppressions>