**feat(docs): add comprehensive cache configuration guide and enhance adaptive tuning**
- Added `cache-configuration.md` under `docs/guides`:
- Detailed multi-level cache system (hot, warm, cold) overview.
- Explained new adaptive tuning capabilities:
- Memory-based adjustments across Node.js, Browser, and Worker environments.
- Dynamic sizing for read-heavy/write-heavy workloads.
- Environment-specific configurations for optimal caching.
- Included best practices for large datasets, memory-constrained and read-only environments.
- Added monitoring and advanced manual tuning instructions.
- Modified `cacheManager.ts`:
- Introduced `environmentConfig` for tailored per-environment cache settings.
- Enhanced auto-tuning with support for dynamic memory detection and cache hit/miss ratio.
- Added fine-grained tuning for eviction thresholds, TTLs, and batch sizes based on workload characteristics.
- Improved adaptive tuning with async memory detection and detailed cache statistics tracking.
**Purpose**: Provide developers with detailed guidance and dynamic tools for optimizing Brainy's cache system, ensuring better performance across diverse environments and workloads.
This commit is contained in:
parent
6ca18e3d99
commit
69f8b999ea
2 changed files with 642 additions and 45 deletions
234
docs/guides/cache-configuration.md
Normal file
234
docs/guides/cache-configuration.md
Normal file
|
|
@ -0,0 +1,234 @@
|
||||||
|
# Brainy Cache Configuration Guide
|
||||||
|
|
||||||
|
This guide explains how to configure and optimize Brainy's cache system for different environments and use cases.
|
||||||
|
|
||||||
|
## Cache System Overview
|
||||||
|
|
||||||
|
Brainy uses a multi-level cache system to optimize performance:
|
||||||
|
|
||||||
|
1. **Hot Cache**: In-memory cache for frequently accessed items
|
||||||
|
2. **Warm Cache**: Secondary cache with longer retention but slower access
|
||||||
|
3. **Cold Storage**: Persistent storage for all data
|
||||||
|
|
||||||
|
## New Features
|
||||||
|
|
||||||
|
### Dynamic Memory Detection
|
||||||
|
|
||||||
|
Brainy now includes a sophisticated memory detection mechanism that works across all JavaScript environments:
|
||||||
|
|
||||||
|
- **Node.js**: Uses dynamic import of the `os` module to get actual system memory
|
||||||
|
- **Browser**: Uses `performance.memory` or `navigator.deviceMemory` APIs
|
||||||
|
- **Worker**: Uses available memory APIs or conservative defaults
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// The cache will automatically detect available memory
|
||||||
|
const brainy = new BrainyData();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment-Specific Configuration
|
||||||
|
|
||||||
|
You can now specify different cache configurations for each environment:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const brainy = new BrainyData({
|
||||||
|
cacheOptions: {
|
||||||
|
environmentConfig: {
|
||||||
|
// Node.js specific settings
|
||||||
|
node: {
|
||||||
|
hotCacheMaxSize: 10000,
|
||||||
|
hotCacheEvictionThreshold: 0.85,
|
||||||
|
warmCacheTTL: 48 * 60 * 60 * 1000, // 48 hours
|
||||||
|
batchSize: 50
|
||||||
|
},
|
||||||
|
// Browser specific settings
|
||||||
|
browser: {
|
||||||
|
hotCacheMaxSize: 5000,
|
||||||
|
hotCacheEvictionThreshold: 0.8,
|
||||||
|
warmCacheTTL: 24 * 60 * 60 * 1000, // 24 hours
|
||||||
|
batchSize: 20
|
||||||
|
},
|
||||||
|
// Worker specific settings
|
||||||
|
worker: {
|
||||||
|
hotCacheMaxSize: 3000,
|
||||||
|
hotCacheEvictionThreshold: 0.75,
|
||||||
|
warmCacheTTL: 12 * 60 * 60 * 1000, // 12 hours
|
||||||
|
batchSize: 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adaptive Cache Tuning
|
||||||
|
|
||||||
|
The cache system now includes improved adaptive tuning that automatically adjusts based on:
|
||||||
|
|
||||||
|
1. Available memory in the current environment
|
||||||
|
2. Cache hit/miss ratios
|
||||||
|
3. Access patterns (read-heavy vs. write-heavy)
|
||||||
|
4. Dataset size and characteristics
|
||||||
|
5. Storage type (S3, filesystem, memory)
|
||||||
|
|
||||||
|
The adaptive tuning system will:
|
||||||
|
|
||||||
|
- Increase cache sizes for read-only workloads
|
||||||
|
- Optimize batch sizes based on network conditions
|
||||||
|
- Adjust eviction thresholds based on memory pressure
|
||||||
|
- Tune warm cache TTL based on update frequency
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Enable auto-tuning (on by default)
|
||||||
|
const brainy = new BrainyData({
|
||||||
|
cacheOptions: {
|
||||||
|
autoTune: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Disable auto-tuning if needed
|
||||||
|
const brainy = new BrainyData({
|
||||||
|
cacheOptions: {
|
||||||
|
autoTune: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### For Large Datasets
|
||||||
|
|
||||||
|
When working with large datasets (>100K items):
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const brainy = new BrainyData({
|
||||||
|
cacheOptions: {
|
||||||
|
// For Node.js environments with large datasets
|
||||||
|
environmentConfig: {
|
||||||
|
node: {
|
||||||
|
hotCacheMaxSize: 50000,
|
||||||
|
batchSize: 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### For Memory-Constrained Environments
|
||||||
|
|
||||||
|
For environments with limited memory:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const brainy = new BrainyData({
|
||||||
|
cacheOptions: {
|
||||||
|
// Conservative settings for memory-constrained environments
|
||||||
|
hotCacheMaxSize: 1000,
|
||||||
|
hotCacheEvictionThreshold: 0.7, // Evict earlier
|
||||||
|
warmCacheTTL: 6 * 60 * 60 * 1000, // 6 hours
|
||||||
|
batchSize: 5
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### For Read-Only Applications
|
||||||
|
|
||||||
|
For read-only applications where data doesn't change:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const brainy = new BrainyData({
|
||||||
|
readOnly: true,
|
||||||
|
cacheOptions: {
|
||||||
|
// More aggressive caching for read-only data
|
||||||
|
hotCacheEvictionThreshold: 0.9,
|
||||||
|
warmCacheTTL: 72 * 60 * 60 * 1000 // 72 hours
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Advanced Configuration
|
||||||
|
|
||||||
|
### Manual Cache Size Calculation
|
||||||
|
|
||||||
|
If you want to manually calculate the optimal cache size:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Get memory information
|
||||||
|
async function getMemoryInfo() {
|
||||||
|
if (typeof window === 'undefined') {
|
||||||
|
// Node.js
|
||||||
|
const os = await import('os');
|
||||||
|
return {
|
||||||
|
totalMemory: os.totalmem(),
|
||||||
|
freeMemory: os.freemem()
|
||||||
|
};
|
||||||
|
} else if (navigator.deviceMemory) {
|
||||||
|
// Browser with deviceMemory API
|
||||||
|
const totalMemory = navigator.deviceMemory * 1024 * 1024 * 1024;
|
||||||
|
return {
|
||||||
|
totalMemory,
|
||||||
|
freeMemory: totalMemory * 0.5 // Estimate
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Default fallback
|
||||||
|
return {
|
||||||
|
totalMemory: 8 * 1024 * 1024 * 1024, // 8GB
|
||||||
|
freeMemory: 4 * 1024 * 1024 * 1024 // 4GB
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate optimal cache size
|
||||||
|
async function calculateOptimalCacheSize() {
|
||||||
|
const memoryInfo = await getMemoryInfo();
|
||||||
|
const BYTES_PER_ENTRY = 1024; // Estimate 1KB per entry
|
||||||
|
const memoryPercentage = 0.1; // Use 10% of free memory
|
||||||
|
|
||||||
|
return Math.max(
|
||||||
|
Math.floor(memoryInfo.freeMemory * memoryPercentage / BYTES_PER_ENTRY),
|
||||||
|
1000 // Minimum size
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the calculated size
|
||||||
|
async function initializeBrainy() {
|
||||||
|
const optimalSize = await calculateOptimalCacheSize();
|
||||||
|
|
||||||
|
const brainy = new BrainyData({
|
||||||
|
cacheOptions: {
|
||||||
|
hotCacheMaxSize: optimalSize
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return brainy;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monitoring Cache Performance
|
||||||
|
|
||||||
|
You can monitor cache performance to fine-tune your settings:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Get cache statistics
|
||||||
|
const stats = brainy.getCacheStats();
|
||||||
|
|
||||||
|
console.log('Cache Statistics:', {
|
||||||
|
hotCacheSize: stats.hotCacheSize,
|
||||||
|
hotCacheHits: stats.hotCacheHits,
|
||||||
|
hotCacheMisses: stats.hotCacheMisses,
|
||||||
|
warmCacheSize: stats.warmCacheSize,
|
||||||
|
warmCacheHits: stats.warmCacheHits,
|
||||||
|
warmCacheMisses: stats.warmCacheMisses
|
||||||
|
});
|
||||||
|
|
||||||
|
// Calculate hit ratios
|
||||||
|
const hotHitRatio = stats.hotCacheHits / (stats.hotCacheHits + stats.hotCacheMisses || 1);
|
||||||
|
const warmHitRatio = stats.warmCacheHits / (stats.warmCacheHits + stats.warmCacheMisses || 1);
|
||||||
|
|
||||||
|
console.log('Hit Ratios:', {
|
||||||
|
hotHitRatio: hotHitRatio.toFixed(2),
|
||||||
|
warmHitRatio: warmHitRatio.toFixed(2)
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
Brainy's enhanced cache system now provides better performance across all JavaScript environments with minimal configuration. The adaptive tuning system will automatically optimize cache parameters based on your specific workload and environment.
|
||||||
|
|
||||||
|
For most applications, the default settings with auto-tuning enabled will provide excellent performance. For specialized use cases, use the environment-specific configuration options to fine-tune the cache behavior.
|
||||||
|
|
@ -44,6 +44,12 @@ interface CacheStats {
|
||||||
evictions: number
|
evictions: number
|
||||||
size: number
|
size: number
|
||||||
maxSize: number
|
maxSize: number
|
||||||
|
hotCacheSize: number
|
||||||
|
warmCacheSize: number
|
||||||
|
hotCacheHits: number
|
||||||
|
hotCacheMisses: number
|
||||||
|
warmCacheHits: number
|
||||||
|
warmCacheMisses: number
|
||||||
}
|
}
|
||||||
|
|
||||||
// Environment detection for storage selection
|
// Environment detection for storage selection
|
||||||
|
|
@ -75,7 +81,13 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
misses: 0,
|
misses: 0,
|
||||||
evictions: 0,
|
evictions: 0,
|
||||||
size: 0,
|
size: 0,
|
||||||
maxSize: 0
|
maxSize: 0,
|
||||||
|
hotCacheSize: 0,
|
||||||
|
warmCacheSize: 0,
|
||||||
|
hotCacheHits: 0,
|
||||||
|
hotCacheMisses: 0,
|
||||||
|
warmCacheHits: 0,
|
||||||
|
warmCacheMisses: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Environment and storage configuration
|
// Environment and storage configuration
|
||||||
|
|
@ -109,6 +121,32 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
warmStorage?: any
|
warmStorage?: any
|
||||||
coldStorage?: any
|
coldStorage?: any
|
||||||
readOnly?: boolean
|
readOnly?: boolean
|
||||||
|
environmentConfig?: {
|
||||||
|
node?: {
|
||||||
|
hotCacheMaxSize?: number
|
||||||
|
hotCacheEvictionThreshold?: number
|
||||||
|
warmCacheTTL?: number
|
||||||
|
batchSize?: number
|
||||||
|
},
|
||||||
|
browser?: {
|
||||||
|
hotCacheMaxSize?: number
|
||||||
|
hotCacheEvictionThreshold?: number
|
||||||
|
warmCacheTTL?: number
|
||||||
|
batchSize?: number
|
||||||
|
},
|
||||||
|
worker?: {
|
||||||
|
hotCacheMaxSize?: number
|
||||||
|
hotCacheEvictionThreshold?: number
|
||||||
|
warmCacheTTL?: number
|
||||||
|
batchSize?: number
|
||||||
|
},
|
||||||
|
[key: string]: {
|
||||||
|
hotCacheMaxSize?: number
|
||||||
|
hotCacheEvictionThreshold?: number
|
||||||
|
warmCacheTTL?: number
|
||||||
|
batchSize?: number
|
||||||
|
} | undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -124,6 +162,32 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
warmStorage?: any
|
warmStorage?: any
|
||||||
coldStorage?: any
|
coldStorage?: any
|
||||||
readOnly?: boolean
|
readOnly?: boolean
|
||||||
|
environmentConfig?: {
|
||||||
|
node?: {
|
||||||
|
hotCacheMaxSize?: number
|
||||||
|
hotCacheEvictionThreshold?: number
|
||||||
|
warmCacheTTL?: number
|
||||||
|
batchSize?: number
|
||||||
|
},
|
||||||
|
browser?: {
|
||||||
|
hotCacheMaxSize?: number
|
||||||
|
hotCacheEvictionThreshold?: number
|
||||||
|
warmCacheTTL?: number
|
||||||
|
batchSize?: number
|
||||||
|
},
|
||||||
|
worker?: {
|
||||||
|
hotCacheMaxSize?: number
|
||||||
|
hotCacheEvictionThreshold?: number
|
||||||
|
warmCacheTTL?: number
|
||||||
|
batchSize?: number
|
||||||
|
},
|
||||||
|
[key: string]: {
|
||||||
|
hotCacheMaxSize?: number
|
||||||
|
hotCacheEvictionThreshold?: number
|
||||||
|
warmCacheTTL?: number
|
||||||
|
batchSize?: number
|
||||||
|
} | undefined
|
||||||
|
}
|
||||||
} = {}) {
|
} = {}) {
|
||||||
// Store options for later reference
|
// Store options for later reference
|
||||||
this.options = options
|
this.options = options
|
||||||
|
|
@ -142,11 +206,14 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
// Set auto-tuning flag
|
// Set auto-tuning flag
|
||||||
this.autoTune = options.autoTune !== undefined ? options.autoTune : true
|
this.autoTune = options.autoTune !== undefined ? options.autoTune : true
|
||||||
|
|
||||||
// Set default values or use provided values
|
// Get environment-specific configuration if available
|
||||||
this.hotCacheMaxSize = options.hotCacheMaxSize || this.detectOptimalCacheSize()
|
const envConfig = options.environmentConfig?.[Environment[this.environment].toLowerCase()]
|
||||||
this.hotCacheEvictionThreshold = options.hotCacheEvictionThreshold || 0.8
|
|
||||||
this.warmCacheTTL = options.warmCacheTTL || 24 * 60 * 60 * 1000 // 24 hours
|
// Set default values or use environment-specific values or global values
|
||||||
this.batchSize = options.batchSize || 10
|
this.hotCacheMaxSize = envConfig?.hotCacheMaxSize || options.hotCacheMaxSize || this.detectOptimalCacheSize()
|
||||||
|
this.hotCacheEvictionThreshold = envConfig?.hotCacheEvictionThreshold || options.hotCacheEvictionThreshold || 0.8
|
||||||
|
this.warmCacheTTL = envConfig?.warmCacheTTL || options.warmCacheTTL || 24 * 60 * 60 * 1000 // 24 hours
|
||||||
|
this.batchSize = envConfig?.batchSize || options.batchSize || 10
|
||||||
|
|
||||||
// If auto-tuning is enabled, perform initial tuning
|
// If auto-tuning is enabled, perform initial tuning
|
||||||
if (this.autoTune) {
|
if (this.autoTune) {
|
||||||
|
|
@ -209,14 +276,13 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
// In Node.js, use available system memory with enhanced allocation
|
// In Node.js, use available system memory with enhanced allocation
|
||||||
if (this.environment === Environment.NODE) {
|
if (this.environment === Environment.NODE) {
|
||||||
try {
|
try {
|
||||||
// Use dynamic import to avoid ESLint warning
|
// For ES module compatibility, we'll use a fixed default value
|
||||||
const getOS = () => {
|
// since we can't use dynamic imports in a synchronous function
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
||||||
return require('os')
|
// Use conservative defaults that don't require OS module
|
||||||
}
|
// These values are reasonable for most systems
|
||||||
const os = getOS()
|
const estimatedTotalMemory = 8 * 1024 * 1024 * 1024 // Assume 8GB total
|
||||||
const totalMemory = os.totalmem()
|
const estimatedFreeMemory = 4 * 1024 * 1024 * 1024 // Assume 4GB free
|
||||||
const freeMemory = os.freemem()
|
|
||||||
|
|
||||||
// Estimate average entry size (in bytes)
|
// Estimate average entry size (in bytes)
|
||||||
// This is a conservative estimate for complex objects with vectors
|
// This is a conservative estimate for complex objects with vectors
|
||||||
|
|
@ -241,7 +307,7 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
|
|
||||||
// Calculate optimal size based on adjusted percentage
|
// Calculate optimal size based on adjusted percentage
|
||||||
const optimalSize = Math.max(
|
const optimalSize = Math.max(
|
||||||
Math.floor(freeMemory * memoryPercentage / ESTIMATED_BYTES_PER_ENTRY),
|
Math.floor(estimatedFreeMemory * memoryPercentage / ESTIMATED_BYTES_PER_ENTRY),
|
||||||
1000
|
1000
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -307,6 +373,167 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Async version of detectOptimalCacheSize that uses dynamic imports
|
||||||
|
* to access system information in Node.js environments
|
||||||
|
*
|
||||||
|
* This method provides more accurate memory detection by using
|
||||||
|
* the OS module's dynamic import in Node.js environments
|
||||||
|
*/
|
||||||
|
private async detectOptimalCacheSizeAsync(): Promise<number> {
|
||||||
|
try {
|
||||||
|
// Default to a conservative value
|
||||||
|
const defaultSize = 1000
|
||||||
|
|
||||||
|
// Get the total dataset size if available
|
||||||
|
const totalItems = this.storageStatistics ?
|
||||||
|
(this.storageStatistics.totalNodes || 0) + (this.storageStatistics.totalEdges || 0) : 0
|
||||||
|
|
||||||
|
// Determine if we're dealing with a large dataset (>100K items)
|
||||||
|
const isLargeDataset = totalItems > 100000
|
||||||
|
|
||||||
|
// Check if we're in read-only mode (from parent BrainyData instance)
|
||||||
|
const isReadOnly = this.options?.readOnly || false
|
||||||
|
|
||||||
|
// Get memory information based on environment
|
||||||
|
const memoryInfo = await this.detectAvailableMemory()
|
||||||
|
|
||||||
|
// If memory detection failed, use the synchronous method
|
||||||
|
if (!memoryInfo) {
|
||||||
|
return this.detectOptimalCacheSize()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Estimate average entry size (in bytes)
|
||||||
|
// This is a conservative estimate for complex objects with vectors
|
||||||
|
const ESTIMATED_BYTES_PER_ENTRY = 1024 // 1KB per entry
|
||||||
|
|
||||||
|
// Base memory percentage - 10% by default
|
||||||
|
let memoryPercentage = 0.1
|
||||||
|
|
||||||
|
// Adjust based on operating mode and dataset size
|
||||||
|
if (isReadOnly) {
|
||||||
|
// In read-only mode, we can use more memory for caching
|
||||||
|
memoryPercentage = 0.25 // 25% of free memory
|
||||||
|
|
||||||
|
// For large datasets in read-only mode, be even more aggressive
|
||||||
|
if (isLargeDataset) {
|
||||||
|
memoryPercentage = 0.4 // 40% of free memory
|
||||||
|
}
|
||||||
|
} else if (isLargeDataset) {
|
||||||
|
// For large datasets in normal mode, increase slightly
|
||||||
|
memoryPercentage = 0.15 // 15% of free memory
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate optimal size based on adjusted percentage
|
||||||
|
const optimalSize = Math.max(
|
||||||
|
Math.floor(memoryInfo.freeMemory * memoryPercentage / ESTIMATED_BYTES_PER_ENTRY),
|
||||||
|
1000
|
||||||
|
)
|
||||||
|
|
||||||
|
// If we know the total dataset size, cap at a reasonable percentage
|
||||||
|
if (totalItems > 0) {
|
||||||
|
// In read-only mode, we can cache a larger percentage
|
||||||
|
const maxPercentage = isReadOnly ? 0.5 : 0.3
|
||||||
|
const maxItems = Math.ceil(totalItems * maxPercentage)
|
||||||
|
|
||||||
|
// Return the smaller of the two to avoid excessive memory usage
|
||||||
|
return Math.min(optimalSize, maxItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
return optimalSize
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Error detecting optimal cache size asynchronously:', error)
|
||||||
|
return 1000 // Conservative default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects available memory across different environments
|
||||||
|
*
|
||||||
|
* This method uses different techniques to detect memory in:
|
||||||
|
* - Node.js: Uses the OS module with dynamic import
|
||||||
|
* - Browser: Uses performance.memory or navigator.deviceMemory
|
||||||
|
* - Worker: Uses performance.memory if available
|
||||||
|
*
|
||||||
|
* @returns An object with totalMemory and freeMemory in bytes, or null if detection fails
|
||||||
|
*/
|
||||||
|
private async detectAvailableMemory(): Promise<{ totalMemory: number, freeMemory: number } | null> {
|
||||||
|
try {
|
||||||
|
// Node.js environment
|
||||||
|
if (this.environment === Environment.NODE) {
|
||||||
|
try {
|
||||||
|
// Use dynamic import for OS module
|
||||||
|
const os = await import('os')
|
||||||
|
|
||||||
|
// Get actual system memory information
|
||||||
|
const totalMemory = os.totalmem()
|
||||||
|
const freeMemory = os.freemem()
|
||||||
|
|
||||||
|
return { totalMemory, freeMemory }
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Failed to detect memory in Node.js environment:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Browser environment
|
||||||
|
if (this.environment === Environment.BROWSER) {
|
||||||
|
// Try using performance.memory (Chrome only)
|
||||||
|
if (performance && (performance as any).memory) {
|
||||||
|
const memoryInfo = (performance as any).memory
|
||||||
|
|
||||||
|
// jsHeapSizeLimit is the maximum size of the heap
|
||||||
|
// totalJSHeapSize is the currently allocated heap size
|
||||||
|
// usedJSHeapSize is the amount of heap currently being used
|
||||||
|
const totalMemory = memoryInfo.jsHeapSizeLimit || 0
|
||||||
|
const usedMemory = memoryInfo.usedJSHeapSize || 0
|
||||||
|
const freeMemory = Math.max(totalMemory - usedMemory, 0)
|
||||||
|
|
||||||
|
return { totalMemory, freeMemory }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try using navigator.deviceMemory as fallback
|
||||||
|
if (navigator.deviceMemory) {
|
||||||
|
// deviceMemory is in GB, convert to bytes
|
||||||
|
const totalMemory = navigator.deviceMemory * 1024 * 1024 * 1024
|
||||||
|
// Assume 50% is free
|
||||||
|
const freeMemory = totalMemory * 0.5
|
||||||
|
|
||||||
|
return { totalMemory, freeMemory }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Worker environment
|
||||||
|
if (this.environment === Environment.WORKER) {
|
||||||
|
// Try using performance.memory if available (Chrome workers)
|
||||||
|
if (performance && (performance as any).memory) {
|
||||||
|
const memoryInfo = (performance as any).memory
|
||||||
|
|
||||||
|
const totalMemory = memoryInfo.jsHeapSizeLimit || 0
|
||||||
|
const usedMemory = memoryInfo.usedJSHeapSize || 0
|
||||||
|
const freeMemory = Math.max(totalMemory - usedMemory, 0)
|
||||||
|
|
||||||
|
return { totalMemory, freeMemory }
|
||||||
|
}
|
||||||
|
|
||||||
|
// For workers, use a conservative estimate
|
||||||
|
// Assume 2GB total memory with 1GB free
|
||||||
|
return {
|
||||||
|
totalMemory: 2 * 1024 * 1024 * 1024,
|
||||||
|
freeMemory: 1 * 1024 * 1024 * 1024
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all detection methods fail, use conservative defaults
|
||||||
|
return {
|
||||||
|
totalMemory: 8 * 1024 * 1024 * 1024, // Assume 8GB total
|
||||||
|
freeMemory: 4 * 1024 * 1024 * 1024 // Assume 4GB free
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Memory detection failed:', error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tune cache parameters based on statistics and environment
|
* Tune cache parameters based on statistics and environment
|
||||||
* This method is called periodically if auto-tuning is enabled
|
* This method is called periodically if auto-tuning is enabled
|
||||||
|
|
@ -339,17 +566,20 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
this.storageStatistics = await this.coldStorage.getStatistics()
|
this.storageStatistics = await this.coldStorage.getStatistics()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tune hot cache size
|
// Get cache statistics for adaptive tuning
|
||||||
this.tuneHotCacheSize()
|
const cacheStats = this.getStats()
|
||||||
|
|
||||||
// Tune eviction threshold
|
// Use the async version of tuneHotCacheSize which uses detectOptimalCacheSizeAsync
|
||||||
this.tuneEvictionThreshold()
|
await this.tuneHotCacheSize()
|
||||||
|
|
||||||
// Tune warm cache TTL
|
// Tune eviction threshold based on hit/miss ratio
|
||||||
this.tuneWarmCacheTTL()
|
this.tuneEvictionThreshold(cacheStats)
|
||||||
|
|
||||||
// Tune batch size
|
// Tune warm cache TTL based on access patterns
|
||||||
this.tuneBatchSize()
|
this.tuneWarmCacheTTL(cacheStats)
|
||||||
|
|
||||||
|
// Tune batch size based on access patterns and storage type
|
||||||
|
this.tuneBatchSize(cacheStats)
|
||||||
|
|
||||||
// Log tuned parameters if debug is enabled
|
// Log tuned parameters if debug is enabled
|
||||||
if (process.env.DEBUG) {
|
if (process.env.DEBUG) {
|
||||||
|
|
@ -357,7 +587,15 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
hotCacheMaxSize: this.hotCacheMaxSize,
|
hotCacheMaxSize: this.hotCacheMaxSize,
|
||||||
hotCacheEvictionThreshold: this.hotCacheEvictionThreshold,
|
hotCacheEvictionThreshold: this.hotCacheEvictionThreshold,
|
||||||
warmCacheTTL: this.warmCacheTTL,
|
warmCacheTTL: this.warmCacheTTL,
|
||||||
batchSize: this.batchSize
|
batchSize: this.batchSize,
|
||||||
|
cacheStats: {
|
||||||
|
hotCacheSize: cacheStats.hotCacheSize,
|
||||||
|
warmCacheSize: cacheStats.warmCacheSize,
|
||||||
|
hotCacheHits: cacheStats.hotCacheHits,
|
||||||
|
hotCacheMisses: cacheStats.hotCacheMisses,
|
||||||
|
warmCacheHits: cacheStats.warmCacheHits,
|
||||||
|
warmCacheMisses: cacheStats.warmCacheMisses
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -382,9 +620,9 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
* - For read-only mode, prioritize cache size over eviction speed
|
* - For read-only mode, prioritize cache size over eviction speed
|
||||||
* - Dynamically adjust based on hit/miss ratio and query patterns
|
* - Dynamically adjust based on hit/miss ratio and query patterns
|
||||||
*/
|
*/
|
||||||
private tuneHotCacheSize(): void {
|
private async tuneHotCacheSize(): Promise<void> {
|
||||||
// Start with the base size from environment detection
|
// Use the async version to get more accurate memory information
|
||||||
let optimalSize = this.detectOptimalCacheSize()
|
let optimalSize = await this.detectOptimalCacheSizeAsync()
|
||||||
|
|
||||||
// Check if we're in read-only mode
|
// Check if we're in read-only mode
|
||||||
const isReadOnly = this.options?.readOnly || false
|
const isReadOnly = this.options?.readOnly || false
|
||||||
|
|
@ -511,6 +749,7 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
* It is tuned based on:
|
* It is tuned based on:
|
||||||
* 1. Cache hit/miss ratio
|
* 1. Cache hit/miss ratio
|
||||||
* 2. Operation patterns (read-heavy vs. write-heavy workloads)
|
* 2. Operation patterns (read-heavy vs. write-heavy workloads)
|
||||||
|
* 3. Memory pressure and available resources
|
||||||
*
|
*
|
||||||
* Algorithm:
|
* Algorithm:
|
||||||
* - Start with a default threshold of 0.8 (80% of max size)
|
* - Start with a default threshold of 0.8 (80% of max size)
|
||||||
|
|
@ -518,24 +757,30 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
* - For low hit ratios, decrease the threshold to evict items more aggressively
|
* - For low hit ratios, decrease the threshold to evict items more aggressively
|
||||||
* - For read-heavy workloads, use a higher threshold
|
* - For read-heavy workloads, use a higher threshold
|
||||||
* - For write-heavy workloads, use a lower threshold
|
* - For write-heavy workloads, use a lower threshold
|
||||||
|
* - Under memory pressure, use a lower threshold to conserve resources
|
||||||
|
*
|
||||||
|
* @param cacheStats Optional cache statistics for more adaptive tuning
|
||||||
*/
|
*/
|
||||||
private tuneEvictionThreshold(): void {
|
private tuneEvictionThreshold(cacheStats?: CacheStats): void {
|
||||||
// Default threshold
|
// Default threshold
|
||||||
let threshold = 0.8
|
let threshold = 0.8
|
||||||
|
|
||||||
|
// Use provided cache stats or internal stats
|
||||||
|
const stats = cacheStats || this.getStats()
|
||||||
|
|
||||||
// Adjust based on hit/miss ratio if we have enough data
|
// Adjust based on hit/miss ratio if we have enough data
|
||||||
const totalAccesses = this.stats.hits + this.stats.misses
|
const totalHotAccesses = stats.hotCacheHits + stats.hotCacheMisses
|
||||||
if (totalAccesses > 100) {
|
if (totalHotAccesses > 100) {
|
||||||
const hitRatio = this.stats.hits / totalAccesses
|
const hotHitRatio = stats.hotCacheHits / totalHotAccesses
|
||||||
|
|
||||||
// If hit ratio is high, we can use a higher threshold
|
// If hit ratio is high, we can use a higher threshold
|
||||||
// If hit ratio is low, we should use a lower threshold to evict more aggressively
|
// If hit ratio is low, we should use a lower threshold to evict more aggressively
|
||||||
if (hitRatio > 0.8) {
|
if (hotHitRatio > 0.8) {
|
||||||
// High hit ratio, increase threshold (up to 0.9)
|
// High hit ratio, increase threshold (up to 0.9)
|
||||||
threshold = Math.min(0.9, 0.8 + (hitRatio - 0.8))
|
threshold = Math.min(0.9, 0.8 + (hotHitRatio - 0.8) * 0.5)
|
||||||
} else if (hitRatio < 0.5) {
|
} else if (hotHitRatio < 0.5) {
|
||||||
// Low hit ratio, decrease threshold (down to 0.6)
|
// Low hit ratio, decrease threshold (down to 0.6)
|
||||||
threshold = Math.max(0.6, 0.8 - (0.5 - hitRatio))
|
threshold = Math.max(0.6, 0.8 - (0.5 - hotHitRatio) * 0.5)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -564,6 +809,24 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check memory pressure - if hot cache is growing too fast relative to hits,
|
||||||
|
// reduce the threshold to conserve memory
|
||||||
|
if (stats.hotCacheSize > 0 && totalHotAccesses > 0) {
|
||||||
|
const sizeToAccessRatio = stats.hotCacheSize / totalHotAccesses
|
||||||
|
|
||||||
|
// If the ratio is high, it means we're caching a lot but not getting many hits
|
||||||
|
if (sizeToAccessRatio > 10) {
|
||||||
|
// Reduce threshold more aggressively under high memory pressure
|
||||||
|
threshold = Math.max(0.5, threshold - 0.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're in read-only mode, we can be more aggressive with caching
|
||||||
|
const isReadOnly = this.options?.readOnly || false
|
||||||
|
if (isReadOnly) {
|
||||||
|
threshold = Math.min(0.95, threshold + 0.05)
|
||||||
|
}
|
||||||
|
|
||||||
// Update the eviction threshold
|
// Update the eviction threshold
|
||||||
this.hotCacheEvictionThreshold = threshold
|
this.hotCacheEvictionThreshold = threshold
|
||||||
}
|
}
|
||||||
|
|
@ -574,16 +837,43 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
* The warm cache TTL determines how long items remain in the warm cache.
|
* The warm cache TTL determines how long items remain in the warm cache.
|
||||||
* It is tuned based on:
|
* It is tuned based on:
|
||||||
* 1. Update frequency from operation statistics
|
* 1. Update frequency from operation statistics
|
||||||
|
* 2. Warm cache hit/miss ratio
|
||||||
|
* 3. Access patterns and frequency
|
||||||
|
* 4. Available storage resources
|
||||||
*
|
*
|
||||||
* Algorithm:
|
* Algorithm:
|
||||||
* - Start with a default TTL of 24 hours
|
* - Start with a default TTL of 24 hours
|
||||||
* - For frequently updated data, use a shorter TTL
|
* - For frequently updated data, use a shorter TTL
|
||||||
* - For rarely updated data, use a longer TTL
|
* - For rarely updated data, use a longer TTL
|
||||||
|
* - For frequently accessed data, use a longer TTL
|
||||||
|
* - For rarely accessed data, use a shorter TTL
|
||||||
|
* - Under storage pressure, use a shorter TTL
|
||||||
|
*
|
||||||
|
* @param cacheStats Optional cache statistics for more adaptive tuning
|
||||||
*/
|
*/
|
||||||
private tuneWarmCacheTTL(): void {
|
private tuneWarmCacheTTL(cacheStats?: CacheStats): void {
|
||||||
// Default TTL (24 hours)
|
// Default TTL (24 hours)
|
||||||
let ttl = 24 * 60 * 60 * 1000
|
let ttl = 24 * 60 * 60 * 1000
|
||||||
|
|
||||||
|
// Use provided cache stats or internal stats
|
||||||
|
const stats = cacheStats || this.getStats()
|
||||||
|
|
||||||
|
// Adjust based on warm cache hit/miss ratio if we have enough data
|
||||||
|
const totalWarmAccesses = stats.warmCacheHits + stats.warmCacheMisses
|
||||||
|
if (totalWarmAccesses > 50) {
|
||||||
|
const warmHitRatio = stats.warmCacheHits / totalWarmAccesses
|
||||||
|
|
||||||
|
// If warm cache hit ratio is high, items in warm cache are useful
|
||||||
|
// so we should keep them longer
|
||||||
|
if (warmHitRatio > 0.7) {
|
||||||
|
// High hit ratio, increase TTL (up to 36 hours)
|
||||||
|
ttl = Math.min(36 * 60 * 60 * 1000, ttl * (1 + (warmHitRatio - 0.7)))
|
||||||
|
} else if (warmHitRatio < 0.3) {
|
||||||
|
// Low hit ratio, decrease TTL (down to 12 hours)
|
||||||
|
ttl = Math.max(12 * 60 * 60 * 1000, ttl * (0.8 - (0.3 - warmHitRatio)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If we have storage statistics with operation counts, adjust based on update frequency
|
// If we have storage statistics with operation counts, adjust based on update frequency
|
||||||
if (this.storageStatistics && this.storageStatistics.operations) {
|
if (this.storageStatistics && this.storageStatistics.operations) {
|
||||||
const ops = this.storageStatistics.operations
|
const ops = this.storageStatistics.operations
|
||||||
|
|
@ -597,14 +887,31 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
// For rarely updated data, use longer TTL
|
// For rarely updated data, use longer TTL
|
||||||
if (updateRatio > 0.3) {
|
if (updateRatio > 0.3) {
|
||||||
// Frequently updated, decrease TTL (down to 6 hours)
|
// Frequently updated, decrease TTL (down to 6 hours)
|
||||||
ttl = Math.max(6 * 60 * 60 * 1000, ttl * (1 - updateRatio))
|
ttl = Math.max(6 * 60 * 60 * 1000, ttl * (1 - updateRatio * 0.5))
|
||||||
} else if (updateRatio < 0.1) {
|
} else if (updateRatio < 0.1) {
|
||||||
// Rarely updated, increase TTL (up to 48 hours)
|
// Rarely updated, increase TTL (up to 48 hours)
|
||||||
ttl = Math.min(48 * 60 * 60 * 1000, ttl * (1.5 - updateRatio))
|
ttl = Math.min(48 * 60 * 60 * 1000, ttl * (1.2 - updateRatio))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check warm cache size relative to hot cache size
|
||||||
|
// If warm cache is much larger than hot cache, reduce TTL to prevent excessive storage use
|
||||||
|
if (stats.warmCacheSize > 0 && stats.hotCacheSize > 0) {
|
||||||
|
const warmToHotRatio = stats.warmCacheSize / stats.hotCacheSize
|
||||||
|
|
||||||
|
if (warmToHotRatio > 5) {
|
||||||
|
// Warm cache is much larger than hot cache, reduce TTL
|
||||||
|
ttl = Math.max(6 * 60 * 60 * 1000, ttl * (0.9 - Math.min(0.3, (warmToHotRatio - 5) / 20)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're in read-only mode, we can use a longer TTL
|
||||||
|
const isReadOnly = this.options?.readOnly || false
|
||||||
|
if (isReadOnly) {
|
||||||
|
ttl = Math.min(72 * 60 * 60 * 1000, ttl * 1.5)
|
||||||
|
}
|
||||||
|
|
||||||
// Update the warm cache TTL
|
// Update the warm cache TTL
|
||||||
this.warmCacheTTL = ttl
|
this.warmCacheTTL = ttl
|
||||||
}
|
}
|
||||||
|
|
@ -621,6 +928,7 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
* 5. Operating mode (read-only vs. read-write)
|
* 5. Operating mode (read-only vs. read-write)
|
||||||
* 6. Storage type (S3, filesystem, memory)
|
* 6. Storage type (S3, filesystem, memory)
|
||||||
* 7. Dataset size
|
* 7. Dataset size
|
||||||
|
* 8. Cache efficiency and access patterns
|
||||||
*
|
*
|
||||||
* Enhanced algorithm:
|
* Enhanced algorithm:
|
||||||
* - Start with a default based on the environment
|
* - Start with a default based on the environment
|
||||||
|
|
@ -628,11 +936,17 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
* - For read-only mode, use larger batches to improve throughput
|
* - For read-only mode, use larger batches to improve throughput
|
||||||
* - Dynamically adjust based on network latency and throughput
|
* - Dynamically adjust based on network latency and throughput
|
||||||
* - Balance between memory usage and performance
|
* - Balance between memory usage and performance
|
||||||
|
* - Adapt to cache hit/miss patterns
|
||||||
|
*
|
||||||
|
* @param cacheStats Optional cache statistics for more adaptive tuning
|
||||||
*/
|
*/
|
||||||
private tuneBatchSize(): void {
|
private tuneBatchSize(cacheStats?: CacheStats): void {
|
||||||
// Default batch size
|
// Default batch size
|
||||||
let batchSize = 10
|
let batchSize = 10
|
||||||
|
|
||||||
|
// Use provided cache stats or internal stats
|
||||||
|
const stats = cacheStats || this.getStats()
|
||||||
|
|
||||||
// Check if we're in read-only mode
|
// Check if we're in read-only mode
|
||||||
const isReadOnly = this.options?.readOnly || false
|
const isReadOnly = this.options?.readOnly || false
|
||||||
|
|
||||||
|
|
@ -688,6 +1002,39 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
batchSize = isReadOnly ? 20 : 15
|
batchSize = isReadOnly ? 20 : 15
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adjust based on cache hit/miss ratios
|
||||||
|
const totalHotAccesses = stats.hotCacheHits + stats.hotCacheMisses
|
||||||
|
const totalWarmAccesses = stats.warmCacheHits + stats.warmCacheMisses
|
||||||
|
|
||||||
|
if (totalHotAccesses > 100) {
|
||||||
|
const hotHitRatio = stats.hotCacheHits / totalHotAccesses
|
||||||
|
|
||||||
|
// If hot cache hit ratio is high, we're effectively using the cache
|
||||||
|
// so we can use larger batches for better throughput
|
||||||
|
if (hotHitRatio > 0.8) {
|
||||||
|
// High hit ratio, increase batch size
|
||||||
|
batchSize = Math.min(batchSize * 1.5, isRemoteStorage ? 250 : 150)
|
||||||
|
} else if (hotHitRatio < 0.4) {
|
||||||
|
// Low hit ratio, we might be fetching too much at once
|
||||||
|
// Reduce batch size to be more selective
|
||||||
|
batchSize = Math.max(5, batchSize * 0.8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalWarmAccesses > 50) {
|
||||||
|
const warmHitRatio = stats.warmCacheHits / totalWarmAccesses
|
||||||
|
|
||||||
|
// If warm cache hit ratio is high, prefetching is effective
|
||||||
|
// so we can use larger batches
|
||||||
|
if (warmHitRatio > 0.7) {
|
||||||
|
// High warm hit ratio, increase batch size
|
||||||
|
batchSize = Math.min(batchSize * 1.3, isRemoteStorage ? 200 : 120)
|
||||||
|
} else if (warmHitRatio < 0.3) {
|
||||||
|
// Low warm hit ratio, reduce batch size
|
||||||
|
batchSize = Math.max(5, batchSize * 0.9)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If we have storage statistics with operation counts, adjust based on operation patterns
|
// If we have storage statistics with operation counts, adjust based on operation patterns
|
||||||
if (this.storageStatistics && this.storageStatistics.operations) {
|
if (this.storageStatistics && this.storageStatistics.operations) {
|
||||||
const ops = this.storageStatistics.operations
|
const ops = this.storageStatistics.operations
|
||||||
|
|
@ -721,10 +1068,20 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adjust based on hit/miss ratio if we have enough data
|
// Check if we're experiencing memory pressure
|
||||||
const totalAccesses = this.stats.hits + this.stats.misses
|
if (stats.hotCacheSize > 0 && this.hotCacheMaxSize > 0) {
|
||||||
|
const cacheUtilization = stats.hotCacheSize / this.hotCacheMaxSize
|
||||||
|
|
||||||
|
// If cache utilization is high, reduce batch size to avoid memory pressure
|
||||||
|
if (cacheUtilization > 0.85) {
|
||||||
|
batchSize = Math.max(5, Math.floor(batchSize * 0.8))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust based on overall hit/miss ratio if we have enough data
|
||||||
|
const totalAccesses = stats.hotCacheHits + stats.hotCacheMisses + stats.warmCacheHits + stats.warmCacheMisses
|
||||||
if (totalAccesses > 100) {
|
if (totalAccesses > 100) {
|
||||||
const hitRatio = this.stats.hits / totalAccesses
|
const hitRatio = (stats.hotCacheHits + stats.warmCacheHits) / totalAccesses
|
||||||
|
|
||||||
// Base adjustment factors
|
// Base adjustment factors
|
||||||
let increaseFactorForLowHitRatio = isRemoteStorage ? 1.5 : 1.2
|
let increaseFactorForLowHitRatio = isRemoteStorage ? 1.5 : 1.2
|
||||||
|
|
@ -774,8 +1131,8 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
|
|
||||||
batchSize = Math.min(maxBatchSize, batchSize)
|
batchSize = Math.min(maxBatchSize, batchSize)
|
||||||
|
|
||||||
// Update the batch size
|
// Update the batch size with the adaptively tuned value
|
||||||
this.batchSize = batchSize
|
this.batchSize = Math.round(batchSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1081,7 +1438,13 @@ export class CacheManager<T extends HNSWNode | Edge> {
|
||||||
misses: 0,
|
misses: 0,
|
||||||
evictions: 0,
|
evictions: 0,
|
||||||
size: 0,
|
size: 0,
|
||||||
maxSize: this.hotCacheMaxSize
|
maxSize: this.hotCacheMaxSize,
|
||||||
|
hotCacheSize: 0,
|
||||||
|
warmCacheSize: 0,
|
||||||
|
hotCacheHits: 0,
|
||||||
|
hotCacheMisses: 0,
|
||||||
|
warmCacheHits: 0,
|
||||||
|
warmCacheMisses: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue