Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* LocalityUtil.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;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.Executor;
import java.util.function.BiFunction;
import com.apple.foundationdb.async.AsyncIterable;
import com.apple.foundationdb.async.AsyncIterator;
import com.apple.foundationdb.async.AsyncUtil;
import com.apple.foundationdb.async.CloseableAsyncIterator;
import com.apple.foundationdb.tuple.ByteArrayUtil;
/**
* The FoundationDB API comes with a set of functions for discovering the
* storage locations of keys within your cluster. This information can be useful
* for advanced users who wish to take into account the location of keys in the
* design of applications or processes.
*
*/
public class LocalityUtil {
/**
* Returns a {@code CloseableAsyncIterator} of keys {@code k} such that
* {@code begin <= k < end} and {@code k} is located at the start of a
* contiguous range stored on a single server.
*
* This method is not transactional. The returned boundaries are an estimate
* and may not represent the exact boundary locations at any database version.
*
* @param db the database to query
* @param begin the inclusive start of the range
* @param end the exclusive end of the range
*
* @return an sequence of keys denoting the start of single-server ranges
*/
public static CloseableAsyncIterator getBoundaryKeys(Database db, byte[] begin, byte[] end) {
return getBoundaryKeys_internal(db.createTransaction(), begin, end);
}
/**
* Returns a {@code CloseableAsyncIterator} of keys {@code k} such that
* {@code begin <= k < end} and {@code k} is located at the start of a
* contiguous range stored on a single server.
*
* This method is not transactional. The returned boundaries
* are an estimate and may not represent the exact boundary locations at
* any database version. The passed {@code Transaction} is not used
* for reads directly, instead it is used to get access to associated
* {@link Database}. As a result, options (such as retry limit) set on the
* passed {@code Transaction} will not be applied. If, however, the passed
* {@code Transaction} has already gotten a read version there is some
* latency advantage to using this form of the method. Also, if the database
* is unavailable prior to the function call, any timeout set on the
* passed {@code Transaction} will still trigger.
*
* @param tr the transaction on which to base the query
* @param begin the inclusive start of the range
* @param end the exclusive end of the range
*
* @return an sequence of keys denoting the start of single-server ranges
*/
public static CloseableAsyncIterator getBoundaryKeys(Transaction tr, byte[] begin, byte[] end) {
Transaction local = tr.getDatabase().createTransaction(tr.getExecutor());
CompletableFuture readVersion = tr.getReadVersion();
if(readVersion.isDone() && !readVersion.isCompletedExceptionally()) {
local.setReadVersion(readVersion.getNow(null));
}
return new BoundaryIterator(local, begin, end);
}
/**
* Returns a list of public network addresses as strings, one for each of
* the storage servers responsible for storing {@code key} and its associated
* value.
*
* If locality information is not available, the returned future will carry a
* {@link FDBException} locality_information_unavailable.
*
* @param tr the transaction in which to gather location information
* @param key the key for which to gather location information
*
* @return a list of addresses in string form
*/
public static CompletableFuture getAddressesForKey(Transaction tr, byte[] key) {
if (!(tr instanceof FDBTransaction)) {
CompletableFuture future = new CompletableFuture<>();
future.completeExceptionally(new FDBException("locality_information_unavailable", 1033));
return future;
}
return ((FDBTransaction)tr).getAddressesForKey(key);
}
private static CloseableAsyncIterator getBoundaryKeys_internal(Transaction tr, byte[] begin, byte[] end) {
return new BoundaryIterator(tr, begin, end);
}
static class BoundaryIterator implements CloseableAsyncIterator {
Transaction tr;
byte[] begin;
byte[] lastBegin;
final byte[] end;
final AsyncIterable firstGet;
AsyncIterator block;
private CompletableFuture nextFuture;
private boolean closed;
BoundaryIterator(Transaction tr, byte[] begin, byte[] end) {
this.tr = tr;
this.begin = Arrays.copyOf(begin, begin.length);
this.end = Arrays.copyOf(end, end.length);
lastBegin = begin;
tr.options().setReadSystemKeys();
tr.options().setLockAware();
firstGet = tr.getRange(keyServersForKey(begin), keyServersForKey(end));
block = firstGet.iterator();
nextFuture = AsyncUtil.composeHandleAsync(block.onHasNext(), handler, tr.getExecutor());
closed = false;
}
@Override
public CompletableFuture onHasNext() {
return nextFuture;
}
@Override
public boolean hasNext() {
return nextFuture.join();
}
CompletableFuture restartGet() {
if(ByteArrayUtil.compareUnsigned(begin, end) >= 0) {
return AsyncUtil.READY_FALSE;
}
lastBegin = begin;
tr.options().setReadSystemKeys();
block = tr.getRange(
keyServersForKey(begin),
keyServersForKey(end)).iterator();
nextFuture = AsyncUtil.composeHandleAsync(block.onHasNext(), handler, tr.getExecutor());
return nextFuture;
}
BiFunction> handler = new BiFunction>() {
@Override
public CompletableFuture apply(Boolean b, Throwable o) {
if(b != null) {
return CompletableFuture.completedFuture(b);
}
if(o instanceof FDBException) {
FDBException err = (FDBException) o;
if(err.getCode() == 1007 && !Arrays.equals(begin, lastBegin)) {
Executor executor = BoundaryIterator.this.tr.getExecutor();
BoundaryIterator.this.tr.close();
BoundaryIterator.this.tr = BoundaryIterator.this.tr.getDatabase().createTransaction(executor);
return restartGet();
}
}
if(!(o instanceof RuntimeException))
throw new CompletionException(o);
CompletableFuture onError = BoundaryIterator.this.tr.onError(o);
return onError.thenComposeAsync(tr -> {
BoundaryIterator.this.tr = tr;
return restartGet();
}, tr.getExecutor());
}
};
@Override
public byte[] next() {
if(!nextFuture.isDone()) {
throw new IllegalStateException("Call to next without hasNext()=true");
}
KeyValue o = block.next();
byte[] key = o.getKey();
byte[] suffix = Arrays.copyOfRange(key, 13, key.length);
BoundaryIterator.this.begin = ByteArrayUtil.join(suffix, new byte[] { (byte)0 });
nextFuture = AsyncUtil.composeHandleAsync(block.onHasNext(), handler, tr.getExecutor());
return suffix;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Boundary keys are read-only");
}
@Override
public void close() {
BoundaryIterator.this.tr.close();
closed = true;
}
@Override
protected void finalize() throws Throwable {
try {
if(FDB.instance().warnOnUnclosed && !closed) {
System.err.println("CloseableAsyncIterator not closed (getBoundaryKeys)");
}
if(!closed) {
close();
}
}
finally {
super.finalize();
}
}
}
private static final Charset ASCII = Charset.forName("US-ASCII");
static byte[] keyServersForKey(byte[] key) {
return ByteArrayUtil.join(new byte[] { (byte)255 },
"/keyServers/".getBytes(ASCII),
key);
}
private LocalityUtil() {}
}