Hierarchical namespace management mapping human-readable paths to efficient binary prefixes. The directory layer provides a file-system-like organization of the keyspace.
Create directory layer and directory subspaces.
/**
* Create default directory layer.
* Uses default subspaces for node and content storage.
*/
class DirectoryLayer implements Directory {
DirectoryLayer();
}
/**
* Create directory layer with custom subspaces.
*
* Parameters:
* - nodeSubspace: Subspace - Subspace for directory metadata storage
* - contentSubspace: Subspace - Subspace for directory prefix allocation
*/
class DirectoryLayer implements Directory {
DirectoryLayer(Subspace nodeSubspace, Subspace contentSubspace);
}Usage examples:
import com.apple.foundationdb.directory.*;
import com.apple.foundationdb.subspace.Subspace;
import java.util.Arrays;
import java.util.List;
// Default directory layer
DirectoryLayer rootDir = new DirectoryLayer();
// Custom directory layer with specific subspaces
Subspace nodeSpace = new Subspace(Tuple.from("dir", "nodes"));
Subspace contentSpace = new Subspace(Tuple.from("dir", "content"));
DirectoryLayer customDir = new DirectoryLayer(nodeSpace, contentSpace);
// Access global default instance
DirectoryLayer dir = DirectoryLayer.getDefault();Create directory subspaces at specified paths.
/**
* Create or open directory at path.
* Creates directory if it doesn't exist, opens if it does.
*
* Parameters:
* - tcx: TransactionContext - Context for transaction execution
* - subpath: List<String> - Path segments for directory
*
* Returns:
* CompletableFuture<DirectorySubspace> - Directory subspace at path
*/
CompletableFuture<DirectorySubspace> Directory.createOrOpen(
TransactionContext tcx, List<String> subpath
);
/**
* Create or open directory with layer check.
*
* Parameters:
* - tcx: TransactionContext - Context for transaction execution
* - subpath: List<String> - Path segments for directory
* - layer: byte[] - Expected layer metadata
*
* Returns:
* CompletableFuture<DirectorySubspace> - Directory subspace at path
*
* Throws:
* MismatchedLayerException - If directory exists with different layer
*/
CompletableFuture<DirectorySubspace> Directory.createOrOpen(
TransactionContext tcx, List<String> subpath, byte[] layer
);
/**
* Create new directory at path.
* Fails if directory already exists.
*
* Parameters:
* - tcx: TransactionContext - Context for transaction execution
* - subpath: List<String> - Path segments for directory
*
* Returns:
* CompletableFuture<DirectorySubspace> - New directory subspace
*
* Throws:
* DirectoryAlreadyExistsException - If directory exists
*/
CompletableFuture<DirectorySubspace> Directory.create(
TransactionContext tcx, List<String> subpath
);
/**
* Create new directory with layer metadata.
*
* Parameters:
* - tcx: TransactionContext - Context for transaction execution
* - subpath: List<String> - Path segments for directory
* - layer: byte[] - Layer metadata for directory
*
* Returns:
* CompletableFuture<DirectorySubspace> - New directory subspace
*/
CompletableFuture<DirectorySubspace> Directory.create(
TransactionContext tcx, List<String> subpath, byte[] layer
);
/**
* Create new directory with custom prefix.
* Allows specifying both layer metadata and prefix instead of auto-allocation.
*
* Parameters:
* - tcx: TransactionContext - Context for transaction execution
* - subpath: List<String> - Path segments for directory
* - layer: byte[] - Layer metadata for directory
* - prefix: byte[] - Custom prefix for directory (null for auto-allocation)
*
* Returns:
* CompletableFuture<DirectorySubspace> - New directory subspace
*
* Throws:
* DirectoryAlreadyExistsException - If directory exists
*/
CompletableFuture<DirectorySubspace> Directory.create(
TransactionContext tcx, List<String> subpath, byte[] layer, byte[] prefix
);
/**
* Get the DirectoryLayer that was used to create this Directory.
*
* Returns:
* DirectoryLayer - Parent directory layer instance
*/
DirectoryLayer Directory.getDirectoryLayer();Usage examples:
DirectoryLayer dir = new DirectoryLayer();
// Create or open directory (idempotent)
DirectorySubspace appDir = dir.createOrOpen(
db,
Arrays.asList("myapp", "users")
).join();
// Create with layer metadata
byte[] layer = "user_data".getBytes();
DirectorySubspace userDir = dir.createOrOpen(
db,
Arrays.asList("myapp", "users"),
layer
).join();
// Create new directory (fails if exists)
try {
DirectorySubspace configDir = dir.create(
db,
Arrays.asList("myapp", "config")
).join();
} catch (DirectoryAlreadyExistsException e) {
System.out.println("Directory already exists");
}
// Use directory subspace as key prefix
db.run(tr -> {
byte[] key = appDir.pack(Tuple.from("user123", "profile"));
tr.set(key, "user data".getBytes());
return null;
});Open existing directories.
/**
* Open existing directory at path.
* Fails if directory doesn't exist.
*
* Parameters:
* - tcx: ReadTransactionContext - Context for read transaction
* - subpath: List<String> - Path segments for directory
*
* Returns:
* CompletableFuture<DirectorySubspace> - Directory subspace at path
*
* Throws:
* NoSuchDirectoryException - If directory doesn't exist
*/
CompletableFuture<DirectorySubspace> Directory.open(
ReadTransactionContext tcx, List<String> subpath
);
/**
* Open existing directory with layer check.
*
* Parameters:
* - tcx: ReadTransactionContext - Context for read transaction
* - subpath: List<String> - Path segments for directory
* - layer: byte[] - Expected layer metadata
*
* Returns:
* CompletableFuture<DirectorySubspace> - Directory subspace at path
*
* Throws:
* NoSuchDirectoryException - If directory doesn't exist
* MismatchedLayerException - If layer doesn't match
*/
CompletableFuture<DirectorySubspace> Directory.open(
ReadTransactionContext tcx, List<String> subpath, byte[] layer
);Usage examples:
// Open existing directory
try {
DirectorySubspace dir = rootDir.open(
db,
Arrays.asList("myapp", "users")
).join();
} catch (NoSuchDirectoryException e) {
System.out.println("Directory not found");
}
// Open with layer verification
byte[] expectedLayer = "user_data".getBytes();
try {
DirectorySubspace dir = rootDir.open(
db,
Arrays.asList("myapp", "users"),
expectedLayer
).join();
} catch (MismatchedLayerException e) {
System.out.println("Layer mismatch: " + e.getMessage());
}Check existence and list subdirectories.
/**
* Check if directory exists at path.
*
* Parameters:
* - tcx: ReadTransactionContext - Context for read transaction
* - subpath: List<String> - Path segments for directory
*
* Returns:
* CompletableFuture<Boolean> - True if directory exists
*/
CompletableFuture<Boolean> Directory.exists(
ReadTransactionContext tcx, List<String> subpath
);
/**
* List immediate subdirectories at path.
*
* Parameters:
* - tcx: ReadTransactionContext - Context for read transaction
* - subpath: List<String> - Path segments for directory (empty for root)
*
* Returns:
* CompletableFuture<List<String>> - List of subdirectory names
*/
CompletableFuture<List<String>> Directory.list(
ReadTransactionContext tcx, List<String> subpath
);Usage examples:
// Check if directory exists
boolean exists = rootDir.exists(
db,
Arrays.asList("myapp", "users")
).join();
if (exists) {
System.out.println("Directory exists");
}
// List subdirectories
List<String> subdirs = rootDir.list(
db,
Arrays.asList("myapp")
).join();
for (String name : subdirs) {
System.out.println("Subdirectory: " + name);
}
// List root-level directories
List<String> rootDirs = rootDir.list(
db,
Arrays.asList() // Empty path for root
).join();Move and remove directories.
/**
* Move directory from old path to new path.
*
* Parameters:
* - tcx: TransactionContext - Context for transaction execution
* - oldPath: List<String> - Current path of directory
* - newPath: List<String> - New path for directory
*
* Returns:
* CompletableFuture<DirectorySubspace> - Directory at new location
*
* Throws:
* DirectoryMoveException - If move is invalid or fails
*/
CompletableFuture<DirectorySubspace> Directory.move(
TransactionContext tcx, List<String> oldPath, List<String> newPath
);
/**
* Move this directory to new absolute path.
*
* Parameters:
* - tcx: TransactionContext - Context for transaction execution
* - newAbsolutePath: List<String> - New absolute path
*
* Returns:
* CompletableFuture<DirectorySubspace> - Directory at new location
*/
CompletableFuture<DirectorySubspace> Directory.moveTo(
TransactionContext tcx, List<String> newAbsolutePath
);
/**
* Remove directory at path.
* Directory must be empty or removeIfExists must handle non-empty.
*
* Parameters:
* - tcx: TransactionContext - Context for transaction execution
* - subpath: List<String> - Path of directory to remove
*
* Returns:
* CompletableFuture<Void> - Completes when directory is removed
*
* Throws:
* NoSuchDirectoryException - If directory doesn't exist
*/
CompletableFuture<Void> Directory.remove(
TransactionContext tcx, List<String> subpath
);
/**
* Remove directory if it exists.
*
* Parameters:
* - tcx: TransactionContext - Context for transaction execution
* - subpath: List<String> - Path of directory to remove
*
* Returns:
* CompletableFuture<Boolean> - True if directory was removed, false if didn't exist
*/
CompletableFuture<Boolean> Directory.removeIfExists(
TransactionContext tcx, List<String> subpath
);Usage examples:
// Move directory
rootDir.move(
db,
Arrays.asList("myapp", "old_users"),
Arrays.asList("myapp", "users")
).join();
// Move using moveTo
DirectorySubspace dir = rootDir.open(
db,
Arrays.asList("temp", "data")
).join();
dir.moveTo(db, Arrays.asList("archive", "data")).join();
// Remove directory
try {
rootDir.remove(db, Arrays.asList("myapp", "temp")).join();
System.out.println("Directory removed");
} catch (NoSuchDirectoryException e) {
System.out.println("Directory not found");
}
// Remove if exists (no exception)
boolean removed = rootDir.removeIfExists(
db,
Arrays.asList("myapp", "cache")
).join();
System.out.println(removed ? "Removed" : "Didn't exist");Query directory metadata.
/**
* Get directory path as list of names.
*
* Returns:
* List<String> - Path segments for this directory
*/
List<String> Directory.getPath();
/**
* Get layer metadata for directory.
*
* Returns:
* byte[] - Layer byte string
*/
byte[] Directory.getLayer();
/**
* Get parent directory layer.
*
* Returns:
* DirectoryLayer - Parent directory layer instance
*/
DirectoryLayer Directory.getDirectoryLayer();Usage examples:
DirectorySubspace dir = rootDir.open(
db,
Arrays.asList("myapp", "users", "profiles")
).join();
// Get path
List<String> path = dir.getPath();
// ["myapp", "users", "profiles"]
// Get layer
byte[] layer = dir.getLayer();
String layerStr = new String(layer);
// Get directory layer
DirectoryLayer parentLayer = dir.getDirectoryLayer();DirectorySubspace combines Directory and Subspace functionality, inheriting all Subspace methods for key packing, unpacking, and range operations.
Usage examples:
DirectorySubspace dir = rootDir.createOrOpen(
db,
Arrays.asList("myapp", "users")
).join();
// Use as Subspace for key packing
byte[] key1 = dir.pack(Tuple.from("user123"));
byte[] key2 = dir.pack(Tuple.from("user456", "profile"));
db.run(tr -> {
tr.set(key1, "user data".getBytes());
tr.set(key2, "profile data".getBytes());
return null;
});
// Use directory range
Range dirRange = dir.range();
db.read(tr -> {
for (KeyValue kv : tr.getRange(dirRange)) {
Tuple key = dir.unpack(kv.getKey());
// Process keys in this directory
}
return null;
});interface Directory {
// All methods documented above
}
class DirectoryLayer implements Directory {
DirectoryLayer();
DirectoryLayer(Subspace nodeSubspace, Subspace contentSubspace);
static DirectoryLayer getDefault();
}
class DirectorySubspace extends Subspace implements Directory {
// Inherits all Subspace methods (pack, unpack, range, etc.)
// Implements all Directory methods
}
class DirectoryPartition extends DirectorySubspace {
// Partition implementation for isolated directory trees
}/**
* Base exception for directory layer operations.
* Contains path that caused the error.
*/
class DirectoryException extends RuntimeException {
public final List<String> path;
DirectoryException(String message, List<String> path);
String getMessage();
List<String> getPath();
}
/**
* Thrown when attempting to create directory that already exists.
* Only thrown by create() method, not createOrOpen().
*/
class DirectoryAlreadyExistsException extends DirectoryException {
DirectoryAlreadyExistsException(List<String> path);
}
/**
* Thrown when directory doesn't exist.
* Thrown by open(), move(), and remove() when directory not found.
*/
class NoSuchDirectoryException extends DirectoryException {
NoSuchDirectoryException(List<String> path);
}
/**
* Thrown when directory's layer doesn't match expected value.
* Occurs when opening directory with different layer than stored.
*/
class MismatchedLayerException extends DirectoryException {
public final byte[] stored;
public final byte[] expected;
MismatchedLayerException(List<String> path, byte[] stored, byte[] expected);
}
/**
* Thrown when directory move operation fails.
* Occurs when moving to invalid location or when destination exists.
*/
class DirectoryMoveException extends RuntimeException {
public final List<String> sourcePath;
public final List<String> destinationPath;
DirectoryMoveException(String message, List<String> sourcePath, List<String> destinationPath);
}
/**
* Thrown for directory layer version incompatibilities.
* Occurs when directory metadata format is incompatible.
*/
class DirectoryVersionException extends RuntimeException {
DirectoryVersionException(String message);
String getMessage();
}