or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

examples

edge-cases.mdreal-world-scenarios.md
index.md
tile.json

tenant-management.mddocs/reference/

Tenant Management

Multi-tenancy support for secure key-space isolation in shared FoundationDB deployments. Tenants provide logical separation of data with independent key-spaces.

Capabilities

Opening Tenants

Open existing tenants for transaction execution.

/**
 * Open an existing tenant using default executor.
 * Opening does not validate tenant existence - errors occur on first use.
 * 
 * Parameters:
 * - tenantName: byte[] - Name of tenant to open
 * 
 * Returns:
 * Tenant - Tenant object for creating transactions
 */
Tenant Database.openTenant(byte[] tenantName);

/**
 * Open tenant using Tuple name (convenience method).
 * Tenant name is generated by packing the Tuple.
 * 
 * Parameters:
 * - tenantName: Tuple - Tenant name as Tuple
 * 
 * Returns:
 * Tenant - Tenant object for creating transactions
 */
Tenant Database.openTenant(Tuple tenantName);

/**
 * Open tenant with custom executor for async operations.
 * 
 * Parameters:
 * - tenantName: byte[] - Name of tenant to open
 * - e: Executor - Executor for asynchronous callbacks
 * 
 * Returns:
 * Tenant - Tenant object for creating transactions
 */
Tenant Database.openTenant(byte[] tenantName, Executor e);

/**
 * Open tenant using Tuple name with custom executor.
 * 
 * Parameters:
 * - tenantName: Tuple - Tenant name as Tuple
 * - e: Executor - Executor for asynchronous callbacks
 * 
 * Returns:
 * Tenant - Tenant object for creating transactions
 */
Tenant Database.openTenant(Tuple tenantName, Executor e);

/**
 * Open tenant with custom executor and event tracking.
 * 
 * Parameters:
 * - tenantName: byte[] - Name of tenant to open
 * - e: Executor - Executor for asynchronous callbacks
 * - eventKeeper: EventKeeper - Instrumentation for tracking operations
 * 
 * Returns:
 * Tenant - Tenant object for creating transactions
 */
Tenant Database.openTenant(byte[] tenantName, Executor e, EventKeeper eventKeeper);

/**
 * Open tenant using Tuple name with custom executor and event tracking.
 * 
 * Parameters:
 * - tenantName: Tuple - Tenant name as Tuple
 * - e: Executor - Executor for asynchronous callbacks
 * - eventKeeper: EventKeeper - Instrumentation for tracking operations
 * 
 * Returns:
 * Tenant - Tenant object for creating transactions
 */
Tenant Database.openTenant(Tuple tenantName, Executor e, EventKeeper eventKeeper);

Usage examples:

import com.apple.foundationdb.*;
import com.apple.foundationdb.tuple.Tuple;

// Open tenant with byte array name
Tenant tenant1 = db.openTenant("app_tenant_1".getBytes());

// Open tenant with Tuple name
Tenant tenant2 = db.openTenant(Tuple.from("app", "tenant", 1));

// Open tenant with custom executor
Executor customExecutor = Executors.newFixedThreadPool(10);
Tenant tenant3 = db.openTenant("tenant3".getBytes(), customExecutor);

// Use tenant
try (Tenant tenant = db.openTenant("my_tenant".getBytes())) {
    tenant.run(tr -> {
        tr.set("key".getBytes(), "value".getBytes());
        return null;
    });
}

Creating Tenants

Create new tenants for isolating data.

/**
 * Create tenant within a transaction.
 * Idempotent: completes successfully if tenant already exists.
 * Transaction must be committed for creation to take effect.
 *
 * Parameters:
 * - tr: Transaction - Transaction in which to create tenant
 * - tenantName: byte[] - Name for new tenant
 *
 * Throws:
 * FDBException - If creation fails on commit
 */
static void TenantManagement.createTenant(Transaction tr, byte[] tenantName);

/**
 * Create tenant using Tuple name within a transaction.
 * Idempotent: completes successfully if tenant already exists.
 *
 * Parameters:
 * - tr: Transaction - Transaction in which to create tenant
 * - tenantName: Tuple - Name for new tenant as Tuple
 */
static void TenantManagement.createTenant(Transaction tr, Tuple tenantName);

/**
 * Create tenant with automatic retry loop.
 * Checks existence first and throws tenant_already_exists error (2132) if tenant exists.
 * Uses database's transaction retry mechanism.
 *
 * Parameters:
 * - db: Database - Database in which to create tenant
 * - tenantName: byte[] - Name for new tenant
 *
 * Returns:
 * CompletableFuture<Void> - Completes when tenant is created
 *
 * Throws:
 * FDBException - With code 2132 (tenant_already_exists) if tenant already exists
 */
static CompletableFuture<Void> TenantManagement.createTenant(Database db, byte[] tenantName);

/**
 * Create tenant with Tuple name using automatic retry loop.
 * Checks existence first and throws tenant_already_exists error (2132) if tenant exists.
 *
 * Parameters:
 * - db: Database - Database in which to create tenant
 * - tenantName: Tuple - Name for new tenant as Tuple
 *
 * Returns:
 * CompletableFuture<Void> - Completes when tenant is created
 *
 * Throws:
 * FDBException - With code 2132 (tenant_already_exists) if tenant already exists
 */
static CompletableFuture<Void> TenantManagement.createTenant(Database db, Tuple tenantName);

Usage examples:

import com.apple.foundationdb.*;
import com.apple.foundationdb.tuple.Tuple;

// Create tenant with retry loop (recommended)
TenantManagement.createTenant(db, "new_tenant".getBytes()).join();

// Create tenant with Tuple name
TenantManagement.createTenant(db, Tuple.from("app", "user", 12345)).join();

// Create tenant within existing transaction
db.run(tr -> {
    TenantManagement.createTenant(tr, "tenant1".getBytes());
    TenantManagement.createTenant(tr, "tenant2".getBytes());
    return null;
});

// Create multiple tenants
List<String> tenantNames = Arrays.asList("tenant_a", "tenant_b", "tenant_c");
List<CompletableFuture<Void>> futures = tenantNames.stream()
    .map(name -> TenantManagement.createTenant(db, name.getBytes()))
    .collect(Collectors.toList());

CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
System.out.println("All tenants created");

Deleting Tenants

Remove tenants and their metadata.

/**
 * Delete tenant within a transaction.
 * Idempotent: completes successfully if tenant does not exist.
 * Tenant must be empty (contain no data).
 * Transaction must be committed for deletion to take effect.
 *
 * Parameters:
 * - tr: Transaction - Transaction in which to delete tenant
 * - tenantName: byte[] - Name of tenant to delete
 *
 * Throws:
 * FDBException - If tenant contains data or deletion fails on commit
 */
static void TenantManagement.deleteTenant(Transaction tr, byte[] tenantName);

/**
 * Delete tenant using Tuple name within a transaction.
 * Idempotent: completes successfully if tenant does not exist.
 * Tenant must be empty (contain no data).
 *
 * Parameters:
 * - tr: Transaction - Transaction in which to delete tenant
 * - tenantName: Tuple - Name of tenant to delete as Tuple
 */
static void TenantManagement.deleteTenant(Transaction tr, Tuple tenantName);

/**
 * Delete tenant with automatic retry loop.
 * Checks existence first and throws tenant_not_found error (2131) if tenant does not exist.
 * Tenant must be empty (contain no data).
 *
 * Parameters:
 * - db: Database - Database containing tenant
 * - tenantName: byte[] - Name of tenant to delete
 *
 * Returns:
 * CompletableFuture<Void> - Completes when tenant is deleted
 *
 * Throws:
 * FDBException - With code 2131 (tenant_not_found) if tenant does not exist
 *                or if tenant contains data
 */
static CompletableFuture<Void> TenantManagement.deleteTenant(Database db, byte[] tenantName);

/**
 * Delete tenant with Tuple name using automatic retry loop.
 * Checks existence first and throws tenant_not_found error (2131) if tenant does not exist.
 * Tenant must be empty (contain no data).
 *
 * Parameters:
 * - db: Database - Database containing tenant
 * - tenantName: Tuple - Name of tenant to delete as Tuple
 *
 * Returns:
 * CompletableFuture<Void> - Completes when tenant is deleted
 *
 * Throws:
 * FDBException - With code 2131 (tenant_not_found) if tenant does not exist
 *                or if tenant contains data
 */
static CompletableFuture<Void> TenantManagement.deleteTenant(Database db, Tuple tenantName);

Usage examples:

// Delete tenant (must be empty)
TenantManagement.deleteTenant(db, "old_tenant".getBytes()).join();

// Clear tenant data then delete
Tenant tenant = db.openTenant("tenant_to_delete".getBytes());
tenant.run(tr -> {
    // Clear all data in tenant
    tr.clear(new byte[0], new byte[]{(byte)0xFF});
    return null;
});

// Now delete the empty tenant
TenantManagement.deleteTenant(db, "tenant_to_delete".getBytes()).join();

Listing Tenants

Query available tenants in a database.

/**
 * List tenants in specified range.
 * Returns iterator over tenant metadata.
 * 
 * Parameters:
 * - db: Database - Database to query
 * - begin: byte[] - Start of tenant name range (inclusive)
 * - end: byte[] - End of tenant name range (exclusive)
 * - limit: int - Maximum tenants to return
 * 
 * Returns:
 * CloseableAsyncIterator<KeyValue> - Iterator over tenant entries
 *   Keys are tenant names, values are tenant metadata (JSON)
 */
static CloseableAsyncIterator<KeyValue> TenantManagement.listTenants(
    Database db, byte[] begin, byte[] end, int limit
);

/**
 * List tenants using Tuple range.
 * 
 * Parameters:
 * - db: Database - Database to query
 * - begin: Tuple - Start of tenant name range (inclusive)
 * - end: Tuple - End of tenant name range (exclusive)
 * - limit: int - Maximum tenants to return
 * 
 * Returns:
 * CloseableAsyncIterator<KeyValue> - Iterator over tenant entries
 */
static CloseableAsyncIterator<KeyValue> TenantManagement.listTenants(
    Database db, Tuple begin, Tuple end, int limit
);

Usage examples:

import com.apple.foundationdb.async.CloseableAsyncIterator;

// List all tenants
try (CloseableAsyncIterator<KeyValue> iter = 
         TenantManagement.listTenants(db, new byte[0], new byte[]{(byte)0xFF}, 1000)) {
    
    while (iter.hasNext()) {
        KeyValue kv = iter.next();
        String tenantName = new String(kv.getKey());
        String metadata = new String(kv.getValue());
        System.out.println("Tenant: " + tenantName + ", Metadata: " + metadata);
    }
}

// List tenants with prefix
byte[] prefix = "app_".getBytes();
byte[] prefixEnd = "app`".getBytes(); // Next prefix after "app_"

try (CloseableAsyncIterator<KeyValue> iter = 
         TenantManagement.listTenants(db, prefix, prefixEnd, 100)) {
    
    List<String> tenantNames = new ArrayList<>();
    while (iter.hasNext()) {
        tenantNames.add(new String(iter.next().getKey()));
    }
    System.out.println("Found " + tenantNames.size() + " tenants");
}

// List tenants using Tuple range
Tuple begin = Tuple.from("org", "users");
Tuple end = Tuple.from("org", "users", 999999);

try (CloseableAsyncIterator<KeyValue> iter = 
         TenantManagement.listTenants(db, begin, end, 1000)) {
    
    for (KeyValue kv : iter) {
        System.out.println("Tenant: " + new String(kv.getKey()));
    }
}

Tenant Operations

Execute transactions and query tenant information.

/**
 * Create transaction scoped to tenant key-space.
 * 
 * Returns:
 * Transaction - New transaction in tenant context
 */
Transaction Tenant.createTransaction();

/**
 * Create transaction with custom executor.
 * 
 * Parameters:
 * - e: Executor - Executor for asynchronous operations
 * 
 * Returns:
 * Transaction - New transaction in tenant context
 */
Transaction Tenant.createTransaction(Executor e);

/**
 * Create transaction with custom executor and event tracking.
 * 
 * Parameters:
 * - e: Executor - Executor for asynchronous operations
 * - eventKeeper: EventKeeper - Instrumentation for tracking operations
 * 
 * Returns:
 * Transaction - New transaction in tenant context
 */
Transaction Tenant.createTransaction(Executor e, EventKeeper eventKeeper);

/**
 * Run transactional function with automatic retry.
 * 
 * Type Parameters:
 * - T: Return type
 * 
 * Parameters:
 * - retryable: Function<? super Transaction, T> - Function to execute
 * 
 * Returns:
 * T - Result of function
 */
<T> T Tenant.run(Function<? super Transaction, T> retryable);

/**
 * Run transactional function with custom executor.
 * 
 * Type Parameters:
 * - T: Return type
 * 
 * Parameters:
 * - retryable: Function<? super Transaction, T> - Function to execute
 * - e: Executor - Executor for asynchronous operations
 * 
 * Returns:
 * T - Result of function
 */
<T> T Tenant.run(Function<? super Transaction, T> retryable, Executor e);

/**
 * Run async transactional function with automatic retry.
 * 
 * Type Parameters:
 * - T: Return type
 * 
 * Parameters:
 * - retryable: Function<? super Transaction, ? extends CompletableFuture<T>>
 * 
 * Returns:
 * CompletableFuture<T> - Future completing with result
 */
<T> CompletableFuture<T> Tenant.runAsync(
    Function<? super Transaction, ? extends CompletableFuture<T>> retryable
);

/**
 * Run async transactional function with custom executor.
 * 
 * Type Parameters:
 * - T: Return type
 * 
 * Parameters:
 * - retryable: Function<? super Transaction, ? extends CompletableFuture<T>>
 * - e: Executor - Executor for asynchronous operations
 * 
 * Returns:
 * CompletableFuture<T> - Future completing with result
 */
<T> CompletableFuture<T> Tenant.runAsync(
    Function<? super Transaction, ? extends CompletableFuture<T>> retryable, Executor e
);

/**
 * Run read-only function with automatic retry.
 * 
 * Type Parameters:
 * - T: Return type
 * 
 * Parameters:
 * - retryable: Function<? super ReadTransaction, T> - Function to execute
 * 
 * Returns:
 * T - Result of function
 */
<T> T Tenant.read(Function<? super ReadTransaction, T> retryable);

/**
 * Run read-only function with custom executor.
 * 
 * Type Parameters:
 * - T: Return type
 * 
 * Parameters:
 * - retryable: Function<? super ReadTransaction, T> - Function to execute
 * - e: Executor - Executor for asynchronous operations
 * 
 * Returns:
 * T - Result of function
 */
<T> T Tenant.read(Function<? super ReadTransaction, T> retryable, Executor e);

/**
 * Run async read-only function with automatic retry.
 * 
 * Type Parameters:
 * - T: Return type
 * 
 * Parameters:
 * - retryable: Function<? super ReadTransaction, ? extends CompletableFuture<T>>
 * 
 * Returns:
 * CompletableFuture<T> - Future completing with result
 */
<T> CompletableFuture<T> Tenant.readAsync(
    Function<? super ReadTransaction, ? extends CompletableFuture<T>> retryable
);

/**
 * Run async read-only function with custom executor.
 * 
 * Type Parameters:
 * - T: Return type
 * 
 * Parameters:
 * - retryable: Function<? super ReadTransaction, ? extends CompletableFuture<T>>
 * - e: Executor - Executor for asynchronous operations
 * 
 * Returns:
 * CompletableFuture<T> - Future completing with result
 */
<T> CompletableFuture<T> Tenant.readAsync(
    Function<? super ReadTransaction, ? extends CompletableFuture<T>> retryable, Executor e
);

/**
 * Get tenant name as byte array.
 *
 * Returns:
 * byte[] - Tenant name
 */
byte[] Tenant.getName();

/**
 * Get unique tenant ID assigned by FDB using default executor.
 *
 * Returns:
 * CompletableFuture<Long> - Tenant ID
 */
CompletableFuture<Long> Tenant.getId();

/**
 * Get unique tenant ID assigned by FDB with custom executor.
 *
 * Parameters:
 * - e: Executor - Executor for asynchronous operation
 *
 * Returns:
 * CompletableFuture<Long> - Tenant ID
 */
CompletableFuture<Long> Tenant.getId(Executor e);

/**
 * Close tenant and release resources.
 */
void Tenant.close();

Usage examples:

// Execute transaction in tenant
Tenant tenant = db.openTenant("user_1001".getBytes());

tenant.run(tr -> {
    tr.set("profile".getBytes(), "user data".getBytes());
    tr.set("settings".getBytes(), "preferences".getBytes());
    return null;
});

// Read from tenant
String profile = tenant.read(tr -> {
    byte[] value = tr.get("profile".getBytes()).join();
    return value != null ? new String(value) : null;
});

// Get tenant information
byte[] name = tenant.getName();
long id = tenant.getId(tenant.getExecutor()).join();
System.out.println("Tenant " + new String(name) + " has ID: " + id);

// Async tenant operations
tenant.runAsync(tr -> {
    return tr.get("key".getBytes())
        .thenCompose(value -> {
            if (value != null) {
                tr.set("key_copy".getBytes(), value);
            }
            return CompletableFuture.completedFuture(null);
        });
}).join();

Tenant Blob Granule Operations

Manage blob storage for tenants (similar to Database operations).

/**
 * Mark tenant range for blobbification using default executor.
 *
 * Parameters:
 * - beginKey: byte[] - Start of range (inclusive)
 * - endKey: byte[] - End of range (exclusive)
 *
 * Returns:
 * CompletableFuture<Boolean> - True if operation succeeded
 */
CompletableFuture<Boolean> Tenant.blobbifyRange(byte[] beginKey, byte[] endKey);

/**
 * Mark tenant range for blobbification.
 *
 * Parameters:
 * - beginKey: byte[] - Start of range (inclusive)
 * - endKey: byte[] - End of range (exclusive)
 * - e: Executor - Executor for asynchronous operation
 *
 * Returns:
 * CompletableFuture<Boolean> - True if operation succeeded
 */
CompletableFuture<Boolean> Tenant.blobbifyRange(byte[] beginKey, byte[] endKey, Executor e);

/**
 * Mark tenant range for blobbification and wait for completion (blocking) using default executor.
 *
 * Parameters:
 * - beginKey: byte[] - Start of range (inclusive)
 * - endKey: byte[] - End of range (exclusive)
 *
 * Returns:
 * CompletableFuture<Boolean> - True if operation succeeded
 */
CompletableFuture<Boolean> Tenant.blobbifyRangeBlocking(byte[] beginKey, byte[] endKey);

/**
 * Mark tenant range for blobbification and wait for completion (blocking).
 *
 * Parameters:
 * - beginKey: byte[] - Start of range (inclusive)
 * - endKey: byte[] - End of range (exclusive)
 * - e: Executor - Executor for asynchronous operation
 *
 * Returns:
 * CompletableFuture<Boolean> - True if operation succeeded
 */
CompletableFuture<Boolean> Tenant.blobbifyRangeBlocking(byte[] beginKey, byte[] endKey, Executor e);

/**
 * Remove blobbification from tenant range using default executor.
 *
 * Parameters:
 * - beginKey: byte[] - Start of range (inclusive)
 * - endKey: byte[] - End of range (exclusive)
 *
 * Returns:
 * CompletableFuture<Boolean> - True if operation succeeded
 */
CompletableFuture<Boolean> Tenant.unblobbifyRange(byte[] beginKey, byte[] endKey);

/**
 * Remove blobbification from tenant range.
 *
 * Parameters:
 * - beginKey: byte[] - Start of range (inclusive)
 * - endKey: byte[] - End of range (exclusive)
 * - e: Executor - Executor for asynchronous operation
 *
 * Returns:
 * CompletableFuture<Boolean> - True if operation succeeded
 */
CompletableFuture<Boolean> Tenant.unblobbifyRange(byte[] beginKey, byte[] endKey, Executor e);

/**
 * List blobbified ranges in tenant using default executor.
 *
 * Parameters:
 * - beginKey: byte[] - Start of query range (inclusive)
 * - endKey: byte[] - End of query range (exclusive)
 * - rangeLimit: int - Maximum number of ranges to return
 *
 * Returns:
 * CompletableFuture<KeyRangeArrayResult> - Array of blobbified ranges
 */
CompletableFuture<KeyRangeArrayResult> Tenant.listBlobbifiedRanges(
    byte[] beginKey, byte[] endKey, int rangeLimit
);

/**
 * List blobbified ranges in tenant.
 *
 * Parameters:
 * - beginKey: byte[] - Start of query range (inclusive)
 * - endKey: byte[] - End of query range (exclusive)
 * - rangeLimit: int - Maximum number of ranges to return
 * - e: Executor - Executor for asynchronous operation
 *
 * Returns:
 * CompletableFuture<KeyRangeArrayResult> - Array of blobbified ranges
 */
CompletableFuture<KeyRangeArrayResult> Tenant.listBlobbifiedRanges(
    byte[] beginKey, byte[] endKey, int rangeLimit, Executor e
);

/**
 * Purge blob granules in tenant range using default executor and default purgeVersion.
 *
 * Parameters:
 * - beginKey: byte[] - Start of range (inclusive)
 * - endKey: byte[] - End of range (exclusive)
 * - force: boolean - Force purge even if data might be needed
 *
 * Returns:
 * CompletableFuture<byte[]> - Purge key for tracking completion
 */
CompletableFuture<byte[]> Tenant.purgeBlobGranules(byte[] beginKey, byte[] endKey, boolean force);

/**
 * Purge blob granules in tenant range using default executor.
 *
 * Parameters:
 * - beginKey: byte[] - Start of range (inclusive)
 * - endKey: byte[] - End of range (exclusive)
 * - purgeVersion: long - Version up to which to purge (-2 for default)
 * - force: boolean - Force purge even if data might be needed
 *
 * Returns:
 * CompletableFuture<byte[]> - Purge key for tracking completion
 */
CompletableFuture<byte[]> Tenant.purgeBlobGranules(
    byte[] beginKey, byte[] endKey, long purgeVersion, boolean force
);

/**
 * Purge blob granules in tenant range.
 *
 * Parameters:
 * - beginKey: byte[] - Start of range (inclusive)
 * - endKey: byte[] - End of range (exclusive)
 * - purgeVersion: long - Version up to which to purge (-2 for default)
 * - force: boolean - Force purge even if data might be needed
 * - e: Executor - Executor for asynchronous operation
 *
 * Returns:
 * CompletableFuture<byte[]> - Purge key for tracking completion
 */
CompletableFuture<byte[]> Tenant.purgeBlobGranules(
    byte[] beginKey, byte[] endKey, long purgeVersion, boolean force, Executor e
);

/**
 * Wait for tenant purge operation to complete using default executor.
 *
 * Parameters:
 * - purgeKey: byte[] - Key returned from purgeBlobGranules
 *
 * Returns:
 * CompletableFuture<Void> - Completes when purge is done
 */
CompletableFuture<Void> Tenant.waitPurgeGranulesComplete(byte[] purgeKey);

/**
 * Wait for tenant purge operation to complete.
 *
 * Parameters:
 * - purgeKey: byte[] - Key returned from purgeBlobGranules
 * - e: Executor - Executor for asynchronous operation
 *
 * Returns:
 * CompletableFuture<Void> - Completes when purge is done
 */
CompletableFuture<Void> Tenant.waitPurgeGranulesComplete(byte[] purgeKey, Executor e);

/**
 * Verify tenant blob range integrity using default executor at latest version.
 *
 * Parameters:
 * - beginKey: byte[] - Start of range (inclusive)
 * - endKey: byte[] - End of range (exclusive)
 *
 * Returns:
 * CompletableFuture<Long> - Version verified, or error code
 */
CompletableFuture<Long> Tenant.verifyBlobRange(byte[] beginKey, byte[] endKey);

/**
 * Verify tenant blob range integrity at specific version using default executor.
 *
 * Parameters:
 * - beginKey: byte[] - Start of range (inclusive)
 * - endKey: byte[] - End of range (exclusive)
 * - version: long - Database version to verify at (-2 for latest)
 *
 * Returns:
 * CompletableFuture<Long> - Version verified, or error code
 */
CompletableFuture<Long> Tenant.verifyBlobRange(byte[] beginKey, byte[] endKey, long version);

/**
 * Verify tenant blob range integrity.
 *
 * Parameters:
 * - beginKey: byte[] - Start of range (inclusive)
 * - endKey: byte[] - End of range (exclusive)
 * - version: long - Database version to verify at (-2 for latest)
 * - e: Executor - Executor for asynchronous operation
 *
 * Returns:
 * CompletableFuture<Long> - Version verified, or error code
 */
CompletableFuture<Long> Tenant.verifyBlobRange(
    byte[] beginKey, byte[] endKey, long version, Executor e
);

/**
 * Flush tenant blob range to storage using default executor at latest version.
 *
 * Parameters:
 * - beginKey: byte[] - Start of range (inclusive)
 * - endKey: byte[] - End of range (exclusive)
 * - compact: boolean - Whether to compact after flushing
 *
 * Returns:
 * CompletableFuture<Boolean> - True if flush succeeded
 */
CompletableFuture<Boolean> Tenant.flushBlobRange(byte[] beginKey, byte[] endKey, boolean compact);

/**
 * Flush tenant blob range to storage at specific version using default executor.
 *
 * Parameters:
 * - beginKey: byte[] - Start of range (inclusive)
 * - endKey: byte[] - End of range (exclusive)
 * - compact: boolean - Whether to compact after flushing
 * - version: long - Database version to flush to (-2 for latest)
 *
 * Returns:
 * CompletableFuture<Boolean> - True if flush succeeded
 */
CompletableFuture<Boolean> Tenant.flushBlobRange(
    byte[] beginKey, byte[] endKey, boolean compact, long version
);

/**
 * Flush tenant blob range to storage.
 *
 * Parameters:
 * - beginKey: byte[] - Start of range (inclusive)
 * - endKey: byte[] - End of range (exclusive)
 * - compact: boolean - Whether to compact after flushing
 * - version: long - Database version to flush to (-2 for latest)
 * - e: Executor - Executor for asynchronous operation
 *
 * Returns:
 * CompletableFuture<Boolean> - True if flush succeeded
 */
CompletableFuture<Boolean> Tenant.flushBlobRange(
    byte[] beginKey, byte[] endKey, boolean compact, long version, Executor e
);

Types

interface Tenant extends AutoCloseable, TransactionContext {
    // All methods documented above
}

class TenantManagement {
    // All static methods documented above
}

Important Notes

Tenant Existence

  • Opening a tenant does not validate its existence
  • Errors occur when attempting operations on non-existent tenant
  • createTenant succeeds if tenant already exists (idempotent)
  • deleteTenant succeeds if tenant doesn't exist (idempotent)

Tenant Deletion

  • Tenant must be empty before deletion
  • Deletion fails if tenant contains any data
  • Clear all tenant data before calling deleteTenant
  • Use transaction with tenant to clear data

Tenant Isolation

  • Tenants provide complete key-space isolation
  • Keys in one tenant are invisible to other tenants
  • Transactions on tenant cannot access other tenant data
  • System key access does not cross tenant boundaries

Tenant Naming

  • Tenant names are byte arrays
  • Tuple.pack() useful for structured tenant names
  • Tenant names should be unique within database
  • No restrictions on tenant name format

Multi-Tenancy Best Practices

  • Create tenants during application provisioning
  • Reuse Tenant objects for same tenant
  • Always close Tenant objects when done
  • Use listTenants for administrative operations