78 lines
3.4 KiB
JavaScript
78 lines
3.4 KiB
JavaScript
// backend/db/capacityTracker.js
|
||
// ─────────────────────────────────────────────────────────────────────────────
|
||
// MongoDB Capacity & Data Size Breakdown per Network Agent.
|
||
// Uses $collStats (O(1)) + per-agent document counts (indexed) for speed.
|
||
// Results are cached in memory and refreshed on each call.
|
||
// ─────────────────────────────────────────────────────────────────────────────
|
||
|
||
const mongoose = require('mongoose');
|
||
|
||
// In-memory cache — shared with the agents/storage API endpoint
|
||
let agentSizesCache = {}; // { agentUuid: sizeMB }
|
||
let lastCacheUpdate = null; // Date of last successful update
|
||
|
||
async function logCapacityStats(prefix = '[MongoDB]') {
|
||
try {
|
||
if (!mongoose.connection || !mongoose.connection.db) return;
|
||
const db = mongoose.connection.db;
|
||
|
||
// 1. Overall database stats (fast — reads WiredTiger metadata)
|
||
const stats = await db.command({ dbStats: 1 });
|
||
const dataSizeMB = (stats.dataSize / (1024 * 1024)).toFixed(2);
|
||
const storageMB = (stats.storageSize / (1024 * 1024)).toFixed(2);
|
||
console.log(`${prefix} Capacity Used: Data Size = ${dataSizeMB} MB, Storage Size = ${storageMB} MB`);
|
||
|
||
// 2. Fast per-agent estimate: avgObjSize (from $collStats) × document count per agent
|
||
const agentBytes = {};
|
||
const collections = await db.listCollections().toArray();
|
||
|
||
for (const colInfo of collections) {
|
||
const colName = colInfo.name;
|
||
if (colName.startsWith('system.')) continue;
|
||
const col = db.collection(colName);
|
||
|
||
// Check collection has agent-tagged documents
|
||
const sampleDoc = await col.findOne({ agent_uuid: { $ne: null } }, { projection: { _id: 1 } });
|
||
if (!sampleDoc) continue;
|
||
|
||
// $collStats is O(1) — reads storage engine metadata, never scans documents
|
||
const collStatsArr = await col.aggregate([{ $collStats: { storageStats: {} } }]).toArray();
|
||
const avgObjSize = collStatsArr[0]?.storageStats?.avgObjSize || 512; // bytes
|
||
|
||
// Count documents per agent using the existing agent_uuid index
|
||
const countResult = await col.aggregate([
|
||
{ $group: { _id: '$agent_uuid', count: { $sum: 1 } } }
|
||
]).toArray();
|
||
|
||
for (const r of countResult) {
|
||
const agent = r._id || 'Unknown';
|
||
agentBytes[agent] = (agentBytes[agent] || 0) + (r.count * avgObjSize);
|
||
}
|
||
}
|
||
|
||
// 3. Format, log, and update cache
|
||
const sorted = Object.entries(agentBytes)
|
||
.map(([agent, bytes]) => ({ agent, sizeMB: parseFloat((bytes / (1024 * 1024)).toFixed(2)) }))
|
||
.sort((a, b) => b.sizeMB - a.sizeMB);
|
||
|
||
if (sorted.length > 0) {
|
||
console.log(`${prefix} Data Size Breakdown per Agent:`);
|
||
for (const { agent, sizeMB } of sorted) {
|
||
console.log(` - ${agent}: ${sizeMB.toFixed(2)} MB`);
|
||
}
|
||
}
|
||
|
||
agentSizesCache = {};
|
||
for (const { agent, sizeMB } of sorted) {
|
||
agentSizesCache[agent] = sizeMB;
|
||
}
|
||
lastCacheUpdate = new Date();
|
||
|
||
} catch (err) {
|
||
console.warn(`${prefix} Could not retrieve DB capacity breakdown:`, err.message);
|
||
}
|
||
}
|
||
|
||
module.exports = { logCapacityStats, agentSizesCache: () => agentSizesCache, lastCacheUpdate: () => lastCacheUpdate };
|
||
|