fix(vfs): prevent race condition in bulkWrite by ordering operations

- Process mkdir operations sequentially first (sorted by path depth)
- Then process write/delete/update operations in parallel batches
- Prevents duplicate directory entities when mkdir and write for
  related paths are in the same batch
- Add comprehensive tests for bulkWrite race condition scenarios
- Update API documentation for accuracy

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
David Snelling 2025-12-11 13:26:07 -08:00
parent ec6fe0c039
commit c8eb813a15
7 changed files with 906 additions and 340 deletions

View file

@ -13,7 +13,7 @@ The main VFS class (`src/vfs/VirtualFileSystem.ts`) provides all filesystem oper
```javascript
const brain = new Brainy({ storage: { type: 'memory' } })
await brain.init()
const vfs = brain.vfs()
const vfs = brain.vfs
await vfs.init()
```
@ -366,31 +366,90 @@ VFS scales to millions of files:
All VFS methods are available immediately after initialization:
```javascript
const vfs = brain.vfs()
const vfs = brain.vfs
await vfs.init()
// Core file operations
await vfs.writeFile() // Write files
await vfs.readFile() // Read files
await vfs.appendFile() // Append to files
await vfs.mkdir() // Create directories
await vfs.readdir() // List directory contents
await vfs.rmdir() // Remove directories
await vfs.stat() // Get file metadata
await vfs.exists() // Check if path exists
await vfs.unlink() // Delete files
// Path operations
await vfs.copy() // Copy files/directories
await vfs.move() // Move files/directories
await vfs.rename() // Rename files/directories
await vfs.chmod() // Change permissions
await vfs.chown() // Change ownership
// Symlinks
await vfs.symlink() // Create symbolic link
await vfs.readlink() // Read symlink target
await vfs.realpath() // Resolve symlink to real path
// Semantic features
await vfs.search() // Semantic search
await vfs.findSimilar() // Find similar files
await vfs.addRelationship()// Add relationships
// Todo management
// Todo & metadata management
await vfs.addTodo() // Add todos
await vfs.getTodos() // Get todos
await vfs.setTodos() // Set all todos
await vfs.setMetadata() // Set metadata
await vfs.getMetadata() // Get metadata
// Export
await vfs.exportToJSON() // Export to JSON
await vfs.bulkWrite() // Bulk operations
// Tree operations
await vfs.getTreeStructure() // Get tree structure
await vfs.getDirectChildren() // Get direct children
// Bulk operations
await vfs.bulkWrite() // Bulk write operations
// Import
await vfs.importFile() // Import file from filesystem
await vfs.importDirectory()// Import directory from filesystem
```
## Bulk Write Operations
**v6.5.0**: `bulkWrite` efficiently processes multiple VFS operations with automatic ordering to prevent race conditions.
```javascript
const result = await vfs.bulkWrite([
{ type: 'mkdir', path: '/project/src' },
{ type: 'mkdir', path: '/project/tests' },
{ type: 'write', path: '/project/src/index.ts', data: '// main file' },
{ type: 'write', path: '/project/package.json', data: '{}' },
{ type: 'delete', path: '/old-file.txt' },
{ type: 'update', path: '/config.json', options: { metadata: { updated: true } } }
])
console.log(`Successful: ${result.successful}, Failed: ${result.failed.length}`)
```
**Supported operation types:**
- `mkdir` - Create directory (with optional `options: { recursive: true }`)
- `write` - Write file content
- `delete` - Delete file
- `update` - Update file metadata only
**Operation ordering (v6.5.0):**
1. `mkdir` operations run **first**, sequentially, sorted by path depth (shallowest first)
2. Other operations (`write`, `delete`, `update`) run **after** in parallel batches of 10
This ordering prevents race conditions where file writes might fail because parent directories haven't been created yet.
**Error handling:**
- Operations continue on individual failures
- Failed operations are recorded in `result.failed` with error details
- Use `recursive: true` on mkdir to make them idempotent
## Complete Example
```javascript
@ -404,7 +463,7 @@ async function vfsExample() {
})
await brain.init()
const vfs = brain.vfs()
const vfs = brain.vfs
await vfs.init()
// Create project structure