Skip to content

Commit 12edadd

Browse files
committed
Merge branch 'release-6.3'
# Conflicts: # CMakeLists.txt # fdbclient/Knobs.cpp # fdbclient/MasterProxyInterface.h # fdbrpc/simulator.h # fdbserver/MasterProxyServer.actor.cpp # tests/fast/CycleAndLock.txt # tests/fast/TxnStateStoreCycleTest.txt # tests/fast/VersionStamp.txt # tests/slow/ParallelRestoreOldBackupApiCorrectnessAtomicRestore.txt # tests/slow/ParallelRestoreOldBackupCorrectnessCycle.txt # versions.target
2 parents ad31de6 + e639c44 commit 12edadd

File tree

70 files changed

+1990
-233
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1990
-233
lines changed

bindings/java/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ set(JAVA_BINDING_SRCS
2222
src/main/com/apple/foundationdb/directory/NoSuchDirectoryException.java
2323
src/main/com/apple/foundationdb/directory/package-info.java
2424
src/main/com/apple/foundationdb/directory/PathUtil.java
25+
src/main/com/apple/foundationdb/DirectBufferIterator.java
26+
src/main/com/apple/foundationdb/DirectBufferPool.java
2527
src/main/com/apple/foundationdb/FDB.java
2628
src/main/com/apple/foundationdb/FDBDatabase.java
2729
src/main/com/apple/foundationdb/FDBTransaction.java

bindings/java/fdbJNI.cpp

+62-36
Original file line numberDiff line numberDiff line change
@@ -305,42 +305,6 @@ JNIEXPORT jobject JNICALL Java_com_apple_foundationdb_FutureStrings_FutureString
305305
return arr;
306306
}
307307

308-
JNIEXPORT jobject JNICALL Java_com_apple_foundationdb_FutureResults_FutureResults_1getSummary(JNIEnv *jenv, jobject, jlong future) {
309-
if( !future ) {
310-
throwParamNotNull(jenv);
311-
return JNI_NULL;
312-
}
313-
314-
FDBFuture *f = (FDBFuture *)future;
315-
316-
const FDBKeyValue *kvs;
317-
int count;
318-
fdb_bool_t more;
319-
fdb_error_t err = fdb_future_get_keyvalue_array( f, &kvs, &count, &more );
320-
if( err ) {
321-
safeThrow( jenv, getThrowable( jenv, err ) );
322-
return JNI_NULL;
323-
}
324-
325-
jbyteArray lastKey = JNI_NULL;
326-
if(count) {
327-
lastKey = jenv->NewByteArray(kvs[count - 1].key_length);
328-
if( !lastKey ) {
329-
if( !jenv->ExceptionOccurred() )
330-
throwOutOfMem(jenv);
331-
return JNI_NULL;
332-
}
333-
334-
jenv->SetByteArrayRegion(lastKey, 0, kvs[count - 1].key_length, (jbyte *)kvs[count - 1].key);
335-
}
336-
337-
jobject result = jenv->NewObject(range_result_summary_class, range_result_summary_init, lastKey, count, (jboolean)more);
338-
if( jenv->ExceptionOccurred() )
339-
return JNI_NULL;
340-
341-
return result;
342-
}
343-
344308
// SOMEDAY: explore doing this more efficiently with Direct ByteBuffers
345309
JNIEXPORT jobject JNICALL Java_com_apple_foundationdb_FutureResults_FutureResults_1get(JNIEnv *jenv, jobject, jlong future) {
346310
if( !future ) {
@@ -640,6 +604,68 @@ JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1
640604
return (jlong)f;
641605
}
642606

607+
JNIEXPORT void JNICALL Java_com_apple_foundationdb_FutureResults_FutureResults_1getDirect(
608+
JNIEnv* jenv, jobject, jlong future, jobject jbuffer, jint bufferCapacity) {
609+
610+
if( !future ) {
611+
throwParamNotNull(jenv);
612+
return;
613+
}
614+
615+
uint8_t* buffer = (uint8_t*)jenv->GetDirectBufferAddress(jbuffer);
616+
if (!buffer) {
617+
if (!jenv->ExceptionOccurred())
618+
throwRuntimeEx(jenv, "Error getting handle to native resources");
619+
return;
620+
}
621+
622+
FDBFuture* f = (FDBFuture*)future;
623+
const FDBKeyValue *kvs;
624+
int count;
625+
fdb_bool_t more;
626+
fdb_error_t err = fdb_future_get_keyvalue_array( f, &kvs, &count, &more );
627+
if( err ) {
628+
safeThrow( jenv, getThrowable( jenv, err ) );
629+
return;
630+
}
631+
632+
// Capacity for Metadata+Keys+Values
633+
// => sizeof(jint) for total key/value pairs
634+
// => sizeof(jint) to store more flag
635+
// => sizeof(jint) to store key length per KV pair
636+
// => sizeof(jint) to store value length per KV pair
637+
int totalCapacityNeeded = 2 * sizeof(jint);
638+
for(int i = 0; i < count; i++) {
639+
totalCapacityNeeded += kvs[i].key_length + kvs[i].value_length + 2*sizeof(jint);
640+
if (bufferCapacity < totalCapacityNeeded) {
641+
count = i; /* Only fit first `i` K/V pairs */
642+
more = true;
643+
break;
644+
}
645+
}
646+
647+
int offset = 0;
648+
649+
// First copy RangeResultSummary, i.e. [keyCount, more]
650+
memcpy(buffer + offset, &count, sizeof(jint));
651+
offset += sizeof(jint);
652+
653+
memcpy(buffer + offset, &more, sizeof(jint));
654+
offset += sizeof(jint);
655+
656+
for (int i = 0; i < count; i++) {
657+
memcpy(buffer + offset, &kvs[i].key_length, sizeof(jint));
658+
memcpy(buffer + offset + sizeof(jint), &kvs[i].value_length, sizeof(jint));
659+
offset += 2 * sizeof(jint);
660+
661+
memcpy(buffer + offset, kvs[i].key, kvs[i].key_length);
662+
offset += kvs[i].key_length;
663+
664+
memcpy(buffer + offset, kvs[i].value, kvs[i].value_length);
665+
offset += kvs[i].value_length;
666+
}
667+
}
668+
643669
JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1getEstimatedRangeSizeBytes(JNIEnv *jenv, jobject, jlong tPtr,
644670
jbyteArray beginKeyBytes, jbyteArray endKeyBytes) {
645671
if( !tPtr || !beginKeyBytes || !endKeyBytes) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* DirectBufferIterator.java
3+
*
4+
* This source file is part of the FoundationDB open source project
5+
*
6+
* Copyright 2015-2020 Apple Inc. and the FoundationDB project authors
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
package com.apple.foundationdb;
22+
23+
import java.io.Closeable;
24+
import java.nio.ByteBuffer;
25+
import java.nio.ByteOrder;
26+
import java.util.Iterator;
27+
import java.util.NoSuchElementException;
28+
29+
/**
30+
* Holds the direct buffer that is shared with JNI wrapper. A typical usage is as follows:
31+
*
32+
* The serialization format of result is =>
33+
* [int keyCount, boolean more, ListOf<(int keyLen, int valueLen, byte[] key, byte[] value)>]
34+
*/
35+
class DirectBufferIterator implements Iterator<KeyValue>, AutoCloseable {
36+
private ByteBuffer byteBuffer;
37+
private int current = 0;
38+
private int keyCount = -1;
39+
private boolean more = false;
40+
41+
public DirectBufferIterator(ByteBuffer buffer) {
42+
byteBuffer = buffer;
43+
byteBuffer.order(ByteOrder.nativeOrder());
44+
}
45+
46+
@Override
47+
public void close() {
48+
if (byteBuffer != null) {
49+
DirectBufferPool.getInstance().add(byteBuffer);
50+
byteBuffer = null;
51+
}
52+
}
53+
54+
public boolean hasResultReady() {
55+
return keyCount > -1;
56+
}
57+
58+
@Override
59+
public boolean hasNext() {
60+
assert (hasResultReady());
61+
return current < keyCount;
62+
}
63+
64+
@Override
65+
public KeyValue next() {
66+
assert (hasResultReady()); // Must be called once its ready.
67+
if (!hasNext()) {
68+
throw new NoSuchElementException();
69+
}
70+
71+
final int keyLen = byteBuffer.getInt();
72+
final int valueLen = byteBuffer.getInt();
73+
byte[] key = new byte[keyLen];
74+
byteBuffer.get(key);
75+
76+
byte[] value = new byte[valueLen];
77+
byteBuffer.get(value);
78+
79+
current += 1;
80+
return new KeyValue(key, value);
81+
}
82+
83+
public ByteBuffer getBuffer() {
84+
return byteBuffer;
85+
}
86+
87+
public int count() {
88+
assert (hasResultReady());
89+
return keyCount;
90+
}
91+
92+
public boolean hasMore() {
93+
assert (hasResultReady());
94+
return more;
95+
}
96+
97+
public int currentIndex() {
98+
return current;
99+
}
100+
101+
public void readResultsSummary() {
102+
byteBuffer.rewind();
103+
byteBuffer.position(0);
104+
105+
keyCount = byteBuffer.getInt();
106+
more = byteBuffer.getInt() > 0;
107+
}
108+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* DirectBufferPool.java
3+
*
4+
* This source file is part of the FoundationDB open source project
5+
*
6+
* Copyright 2015-2020 Apple Inc. and the FoundationDB project authors
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
package com.apple.foundationdb;
22+
23+
import java.nio.ByteBuffer;
24+
import java.util.concurrent.ArrayBlockingQueue;
25+
26+
/**
27+
* A singleton that manages a pool of {@link DirectByteBuffer}, that will be
28+
* shared by the {@link DirectBufferIterator} instances. It is responsibilty of
29+
* user to return the borrowed buffers.
30+
*/
31+
class DirectBufferPool {
32+
static final DirectBufferPool __instance = new DirectBufferPool();
33+
34+
// When tuning this, make sure that the size of the buffer,
35+
// is always greater than the maximum size KV allowed by FDB.
36+
// Current limits is :
37+
// 10kB for key + 100kB for value + 1 int for count + 1 int for more + 2 int for KV size
38+
static public final int MIN_BUFFER_SIZE = (10 + 100) * 1000 + Integer.BYTES * 4;
39+
40+
static private final int DEFAULT_NUM_BUFFERS = 128;
41+
static private final int DEFAULT_BUFFER_SIZE = 1024 * 512;
42+
43+
private ArrayBlockingQueue<ByteBuffer> buffers;
44+
private int currentBufferCapacity;
45+
46+
public DirectBufferPool() {
47+
resize(DEFAULT_NUM_BUFFERS, DEFAULT_BUFFER_SIZE);
48+
}
49+
50+
public static DirectBufferPool getInstance() {
51+
return __instance;
52+
}
53+
54+
/**
55+
* Resizes buffer pool with given capacity and buffer size. Throws OutOfMemory exception
56+
* if unable to allocate as asked.
57+
*/
58+
public synchronized void resize(int newPoolSize, int bufferSize) {
59+
if (bufferSize < MIN_BUFFER_SIZE) {
60+
throw new IllegalArgumentException("'bufferSize' must be at-least: " + MIN_BUFFER_SIZE + " bytes");
61+
}
62+
buffers = new ArrayBlockingQueue<>(newPoolSize);
63+
currentBufferCapacity = bufferSize;
64+
while (buffers.size() < newPoolSize) {
65+
ByteBuffer buffer = ByteBuffer.allocateDirect(bufferSize);
66+
buffers.add(buffer);
67+
}
68+
}
69+
70+
/**
71+
* Requests a {@link DirectByteBuffer} from our pool. Returns null if pool is empty.
72+
*/
73+
public synchronized ByteBuffer poll() {
74+
return buffers.poll();
75+
}
76+
77+
/**
78+
* Returns the {@link DirectByteBuffer} that was borrowed from our pool.
79+
*/
80+
public synchronized void add(ByteBuffer buffer) {
81+
if (buffer.capacity() != currentBufferCapacity) {
82+
// This can happen when a resize is called while there are outstanding requests,
83+
// older buffers will be returned eventually.
84+
return;
85+
}
86+
87+
buffers.offer(buffer);
88+
}
89+
}

bindings/java/src/main/com/apple/foundationdb/FDB.java

+32-1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ public Thread newThread(Runnable r) {
8585
private volatile boolean netStarted = false;
8686
private volatile boolean netStopped = false;
8787
volatile boolean warnOnUnclosed = true;
88+
private boolean enableDirectBufferQueries = false;
89+
8890
private boolean useShutdownHook = true;
8991
private Thread shutdownHook;
9092
private final Semaphore netRunning = new Semaphore(1);
@@ -229,6 +231,35 @@ public int getAPIVersion() {
229231
return apiVersion;
230232
}
231233

234+
/**
235+
* Enables or disables use of DirectByteBuffers for getRange() queries.
236+
*
237+
* @param enabled Whether DirectByteBuffer should be used for getRange() queries.
238+
*/
239+
public void enableDirectBufferQuery(boolean enabled) {
240+
enableDirectBufferQueries = enabled;
241+
}
242+
243+
/**
244+
* Determines whether {@code getRange()} queries can use {@code DirectByteBuffer} from
245+
* {@link DirectBufferPool} to copy results.
246+
*
247+
* @return {@code true} if direct buffer queries have been enabled and {@code false} otherwise
248+
*/
249+
public boolean isDirectBufferQueriesEnabled() {
250+
return enableDirectBufferQueries;
251+
}
252+
253+
/**
254+
* Resizes the DirectBufferPool with given parameters, which is used by getRange() requests.
255+
*
256+
* @param poolSize Number of buffers in pool
257+
* @param bufferSize Size of each buffer in bytes
258+
*/
259+
public void resizeDirectBufferPool(int poolSize, int bufferSize) {
260+
DirectBufferPool.getInstance().resize(poolSize, bufferSize);
261+
}
262+
232263
/**
233264
* Connects to the cluster specified by the
234265
* <a href="/foundationdb/administration.html#default-cluster-file" target="_blank">default fdb.cluster file</a>.
@@ -507,4 +538,4 @@ protected static boolean evalErrorPredicate(int predicate, int code) {
507538
private native boolean Error_predicate(int predicate, int code);
508539

509540
private native long Database_create(String clusterFilePath) throws FDBException;
510-
}
541+
}

0 commit comments

Comments
 (0)