This commit is contained in:
Raven Scott
2026-05-28 01:14:13 -04:00
parent 6ccfac862d
commit d95baaed1c
3 changed files with 118 additions and 74 deletions
+1 -1
View File
@@ -644,7 +644,7 @@ See [test-scripts/README.md](../test-scripts/README.md) for more information abo
...
}
```
- Restart P2NS — data is copied once from `previousVersion` to the new core, then `migrated` is set to `true` (`previousVersion` stays in config for reference)
- Restart P2NS — data is copied once from `previousVersion` to the new core when that core has records; if there is nothing to copy, migration is **skipped** and `migrated` is still set to `true` (`previousVersion` stays in config for reference)
- On the next bump, update `previousVersion` to the version you are leaving (e.g. `1.4.1` → `1.4.2` with `"previousVersion": "1.4.1"`) and set `migrated` back to `false`
- Coordinate the same version bump with all peers so replication uses the same core topic
- If upgrading from before auto-migration and data appears missing, add the old version to `hyperdb.versionHistory` once (e.g. `"versionHistory": ["1.2.1"]`) and `"migrated": false`
+100 -56
View File
@@ -359,6 +359,27 @@ async function readPluginHyperdbConfig(pluginDir) {
return config && config.hyperdb ? config.hyperdb : null;
}
/**
* Record successful migration (or intentional skip) for the target version.
* @param {string} pluginDir
* @param {string} pluginDomain
* @param {string} targetVersion
* @param {string|null} sourceVersion
* @returns {Promise<void>}
*/
async function finalizeVersionMigration(pluginDir, pluginDomain, targetVersion, sourceVersion = null) {
try {
await writeVersionManifest(pluginDir, targetVersion);
} catch (err) {
logWarn('DBVersionMigration', `Could not write manifest for ${pluginDomain}: ${err.message}`);
}
await appendVersionHistory(pluginDir, targetVersion);
if (sourceVersion && sourceVersion !== targetVersion) {
await appendVersionHistory(pluginDir, sourceVersion);
}
await markMigrationCompleteInConfig(pluginDir, pluginDomain);
}
/**
* Mark migration complete in config.json (hyperdb.migrated = true; previousVersion is kept).
* @param {string} pluginDir
@@ -393,6 +414,29 @@ function isMigrationMarkedComplete(hyperdbConfig) {
return !!(hyperdbConfig && hyperdbConfig.migrated === true);
}
/**
* @param {string} pluginDir
* @param {string} pluginDomain
* @param {string} dbDir
* @param {string} version
* @param {string[]} collectionIds
* @returns {Promise<boolean>}
*/
async function versionCoreHasRecordsAt(pluginDir, pluginDomain, version, dbDir, collectionIds) {
const pluginStoreDir = getPluginDbDir(pluginDir);
const store = new Corestore(pluginStoreDir);
await store.ready();
try {
return await versionCoreHasRecords(store, pluginDomain, version, dbDir, collectionIds);
} finally {
try {
await store.close();
} catch (err) {
logDebug('DBVersionMigration', `Error closing version probe store: ${err.message}`);
}
}
}
/**
* Resolve source version when manifest is missing but an older core may still hold data.
* @param {string} pluginDomain
@@ -462,6 +506,7 @@ async function discoverLegacySourceVersion(pluginDomain, pluginDir, dbDir, targe
async function ensurePluginDatabaseVersionMigration(pluginDomain, pluginDir, dbDir) {
const targetVersion = await readPluginConfigVersion(pluginDir);
const hyperdbConfig = await readPluginHyperdbConfig(pluginDir);
const migrationPending = !isMigrationMarkedComplete(hyperdbConfig);
let collectionIds = getCollectionIds(hyperdbConfig);
if (collectionIds.length === 0) {
@@ -470,13 +515,17 @@ async function ensurePluginDatabaseVersionMigration(pluginDomain, pluginDir, dbD
collectionIds = getCollectionIdsFromDefinition(def);
} catch (err) {
logWarn('DBVersionMigration', `Could not resolve collections for ${pluginDomain}: ${err.message}`);
if (migrationPending) {
logWarn('DBVersionMigration', `Marking migration complete for ${pluginDomain} to avoid retry loop`);
await finalizeVersionMigration(pluginDir, pluginDomain, targetVersion, hyperdbConfig?.previousVersion || null);
}
return;
}
}
const manifest = await readVersionManifest(pluginDir);
if (isMigrationMarkedComplete(hyperdbConfig)) {
if (!migrationPending) {
if (!manifest || manifest.version !== targetVersion) {
try {
await writeVersionManifest(pluginDir, targetVersion);
@@ -490,8 +539,7 @@ async function ensurePluginDatabaseVersionMigration(pluginDomain, pluginDir, dbD
}
if (manifest && manifest.version === targetVersion && !hyperdbConfig?.previousVersion) {
await markMigrationCompleteInConfig(pluginDir, pluginDomain);
await appendVersionHistory(pluginDir, targetVersion);
await finalizeVersionMigration(pluginDir, pluginDomain, targetVersion, null);
return;
}
@@ -509,34 +557,14 @@ async function ensurePluginDatabaseVersionMigration(pluginDomain, pluginDir, dbD
}
if (!sourceVersion) {
const pluginStoreDir = getPluginDbDir(pluginDir);
const store = new Corestore(pluginStoreDir);
await store.ready();
try {
const currentHasData = await versionCoreHasRecords(
store,
pluginDomain,
targetVersion,
dbDir,
collectionIds
);
if (currentHasData) {
if (await versionCoreHasRecordsAt(pluginDir, pluginDomain, targetVersion, dbDir, collectionIds)) {
logInfo(
'DBVersionMigration',
`No manifest for ${pluginDomain}; data already present on v${targetVersion}, recording manifest`
`No manifest for ${pluginDomain}; data already on v${targetVersion} — migration skipped`
);
await writeVersionManifest(pluginDir, targetVersion);
await appendVersionHistory(pluginDir, targetVersion);
await markMigrationCompleteInConfig(pluginDir, pluginDomain);
await finalizeVersionMigration(pluginDir, pluginDomain, targetVersion, null);
return;
}
} finally {
try {
await store.close();
} catch (err) {
logDebug('DBVersionMigration', `Error closing probe store: ${err.message}`);
}
}
sourceVersion = await discoverLegacySourceVersion(
pluginDomain,
@@ -548,45 +576,44 @@ async function ensurePluginDatabaseVersionMigration(pluginDomain, pluginDir, dbD
);
if (!sourceVersion) {
logDebug(
logInfo(
'DBVersionMigration',
`No prior database version to migrate for ${pluginDomain} (target v${targetVersion})`
`No prior database version with data for ${pluginDomain} (target v${targetVersion}) — migration skipped`
);
await writeVersionManifest(pluginDir, targetVersion);
await appendVersionHistory(pluginDir, targetVersion);
await markMigrationCompleteInConfig(pluginDir, pluginDomain);
await finalizeVersionMigration(pluginDir, pluginDomain, targetVersion, hyperdbConfig?.previousVersion || null);
return;
}
}
if (sourceVersion === targetVersion) {
await writeVersionManifest(pluginDir, targetVersion);
await appendVersionHistory(pluginDir, targetVersion);
await markMigrationCompleteInConfig(pluginDir, pluginDomain);
logInfo('DBVersionMigration', `Source and target are both v${targetVersion} for ${pluginDomain} — migration skipped`);
await finalizeVersionMigration(pluginDir, pluginDomain, targetVersion, sourceVersion);
return;
}
const pluginStoreDir = getPluginDbDir(pluginDir);
const probeStore = new Corestore(pluginStoreDir);
await probeStore.ready();
try {
if (await versionCoreHasRecords(probeStore, pluginDomain, targetVersion, dbDir, collectionIds)) {
if (await versionCoreHasRecordsAt(pluginDir, pluginDomain, targetVersion, dbDir, collectionIds)) {
logInfo(
'DBVersionMigration',
`Target v${targetVersion} for ${pluginDomain} already has data; recording manifest without copy`
`Target v${targetVersion} for ${pluginDomain} already has data — migration skipped`
);
await writeVersionManifest(pluginDir, targetVersion);
await appendVersionHistory(pluginDir, targetVersion);
await appendVersionHistory(pluginDir, sourceVersion);
await markMigrationCompleteInConfig(pluginDir, pluginDomain);
await finalizeVersionMigration(pluginDir, pluginDomain, targetVersion, sourceVersion);
return;
}
} finally {
try {
await probeStore.close();
} catch (err) {
logDebug('DBVersionMigration', `Error closing target probe store: ${err.message}`);
}
const sourceHasData = await versionCoreHasRecordsAt(
pluginDir,
pluginDomain,
sourceVersion,
dbDir,
collectionIds
);
if (!sourceHasData) {
logInfo(
'DBVersionMigration',
`No data on v${sourceVersion} for ${pluginDomain} — migration skipped (nothing to copy)`
);
await finalizeVersionMigration(pluginDir, pluginDomain, targetVersion, sourceVersion);
return;
}
try {
@@ -609,11 +636,19 @@ async function ensurePluginDatabaseVersionMigration(pluginDomain, pluginDir, dbD
hyperdbConfig
);
if (hadLegacy && hadLegacy !== sourceVersion) {
const altHasData = await versionCoreHasRecordsAt(
pluginDir,
pluginDomain,
hadLegacy,
dbDir,
collectionIds
);
if (altHasData) {
logWarn(
'DBVersionMigration',
`Manifest pointed at v${sourceVersion} but data was found on v${hadLegacy}; retrying migration`
`No records on v${sourceVersion}; retrying from v${hadLegacy} for ${pluginDomain}`
);
await migrateBetweenVersions(
const retry = await migrateBetweenVersions(
pluginDomain,
pluginDir,
dbDir,
@@ -621,6 +656,18 @@ async function ensurePluginDatabaseVersionMigration(pluginDomain, pluginDir, dbD
targetVersion,
collectionIds
);
if (retry.migrated === 0) {
logInfo(
'DBVersionMigration',
`Retry from v${hadLegacy} copied no records for ${pluginDomain} — migration skipped`
);
}
}
} else {
logInfo(
'DBVersionMigration',
`Migration from v${sourceVersion} copied no records for ${pluginDomain} — treating as skip`
);
}
}
} catch (err) {
@@ -631,10 +678,7 @@ async function ensurePluginDatabaseVersionMigration(pluginDomain, pluginDir, dbD
throw err;
}
await writeVersionManifest(pluginDir, targetVersion);
await appendVersionHistory(pluginDir, targetVersion);
await appendVersionHistory(pluginDir, sourceVersion);
await markMigrationCompleteInConfig(pluginDir, pluginDomain);
await finalizeVersionMigration(pluginDir, pluginDomain, targetVersion, sourceVersion);
}
module.exports = {
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "Peer Paste",
"version": "1.4.2",
"version": "1.4.3",
"domain": "peer.paste",
"enabled": true,
"description": "Temporary P2P text snippets with expiration and burn-after-read options",
@@ -10,8 +10,8 @@
"dependencies": {},
"www": "www",
"hyperdb": {
"previousVersion": "1.4.1",
"migrated": true,
"previousVersion": "1.4.2",
"migrated": false,
"schemas": {
"namespace": "peerpaste",
"structs": [