Skip to content

Commit

Permalink
Merge branch 'main' of github.com:apple/foundationdb into jfu-grv-cac…
Browse files Browse the repository at this point in the history
…he-multi-threaded
  • Loading branch information
sfc-gh-jfu committed Apr 6, 2022
2 parents 124aa6e + 38ec762 commit b0ae22f
Show file tree
Hide file tree
Showing 105 changed files with 5,382 additions and 1,372 deletions.
4 changes: 2 additions & 2 deletions bindings/bindingtester/known_testers.py
Expand Up @@ -61,8 +61,8 @@ def _absolute_path(path):
'python': Tester('python', 'python ' + _absolute_path('python/tests/tester.py'), 2040, 23, MAX_API_VERSION, types=ALL_TYPES, tenants_enabled=True),
'python3': Tester('python3', 'python3 ' + _absolute_path('python/tests/tester.py'), 2040, 23, MAX_API_VERSION, types=ALL_TYPES, tenants_enabled=True),
'ruby': Tester('ruby', _absolute_path('ruby/tests/tester.rb'), 2040, 23, MAX_API_VERSION),
'java': Tester('java', _java_cmd + 'StackTester', 2040, 510, MAX_API_VERSION, types=ALL_TYPES),
'java_async': Tester('java', _java_cmd + 'AsyncStackTester', 2040, 510, MAX_API_VERSION, types=ALL_TYPES),
'java': Tester('java', _java_cmd + 'StackTester', 2040, 510, MAX_API_VERSION, types=ALL_TYPES, tenants_enabled=True),
'java_async': Tester('java', _java_cmd + 'AsyncStackTester', 2040, 510, MAX_API_VERSION, types=ALL_TYPES, tenants_enabled=True),
'go': Tester('go', _absolute_path('go/build/bin/_stacktester'), 2040, 200, MAX_API_VERSION, types=ALL_TYPES),
'flow': Tester('flow', _absolute_path('flow/bin/fdb_flow_tester'), 63, 500, MAX_API_VERSION, directory_snapshot_ops_enabled=False),
}
37 changes: 32 additions & 5 deletions bindings/c/test/unit/unit_tests.cpp
Expand Up @@ -949,12 +949,10 @@ std::map<std::string, std::string> fillInRecords(int n) {
return data;
}

GetMappedRangeResult getMappedIndexEntries(int beginId, int endId, fdb::Transaction& tr) {
GetMappedRangeResult getMappedIndexEntries(int beginId, int endId, fdb::Transaction& tr, std::string mapper) {
std::string indexEntryKeyBegin = indexEntryKey(beginId);
std::string indexEntryKeyEnd = indexEntryKey(endId);

std::string mapper = Tuple().append(prefix).append(RECORD).append("{K[3]}"_sr).append("{...}"_sr).pack().toString();

return get_mapped_range(
tr,
FDB_KEYSEL_FIRST_GREATER_OR_EQUAL((const uint8_t*)indexEntryKeyBegin.c_str(), indexEntryKeyBegin.size()),
Expand All @@ -969,6 +967,11 @@ GetMappedRangeResult getMappedIndexEntries(int beginId, int endId, fdb::Transact
/* reverse */ 0);
}

GetMappedRangeResult getMappedIndexEntries(int beginId, int endId, fdb::Transaction& tr) {
std::string mapper = Tuple().append(prefix).append(RECORD).append("{K[3]}"_sr).append("{...}"_sr).pack().toString();
return getMappedIndexEntries(beginId, endId, tr, mapper);
}

TEST_CASE("fdb_transaction_get_mapped_range") {
const int TOTAL_RECORDS = 20;
fillInRecords(TOTAL_RECORDS);
Expand Down Expand Up @@ -1009,7 +1012,6 @@ TEST_CASE("fdb_transaction_get_mapped_range") {
TEST_CASE("fdb_transaction_get_mapped_range_restricted_to_serializable") {
std::string mapper = Tuple().append(prefix).append(RECORD).append("{K[3]}"_sr).pack().toString();
fdb::Transaction tr(db);
fdb_check(tr.set_option(FDB_TR_OPTION_READ_YOUR_WRITES_DISABLE, nullptr, 0));
auto result = get_mapped_range(
tr,
FDB_KEYSEL_FIRST_GREATER_OR_EQUAL((const uint8_t*)indexEntryKey(0).c_str(), indexEntryKey(0).size()),
Expand Down Expand Up @@ -1039,11 +1041,36 @@ TEST_CASE("fdb_transaction_get_mapped_range_restricted_to_ryw_enable") {
/* target_bytes */ 0,
/* FDBStreamingMode */ FDB_STREAMING_MODE_WANT_ALL,
/* iteration */ 0,
/* snapshot */ true,
/* snapshot */ false,
/* reverse */ 0);
ASSERT(result.err == error_code_unsupported_operation);
}

void assertNotTuple(std::string str) {
try {
Tuple::unpack(str);
} catch (Error& e) {
return;
}
UNREACHABLE();
}

TEST_CASE("fdb_transaction_get_mapped_range_fail_on_mapper_not_tuple") {
// A string that cannot be parsed as tuple.
// "\x15:\x152\x15E\x15\x09\x15\x02\x02MySimpleRecord$repeater-version\x00\x15\x013\x00\x00\x00\x00\x1aU\x90\xba\x00\x00\x00\x02\x15\x04"
std::string mapper = {
'\x15', ':', '\x15', '2', '\x15', 'E', '\x15', '\t', '\x15', '\x02', '\x02', 'M',
'y', 'S', 'i', 'm', 'p', 'l', 'e', 'R', 'e', 'c', 'o', 'r',
'd', '$', 'r', 'e', 'p', 'e', 'a', 't', 'e', 'r', '-', 'v',
'e', 'r', 's', 'i', 'o', 'n', '\x00', '\x15', '\x01', '3', '\x00', '\x00',
'\x00', '\x00', '\x1a', 'U', '\x90', '\xba', '\x00', '\x00', '\x00', '\x02', '\x15', '\x04'
};
assertNotTuple(mapper);
fdb::Transaction tr(db);
auto result = getMappedIndexEntries(1, 3, tr, mapper);
ASSERT(result.err == error_code_mapper_not_tuple);
}

TEST_CASE("fdb_transaction_get_range reverse") {
std::map<std::string, std::string> data = create_data({ { "a", "1" }, { "b", "2" }, { "c", "3" }, { "d", "4" } });
insert_data(db, data);
Expand Down
3 changes: 3 additions & 0 deletions bindings/java/CMakeLists.txt
Expand Up @@ -32,6 +32,7 @@ set(JAVA_BINDING_SRCS
src/main/com/apple/foundationdb/DirectBufferPool.java
src/main/com/apple/foundationdb/FDB.java
src/main/com/apple/foundationdb/FDBDatabase.java
src/main/com/apple/foundationdb/FDBTenant.java
src/main/com/apple/foundationdb/FDBTransaction.java
src/main/com/apple/foundationdb/FutureInt64.java
src/main/com/apple/foundationdb/FutureKey.java
Expand Down Expand Up @@ -64,6 +65,8 @@ set(JAVA_BINDING_SRCS
src/main/com/apple/foundationdb/ReadTransactionContext.java
src/main/com/apple/foundationdb/subspace/package-info.java
src/main/com/apple/foundationdb/subspace/Subspace.java
src/main/com/apple/foundationdb/Tenant.java
src/main/com/apple/foundationdb/TenantManagement.java
src/main/com/apple/foundationdb/Transaction.java
src/main/com/apple/foundationdb/TransactionContext.java
src/main/com/apple/foundationdb/EventKeeper.java
Expand Down
53 changes: 53 additions & 0 deletions bindings/java/fdbJNI.cpp
Expand Up @@ -663,6 +663,34 @@ JNIEXPORT jbyteArray JNICALL Java_com_apple_foundationdb_FutureKey_FutureKey_1ge
return result;
}

JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBDatabase_Database_1openTenant(JNIEnv* jenv,
jobject,
jlong dbPtr,
jbyteArray tenantNameBytes) {
if (!dbPtr || !tenantNameBytes) {
throwParamNotNull(jenv);
return 0;
}
FDBDatabase* database = (FDBDatabase*)dbPtr;
FDBTenant* tenant;

uint8_t* barr = (uint8_t*)jenv->GetByteArrayElements(tenantNameBytes, JNI_NULL);
if (!barr) {
if (!jenv->ExceptionOccurred())
throwRuntimeEx(jenv, "Error getting handle to native resources");
return 0;
}

fdb_error_t err = fdb_database_open_tenant(database, barr, jenv->GetArrayLength(tenantNameBytes), &tenant);
if (err) {
safeThrow(jenv, getThrowable(jenv, err));
return 0;
}

jenv->ReleaseByteArrayElements(tenantNameBytes, (jbyte*)barr, JNI_ABORT);
return (jlong)tenant;
}

JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBDatabase_Database_1createTransaction(JNIEnv* jenv,
jobject,
jlong dbPtr) {
Expand Down Expand Up @@ -764,6 +792,31 @@ JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDB_Database_1create(JNIEnv*
return (jlong)db;
}

JNIEXPORT jlong JNICALL Java_com_apple_foundationdb_FDBTenant_Tenant_1createTransaction(JNIEnv* jenv,
jobject,
jlong tPtr) {
if (!tPtr) {
throwParamNotNull(jenv);
return 0;
}
FDBTenant* tenant = (FDBTenant*)tPtr;
FDBTransaction* tr;
fdb_error_t err = fdb_tenant_create_transaction(tenant, &tr);
if (err) {
safeThrow(jenv, getThrowable(jenv, err));
return 0;
}
return (jlong)tr;
}

JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTenant_Tenant_1dispose(JNIEnv* jenv, jobject, jlong tPtr) {
if (!tPtr) {
throwParamNotNull(jenv);
return;
}
fdb_tenant_destroy((FDBTenant*)tPtr);
}

JNIEXPORT void JNICALL Java_com_apple_foundationdb_FDBTransaction_Transaction_1setVersion(JNIEnv* jenv,
jobject,
jlong tPtr,
Expand Down
76 changes: 74 additions & 2 deletions bindings/java/src/main/com/apple/foundationdb/Database.java
Expand Up @@ -23,6 +23,7 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Function;
import com.apple.foundationdb.tuple.Tuple;

/**
* A mutable, lexicographically ordered mapping from binary keys to binary values.
Expand All @@ -41,11 +42,82 @@
*/
public interface Database extends AutoCloseable, TransactionContext {
/**
* Creates a {@link Transaction} that operates on this {@code Database}.<br>
* Opens an existing tenant to be used for running transactions.<br>
* <br>
* <b>Note:</b> opening a tenant does not check its existence in the cluster. If the tenant does not exist,
* attempts to read or write data with it will fail.
*
* @param tenantName The name of the tenant to open.
* @return a {@link Tenant} that can be used to create transactions that will operate in the tenant's key-space.
*/
default Tenant openTenant(byte[] tenantName) {
return openTenant(tenantName, getExecutor());
}

/**
* Opens an existing tenant to be used for running transactions. This is a convenience method that generates the
* tenant name by packing a {@code Tuple}.<br>
* <br>
* <b>Note:</b> opening a tenant does not check its existence in the cluster. If the tenant does not exist,
* attempts to read or write data with it will fail.
*
* @param tenantName The name of the tenant to open, as a Tuple.
* @return a {@link Tenant} that can be used to create transactions that will operate in the tenant's key-space.
*/
Tenant openTenant(Tuple tenantName);

/**
* Opens an existing tenant to be used for running transactions.
*
* @param tenantName The name of the tenant to open.
* @param e the {@link Executor} to use when executing asynchronous callbacks.
* @return a {@link Tenant} that can be used to create transactions that will operate in the tenant's key-space.
*/
Tenant openTenant(byte[] tenantName, Executor e);

/**
* Opens an existing tenant to be used for running transactions. This is a convenience method that generates the
* tenant name by packing a {@code Tuple}.
*
* @param tenantName The name of the tenant to open, as a Tuple.
* @param e the {@link Executor} to use when executing asynchronous callbacks.
* @return a {@link Tenant} that can be used to create transactions that will operate in the tenant's key-space.
*/
Tenant openTenant(Tuple tenantName, Executor e);

/**
* Opens an existing tenant to be used for running transactions.
*
* @param tenantName The name of the tenant to open.
* @param e the {@link Executor} to use when executing asynchronous callbacks.
* @param eventKeeper the {@link EventKeeper} to use when tracking instrumented calls for the tenant's transactions.
* @return a {@link Tenant} that can be used to create transactions that will operate in the tenant's key-space.
*/
Tenant openTenant(byte[] tenantName, Executor e, EventKeeper eventKeeper);

/**
* Opens an existing tenant to be used for running transactions. This is a convenience method that generates the
* tenant name by packing a {@code Tuple}.
*
* @param tenantName The name of the tenant to open, as a Tuple.
* @param e the {@link Executor} to use when executing asynchronous callbacks.
* @param eventKeeper the {@link EventKeeper} to use when tracking instrumented calls for the tenant's transactions.
* @return a {@link Tenant} that can be used to create transactions that will operate in the tenant's key-space.
*/
Tenant openTenant(Tuple tenantName, Executor e, EventKeeper eventKeeper);

/**
* Creates a {@link Transaction} that operates on this {@code Database}. Creating a transaction
* in this way does not associate it with a {@code Tenant}, and as a result the transaction will
* operate on the entire key-space for the database.<br>
* <br>
* <b>Note:</b> Java transactions automatically set the {@link TransactionOptions#setUsedDuringCommitProtectionDisable}
* option. This is because the Java bindings disallow use of {@code Transaction} objects after
* {@link Transaction#onError} is called.
* {@link Transaction#onError} is called.<br>
* <br>
* <b>Note:</b> Transactions created directly on a {@code Database} object cannot be used in a cluster
* that requires tenant-based access. To run transactions in those clusters, you must first open a tenant
* with {@link #openTenant(byte[])}.
*
* @return a newly created {@code Transaction} that reads from and writes to this {@code Database}.
*/
Expand Down
41 changes: 41 additions & 0 deletions bindings/java/src/main/com/apple/foundationdb/FDBDatabase.java
Expand Up @@ -27,6 +27,8 @@
import java.util.function.Function;

import com.apple.foundationdb.async.AsyncUtil;
import com.apple.foundationdb.tuple.ByteArrayUtil;
import com.apple.foundationdb.tuple.Tuple;

class FDBDatabase extends NativeObjectWrapper implements Database, OptionConsumer {
private DatabaseOptions options;
Expand Down Expand Up @@ -116,6 +118,44 @@ protected void finalize() throws Throwable {
}
}

@Override
public Tenant openTenant(byte[] tenantName, Executor e) {
return openTenant(tenantName, e, eventKeeper);
}

@Override
public Tenant openTenant(Tuple tenantName) {
return openTenant(tenantName.pack());
}

@Override
public Tenant openTenant(Tuple tenantName, Executor e) {
return openTenant(tenantName.pack(), e);
}

@Override
public Tenant openTenant(byte[] tenantName, Executor e, EventKeeper eventKeeper) {
pointerReadLock.lock();
Tenant tenant = null;
try {
tenant = new FDBTenant(Database_openTenant(getPtr(), tenantName), this, tenantName, e, eventKeeper);
return tenant;
} catch (RuntimeException err) {
if (tenant != null) {
tenant.close();
}

throw err;
} finally {
pointerReadLock.unlock();
}
}

@Override
public Tenant openTenant(Tuple tenantName, Executor e, EventKeeper eventKeeper) {
return openTenant(tenantName.pack(), e, eventKeeper);
}

@Override
public Transaction createTransaction(Executor e) {
return createTransaction(e, eventKeeper);
Expand Down Expand Up @@ -170,6 +210,7 @@ protected void closeInternal(long cPtr) {
Database_dispose(cPtr);
}

private native long Database_openTenant(long cPtr, byte[] tenantName);
private native long Database_createTransaction(long cPtr);
private native void Database_dispose(long cPtr);
private native void Database_setOption(long cPtr, int code, byte[] value) throws FDBException;
Expand Down

0 comments on commit b0ae22f

Please sign in to comment.