added a style guide ; fixed errors found from the style guide ; updated tests to use java 8 closures

This commit is contained in:
Alec Grieser 2017-12-13 16:16:31 -08:00
parent 4d734a4925
commit 33f8b2f7cf
54 changed files with 1218 additions and 1221 deletions

View File

@ -0,0 +1,148 @@
<!--
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.
-->
<?xml version="1.0" encoding="UTF-8"?>
<!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"/>
<!-- I think we want this, just maybe not right now.
<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

@ -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 {
@ -116,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
@ -135,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(
@ -398,7 +400,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

@ -77,17 +77,17 @@ class FDBDatabase extends NativeObjectWrapper implements Database, OptionConsume
trRef.get().commit().thenApply(o -> {
returnValue.set(returnVal);
return false;
})
, 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),
(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());

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 {
@ -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();

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

@ -209,8 +209,8 @@ public class LocalityUtil {
@Override
public void remove() {
throw new UnsupportedOperationException("Boundary keys are read-only");
}
throw new UnsupportedOperationException("Boundary keys are read-only");
}
@Override
public void close() {
@ -232,7 +232,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

@ -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,7 +25,7 @@ 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) {
@ -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

@ -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;

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;
/**

View File

@ -51,7 +51,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, ? extends 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) {
@ -61,18 +61,74 @@ 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 forEach(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 forEach(iterable.iterator(), consumer, executor);
}
/**
* Run the {@code consumer} on each element of 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> forEach(final AsyncIterator<V> iterator, final Consumer<? super V> consumer) {
return forEach(iterator, consumer, DEFAULT_EXECUTOR);
}
/**
* Run the {@code consumer} on each element of 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> forEach(final AsyncIterator<V> iterator, final Consumer<? super V> consumer, final Executor executor) {
return iterator.onHasNext().thenComposeAsync(hasAny -> {
if (hasAny) {
@ -387,16 +443,65 @@ public class AsyncUtil {
});
}
public static <V, T> CompletableFuture<T> composeHandle(CompletableFuture<V> future, BiFunction<V,Throwable,? extends CompletableFuture<T>> fn) {
return future.handle(fn).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).
*
* @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());
}
public static <V, T> CompletableFuture<T> composeHandleAsync(CompletableFuture<V> future, BiFunction<V,Throwable,? extends CompletableFuture<T>> fn) {
return composeHandleAsync(future, fn, 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 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);
}
public static <V, T> CompletableFuture<T> composeHandleAsync(CompletableFuture<V> future, BiFunction<V,Throwable,? extends CompletableFuture<T>> fn, Executor executor) {
return future.handleAsync(fn, executor).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 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());
}
/**

View File

@ -66,8 +66,7 @@ import com.apple.foundationdb.tuple.Tuple;
* access to subspaces.
* </p>
*/
public class DirectoryLayer implements Directory
{
public class DirectoryLayer implements Directory {
private static final Charset UTF_8 = Charset.forName("UTF-8");
private static final byte[] LITTLE_ENDIAN_LONG_ONE = { 1, 0, 0, 0, 0, 0, 0, 0 };
private static final byte[] HIGH_CONTENTION_KEY = "hca".getBytes(UTF_8);
@ -181,22 +180,22 @@ public class DirectoryLayer implements Directory
* Creates a new {@code DirectoryLayer} formed with a specified node subspace and default content subspace.
* Prefixes can not be specified in calls to {@link Directory#create(TransactionContext, List, byte[], byte[])}.
*
* @param node_subspace a {@link Subspace} used to store directory metadata
* @return a {@code DirectoryLayer} formed with {@code node_subspace} and a default content subspace
* @param nodeSubspace a {@link Subspace} used to store directory metadata
* @return a {@code DirectoryLayer} formed with {@code nodeSubspace} and a default content subspace
*/
public static Directory createWithNodeSubspace(Subspace node_subspace) {
return new DirectoryLayer(node_subspace, DEFAULT_CONTENT_SUBSPACE);
public static Directory createWithNodeSubspace(Subspace nodeSubspace) {
return new DirectoryLayer(nodeSubspace, DEFAULT_CONTENT_SUBSPACE);
}
/**
* Creates a new {@code DirectoryLayer} formed with a default node subspace and specified content subspace.
* Prefixes can not be specified in calls to {@link Directory#create(TransactionContext, List, byte[], byte[])}.
*
* @param content_subspace a {@link Subspace} used to store directory content
* @return a {@code DirectoryLayer} formed with a {@code content_subspace} and a default node subspace
* @param contentSubspace a {@link Subspace} used to store directory content
* @return a {@code DirectoryLayer} formed with a {@code contentSubspace} and a default node subspace
*/
public static Directory createWithContentSubspace(Subspace content_subspace) {
return new DirectoryLayer(DEFAULT_NODE_SUBSPACE, content_subspace);
public static Directory createWithContentSubspace(Subspace contentSubspace) {
return new DirectoryLayer(DEFAULT_NODE_SUBSPACE, contentSubspace);
}
/**
@ -229,9 +228,9 @@ public class DirectoryLayer implements Directory
}
DirectoryLayer other = (DirectoryLayer)rhs;
return (path == other.path || path.equals(other.path))
&& nodeSubspace.equals(other.nodeSubspace)
&& contentSubspace.equals(other.contentSubspace);
return (path == other.path || path.equals(other.path)) &&
nodeSubspace.equals(other.nodeSubspace) &&
contentSubspace.equals(other.contentSubspace);
}
/**
@ -410,47 +409,46 @@ public class DirectoryLayer implements Directory
final List<String> newPathCopy = new ArrayList<>(newPath);
return tcx.runAsync(tr -> checkOrWriteVersion(tr).thenComposeAsync(ignore -> {
if(oldPathCopy.size() <= newPathCopy.size() && oldPathCopy.equals(newPathCopy.subList(0, oldPathCopy.size())))
throw new DirectoryMoveException("The destination directory cannot be a subdirectory of the source directory.", toAbsolutePath(oldPathCopy), toAbsolutePath(newPathCopy));
if(oldPathCopy.size() <= newPathCopy.size() && oldPathCopy.equals(newPathCopy.subList(0, oldPathCopy.size())))
throw new DirectoryMoveException("The destination directory cannot be a subdirectory of the source directory.", toAbsolutePath(oldPathCopy), toAbsolutePath(newPathCopy));
ArrayList<CompletableFuture<Node>> futures = new ArrayList<>();
futures.add(new NodeFinder(oldPathCopy).find(tr).thenComposeAsync(new NodeMetadataLoader(tr), tr.getExecutor()));
futures.add(new NodeFinder(newPathCopy).find(tr).thenComposeAsync(new NodeMetadataLoader(tr), tr.getExecutor()));
ArrayList<CompletableFuture<Node>> futures = new ArrayList<>();
futures.add(new NodeFinder(oldPathCopy).find(tr).thenComposeAsync(new NodeMetadataLoader(tr), tr.getExecutor()));
futures.add(new NodeFinder(newPathCopy).find(tr).thenComposeAsync(new NodeMetadataLoader(tr), tr.getExecutor()));
return AsyncUtil.getAll(futures);
}, tr.getExecutor())
.thenComposeAsync(nodes -> {
final Node oldNode = nodes.get(0);
final Node newNode = nodes.get(1);
return AsyncUtil.getAll(futures);
}, tr.getExecutor())
.thenComposeAsync(nodes -> {
final Node oldNode = nodes.get(0);
final Node newNode = nodes.get(1);
if(!oldNode.exists())
throw new NoSuchDirectoryException(toAbsolutePath(oldPathCopy));
if(!oldNode.exists())
throw new NoSuchDirectoryException(toAbsolutePath(oldPathCopy));
if(oldNode.isInPartition(false) || newNode.isInPartition(false)) {
if(!oldNode.isInPartition(false) || !newNode.isInPartition(false) || !oldNode.path.equals(newNode.path))
throw new DirectoryMoveException("Cannot move between partitions.", toAbsolutePath(oldPathCopy), toAbsolutePath(newPathCopy));
if(oldNode.isInPartition(false) || newNode.isInPartition(false)) {
if(!oldNode.isInPartition(false) || !newNode.isInPartition(false) || !oldNode.path.equals(newNode.path))
throw new DirectoryMoveException("Cannot move between partitions.", toAbsolutePath(oldPathCopy), toAbsolutePath(newPathCopy));
return newNode.getContents().move(tr, oldNode.getPartitionSubpath(), newNode.getPartitionSubpath());
}
return newNode.getContents().move(tr, oldNode.getPartitionSubpath(), newNode.getPartitionSubpath());
}
if(newNode.exists())
throw new DirectoryAlreadyExistsException(toAbsolutePath(newPathCopy));
if(newNode.exists())
throw new DirectoryAlreadyExistsException(toAbsolutePath(newPathCopy));
final List<String> parentPath = PathUtil.popBack(newPathCopy);
return new NodeFinder(parentPath).find(tr).thenComposeAsync(parentNode -> {
if(!parentNode.exists())
throw new NoSuchDirectoryException(toAbsolutePath(parentPath));
final List<String> parentPath = PathUtil.popBack(newPathCopy);
return new NodeFinder(parentPath).find(tr).thenComposeAsync(parentNode -> {
if(!parentNode.exists())
throw new NoSuchDirectoryException(toAbsolutePath(parentPath));
tr.set(
parentNode.subspace.get(SUB_DIR_KEY).get(getLast(newPathCopy)).getKey(),
contentsOfNode(oldNode.subspace, EMPTY_PATH, EMPTY_BYTES).getKey()
);
tr.set(
parentNode.subspace.get(SUB_DIR_KEY).get(getLast(newPathCopy)).getKey(),
contentsOfNode(oldNode.subspace, EMPTY_PATH, EMPTY_BYTES).getKey()
);
return removeFromParent(tr, oldPathCopy)
return removeFromParent(tr, oldPathCopy)
.thenApply(ignore -> contentsOfNode(oldNode.subspace, newPathCopy, oldNode.layer));
}, tr.getExecutor());
}, tr.getExecutor())
);
}, tr.getExecutor());
}, tr.getExecutor()));
}
/**
@ -528,8 +526,8 @@ public class DirectoryLayer implements Directory
return AsyncUtil.collect(
AsyncUtil.mapIterable(tr.getRange(subdir.range()),
kv -> subdir.unpack(kv.getKey()).getString(0),
tr.getExecutor()
kv -> subdir.unpack(kv.getKey()).getString(0),
tr.getExecutor()
)
);
}, tr.getExecutor())
@ -624,29 +622,28 @@ public class DirectoryLayer implements Directory
final List<String> pathCopy = new ArrayList<>(path);
return tcx.runAsync(tr -> checkOrWriteVersion(tr).thenComposeAsync(ignore -> {
if(pathCopy.size() == 0)
throw new DirectoryException("The root directory cannot be removed.", toAbsolutePath(pathCopy));
if(pathCopy.size() == 0)
throw new DirectoryException("The root directory cannot be removed.", toAbsolutePath(pathCopy));
return new NodeFinder(pathCopy).find(tr).thenComposeAsync(new NodeMetadataLoader(tr), tr.getExecutor());
}, tr.getExecutor())
.thenComposeAsync(node -> {
if(!node.exists()) {
if(mustExist)
throw new NoSuchDirectoryException(toAbsolutePath(pathCopy));
else
return AsyncUtil.READY_FALSE;
}
return new NodeFinder(pathCopy).find(tr).thenComposeAsync(new NodeMetadataLoader(tr), tr.getExecutor());
}, tr.getExecutor())
.thenComposeAsync(node -> {
if(!node.exists()) {
if(mustExist)
throw new NoSuchDirectoryException(toAbsolutePath(pathCopy));
else
return AsyncUtil.READY_FALSE;
}
if(node.isInPartition(false))
return node.getContents().getDirectoryLayer().removeInternal(tr, node.getPartitionSubpath(), mustExist);
else {
ArrayList<CompletableFuture<Void>> futures = new ArrayList<>();
futures.add(removeRecursive(tr, node.subspace));
futures.add(removeFromParent(tr, pathCopy));
return AsyncUtil.tag(AsyncUtil.whenAll(futures), true);
}
}, tr.getExecutor())
);
if(node.isInPartition(false))
return node.getContents().getDirectoryLayer().removeInternal(tr, node.getPartitionSubpath(), mustExist);
else {
ArrayList<CompletableFuture<Void>> futures = new ArrayList<>();
futures.add(removeRecursive(tr, node.subspace));
futures.add(removeFromParent(tr, pathCopy));
return AsyncUtil.tag(AsyncUtil.whenAll(futures), true);
}
}, tr.getExecutor()));
}
private CompletableFuture<Void> removeFromParent(final Transaction tr, final List<String> path) {
@ -706,8 +703,7 @@ public class DirectoryLayer implements Directory
final byte[] layer,
final byte[] prefix,
final boolean allowCreate,
final boolean allowOpen)
{
final boolean allowOpen) {
final List<String> pathCopy = new ArrayList<>(path);
if(prefix != null && !allowManualPrefixes) {
@ -723,35 +719,34 @@ public class DirectoryLayer implements Directory
}
return checkVersion(rtr).thenComposeAsync(ignore -> {
// Root directory contains node metadata and so may not be opened.
if(pathCopy.size() == 0) {
throw new IllegalArgumentException("The root directory may not be opened.");
}
// Root directory contains node metadata and so may not be opened.
if(pathCopy.size() == 0) {
throw new IllegalArgumentException("The root directory may not be opened.");
}
return new NodeFinder(pathCopy).find(rtr).thenComposeAsync(new NodeMetadataLoader(rtr), rtr.getExecutor());
}, rtr.getExecutor())
.thenComposeAsync(existingNode -> {
if(existingNode.exists()) {
if(existingNode.isInPartition(false)) {
List<String> subpath = existingNode.getPartitionSubpath();
DirectoryLayer directoryLayer = existingNode.getContents().getDirectoryLayer();
return directoryLayer.createOrOpenInternal(
rtr, tr, subpath, layer, prefix, allowCreate, allowOpen);
}
return new NodeFinder(pathCopy).find(rtr).thenComposeAsync(new NodeMetadataLoader(rtr), rtr.getExecutor());
}, rtr.getExecutor())
.thenComposeAsync(existingNode -> {
if(existingNode.exists()) {
if(existingNode.isInPartition(false)) {
List<String> subpath = existingNode.getPartitionSubpath();
DirectoryLayer directoryLayer = existingNode.getContents().getDirectoryLayer();
return directoryLayer.createOrOpenInternal(
rtr, tr, subpath, layer, prefix, allowCreate, allowOpen);
}
DirectorySubspace opened = openInternal(pathCopy, layer, existingNode, allowOpen);
return CompletableFuture.completedFuture(opened);
}
else
return createInternal(tr, pathCopy, layer, prefix, allowCreate);
}, rtr.getExecutor());
DirectorySubspace opened = openInternal(pathCopy, layer, existingNode, allowOpen);
return CompletableFuture.completedFuture(opened);
}
else
return createInternal(tr, pathCopy, layer, prefix, allowCreate);
}, rtr.getExecutor());
}
private DirectorySubspace openInternal(final List<String> path,
final byte[] layer,
final Node existingNode,
final boolean allowOpen)
{
final boolean allowOpen) {
if(!allowOpen) {
throw new DirectoryAlreadyExistsException(toAbsolutePath(path));
}
@ -768,8 +763,7 @@ public class DirectoryLayer implements Directory
final List<String> path,
final byte[] layer,
final byte[] prefix,
final boolean allowCreate)
{
final boolean allowCreate) {
if(!allowCreate) {
throw new NoSuchDirectoryException(toAbsolutePath(path));
}
@ -845,7 +839,7 @@ public class DirectoryLayer implements Directory
ByteBuffer versionBuf = ByteBuffer.wrap(versionBytes);
versionBuf.order(ByteOrder.LITTLE_ENDIAN);
Integer version[] = new Integer[3];
Integer[] version = new Integer[3];
for(int i = 0; i < version.length; ++i)
version[i] = versionBuf.getInt();

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

@ -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);
}
}
@ -100,144 +101,83 @@ public class AsyncStackTester {
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 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 AsyncUtil.DONE;
}
});
}
});
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 AsyncUtil.DONE;
}
});
}
});
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 AsyncUtil.DONE;
}
});
}
});
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 AsyncUtil.DONE;
}
});
}
});
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 AsyncUtil.DONE;
}
}
);
}
});
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());
@ -252,43 +192,27 @@ public class AsyncStackTester {
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) {
@ -296,78 +220,57 @@ public class AsyncStackTester {
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 {
@ -397,215 +300,153 @@ public class AsyncStackTester {
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 AsyncUtil.DONE;
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);
}
}
@ -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());
@ -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 AsyncUtil.DONE;
}
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

@ -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;

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,17 +36,16 @@ 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 } );
CloseableAsyncIterator<byte[]> keys = LocalityUtil.getBoundaryKeys(database, new byte[0], new byte[] { (byte)255 });
CompletableFuture<List<byte[]>> collection = AsyncUtil.collect(keys);
List<byte[]> list = collection.join();
System.out.println("Took " + (System.currentTimeMillis() - start) + "ms to get " +
@ -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

@ -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());
@ -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>