ken_nogi/dbbackup/lib/backupLocator.js
Kenichiro NOGI 67cc3da6c8 up
2026-07-13 19:02:04 +09:00

94 lines
3.8 KiB
JavaScript

"use strict";
/*
* 共有ドライブ上の Pleasanter_DB_Backup 配下から、指定ホスト名の最新バックアップ
* (同一タイムスタンプの分割ファイル一式)を特定する。restore.js が使用する。
* 新しい日付フォルダから順に探索し、対象ホスト名のファイルが無ければ古いフォルダへ遡る
* (多サーバー運用で、その日はまだ対象サーバーのバックアップが無い場合に対応するため)。
*/
function parseBackupFileName(fileName, hostname, prefix) {
const escapedHost = hostname.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const re = new RegExp(`^\\[${escapedHost}\\]${prefix}-(\\d{8}-\\d{6})\\.dmp(\\d{3})$`);
const m = re.exec(fileName);
if (!m) return null;
return { timestamp: m[1], partIndex: Number(m[2]) };
}
async function findLatestBackupFileSet(
token,
sharedriveId,
backupFolderId,
hostname,
drive,
logger,
prefix = "postgres"
) {
const dateFolders = (await drive.listChildren(token, sharedriveId, backupFolderId, logger))
.filter((f) => f.fileType === "FOLDER" && /^\d{8}$/.test(f.fileName))
.sort((a, b) => (a.fileName < b.fileName ? 1 : a.fileName > b.fileName ? -1 : 0));
for (const folder of dateFolders) {
const children = await drive.listChildren(token, sharedriveId, folder.fileId, logger);
const matched = children
.map((f) => {
const parsed = parseBackupFileName(f.fileName, hostname, prefix);
return parsed ? { file: f, ...parsed } : null;
})
.filter(Boolean);
if (matched.length === 0) continue;
const latestTimestamp = matched.reduce(
(max, m) => (m.timestamp > max ? m.timestamp : max),
matched[0].timestamp
);
const files = matched
.filter((m) => m.timestamp === latestTimestamp)
.sort((a, b) => a.partIndex - b.partIndex)
.map((m) => m.file);
return { dateFolderName: folder.fileName, timestamp: latestTimestamp, files };
}
return null;
}
function parseConfigArchiveName(fileName, hostname) {
const escapedHost = hostname.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const re = new RegExp(`^\\[${escapedHost}\\]config-(\\d{8}-\\d{6})\\.tar\\.gz$`);
const m = re.exec(fileName);
if (!m) return null;
return { timestamp: m[1] };
}
// 設定ファイルアーカイブ([hostname]config-<timestamp>.tar.gz)は分割されない単一ファイルのため、
// findLatestBackupFileSetとは別に、日付フォルダを新しい順に探索して最初に見つかった1件を返す。
async function findLatestConfigArchive(token, sharedriveId, backupFolderId, hostname, drive, logger) {
const dateFolders = (await drive.listChildren(token, sharedriveId, backupFolderId, logger))
.filter((f) => f.fileType === "FOLDER" && /^\d{8}$/.test(f.fileName))
.sort((a, b) => (a.fileName < b.fileName ? 1 : a.fileName > b.fileName ? -1 : 0));
for (const folder of dateFolders) {
const children = await drive.listChildren(token, sharedriveId, folder.fileId, logger);
const matched = children
.map((f) => {
const parsed = parseConfigArchiveName(f.fileName, hostname);
return parsed ? { file: f, ...parsed } : null;
})
.filter(Boolean)
.sort((a, b) => (a.timestamp < b.timestamp ? 1 : a.timestamp > b.timestamp ? -1 : 0));
if (matched.length === 0) continue;
return { dateFolderName: folder.fileName, timestamp: matched[0].timestamp, file: matched[0].file };
}
return null;
}
module.exports = { findLatestBackupFileSet, parseBackupFileName, findLatestConfigArchive, parseConfigArchiveName };