141 lines
4.6 KiB
JavaScript
141 lines
4.6 KiB
JavaScript
|
|
/**
|
||
|
|
* Backward Compatibility Layer for Storage Migration
|
||
|
|
*
|
||
|
|
* Handles the transition from 'index' to '_system' directory
|
||
|
|
* Ensures services running different versions can coexist
|
||
|
|
*/
|
||
|
|
/**
|
||
|
|
* Backward compatibility strategy for directory migration
|
||
|
|
*/
|
||
|
|
export class StorageCompatibilityLayer {
|
||
|
|
constructor() {
|
||
|
|
this.migrationMetadata = null;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Determines the read strategy based on what's available
|
||
|
|
* @returns Priority-ordered list of directories to try
|
||
|
|
*/
|
||
|
|
static getReadPriority() {
|
||
|
|
return ['_system', 'index']; // Try new location first, fallback to old
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Determines write strategy based on migration state
|
||
|
|
* @param migrationComplete Whether migration is complete
|
||
|
|
* @returns List of directories to write to
|
||
|
|
*/
|
||
|
|
static getWriteTargets(migrationComplete = false) {
|
||
|
|
if (migrationComplete) {
|
||
|
|
return ['_system']; // Only write to new location
|
||
|
|
}
|
||
|
|
// During migration, write to both for compatibility
|
||
|
|
return ['_system', 'index'];
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Check if we should perform migration based on service coordination
|
||
|
|
* @param existingStats Statistics from storage
|
||
|
|
* @returns Whether to initiate migration
|
||
|
|
*/
|
||
|
|
static shouldMigrate(existingStats) {
|
||
|
|
if (!existingStats)
|
||
|
|
return true; // No data yet, use new structure
|
||
|
|
// Check if we have migration metadata in stats
|
||
|
|
const migrationData = existingStats.migrationMetadata;
|
||
|
|
if (!migrationData)
|
||
|
|
return true; // No migration data, start migration
|
||
|
|
// Check schema version
|
||
|
|
if (migrationData.schemaVersion < 2)
|
||
|
|
return true;
|
||
|
|
// Already migrated
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Creates migration metadata
|
||
|
|
*/
|
||
|
|
static createMigrationMetadata() {
|
||
|
|
return {
|
||
|
|
schemaVersion: 2,
|
||
|
|
migrationStarted: new Date().toISOString(),
|
||
|
|
lastUpdatedBy: process.env.HOSTNAME || process.env.INSTANCE_ID || 'unknown'
|
||
|
|
};
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Merge statistics from multiple locations (deduplication)
|
||
|
|
*/
|
||
|
|
static mergeStatistics(primary, fallback) {
|
||
|
|
if (!primary && !fallback)
|
||
|
|
return null;
|
||
|
|
if (!fallback)
|
||
|
|
return primary;
|
||
|
|
if (!primary)
|
||
|
|
return fallback;
|
||
|
|
// Return the most recently updated
|
||
|
|
const primaryTime = new Date(primary.lastUpdated).getTime();
|
||
|
|
const fallbackTime = new Date(fallback.lastUpdated).getTime();
|
||
|
|
return primaryTime >= fallbackTime ? primary : fallback;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Determines if dual-write is needed based on environment
|
||
|
|
* @param storageType The type of storage being used
|
||
|
|
* @returns Whether to write to both old and new locations
|
||
|
|
*/
|
||
|
|
static needsDualWrite(storageType) {
|
||
|
|
// Only need dual-write for shared storage systems
|
||
|
|
const sharedStorageTypes = ['s3', 'r2', 'gcs', 'filesystem'];
|
||
|
|
return sharedStorageTypes.includes(storageType.toLowerCase());
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Grace period for migration (30 days default)
|
||
|
|
* After this period, services can stop reading from old location
|
||
|
|
*/
|
||
|
|
static getMigrationGracePeriodMs() {
|
||
|
|
const days = parseInt(process.env.BRAINY_MIGRATION_GRACE_DAYS || '30', 10);
|
||
|
|
return days * 24 * 60 * 60 * 1000;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Check if migration grace period has expired
|
||
|
|
*/
|
||
|
|
static isGracePeriodExpired(migrationStarted) {
|
||
|
|
const startTime = new Date(migrationStarted).getTime();
|
||
|
|
const now = Date.now();
|
||
|
|
const gracePeriod = this.getMigrationGracePeriodMs();
|
||
|
|
return (now - startTime) > gracePeriod;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Log migration events for monitoring
|
||
|
|
*/
|
||
|
|
static logMigrationEvent(event, details) {
|
||
|
|
if (process.env.NODE_ENV !== 'test') {
|
||
|
|
console.log(`[Brainy Storage Migration] ${event}`, details || '');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Storage paths helper for migration
|
||
|
|
*/
|
||
|
|
export class StoragePaths {
|
||
|
|
/**
|
||
|
|
* Get the statistics file path for a given directory
|
||
|
|
*/
|
||
|
|
static getStatisticsPath(baseDir, filename = 'statistics') {
|
||
|
|
return `${baseDir}/${filename}.json`;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Get distributed config path
|
||
|
|
*/
|
||
|
|
static getDistributedConfigPath(baseDir) {
|
||
|
|
return `${baseDir}/distributed_config.json`;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Check if a path is using the old structure
|
||
|
|
*/
|
||
|
|
static isLegacyPath(path) {
|
||
|
|
return path.includes('/index/') || path.endsWith('/index');
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Convert legacy path to new structure
|
||
|
|
*/
|
||
|
|
static modernizePath(path) {
|
||
|
|
return path.replace('/index/', '/_system/').replace('/index', '/_system');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//# sourceMappingURL=backwardCompatibility.js.map
|