claude-flow-novice 2.0.3 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/cli/commands/guidance.js +487 -668
- package/dist/src/cli/commands/index-validate.js +18 -29
- package/dist/src/cli/commands/mcp-troubleshoot.js +230 -282
- package/dist/src/cli/commands/neural-goal-init.js +92 -125
- package/dist/src/cli/commands/swarm-exec.js +317 -393
- package/dist/src/cli/commands/swarm.js +1 -1
- package/dist/src/cli/commands/validate-framework.js +983 -1100
- package/dist/src/cli/commands/validate.js +144 -223
- package/dist/src/cli/simple-commands/__tests__/agent.test.js +265 -277
- package/dist/src/cli/simple-commands/__tests__/memory.test.js +6 -7
- package/dist/src/cli/simple-commands/__tests__/swarm.test.js +373 -356
- package/dist/src/cli/simple-commands/__tests__/task.test.js +6 -7
- package/dist/src/cli/simple-commands/agent.js +157 -193
- package/dist/src/cli/simple-commands/analysis.js +336 -446
- package/dist/src/cli/simple-commands/automation-executor.js +1095 -1339
- package/dist/src/cli/simple-commands/automation.js +481 -469
- package/dist/src/cli/simple-commands/batch-manager.js +261 -313
- package/dist/src/cli/simple-commands/claude-telemetry.js +241 -267
- package/dist/src/cli/simple-commands/claude-track.js +68 -90
- package/dist/src/cli/simple-commands/concurrent-display.js +266 -320
- package/dist/src/cli/simple-commands/config.js +245 -290
- package/dist/src/cli/simple-commands/coordination.js +182 -234
- package/dist/src/cli/simple-commands/enhanced-ui-views.js +812 -615
- package/dist/src/cli/simple-commands/enhanced-webui-complete.js +922 -981
- package/dist/src/cli/simple-commands/fix-hook-variables.js +274 -294
- package/dist/src/cli/simple-commands/github/gh-coordinator.js +378 -457
- package/dist/src/cli/simple-commands/github/github-api.js +535 -574
- package/dist/src/cli/simple-commands/github/init.js +276 -303
- package/dist/src/cli/simple-commands/github.js +222 -247
- package/dist/src/cli/simple-commands/goal.js +51 -63
- package/dist/src/cli/simple-commands/hive-mind/auto-save-middleware.js +208 -278
- package/dist/src/cli/simple-commands/hive-mind/communication.js +601 -696
- package/dist/src/cli/simple-commands/hive-mind/core.js +907 -979
- package/dist/src/cli/simple-commands/hive-mind/db-optimizer.js +406 -655
- package/dist/src/cli/simple-commands/hive-mind/mcp-wrapper.js +1125 -1245
- package/dist/src/cli/simple-commands/hive-mind/memory.js +854 -1090
- package/dist/src/cli/simple-commands/hive-mind/performance-optimizer.js +459 -574
- package/dist/src/cli/simple-commands/hive-mind/performance-test.js +263 -347
- package/dist/src/cli/simple-commands/hive-mind/queen.js +727 -768
- package/dist/src/cli/simple-commands/hive-mind/session-manager.js +745 -1049
- package/dist/src/cli/simple-commands/hive-mind-optimize.js +227 -283
- package/dist/src/cli/simple-commands/hive-mind-wizard.js +174 -217
- package/dist/src/cli/simple-commands/hive-mind.js +1842 -2283
- package/dist/src/cli/simple-commands/hive.js +90 -79
- package/dist/src/cli/simple-commands/hook-safety.js +431 -521
- package/dist/src/cli/simple-commands/hooks/session-start-soul.js +203 -254
- package/dist/src/cli/simple-commands/hooks.js +1064 -1204
- package/dist/src/cli/simple-commands/init/agent-copier.js +294 -319
- package/dist/src/cli/simple-commands/init/batch-init.js +496 -562
- package/dist/src/cli/simple-commands/init/claude-commands/claude-flow-commands.js +13 -19
- package/dist/src/cli/simple-commands/init/claude-commands/optimized-claude-flow-commands.js +13 -19
- package/dist/src/cli/simple-commands/init/claude-commands/optimized-slash-commands.js +61 -88
- package/dist/src/cli/simple-commands/init/claude-commands/optimized-sparc-commands.js +125 -150
- package/dist/src/cli/simple-commands/init/claude-commands/slash-commands.js +42 -49
- package/dist/src/cli/simple-commands/init/claude-commands/sparc-commands.js +43 -61
- package/dist/src/cli/simple-commands/init/copy-revised-templates.js +141 -147
- package/dist/src/cli/simple-commands/init/executable-wrapper.js +31 -44
- package/dist/src/cli/simple-commands/init/gitignore-updater.js +64 -90
- package/dist/src/cli/simple-commands/init/help.js +104 -107
- package/dist/src/cli/simple-commands/init/hive-mind-init.js +509 -528
- package/dist/src/cli/simple-commands/init/index.js +1510 -1759
- package/dist/src/cli/simple-commands/init/performance-monitor.js +234 -317
- package/dist/src/cli/simple-commands/init/rollback/backup-manager.js +441 -504
- package/dist/src/cli/simple-commands/init/rollback/index.js +289 -364
- package/dist/src/cli/simple-commands/init/rollback/recovery-manager.js +652 -728
- package/dist/src/cli/simple-commands/init/rollback/rollback-executor.js +416 -481
- package/dist/src/cli/simple-commands/init/rollback/state-tracker.js +369 -448
- package/dist/src/cli/simple-commands/init/sparc/roo-readme.js +1 -2
- package/dist/src/cli/simple-commands/init/sparc/roomodes-config.js +122 -99
- package/dist/src/cli/simple-commands/init/sparc/workflows.js +32 -37
- package/dist/src/cli/simple-commands/init/sparc-structure.js +55 -62
- package/dist/src/cli/simple-commands/init/template-copier.js +421 -533
- package/dist/src/cli/simple-commands/init/templates/coordination-md.js +3 -6
- package/dist/src/cli/simple-commands/init/templates/enhanced-templates.js +344 -318
- package/dist/src/cli/simple-commands/init/templates/github-safe-enhanced.js +173 -218
- package/dist/src/cli/simple-commands/init/templates/github-safe.js +65 -75
- package/dist/src/cli/simple-commands/init/templates/memory-bank-md.js +3 -6
- package/dist/src/cli/simple-commands/init/templates/readme-files.js +2 -4
- package/dist/src/cli/simple-commands/init/templates/safe-hook-patterns.js +187 -230
- package/dist/src/cli/simple-commands/init/templates/sparc-modes.js +53 -80
- package/dist/src/cli/simple-commands/init/templates/verification-claude-md.js +101 -85
- package/dist/src/cli/simple-commands/init/validation/config-validator.js +283 -330
- package/dist/src/cli/simple-commands/init/validation/health-checker.js +495 -561
- package/dist/src/cli/simple-commands/init/validation/index.js +302 -358
- package/dist/src/cli/simple-commands/init/validation/mode-validator.js +308 -359
- package/dist/src/cli/simple-commands/init/validation/post-init-validator.js +389 -366
- package/dist/src/cli/simple-commands/init/validation/pre-init-validator.js +270 -268
- package/dist/src/cli/simple-commands/init/validation/test-runner.js +427 -447
- package/dist/src/cli/simple-commands/init.js +1 -2
- package/dist/src/cli/simple-commands/mcp-health.js +131 -158
- package/dist/src/cli/simple-commands/mcp-integration-layer.js +533 -634
- package/dist/src/cli/simple-commands/mcp.js +345 -400
- package/dist/src/cli/simple-commands/memory-consolidation.js +426 -537
- package/dist/src/cli/simple-commands/memory.js +247 -311
- package/dist/src/cli/simple-commands/migrate-hooks.js +39 -46
- package/dist/src/cli/simple-commands/monitor.js +294 -363
- package/dist/src/cli/simple-commands/neural.js +51 -65
- package/dist/src/cli/simple-commands/pair-autofix-only.js +538 -662
- package/dist/src/cli/simple-commands/pair-basic.js +528 -656
- package/dist/src/cli/simple-commands/pair-old.js +430 -543
- package/dist/src/cli/simple-commands/pair-working.js +615 -751
- package/dist/src/cli/simple-commands/pair.js +615 -751
- package/dist/src/cli/simple-commands/performance-hooks.js +83 -111
- package/dist/src/cli/simple-commands/performance-metrics.js +348 -433
- package/dist/src/cli/simple-commands/process-ui-enhanced.js +708 -787
- package/dist/src/cli/simple-commands/process-ui.js +230 -254
- package/dist/src/cli/simple-commands/realtime-update-system.js +525 -611
- package/dist/src/cli/simple-commands/sparc/architecture.js +1704 -1530
- package/dist/src/cli/simple-commands/sparc/commands.js +438 -516
- package/dist/src/cli/simple-commands/sparc/completion.js +1224 -1481
- package/dist/src/cli/simple-commands/sparc/coordinator.js +913 -978
- package/dist/src/cli/simple-commands/sparc/index.js +241 -298
- package/dist/src/cli/simple-commands/sparc/phase-base.js +314 -390
- package/dist/src/cli/simple-commands/sparc/pseudocode.js +965 -869
- package/dist/src/cli/simple-commands/sparc/refinement.js +980 -1273
- package/dist/src/cli/simple-commands/sparc/specification.js +559 -645
- package/dist/src/cli/simple-commands/sparc-modes/architect.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/ask.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/code.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/debug.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/devops.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/docs-writer.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/generic.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/index.js +47 -55
- package/dist/src/cli/simple-commands/sparc-modes/integration.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/mcp.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/monitoring.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/optimization.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/security-review.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/sparc-orchestrator.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/spec-pseudocode.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/supabase-admin.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/swarm.js +101 -87
- package/dist/src/cli/simple-commands/sparc-modes/tdd.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/tutorial.js +1 -1
- package/dist/src/cli/simple-commands/sparc.js +465 -493
- package/dist/src/cli/simple-commands/start-ui.js +108 -132
- package/dist/src/cli/simple-commands/start-wrapper.js +240 -268
- package/dist/src/cli/simple-commands/start.js +1 -1
- package/dist/src/cli/simple-commands/status.js +254 -275
- package/dist/src/cli/simple-commands/stream-chain-clean.js +128 -171
- package/dist/src/cli/simple-commands/stream-chain-fixed.js +61 -82
- package/dist/src/cli/simple-commands/stream-chain-real.js +267 -331
- package/dist/src/cli/simple-commands/stream-chain-working.js +211 -263
- package/dist/src/cli/simple-commands/stream-chain.js +260 -318
- package/dist/src/cli/simple-commands/stream-processor.js +290 -315
- package/dist/src/cli/simple-commands/swarm-executor.js +189 -222
- package/dist/src/cli/simple-commands/swarm-metrics-integration.js +208 -300
- package/dist/src/cli/simple-commands/swarm-ui.js +623 -703
- package/dist/src/cli/simple-commands/swarm-webui-integration.js +258 -286
- package/dist/src/cli/simple-commands/swarm.js +887 -1082
- package/dist/src/cli/simple-commands/task.js +161 -206
- package/dist/src/cli/simple-commands/timestamp-fix.js +59 -89
- package/dist/src/cli/simple-commands/token-tracker.js +258 -316
- package/dist/src/cli/simple-commands/tool-execution-framework.js +433 -519
- package/dist/src/cli/simple-commands/train-and-stream.js +275 -331
- package/dist/src/cli/simple-commands/training-pipeline.js +619 -725
- package/dist/src/cli/simple-commands/training.js +170 -227
- package/dist/src/cli/simple-commands/verification-hooks.js +261 -284
- package/dist/src/cli/simple-commands/verification-integration.js +389 -417
- package/dist/src/cli/simple-commands/verification-training-integration.js +486 -606
- package/dist/src/cli/simple-commands/verification.js +493 -513
- package/dist/src/cli/simple-commands/web-server.js +766 -836
- package/dist/src/cli/simple-commands/webui-validator.js +106 -124
- package/dist/src/coordination/event-bus/demo-wasm-integration.js +212 -251
- package/dist/src/coordination/event-bus/qe-event-bus.js +608 -748
- package/dist/src/coordination/event-bus/qe-event-bus.test.js +379 -454
- package/dist/src/coordination/iteration-tracker.js +363 -454
- package/dist/src/enterprise/analytics-manager.js +1135 -0
- package/dist/src/enterprise/audit-manager.js +1115 -0
- package/dist/src/enterprise/cloud-manager.js +891 -0
- package/dist/src/enterprise/deployment-manager.js +966 -0
- package/dist/src/enterprise/index.js +6 -0
- package/dist/src/enterprise/project-manager.js +584 -0
- package/dist/src/enterprise/security-manager.js +991 -0
- package/dist/src/index.js +1 -1
- package/dist/src/mcp/DEPRECATED.js +46 -60
- package/dist/src/mcp/fixes/mcp-error-fixes.js +115 -134
- package/dist/src/mcp/implementations/agent-tracker.js +114 -128
- package/dist/src/mcp/implementations/daa-tools.js +292 -350
- package/dist/src/mcp/implementations/workflow-tools.js +329 -361
- package/dist/src/mcp/mcp-config-manager.js +1183 -1331
- package/dist/src/mcp/mcp-server-novice-simplified.js +11 -17
- package/dist/src/mcp/mcp-server-novice.js +11 -17
- package/dist/src/mcp/mcp-server-sdk.js +11 -17
- package/dist/src/mcp/mcp-server.js +1620 -1484
- package/dist/src/mcp/ruv-swarm-wrapper.js +209 -239
- package/dist/src/memory/advanced-serializer.js +609 -589
- package/dist/src/memory/enhanced-examples.js +220 -305
- package/dist/src/memory/enhanced-memory.js +295 -336
- package/dist/src/memory/enhanced-session-serializer.js +408 -492
- package/dist/src/memory/fallback-memory-system.js +900 -1021
- package/dist/src/memory/fallback-store.js +93 -131
- package/dist/src/memory/high-performance-serialization.js +592 -730
- package/dist/src/memory/in-memory-store.js +161 -213
- package/dist/src/memory/index.js +123 -157
- package/dist/src/memory/lock-free-structures.js +578 -764
- package/dist/src/memory/memory-mapped-persistence.js +585 -766
- package/dist/src/memory/memory-pressure-manager.js +569 -707
- package/dist/src/memory/migration.js +358 -445
- package/dist/src/memory/shared-memory.js +641 -768
- package/dist/src/memory/sqlite-store.js +245 -325
- package/dist/src/memory/sqlite-wrapper.js +122 -151
- package/dist/src/memory/swarm-memory.js +470 -603
- package/dist/src/memory/test-example.js +126 -134
- package/dist/src/memory/ultra-fast-memory-store.js +622 -821
- package/dist/src/memory/unified-memory-manager.js +356 -437
- package/dist/src/migration/index.js +92 -0
- package/dist/src/migration/logger.js +121 -0
- package/dist/src/migration/migration-analyzer.js +268 -0
- package/dist/src/migration/migration-runner.js +522 -0
- package/dist/src/migration/migration-validator.js +285 -0
- package/dist/src/migration/progress-reporter.js +150 -0
- package/dist/src/migration/rollback-manager.js +321 -0
- package/dist/src/migration/tests/migration-system.test.js +7 -0
- package/dist/src/migration/types.js +3 -0
- package/dist/src/swarm/CodeRefactoringSwarm.js +777 -952
- package/dist/src/swarm/__tests__/integration.test.js +227 -0
- package/dist/src/swarm/__tests__/prompt-copier.test.js +344 -0
- package/dist/src/swarm/advanced-orchestrator.js +1095 -0
- package/dist/src/swarm/claude-code-interface.js +961 -0
- package/dist/src/swarm/claude-flow-executor.js +229 -0
- package/dist/src/swarm/consensus-coordinator.js +475 -0
- package/dist/src/swarm/coordinator.js +2993 -0
- package/dist/src/swarm/direct-executor.js +1180 -0
- package/dist/src/swarm/error-recovery/advanced-error-detection.js +691 -0
- package/dist/src/swarm/error-recovery/automated-recovery-workflows.js +998 -0
- package/dist/src/swarm/error-recovery/error-recovery-coordinator.js +1197 -0
- package/dist/src/swarm/error-recovery/recovery-monitoring.js +772 -0
- package/dist/src/swarm/error-recovery/resilience-architecture.js +714 -0
- package/dist/src/swarm/error-recovery/self-healing-mechanisms.js +1319 -0
- package/dist/src/swarm/error-recovery/test-error-recovery-effectiveness.js +808 -0
- package/dist/src/swarm/executor-v2.js +322 -0
- package/dist/src/swarm/executor.js +815 -0
- package/dist/src/swarm/hive-mind-integration.js +703 -0
- package/dist/src/swarm/index.js +41 -0
- package/dist/src/swarm/json-output-aggregator.js +267 -0
- package/dist/src/swarm/large-scale-coordinator.js +542 -0
- package/dist/src/swarm/mcp-integration-wrapper.js +628 -0
- package/dist/src/swarm/memory.js +1117 -0
- package/dist/src/swarm/optimizations/__tests__/optimization.test.js +348 -0
- package/dist/src/swarm/optimizations/async-file-manager.js +285 -0
- package/dist/src/swarm/optimizations/circular-buffer.js +162 -0
- package/dist/src/swarm/optimizations/connection-pool.js +244 -0
- package/dist/src/swarm/optimizations/index.js +28 -0
- package/dist/src/swarm/optimizations/optimized-executor.js +320 -0
- package/dist/src/swarm/optimizations/ttl-map.js +234 -0
- package/dist/src/swarm/prompt-cli.js +200 -0
- package/dist/src/swarm/prompt-copier-enhanced.js +202 -0
- package/dist/src/swarm/prompt-copier.js +381 -0
- package/dist/src/swarm/prompt-manager.js +295 -0
- package/dist/src/swarm/prompt-utils.js +310 -0
- package/dist/src/swarm/result-aggregator.js +718 -0
- package/dist/src/swarm/sparc-executor.js +1568 -0
- package/dist/src/swarm/strategies/auto.js +758 -0
- package/dist/src/swarm/strategies/base.js +128 -0
- package/dist/src/swarm/strategies/research.js +914 -0
- package/dist/src/swarm/strategies/strategy-metrics-patch.js +2 -0
- package/dist/src/swarm/types.js +52 -0
- package/dist/src/swarm/workers/copy-worker.js +56 -0
- package/dist/src/utils/__tests__/github-cli-safety-wrapper.test.js +332 -400
- package/dist/src/utils/github-cli-safe.js +56 -64
- package/dist/src/utils/github-cli-safety-wrapper.js +451 -546
- package/dist/src/utils/npx-isolated-cache.js +104 -119
- package/dist/src/utils/preference-manager.js +622 -652
- package/dist/src/utils/timezone-utils.js +86 -105
- package/dist/src/validators/epic-config-schema.js +214 -0
- package/dist/src/validators/index.js +10 -0
- package/dist/src/validators/swarm-init-validator.js +259 -0
- package/dist/src/validators/todowrite-batching-validator.js +215 -0
- package/dist/src/validators/todowrite-integration.js +187 -0
- package/package.json +2 -2
|
@@ -4,807 +4,626 @@
|
|
|
4
4
|
* This module implements high-performance persistence using memory-mapped files,
|
|
5
5
|
* incremental backups, and atomic operations to ensure data integrity while
|
|
6
6
|
* maintaining sub-microsecond performance for the in-memory operations.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { promises as fs, constants } from 'fs';
|
|
10
|
-
import { AtomicOperations } from './lock-free-structures.js';
|
|
11
|
-
|
|
7
|
+
*/ import { promises as fs } from "fs";
|
|
12
8
|
/**
|
|
13
9
|
* Memory-mapped persistence configuration
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
PREFAULT_PAGES: true, // Pre-fault memory pages
|
|
33
|
-
USE_HUGE_PAGES: false, // Use huge pages if available
|
|
34
|
-
DIRECT_IO: false, // Use direct I/O (bypass OS cache)
|
|
35
|
-
};
|
|
36
|
-
|
|
10
|
+
*/ const PERSISTENCE_CONFIG = {
|
|
11
|
+
// File layout constants
|
|
12
|
+
HEADER_SIZE: 1024,
|
|
13
|
+
REGION_SIZE: 4096,
|
|
14
|
+
CHECKPOINT_INTERVAL: 5000,
|
|
15
|
+
SYNC_BATCH_SIZE: 16,
|
|
16
|
+
// Backup strategies
|
|
17
|
+
INCREMENTAL_THRESHOLD: 0.1,
|
|
18
|
+
FULL_BACKUP_INTERVAL: 3600,
|
|
19
|
+
// Integrity checking
|
|
20
|
+
CHECKSUM_ENABLED: true,
|
|
21
|
+
MAGIC_NUMBER: 0x464C4F57,
|
|
22
|
+
VERSION: 1,
|
|
23
|
+
// Performance tuning
|
|
24
|
+
PREFAULT_PAGES: true,
|
|
25
|
+
USE_HUGE_PAGES: false,
|
|
26
|
+
DIRECT_IO: false
|
|
27
|
+
};
|
|
37
28
|
/**
|
|
38
29
|
* File header layout for memory-mapped persistence
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
};
|
|
53
|
-
|
|
30
|
+
*/ const FILE_HEADER_LAYOUT = {
|
|
31
|
+
magic: 0,
|
|
32
|
+
version: 4,
|
|
33
|
+
fileSize: 8,
|
|
34
|
+
dataSize: 16,
|
|
35
|
+
regionCount: 24,
|
|
36
|
+
dirtyRegions: 28,
|
|
37
|
+
lastCheckpoint: 32,
|
|
38
|
+
lastFullBackup: 40,
|
|
39
|
+
checksumTable: 48,
|
|
40
|
+
metadataOffset: 56,
|
|
41
|
+
reserved: 64 // 960 bytes reserved for future use
|
|
42
|
+
};
|
|
54
43
|
/**
|
|
55
44
|
* Region metadata layout
|
|
56
|
-
*/
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
};
|
|
64
|
-
|
|
45
|
+
*/ const REGION_METADATA_LAYOUT = {
|
|
46
|
+
checksum: 0,
|
|
47
|
+
lastModified: 4,
|
|
48
|
+
writeCount: 12,
|
|
49
|
+
flags: 16,
|
|
50
|
+
reserved: 20 // 12 bytes reserved
|
|
51
|
+
};
|
|
65
52
|
/**
|
|
66
53
|
* Memory-mapped file persistence manager
|
|
67
|
-
*/
|
|
68
|
-
|
|
69
|
-
constructor(sharedBuffer, backupPath, config = PERSISTENCE_CONFIG) {
|
|
70
|
-
this.sharedBuffer = sharedBuffer;
|
|
71
|
-
this.backupPath = backupPath;
|
|
72
|
-
this.config = config;
|
|
73
|
-
|
|
74
|
-
// Memory region tracking
|
|
75
|
-
this.regionCount = Math.ceil(sharedBuffer.byteLength / config.REGION_SIZE);
|
|
76
|
-
this.dirtyRegions = new Set();
|
|
77
|
-
this.regionChecksums = new Map();
|
|
78
|
-
|
|
79
|
-
// File handles and metadata
|
|
80
|
-
this.fileHandle = null;
|
|
81
|
-
this.fileSize = 0;
|
|
82
|
-
this.isInitialized = false;
|
|
83
|
-
|
|
84
|
-
// Performance metrics
|
|
85
|
-
this.stats = {
|
|
86
|
-
totalBackups: 0,
|
|
87
|
-
incrementalBackups: 0,
|
|
88
|
-
fullBackups: 0,
|
|
89
|
-
totalSyncTime: 0,
|
|
90
|
-
avgSyncTime: 0,
|
|
91
|
-
regionsSync: 0,
|
|
92
|
-
checksumFailures: 0,
|
|
93
|
-
lastBackupTime: 0
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
// Background operations
|
|
97
|
-
this.backgroundSync = null;
|
|
98
|
-
this.checkpointTimer = null;
|
|
99
|
-
|
|
100
|
-
// Integrity verification
|
|
101
|
-
this.checksumTable = new Map();
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
54
|
+
*/ export class MemoryMappedPersistence {
|
|
55
|
+
/**
|
|
105
56
|
* Initialize memory-mapped persistence
|
|
106
|
-
*/
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
57
|
+
*/ async initialize() {
|
|
58
|
+
try {
|
|
59
|
+
await this.createOrOpenBackupFile();
|
|
60
|
+
await this.initializeFileHeader();
|
|
61
|
+
await this.verifyFileIntegrity();
|
|
62
|
+
this.startBackgroundOperations();
|
|
63
|
+
this.isInitialized = true;
|
|
64
|
+
console.log(`Persistence initialized: ${this.backupPath} (${this.regionCount} regions)`);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error('Failed to initialize persistence:', error);
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
124
71
|
* Create or open backup file
|
|
125
|
-
*/
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Open file handle for memory mapping
|
|
150
|
-
this.fileHandle = await fs.open(this.backupPath, 'r+');
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
72
|
+
*/ async createOrOpenBackupFile() {
|
|
73
|
+
const totalFileSize = this.config.HEADER_SIZE + this.regionCount * this.config.REGION_SIZE + this.regionCount * 32; // Metadata per region
|
|
74
|
+
try {
|
|
75
|
+
// Try to open existing file
|
|
76
|
+
const stats = await fs.stat(this.backupPath);
|
|
77
|
+
this.fileSize = stats.size;
|
|
78
|
+
if (this.fileSize < totalFileSize) {
|
|
79
|
+
// File is too small, extend it
|
|
80
|
+
await this.extendFile(totalFileSize);
|
|
81
|
+
}
|
|
82
|
+
} catch (error) {
|
|
83
|
+
if (error.code === 'ENOENT') {
|
|
84
|
+
// File doesn't exist, create it
|
|
85
|
+
await this.createNewBackupFile(totalFileSize);
|
|
86
|
+
} else {
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Open file handle for memory mapping
|
|
91
|
+
this.fileHandle = await fs.open(this.backupPath, 'r+');
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
154
94
|
* Create new backup file with proper structure
|
|
155
|
-
*/
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
} finally {
|
|
178
|
-
await fileHandle.close();
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
console.log(`Created new backup file: ${this.backupPath} (${totalFileSize} bytes)`);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
95
|
+
*/ async createNewBackupFile(totalFileSize) {
|
|
96
|
+
this.fileSize = totalFileSize;
|
|
97
|
+
// Create file and allocate space
|
|
98
|
+
const fileHandle = await fs.open(this.backupPath, 'w+');
|
|
99
|
+
try {
|
|
100
|
+
// Pre-allocate file space
|
|
101
|
+
await fileHandle.truncate(totalFileSize);
|
|
102
|
+
// Initialize with zeros (optional, but ensures consistent state)
|
|
103
|
+
const zeroChunk = Buffer.alloc(64 * 1024, 0); // 64KB zero buffer
|
|
104
|
+
let written = 0;
|
|
105
|
+
while(written < totalFileSize){
|
|
106
|
+
const chunkSize = Math.min(zeroChunk.length, totalFileSize - written);
|
|
107
|
+
await fileHandle.write(zeroChunk, 0, chunkSize, written);
|
|
108
|
+
written += chunkSize;
|
|
109
|
+
}
|
|
110
|
+
await fileHandle.sync();
|
|
111
|
+
} finally{
|
|
112
|
+
await fileHandle.close();
|
|
113
|
+
}
|
|
114
|
+
console.log(`Created new backup file: ${this.backupPath} (${totalFileSize} bytes)`);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
185
117
|
* Extend existing file to accommodate larger shared buffer
|
|
186
|
-
*/
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
/**
|
|
118
|
+
*/ async extendFile(newSize) {
|
|
119
|
+
if (this.fileHandle) {
|
|
120
|
+
await this.fileHandle.truncate(newSize);
|
|
121
|
+
await this.fileHandle.sync();
|
|
122
|
+
this.fileSize = newSize;
|
|
123
|
+
console.log(`Extended backup file to ${newSize} bytes`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
197
127
|
* Initialize file header with metadata
|
|
198
|
-
*/
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
// Write header to file
|
|
222
|
-
await this.fileHandle.write(headerBuffer, 0, this.config.HEADER_SIZE, 0);
|
|
223
|
-
await this.fileHandle.sync();
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
128
|
+
*/ async initializeFileHeader() {
|
|
129
|
+
const headerBuffer = Buffer.alloc(this.config.HEADER_SIZE);
|
|
130
|
+
const headerView = new DataView(headerBuffer.buffer);
|
|
131
|
+
// Write header fields
|
|
132
|
+
headerView.setUint32(FILE_HEADER_LAYOUT.magic, this.config.MAGIC_NUMBER, true);
|
|
133
|
+
headerView.setUint32(FILE_HEADER_LAYOUT.version, this.config.VERSION, true);
|
|
134
|
+
headerView.setBigUint64(FILE_HEADER_LAYOUT.fileSize, BigInt(this.fileSize), true);
|
|
135
|
+
headerView.setBigUint64(FILE_HEADER_LAYOUT.dataSize, BigInt(this.sharedBuffer.byteLength), true);
|
|
136
|
+
headerView.setUint32(FILE_HEADER_LAYOUT.regionCount, this.regionCount, true);
|
|
137
|
+
headerView.setUint32(FILE_HEADER_LAYOUT.dirtyRegions, 0, true);
|
|
138
|
+
headerView.setBigUint64(FILE_HEADER_LAYOUT.lastCheckpoint, BigInt(Date.now()), true);
|
|
139
|
+
headerView.setBigUint64(FILE_HEADER_LAYOUT.lastFullBackup, BigInt(0), true);
|
|
140
|
+
// Calculate offsets
|
|
141
|
+
const checksumTableOffset = this.config.HEADER_SIZE + this.regionCount * this.config.REGION_SIZE;
|
|
142
|
+
const metadataOffset = checksumTableOffset + this.regionCount * 4; // 4 bytes per checksum
|
|
143
|
+
headerView.setBigUint64(FILE_HEADER_LAYOUT.checksumTable, BigInt(checksumTableOffset), true);
|
|
144
|
+
headerView.setBigUint64(FILE_HEADER_LAYOUT.metadataOffset, BigInt(metadataOffset), true);
|
|
145
|
+
// Write header to file
|
|
146
|
+
await this.fileHandle.write(headerBuffer, 0, this.config.HEADER_SIZE, 0);
|
|
147
|
+
await this.fileHandle.sync();
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
227
150
|
* Verify file integrity on startup
|
|
228
|
-
*/
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
await this.loadAndVerifyChecksums();
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
console.log('File integrity verification completed successfully');
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/**
|
|
151
|
+
*/ async verifyFileIntegrity() {
|
|
152
|
+
// Read and verify header
|
|
153
|
+
const headerBuffer = Buffer.alloc(this.config.HEADER_SIZE);
|
|
154
|
+
await this.fileHandle.read(headerBuffer, 0, this.config.HEADER_SIZE, 0);
|
|
155
|
+
const headerView = new DataView(headerBuffer.buffer);
|
|
156
|
+
const magic = headerView.getUint32(FILE_HEADER_LAYOUT.magic, true);
|
|
157
|
+
const version = headerView.getUint32(FILE_HEADER_LAYOUT.version, true);
|
|
158
|
+
if (magic !== this.config.MAGIC_NUMBER) {
|
|
159
|
+
throw new Error(`Invalid magic number: expected ${this.config.MAGIC_NUMBER}, got ${magic}`);
|
|
160
|
+
}
|
|
161
|
+
if (version !== this.config.VERSION) {
|
|
162
|
+
throw new Error(`Unsupported version: expected ${this.config.VERSION}, got ${version}`);
|
|
163
|
+
}
|
|
164
|
+
// Load and verify checksums if enabled
|
|
165
|
+
if (this.config.CHECKSUM_ENABLED) {
|
|
166
|
+
await this.loadAndVerifyChecksums();
|
|
167
|
+
}
|
|
168
|
+
console.log('File integrity verification completed successfully');
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
255
171
|
* Load and verify region checksums
|
|
256
|
-
*/
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
if (corruptRegions > 0) {
|
|
286
|
-
console.warn(`Found ${corruptRegions} corrupt regions during verification`);
|
|
287
|
-
this.stats.checksumFailures += corruptRegions;
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
172
|
+
*/ async loadAndVerifyChecksums() {
|
|
173
|
+
const checksumTableOffset = Number((await this.readFileHeader()).checksumTable);
|
|
174
|
+
const checksumBuffer = Buffer.alloc(this.regionCount * 4);
|
|
175
|
+
await this.fileHandle.read(checksumBuffer, 0, checksumBuffer.length, checksumTableOffset);
|
|
176
|
+
const checksumView = new DataView(checksumBuffer.buffer);
|
|
177
|
+
let corruptRegions = 0;
|
|
178
|
+
for(let i = 0; i < this.regionCount; i++){
|
|
179
|
+
const storedChecksum = checksumView.getUint32(i * 4, true);
|
|
180
|
+
if (storedChecksum !== 0) {
|
|
181
|
+
const regionOffset = this.config.HEADER_SIZE + i * this.config.REGION_SIZE;
|
|
182
|
+
const actualChecksum = await this.calculateRegionChecksum(i, regionOffset);
|
|
183
|
+
if (storedChecksum !== actualChecksum) {
|
|
184
|
+
console.warn(`Checksum mismatch in region ${i}: expected ${storedChecksum}, got ${actualChecksum}`);
|
|
185
|
+
corruptRegions++;
|
|
186
|
+
} else {
|
|
187
|
+
this.checksumTable.set(i, storedChecksum);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (corruptRegions > 0) {
|
|
192
|
+
console.warn(`Found ${corruptRegions} corrupt regions during verification`);
|
|
193
|
+
this.stats.checksumFailures += corruptRegions;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
292
197
|
* Perform incremental backup of dirty regions
|
|
293
|
-
*/
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/**
|
|
198
|
+
*/ async incrementalBackup() {
|
|
199
|
+
if (this.dirtyRegions.size === 0) {
|
|
200
|
+
return {
|
|
201
|
+
backedUpRegions: 0,
|
|
202
|
+
duration: 0
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
const startTime = performance.now();
|
|
206
|
+
const regionsToSync = Array.from(this.dirtyRegions);
|
|
207
|
+
let syncedRegions = 0;
|
|
208
|
+
try {
|
|
209
|
+
// Process regions in batches for better I/O performance
|
|
210
|
+
for(let i = 0; i < regionsToSync.length; i += this.config.SYNC_BATCH_SIZE){
|
|
211
|
+
const batch = regionsToSync.slice(i, i + this.config.SYNC_BATCH_SIZE);
|
|
212
|
+
await this.syncRegionBatch(batch);
|
|
213
|
+
syncedRegions += batch.length;
|
|
214
|
+
}
|
|
215
|
+
// Update checksums if enabled
|
|
216
|
+
if (this.config.CHECKSUM_ENABLED) {
|
|
217
|
+
await this.updateRegionChecksums(regionsToSync);
|
|
218
|
+
}
|
|
219
|
+
// Update header
|
|
220
|
+
await this.updateBackupHeader();
|
|
221
|
+
// Clear dirty flags
|
|
222
|
+
for (const regionIndex of regionsToSync){
|
|
223
|
+
this.dirtyRegions.delete(regionIndex);
|
|
224
|
+
}
|
|
225
|
+
const duration = performance.now() - startTime;
|
|
226
|
+
this.updateBackupStats('incremental', syncedRegions, duration);
|
|
227
|
+
return {
|
|
228
|
+
backedUpRegions: syncedRegions,
|
|
229
|
+
duration
|
|
230
|
+
};
|
|
231
|
+
} catch (error) {
|
|
232
|
+
console.error('Incremental backup failed:', error);
|
|
233
|
+
throw error;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
335
237
|
* Perform full backup of entire shared buffer
|
|
336
|
-
*/
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
return { backedUpRegions: this.regionCount, duration };
|
|
364
|
-
} catch (error) {
|
|
365
|
-
console.error('Full backup failed:', error);
|
|
366
|
-
throw error;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
/**
|
|
238
|
+
*/ async fullBackup() {
|
|
239
|
+
const startTime = performance.now();
|
|
240
|
+
try {
|
|
241
|
+
// Copy entire shared buffer to file
|
|
242
|
+
const bufferView = new Uint8Array(this.sharedBuffer);
|
|
243
|
+
const buffer = Buffer.from(bufferView);
|
|
244
|
+
await this.fileHandle.write(buffer, 0, buffer.length, this.config.HEADER_SIZE);
|
|
245
|
+
// Recalculate all checksums
|
|
246
|
+
if (this.config.CHECKSUM_ENABLED) {
|
|
247
|
+
await this.recalculateAllChecksums();
|
|
248
|
+
}
|
|
249
|
+
// Update header with full backup timestamp
|
|
250
|
+
await this.updateBackupHeader(true);
|
|
251
|
+
// Clear all dirty regions
|
|
252
|
+
this.dirtyRegions.clear();
|
|
253
|
+
const duration = performance.now() - startTime;
|
|
254
|
+
this.updateBackupStats('full', this.regionCount, duration);
|
|
255
|
+
return {
|
|
256
|
+
backedUpRegions: this.regionCount,
|
|
257
|
+
duration
|
|
258
|
+
};
|
|
259
|
+
} catch (error) {
|
|
260
|
+
console.error('Full backup failed:', error);
|
|
261
|
+
throw error;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
371
265
|
* Sync a batch of regions to file
|
|
372
|
-
*/
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
await this.fileHandle.write(regionBuffer, 0, regionSize, fileOffset);
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
// Execute all operations in parallel
|
|
393
|
-
await Promise.all(operations);
|
|
394
|
-
|
|
395
|
-
// Force sync to disk
|
|
396
|
-
await this.fileHandle.sync();
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/**
|
|
266
|
+
*/ async syncRegionBatch(regionIndices) {
|
|
267
|
+
const operations = regionIndices.map(async (regionIndex)=>{
|
|
268
|
+
const regionOffset = regionIndex * this.config.REGION_SIZE;
|
|
269
|
+
const fileOffset = this.config.HEADER_SIZE + regionOffset;
|
|
270
|
+
const regionSize = Math.min(this.config.REGION_SIZE, this.sharedBuffer.byteLength - regionOffset);
|
|
271
|
+
// Create buffer from SharedArrayBuffer region
|
|
272
|
+
const regionView = new Uint8Array(this.sharedBuffer, regionOffset, regionSize);
|
|
273
|
+
const regionBuffer = Buffer.from(regionView);
|
|
274
|
+
// Write region to file
|
|
275
|
+
await this.fileHandle.write(regionBuffer, 0, regionSize, fileOffset);
|
|
276
|
+
});
|
|
277
|
+
// Execute all operations in parallel
|
|
278
|
+
await Promise.all(operations);
|
|
279
|
+
// Force sync to disk
|
|
280
|
+
await this.fileHandle.sync();
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
400
283
|
* Update checksums for specified regions
|
|
401
|
-
*/
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
await this.fileHandle.write(
|
|
423
|
-
checksumBuffer, 0, 4, checksumTableOffset + (regionIndex * 4)
|
|
424
|
-
);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
/**
|
|
284
|
+
*/ async updateRegionChecksums(regionIndices) {
|
|
285
|
+
const checksumUpdates = regionIndices.map(async (regionIndex)=>{
|
|
286
|
+
const regionOffset = this.config.HEADER_SIZE + regionIndex * this.config.REGION_SIZE;
|
|
287
|
+
const checksum = await this.calculateRegionChecksum(regionIndex, regionOffset);
|
|
288
|
+
this.checksumTable.set(regionIndex, checksum);
|
|
289
|
+
return {
|
|
290
|
+
regionIndex,
|
|
291
|
+
checksum
|
|
292
|
+
};
|
|
293
|
+
});
|
|
294
|
+
const results = await Promise.all(checksumUpdates);
|
|
295
|
+
// Write updated checksums to file
|
|
296
|
+
const checksumTableOffset = Number((await this.readFileHeader()).checksumTable);
|
|
297
|
+
for (const { regionIndex, checksum } of results){
|
|
298
|
+
const checksumBuffer = Buffer.allocUnsafe(4);
|
|
299
|
+
checksumBuffer.writeUInt32LE(checksum, 0);
|
|
300
|
+
await this.fileHandle.write(checksumBuffer, 0, 4, checksumTableOffset + regionIndex * 4);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
429
304
|
* Calculate CRC32 checksum for a region
|
|
430
|
-
*/
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
regionData = new Uint8Array(this.sharedBuffer, regionOffset, regionSize);
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
return this.crc32(regionData);
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
/**
|
|
305
|
+
*/ async calculateRegionChecksum(regionIndex, fileOffset) {
|
|
306
|
+
const regionSize = Math.min(this.config.REGION_SIZE, this.sharedBuffer.byteLength - regionIndex * this.config.REGION_SIZE);
|
|
307
|
+
// Read region data from file (for verification) or SharedArrayBuffer (for update)
|
|
308
|
+
let regionData;
|
|
309
|
+
if (fileOffset) {
|
|
310
|
+
const buffer = Buffer.alloc(regionSize);
|
|
311
|
+
await this.fileHandle.read(buffer, 0, regionSize, fileOffset);
|
|
312
|
+
regionData = new Uint8Array(buffer);
|
|
313
|
+
} else {
|
|
314
|
+
const regionOffset = regionIndex * this.config.REGION_SIZE;
|
|
315
|
+
regionData = new Uint8Array(this.sharedBuffer, regionOffset, regionSize);
|
|
316
|
+
}
|
|
317
|
+
return this.crc32(regionData);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
452
320
|
* Recalculate checksums for all regions
|
|
453
|
-
*/
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
const checksumBuffer = Buffer.alloc(this.regionCount * 4);
|
|
474
|
-
const checksumView = new DataView(checksumBuffer.buffer);
|
|
475
|
-
|
|
476
|
-
checksums.forEach((checksum, index) => {
|
|
477
|
-
checksumView.setUint32(index * 4, checksum, true);
|
|
478
|
-
});
|
|
479
|
-
|
|
480
|
-
await this.fileHandle.write(
|
|
481
|
-
checksumBuffer, 0, checksumBuffer.length, checksumTableOffset
|
|
482
|
-
);
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
/**
|
|
321
|
+
*/ async recalculateAllChecksums() {
|
|
322
|
+
this.checksumTable.clear();
|
|
323
|
+
const checksumPromises = Array.from({
|
|
324
|
+
length: this.regionCount
|
|
325
|
+
}, (_, i)=>this.calculateRegionChecksum(i, null));
|
|
326
|
+
const checksums = await Promise.all(checksumPromises);
|
|
327
|
+
// Update checksum table
|
|
328
|
+
checksums.forEach((checksum, index)=>{
|
|
329
|
+
this.checksumTable.set(index, checksum);
|
|
330
|
+
});
|
|
331
|
+
// Write entire checksum table to file
|
|
332
|
+
const checksumTableOffset = Number((await this.readFileHeader()).checksumTable);
|
|
333
|
+
const checksumBuffer = Buffer.alloc(this.regionCount * 4);
|
|
334
|
+
const checksumView = new DataView(checksumBuffer.buffer);
|
|
335
|
+
checksums.forEach((checksum, index)=>{
|
|
336
|
+
checksumView.setUint32(index * 4, checksum, true);
|
|
337
|
+
});
|
|
338
|
+
await this.fileHandle.write(checksumBuffer, 0, checksumBuffer.length, checksumTableOffset);
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
486
341
|
* Update backup header with latest metadata
|
|
487
|
-
*/
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
await this.fileHandle.write(
|
|
501
|
-
headerBuffer, 0, isFullBackup ? 24 : 16,
|
|
502
|
-
FILE_HEADER_LAYOUT.dirtyRegions
|
|
503
|
-
);
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
/**
|
|
342
|
+
*/ async updateBackupHeader(isFullBackup = false) {
|
|
343
|
+
const headerBuffer = Buffer.alloc(64); // Partial header update
|
|
344
|
+
const headerView = new DataView(headerBuffer.buffer);
|
|
345
|
+
const now = BigInt(Date.now());
|
|
346
|
+
headerView.setUint32(0, this.dirtyRegions.size, true); // dirty regions
|
|
347
|
+
headerView.setBigUint64(8, now, true); // last checkpoint
|
|
348
|
+
if (isFullBackup) {
|
|
349
|
+
headerView.setBigUint64(16, now, true); // last full backup
|
|
350
|
+
}
|
|
351
|
+
await this.fileHandle.write(headerBuffer, 0, isFullBackup ? 24 : 16, FILE_HEADER_LAYOUT.dirtyRegions);
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
507
354
|
* Read file header for metadata
|
|
508
|
-
*/
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
/**
|
|
355
|
+
*/ async readFileHeader() {
|
|
356
|
+
const headerBuffer = Buffer.alloc(this.config.HEADER_SIZE);
|
|
357
|
+
await this.fileHandle.read(headerBuffer, 0, this.config.HEADER_SIZE, 0);
|
|
358
|
+
const headerView = new DataView(headerBuffer.buffer);
|
|
359
|
+
return {
|
|
360
|
+
magic: headerView.getUint32(FILE_HEADER_LAYOUT.magic, true),
|
|
361
|
+
version: headerView.getUint32(FILE_HEADER_LAYOUT.version, true),
|
|
362
|
+
fileSize: headerView.getBigUint64(FILE_HEADER_LAYOUT.fileSize, true),
|
|
363
|
+
dataSize: headerView.getBigUint64(FILE_HEADER_LAYOUT.dataSize, true),
|
|
364
|
+
regionCount: headerView.getUint32(FILE_HEADER_LAYOUT.regionCount, true),
|
|
365
|
+
dirtyRegions: headerView.getUint32(FILE_HEADER_LAYOUT.dirtyRegions, true),
|
|
366
|
+
lastCheckpoint: headerView.getBigUint64(FILE_HEADER_LAYOUT.lastCheckpoint, true),
|
|
367
|
+
lastFullBackup: headerView.getBigUint64(FILE_HEADER_LAYOUT.lastFullBackup, true),
|
|
368
|
+
checksumTable: headerView.getBigUint64(FILE_HEADER_LAYOUT.checksumTable, true),
|
|
369
|
+
metadataOffset: headerView.getBigUint64(FILE_HEADER_LAYOUT.metadataOffset, true)
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
530
373
|
* Restore shared buffer from backup file
|
|
531
|
-
*/
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
/**
|
|
374
|
+
*/ async restoreFromBackup() {
|
|
375
|
+
if (!this.isInitialized) {
|
|
376
|
+
await this.initialize();
|
|
377
|
+
}
|
|
378
|
+
const startTime = performance.now();
|
|
379
|
+
try {
|
|
380
|
+
// Verify file integrity before restore
|
|
381
|
+
await this.verifyFileIntegrity();
|
|
382
|
+
// Read data from file to shared buffer
|
|
383
|
+
const dataBuffer = Buffer.alloc(this.sharedBuffer.byteLength);
|
|
384
|
+
await this.fileHandle.read(dataBuffer, 0, dataBuffer.length, this.config.HEADER_SIZE);
|
|
385
|
+
// Copy to SharedArrayBuffer
|
|
386
|
+
const bufferView = new Uint8Array(this.sharedBuffer);
|
|
387
|
+
bufferView.set(dataBuffer);
|
|
388
|
+
// Clear dirty regions after successful restore
|
|
389
|
+
this.dirtyRegions.clear();
|
|
390
|
+
const duration = performance.now() - startTime;
|
|
391
|
+
console.log(`Restore completed in ${duration.toFixed(2)}ms`);
|
|
392
|
+
return {
|
|
393
|
+
success: true,
|
|
394
|
+
duration,
|
|
395
|
+
restoredBytes: dataBuffer.length
|
|
396
|
+
};
|
|
397
|
+
} catch (error) {
|
|
398
|
+
console.error('Restore failed:', error);
|
|
399
|
+
return {
|
|
400
|
+
success: false,
|
|
401
|
+
error: error.message,
|
|
402
|
+
duration: 0
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
567
407
|
* Mark region as dirty for next backup
|
|
568
|
-
*/
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
/**
|
|
408
|
+
*/ markRegionDirty(offset) {
|
|
409
|
+
const regionIndex = Math.floor(offset / this.config.REGION_SIZE);
|
|
410
|
+
this.dirtyRegions.add(regionIndex);
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
575
413
|
* Start background persistence operations
|
|
576
|
-
*/
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
/**
|
|
414
|
+
*/ startBackgroundOperations() {
|
|
415
|
+
// Periodic checkpoints
|
|
416
|
+
this.checkpointTimer = setInterval(async ()=>{
|
|
417
|
+
if (this.dirtyRegions.size > 0) {
|
|
418
|
+
try {
|
|
419
|
+
await this.incrementalBackup();
|
|
420
|
+
} catch (error) {
|
|
421
|
+
console.error('Background checkpoint failed:', error);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}, this.config.CHECKPOINT_INTERVAL);
|
|
425
|
+
// Periodic full backups
|
|
426
|
+
setInterval(async ()=>{
|
|
427
|
+
try {
|
|
428
|
+
await this.fullBackup();
|
|
429
|
+
console.log('Scheduled full backup completed');
|
|
430
|
+
} catch (error) {
|
|
431
|
+
console.error('Scheduled full backup failed:', error);
|
|
432
|
+
}
|
|
433
|
+
}, this.config.FULL_BACKUP_INTERVAL * 1000);
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
601
436
|
* Stop background operations
|
|
602
|
-
*/
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
/**
|
|
437
|
+
*/ stopBackgroundOperations() {
|
|
438
|
+
if (this.checkpointTimer) {
|
|
439
|
+
clearInterval(this.checkpointTimer);
|
|
440
|
+
this.checkpointTimer = null;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
611
444
|
* Graceful shutdown with final backup
|
|
612
|
-
*/
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
console.log('Persistence shutdown completed');
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
/**
|
|
445
|
+
*/ async shutdown() {
|
|
446
|
+
console.log('Shutting down persistence layer...');
|
|
447
|
+
// Stop background operations
|
|
448
|
+
this.stopBackgroundOperations();
|
|
449
|
+
// Perform final incremental backup
|
|
450
|
+
if (this.dirtyRegions.size > 0) {
|
|
451
|
+
await this.incrementalBackup();
|
|
452
|
+
}
|
|
453
|
+
// Close file handle
|
|
454
|
+
if (this.fileHandle) {
|
|
455
|
+
await this.fileHandle.close();
|
|
456
|
+
this.fileHandle = null;
|
|
457
|
+
}
|
|
458
|
+
console.log('Persistence shutdown completed');
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
634
461
|
* Update backup statistics
|
|
635
|
-
*/
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
/**
|
|
462
|
+
*/ updateBackupStats(type, regionCount, duration) {
|
|
463
|
+
this.stats.totalBackups++;
|
|
464
|
+
this.stats.regionsSync += regionCount;
|
|
465
|
+
this.stats.totalSyncTime += duration;
|
|
466
|
+
this.stats.avgSyncTime = this.stats.totalSyncTime / this.stats.totalBackups;
|
|
467
|
+
this.stats.lastBackupTime = Date.now();
|
|
468
|
+
if (type === 'incremental') {
|
|
469
|
+
this.stats.incrementalBackups++;
|
|
470
|
+
} else if (type === 'full') {
|
|
471
|
+
this.stats.fullBackups++;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
651
475
|
* Get persistence statistics
|
|
652
|
-
*/
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
/**
|
|
476
|
+
*/ getStats() {
|
|
477
|
+
return {
|
|
478
|
+
...this.stats,
|
|
479
|
+
dirtyRegions: this.dirtyRegions.size,
|
|
480
|
+
totalRegions: this.regionCount,
|
|
481
|
+
fileSize: this.fileSize,
|
|
482
|
+
isInitialized: this.isInitialized,
|
|
483
|
+
checksumTableSize: this.checksumTable.size
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
665
487
|
* CRC32 checksum implementation
|
|
666
|
-
*/
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
return (crc ^ 0xFFFFFFFF) >>> 0;
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
/**
|
|
488
|
+
*/ crc32(data) {
|
|
489
|
+
const crcTable = this.getCrcTable();
|
|
490
|
+
let crc = 0xFFFFFFFF;
|
|
491
|
+
for(let i = 0; i < data.length; i++){
|
|
492
|
+
crc = crcTable[(crc ^ data[i]) & 0xFF] ^ crc >>> 8;
|
|
493
|
+
}
|
|
494
|
+
return (crc ^ 0xFFFFFFFF) >>> 0;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
679
497
|
* Generate CRC32 lookup table
|
|
680
|
-
*/
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
498
|
+
*/ getCrcTable() {
|
|
499
|
+
if (!this._crcTable) {
|
|
500
|
+
this._crcTable = new Array(256);
|
|
501
|
+
for(let i = 0; i < 256; i++){
|
|
502
|
+
let crc = i;
|
|
503
|
+
for(let j = 0; j < 8; j++){
|
|
504
|
+
crc = crc & 1 ? 0xEDB88320 ^ crc >>> 1 : crc >>> 1;
|
|
505
|
+
}
|
|
506
|
+
this._crcTable[i] = crc;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return this._crcTable;
|
|
510
|
+
}
|
|
511
|
+
constructor(sharedBuffer, backupPath, config = PERSISTENCE_CONFIG){
|
|
512
|
+
this.sharedBuffer = sharedBuffer;
|
|
513
|
+
this.backupPath = backupPath;
|
|
514
|
+
this.config = config;
|
|
515
|
+
// Memory region tracking
|
|
516
|
+
this.regionCount = Math.ceil(sharedBuffer.byteLength / config.REGION_SIZE);
|
|
517
|
+
this.dirtyRegions = new Set();
|
|
518
|
+
this.regionChecksums = new Map();
|
|
519
|
+
// File handles and metadata
|
|
520
|
+
this.fileHandle = null;
|
|
521
|
+
this.fileSize = 0;
|
|
522
|
+
this.isInitialized = false;
|
|
523
|
+
// Performance metrics
|
|
524
|
+
this.stats = {
|
|
525
|
+
totalBackups: 0,
|
|
526
|
+
incrementalBackups: 0,
|
|
527
|
+
fullBackups: 0,
|
|
528
|
+
totalSyncTime: 0,
|
|
529
|
+
avgSyncTime: 0,
|
|
530
|
+
regionsSync: 0,
|
|
531
|
+
checksumFailures: 0,
|
|
532
|
+
lastBackupTime: 0
|
|
533
|
+
};
|
|
534
|
+
// Background operations
|
|
535
|
+
this.backgroundSync = null;
|
|
536
|
+
this.checkpointTimer = null;
|
|
537
|
+
// Integrity verification
|
|
538
|
+
this.checksumTable = new Map();
|
|
539
|
+
}
|
|
540
|
+
}
|
|
698
541
|
/**
|
|
699
542
|
* Backup strategy manager for coordinating different backup approaches
|
|
700
|
-
*/
|
|
701
|
-
|
|
702
|
-
constructor(persistence) {
|
|
703
|
-
this.persistence = persistence;
|
|
704
|
-
this.strategies = new Map();
|
|
705
|
-
this.currentStrategy = 'adaptive';
|
|
706
|
-
|
|
707
|
-
this.initializeStrategies();
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
/**
|
|
543
|
+
*/ export class BackupStrategyManager {
|
|
544
|
+
/**
|
|
711
545
|
* Initialize available backup strategies
|
|
712
|
-
*/
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
priority: 'adaptive'
|
|
744
|
-
});
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
/**
|
|
546
|
+
*/ initializeStrategies() {
|
|
547
|
+
// Aggressive strategy - frequent incremental backups
|
|
548
|
+
this.strategies.set('aggressive', {
|
|
549
|
+
incrementalInterval: 1000,
|
|
550
|
+
fullBackupInterval: 1800,
|
|
551
|
+
dirtyThreshold: 0.05,
|
|
552
|
+
priority: 'consistency'
|
|
553
|
+
});
|
|
554
|
+
// Balanced strategy - moderate backup frequency
|
|
555
|
+
this.strategies.set('balanced', {
|
|
556
|
+
incrementalInterval: 5000,
|
|
557
|
+
fullBackupInterval: 3600,
|
|
558
|
+
dirtyThreshold: 0.1,
|
|
559
|
+
priority: 'balance'
|
|
560
|
+
});
|
|
561
|
+
// Performance strategy - minimize I/O impact
|
|
562
|
+
this.strategies.set('performance', {
|
|
563
|
+
incrementalInterval: 15000,
|
|
564
|
+
fullBackupInterval: 7200,
|
|
565
|
+
dirtyThreshold: 0.2,
|
|
566
|
+
priority: 'performance'
|
|
567
|
+
});
|
|
568
|
+
// Adaptive strategy - adjust based on workload
|
|
569
|
+
this.strategies.set('adaptive', {
|
|
570
|
+
incrementalInterval: 5000,
|
|
571
|
+
fullBackupInterval: 3600,
|
|
572
|
+
dirtyThreshold: 0.1,
|
|
573
|
+
priority: 'adaptive'
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
748
577
|
* Select optimal backup strategy based on workload characteristics
|
|
749
|
-
*/
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
if (selectedStrategy !== this.currentStrategy) {
|
|
775
|
-
this.switchStrategy(selectedStrategy);
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
return selectedStrategy;
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
/**
|
|
578
|
+
*/ selectStrategy(workloadMetrics) {
|
|
579
|
+
const { writeRate, dirtyRatio, memoryPressure, ioLatency// Average I/O latency
|
|
580
|
+
} = workloadMetrics;
|
|
581
|
+
let selectedStrategy = 'balanced';
|
|
582
|
+
if (writeRate > 1000 && dirtyRatio > 0.3) {
|
|
583
|
+
// High write rate with lots of changes - use aggressive
|
|
584
|
+
selectedStrategy = 'aggressive';
|
|
585
|
+
} else if (writeRate < 100 && memoryPressure < 0.5) {
|
|
586
|
+
// Low write rate with plenty of memory - use performance
|
|
587
|
+
selectedStrategy = 'performance';
|
|
588
|
+
} else if (ioLatency > 50) {
|
|
589
|
+
// High I/O latency - minimize backup frequency
|
|
590
|
+
selectedStrategy = 'performance';
|
|
591
|
+
} else {
|
|
592
|
+
// Use adaptive strategy to adjust dynamically
|
|
593
|
+
selectedStrategy = 'adaptive';
|
|
594
|
+
}
|
|
595
|
+
if (selectedStrategy !== this.currentStrategy) {
|
|
596
|
+
this.switchStrategy(selectedStrategy);
|
|
597
|
+
}
|
|
598
|
+
return selectedStrategy;
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
782
601
|
* Switch to different backup strategy
|
|
783
|
-
*/
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
this.persistence.config.INCREMENTAL_THRESHOLD = strategy.dirtyThreshold;
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
/**
|
|
602
|
+
*/ switchStrategy(strategyName) {
|
|
603
|
+
if (!this.strategies.has(strategyName)) {
|
|
604
|
+
throw new Error(`Unknown backup strategy: ${strategyName}`);
|
|
605
|
+
}
|
|
606
|
+
console.log(`Switching backup strategy: ${this.currentStrategy} -> ${strategyName}`);
|
|
607
|
+
this.currentStrategy = strategyName;
|
|
608
|
+
// Reconfigure persistence based on new strategy
|
|
609
|
+
const strategy = this.strategies.get(strategyName);
|
|
610
|
+
this.persistence.config.CHECKPOINT_INTERVAL = strategy.incrementalInterval;
|
|
611
|
+
this.persistence.config.FULL_BACKUP_INTERVAL = strategy.fullBackupInterval;
|
|
612
|
+
this.persistence.config.INCREMENTAL_THRESHOLD = strategy.dirtyThreshold;
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
800
615
|
* Get current strategy configuration
|
|
801
|
-
*/
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
616
|
+
*/ getCurrentStrategy() {
|
|
617
|
+
return {
|
|
618
|
+
name: this.currentStrategy,
|
|
619
|
+
config: this.strategies.get(this.currentStrategy)
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
constructor(persistence){
|
|
623
|
+
this.persistence = persistence;
|
|
624
|
+
this.strategies = new Map();
|
|
625
|
+
this.currentStrategy = 'adaptive';
|
|
626
|
+
this.initializeStrategies();
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
export { PERSISTENCE_CONFIG, FILE_HEADER_LAYOUT };
|