Skip to content

Conversation

@1amageek
Copy link

@1amageek 1amageek commented Nov 7, 2025

Summary

This PR adds a complete implementation of the FoundationDB Directory Layer to the Swift bindings, bringing feature parity with Python, Java, and Go official bindings.

Dependencies

⚠️ This PR depends on #16 (Versionstamp and Subspace support)

What is Directory Layer?

The Directory Layer is a standard component in all major FoundationDB language bindings:

Language Status
Python fdb.directory
Java com.apple.foundationdb.directory
Go fdb/directory package
Swift ❌ Missing (this PR adds it)

Purpose:

  • Provides hierarchical path-based namespace management
  • Maps human-readable paths to short binary prefixes
  • Enables efficient directory moves (metadata-only operation)
  • Automatic prefix allocation prevents key conflicts

Use Cases:

  • Multi-tenant applications (each tenant gets isolated partition)
  • Hierarchical data organization (users/orders/products)
  • Safe key space partitioning

Implementation

New Files:

  • Sources/FoundationDB/Directory/DirectoryLayer.swift - Core directory management system
  • Sources/FoundationDB/Directory/DirectorySubspace.swift - Directory result container
  • Sources/FoundationDB/Directory/DirectoryError.swift - Directory-specific errors
  • Sources/FoundationDB/Directory/DirectoryVersion.swift - Version metadata
  • Sources/FoundationDB/Directory/HighContentionAllocator.swift - Automatic prefix allocation

Features:

  • ✅ Hierarchical path management (similar to file system)
  • ✅ Automatic prefix allocation with High Contention Allocator
  • ✅ Partition support for isolated namespaces
  • ✅ Custom layer type support
  • ✅ Move/remove operations with full metadata integrity
  • ✅ Cross-language compatible metadata structure

API Example:

let directoryLayer = DirectoryLayer(database: database)

// Create or open a directory
let userDir = try await directoryLayer.createOrOpen(path: ["users"])

// Create a partition (isolated namespace)
let tenant = try await directoryLayer.create(
    path: ["tenants", "tenant-1"],
    type: .partition
)

// Move directory (efficient metadata-only operation)
let moved = try await directoryLayer.move(
    oldPath: ["old", "path"],
    newPath: ["new", "path"]
)

// List subdirectories
let subdirs = try await directoryLayer.list(path: ["users"])

// Check existence
let exists = try await directoryLayer.exists(path: ["users", "alice"])

Design

Unified Prefix Coordinate System

The implementation uses a unified coordinate system for consistency:

  • Metadata stores: Relative prefixes (compatible with HCA allocator)
  • API returns: Absolute prefixes (contentPrefix + relativePrefix)
  • Internal conversion: resolve() converts relative → absolute when reading

This ensures compatibility with other language bindings while maintaining clean separation between storage and API layers.

Naming: "DirectoryLayer"

Consistent with official implementations:

  • Python: fdb.DirectoryLayer
  • Java: com.apple.foundationdb.directory.DirectoryLayer
  • Go: directory.NewDirectoryLayer()

"Layer" reflects that it's a complete management system built on top of Subspace/Tuple layers, following FoundationDB's layered architecture concept.

Testing

Test Coverage:

  • Tests/FoundationDBTests/DirectoryLayerTests.swift - 25 comprehensive tests:
    • ✅ Basic CRUD operations (create, open, remove)
    • ✅ Partition creation and traversal
    • ✅ Move/remove operations
    • ✅ Multi-level directory hierarchies
    • ✅ Cross-language metadata compatibility
    • ✅ Error handling (layer mismatch, prefix conflicts)
    • ✅ Data isolation between directories

Test Results:

swift test --filter DirectoryLayerTests
# Result: ✅ 25 tests passed (0.137 seconds)

Compatibility

  • ✅ Compatible with Python/Java/Go Directory Layer implementations
  • ✅ Cross-language metadata structure verified in tests
  • ✅ Follows official FoundationDB Directory Layer specification
  • ✅ No breaking changes to existing API

Documentation

The implementation follows the official FoundationDB documentation:

Checklist

This commit adds two major features to the Swift bindings:

## Versionstamp Support
- Implement 12-byte Versionstamp structure (10-byte transaction version + 2-byte user version)
- Add incomplete versionstamp support for transaction-time assignment
- Implement Tuple integration with versionstamp encoding (type code 0x33)
- Add packWithVersionstamp() for atomic operations

## Subspace Implementation
- Implement Subspace for key namespace management with tuple encoding
- Add range() method using prefix + [0x00] / prefix + [0xFF] pattern
- Implement strinc() algorithm for raw binary prefix support
- Add prefixRange() method for complete prefix coverage
- Define SubspaceError for proper error handling

## Testing
- Add VersionstampTests with 15 test cases
- Add StringIncrementTests with 14 test cases for strinc() algorithm
- Add SubspaceTests with 22 test cases covering range() and prefixRange()
- Verify cross-language compatibility with official bindings

All implementations follow the canonical behavior of official Java, Python, Go, and C++ bindings.
This commit completes the Versionstamp implementation by adding
decode support and comprehensive roundtrip tests.

## Tuple.decode() Integration
- Add versionstamp case (0x33) to Tuple.decode() switch
- Enable automatic Versionstamp decoding in tuples
- Allows reading versionstamped keys from database

## Roundtrip Tests
- Add 5 roundtrip tests (encode → decode)
  - Complete versionstamp roundtrip
  - Incomplete versionstamp roundtrip
  - Mixed tuple with multiple types
  - Multiple versionstamps in one tuple
  - Error handling for insufficient bytes

## Test Fixes
- Fix withUnsafeBytes crash by ensuring exact 4-byte array
- Add size validation before unsafe memory access
- Fix range test expectations (prefix vs prefix + [0x00])

## Code Cleanup
- Remove dead code for API < 520 (no longer supported)
- Simplify to single code path using 4-byte offsets
- Update documentation to reflect API 520+ requirement

All 150 tests now pass successfully.
… system

This commit adds a complete implementation of the FoundationDB Directory Layer,
including hierarchical namespace management, partition support, and high contention
allocation. The implementation ensures consistency between metadata storage and
API return values through a unified prefix coordinate system.

## Key Features

- **Directory Layer**: Hierarchical path-to-prefix mapping with automatic allocation
- **Partition Support**: Isolated namespaces with their own DirectoryLayer instances
- **High Contention Allocator**: Window-based allocation for efficient unique prefixes
- **Unified Prefix Coordinates**: Relative prefixes in metadata, absolute in API returns

## Core Components

### DirectoryLayer.swift (1,250 lines)
- Unified prefix coordinate system (store relative, return absolute)
- Partition-aware operations (create, open, move, list, remove)
- Automatic prefix allocation via HCA
- Manual prefix validation with conflict detection
- Cross-partition move prevention

### DirectoryError.swift (181 lines)
- Comprehensive error types with DocC documentation
- Detailed error descriptions for debugging

### DirectorySubspace.swift (205 lines)
- Lightweight wrapper combining Subspace with path and type
- Convenient key encoding/decoding methods

### HighContentionAllocator.swift (218 lines)
- Official FDB algorithm with dynamic window sizing
- Write conflict detection for concurrent allocations

### DirectoryVersion.swift (56 lines)
- Version management for metadata compatibility

## Bug Fixes

1. **Double-prefix bug**: Removed redundant partition prefix concatenation
2. **Cross-partition move**: Added explicit boundary validation
3. **Manual prefix validation**: Unified absolute/relative coordinate systems
4. **Partition list operations**: Delegate to partition layer for correct metadata lookup

## Design Decisions

### Prefix Coordinate System
- **Metadata storage**: Relative prefixes (HCA-compatible)
- **API return values**: Absolute prefixes (contentSubspace + relative)
- **Manual prefixes**: Treated as relative (same as HCA)

### Removed isInsidePartition Flag
- Replaced with rootLayer reference for cleaner design
- Partition nesting check: `rootLayer != nil`

## Testing

Comprehensive test suite with 23 tests covering:
- Basic operations (create, open, list, move, remove)
- Partition operations and traversal
- Manual prefix collision detection
- Cross-language metadata compatibility
- Deep nested directories within partitions
- Multi-level partition directories

All tests passing: 23/23 ✅
Fixes two HIGH priority bugs identified in code review:

1. move() now stores relative prefix in metadata instead of absolute
   - Prevents double-prefix on reopen
   - Ensures data remains accessible after move

2. removeInternal() now cleans up parent entry when removing partition root
   - Prevents dangling references in parent's subdirs
   - Ensures removed partition cannot be reopened

Added regression tests:
- movePrefixCorrectness: Verifies move preserves prefix through reopen
- removePartitionRootCleansUpParent: Verifies parent cleanup

Added write conflict range optimization extensions:
- setNextWriteNoWriteConflictRange(): Exclude next write from conflict checking
- addWriteConflictKey(): Add single key to write conflict range
- addWriteConflictRange(): Add key range to write conflict range

All 25 tests passing.
@vishesh
Copy link
Contributor

vishesh commented Nov 8, 2025

Thanks for the PR and putting time into this. However, I've few non-code related comments:

  1. Before taking any big task, it is always a good idea to create a GitHub issue to discuss it first. This didn't happen. It causes a bit of annoyance as (a) we may be working on it already, (b) have no agreement on design decisions, or (c) it may be something we are not interested in. This repo is relatively new, so we haven't gotten around to documenting the processes clearly, but I also don't think it’s an unreasonable expectation.

  2. The code is clearly vibe coded, which by itself I don't have any problem with. However, this also makes it much easier to create 5000 line PRs in relatively short period of time and those are quite hard to review. What I'd like to see is smaller PRs starting with simple interfaces. It also gives me confidence that AI generated code was thought through, well-tested and self-reviewed by the person creating the PR. Unfortunately, right now I don't have that confidence.

  3. AI tends to add lot of noise and verbosity in the code. Trivial comments, unnecessary unicode, irrelevant comparison with other bindings, etc etc. It's subjective, but it's lot of noise to my eyes at least. Again, being a rather new project, we don't yet have all these guidelines, but smaller PRs would help. Same goes for review responses, which also appear to be AI generated and quite verbose for what they are saying. If language is a barrier, a Translate app may be a better way to convert what you intend to say.

We still have some pending internal discussions on what Tuple layer should look like. So I don't know if I personally would like to review it right away, and definitely not in its current form. What I would suggest is starting with an issue (maybe a much smaller PR with basic interfaces), and people interested can discuss it, refine the design, guide you in the right direction, and successfully get changes merged in.

@1amageek
Copy link
Author

1amageek commented Nov 8, 2025

Thank you for the honest and constructive feedback. I understand and accept all your points.

On Process:
I apologize for not creating issues first. I will follow this process going forward.
Would it be possible to document the contribution process (issue creation, design discussion, PR size guidelines)? This would help contributors like me understand expectations clearly.

On PR Size:
Understood. I will keep PRs small (~500 lines max) and incremental.

On AI Usage:
I'm using AI assistance with guidelines documented in CLAUDE.md and AGENTS.md in my development environment. Your feedback is exactly what I need to refine these guidelines. I will update them to incorporate:

  • Your feedback here (verbosity, emojis, unnecessary comparisons)
  • Code review perspectives from @glbrntt and @MMcM
  • Swift style preferences for this project

This approach allows me to tune AI prompts consistently to match your expectations and reduce review burden.

On Project Direction:
Could you share the project's development plan or milestones? Understanding the roadmap would help me:

  • Avoid duplicating work
  • Align with internal discussions (like the Tuple layer design)
  • Contribute more effectively

Next Steps:

Thank you for maintaining quality standards. I want to contribute effectively within your process.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants