brainy/docs/technical/CONCURRENCY_ANALYSIS.md
David Snelling 79df44351c **chore: remove outdated changelog and summary documents**
- Deleted `CHANGES.md`, `CHANGES_SUMMARY.md`, `CONCURRENCY_ANALYSIS.md`, `CONCURRENCY_IMPLEMENTATION_SUMMARY.md`, and related developer documentation files.
- Removed redundant or legacy content no longer aligned with the current codebase and workflows.
- Updated repository to reflect streamlined documentation approach, reducing clutter and improving maintainability.

**Purpose**: Simplify and declutter repository by removing obsolete documentation files, ensuring it remains focused and relevant.
2025-07-30 11:51:39 -07:00

207 lines
6.8 KiB
Markdown

# Brainy Concurrency and Performance Analysis
## Issue Summary
Multiple web services are running Brainy with shared S3 storage, causing performance and contention issues in high-throughput scenarios.
## Identified Problems
### 1. Statistics Handling Issues
#### Race Conditions in Statistics Updates
- **Location**: `S3CompatibleStorage.scheduleBatchUpdate()` and `flushStatistics()`
- **Problem**: Multiple service instances update statistics independently without coordination
- **Impact**: Lost updates, inconsistent statistics, data corruption
#### Cache Inconsistency
- **Location**: `S3CompatibleStorage.statisticsCache`
- **Problem**: Each instance maintains its own statistics cache
- **Impact**: Statistics displayed by search service may be stale or incorrect
#### Timer-based Batching Issues
- **Location**: `S3CompatibleStorage.scheduleBatchUpdate()`
- **Problem**: setTimeout-based batching with no coordination between instances
- **Impact**: Statistics updates can be delayed or lost during service restarts
### 2. Index Synchronization Issues
#### Inefficient Full Scans
- **Location**: `BrainyData.checkForUpdates()`
- **Problem**: Calls `getAllNouns()` on every update check
- **Impact**: Extremely expensive for large datasets, poor scalability
#### Race Conditions in Index Updates
- **Location**: `BrainyData.checkForUpdates()` lines 438-456
- **Problem**: Multiple instances can add the same nouns simultaneously
- **Impact**: Inconsistent index state, wasted resources
#### No Distributed Locking
- **Location**: Throughout the codebase
- **Problem**: No mechanism to coordinate updates between multiple instances
- **Impact**: Data corruption, inconsistent state
### 3. Memory and Performance Issues
#### Memory Usage Tracking Race Conditions
- **Location**: `HNSWIndexOptimized.addItem()` lines 347-348
- **Problem**: `this.memoryUsage += totalMemory` and `this.vectorCount++` are not thread-safe
- **Impact**: Incorrect memory usage calculations, potential memory leaks
#### Duplicate Index Maintenance
- **Location**: Each service instance
- **Problem**: Every instance maintains a complete copy of the HNSW index
- **Impact**: Excessive memory usage, slow startup times
#### Polling-based Updates
- **Location**: `BrainyData.startRealtimeUpdates()`
- **Problem**: Uses setInterval for periodic checks instead of event-driven updates
- **Impact**: High latency, unnecessary resource usage
### 4. Storage Contention Issues
#### Concurrent S3 Writes
- **Location**: `S3CompatibleStorage.saveNode()`, `saveEdge()`, etc.
- **Problem**: No coordination for concurrent writes to the same S3 objects
- **Impact**: Data corruption, lost writes
#### No Optimistic Locking
- **Location**: All storage operations
- **Problem**: No mechanism to detect and handle concurrent modifications
- **Impact**: Last-writer-wins scenarios, data loss
## Recommended Solutions
### 1. Implement Distributed Locking
```typescript
// Add to S3CompatibleStorage
private async acquireLock(lockKey: string, ttl: number = 30000): Promise<boolean> {
const lockObject = `locks/${lockKey}`;
const lockValue = `${Date.now()}_${Math.random()}`;
try {
await this.s3Client!.send(new PutObjectCommand({
Bucket: this.bucketName,
Key: lockObject,
Body: lockValue,
ContentType: 'text/plain',
Metadata: {
'expires-at': (Date.now() + ttl).toString()
}
}));
return true;
} catch (error) {
if (error.name === 'ConditionalCheckFailedException') {
return false; // Lock already exists
}
throw error;
}
}
```
### 2. Event-Driven Index Updates
```typescript
// Add to BrainyData
private async setupEventDrivenUpdates(): Promise<void> {
// Use S3 event notifications or implement a change log
const changeLogKey = `${this.indexPrefix}change-log.json`;
// Poll change log instead of full data scan
setInterval(async () => {
const changes = await this.getChangesSince(this.lastUpdateTime);
await this.applyChanges(changes);
}, this.realtimeUpdateConfig.interval);
}
```
### 3. Optimized Statistics Handling
```typescript
// Add to S3CompatibleStorage
private async atomicStatisticsUpdate(updateFn: (stats: StatisticsData) => StatisticsData): Promise<void> {
const lockKey = 'statistics-update';
const lockAcquired = await this.acquireLock(lockKey);
if (!lockAcquired) {
// Another instance is updating, skip this update
return;
}
try {
// Read current statistics
const currentStats = await this.getStatisticsData();
// Apply update
const updatedStats = updateFn(currentStats);
// Write back with version check
await this.saveStatisticsWithVersionCheck(updatedStats);
} finally {
await this.releaseLock(lockKey);
}
}
```
### 4. Shared Index Architecture
```typescript
// New class: SharedHNSWIndex
export class SharedHNSWIndex {
private localCache: Map<string, VectorDocument> = new Map();
private lastSyncTime: number = 0;
async search(queryVector: Vector, k: number): Promise<Array<[string, number]>> {
// Ensure local cache is up to date
await this.syncIfNeeded();
// Perform search on local cache
return this.performLocalSearch(queryVector, k);
}
private async syncIfNeeded(): Promise<void> {
const now = Date.now();
if (now - this.lastSyncTime > this.syncInterval) {
await this.syncFromStorage();
this.lastSyncTime = now;
}
}
}
```
### 5. Change Log Implementation
```typescript
// Add to storage adapters
interface ChangeLogEntry {
timestamp: number;
operation: 'add' | 'update' | 'delete';
entityType: 'noun' | 'verb';
entityId: string;
data?: any;
}
private async appendToChangeLog(entry: ChangeLogEntry): Promise<void> {
const changeLogKey = `change-log/${Date.now()}-${Math.random()}.json`;
await this.s3Client!.send(new PutObjectCommand({
Bucket: this.bucketName,
Key: changeLogKey,
Body: JSON.stringify(entry),
ContentType: 'application/json'
}));
}
```
## Implementation Priority
1. **High Priority**: Implement distributed locking for statistics updates
2. **High Priority**: Add change log mechanism for efficient index synchronization
3. **Medium Priority**: Implement shared index architecture
4. **Medium Priority**: Add optimistic locking for storage operations
5. **Low Priority**: Optimize memory usage tracking
## Performance Improvements Expected
- **Statistics Updates**: 90% reduction in conflicts, near real-time updates
- **Index Synchronization**: 95% reduction in data transfer, faster updates
- **Memory Usage**: 70% reduction per service instance
- **Search Latency**: 50% improvement due to better cache locality