Skip to content

Commit 2980074

Browse files
committed
Add query in stats for collectins size in TB
1 parent 8b5e47a commit 2980074

1 file changed

Lines changed: 42 additions & 0 deletions

File tree

‎src/routes/stats/index.js‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ const { BAD_REQUEST } = require('../../utils/status-codes');
1010

1111
const router = Router({ mergeParams: true });
1212

13+
// In-memory cache for the GridFS size aggregation (expensive full-collection scan)
14+
const CACHE_TTL_MS = 60 * 60 * 1000 * 24; // 24 hour
15+
let gridFsSizeCache = new Map();
16+
1317
// Root -> display available PDBs
1418
router.route('/').get(
1519
handler({
@@ -27,10 +31,48 @@ router.route('/').get(
2731
const database = await getDatabase(request);
2832
// Get database statistics
2933
const dbStats = await database.db.command({ dbStats: 1, scale: 1e6}); // Results in KB
34+
// Compute the real stored size of GridFS files for the queried projects
35+
// Without a query filter this would require aggregating all files in the DB,
36+
// so we skip it and fall back to the dbStats figure instead
37+
const query = request.query.query;
38+
let realDataSizeInTB;
39+
if (!query) {
40+
realDataSizeInTB = +(dbStats.dataSize / 1e6);
41+
} else {
42+
// This is expensive so we cache it with a TTL, keyed by query string
43+
if (!gridFsSizeCache.has(query)
44+
|| Date.now() - gridFsSizeCache.get(query).timestamp > CACHE_TTL_MS) {
45+
const projectsFinder = database.getBaseFilter();
46+
const processedQuery = await database.processProjectsQuery(query);
47+
if (processedQuery.error) return processedQuery;
48+
if (!projectsFinder.$and) projectsFinder.$and = processedQuery;
49+
else projectsFinder.$and = projectsFinder.$and.concat(processedQuery);
50+
// Get all file IDs, including those in MDs
51+
const projectsCursor = await database.projects.find(
52+
projectsFinder,
53+
{ projection: { files: 1, 'mds.files': 1 } },
54+
);
55+
const allProjects = await projectsCursor.toArray();
56+
// Flatten all file IDs
57+
const fileIds = allProjects.flatMap(project => [
58+
...(project.files ?? []).map(f => f.id),
59+
...(project.mds ?? []).flatMap(md => (md.files ?? []).map(f => f.id)),
60+
]);
61+
// Sum 'length' from fs.files for all those IDs
62+
const sizeAgg = await database.db.collection('fs.files').aggregate([
63+
{ $match: { _id: { $in: fileIds } } },
64+
{ $group: { _id: null, totalBytes: { $sum: '$length' } } },
65+
]).toArray();
66+
const totalBytes = sizeAgg.length > 0 ? sizeAgg[0].totalBytes : 0;
67+
gridFsSizeCache.set(query, { totalBytes, timestamp: Date.now() });
68+
}
69+
realDataSizeInTB = +(gridFsSizeCache.get(query).totalBytes / 1e12);
70+
}
3071
// Create a formatted response with values in TB
3172
const storageStats = {
3273
// databaseName: dbStats.db,
3374
dataSizeInTB: +(dbStats.dataSize / 1e6).toFixed(2),
75+
realDataSizeInTB, // Decimals are not fixed because we may have to change the unit (TB vs GB) depending on the value
3476
storageUsedInTB: +(dbStats.storageSize / 1e6).toFixed(2),
3577
indexSizeInMB: +(dbStats.indexSize).toFixed(2),
3678
usedDiskInTB: +(dbStats.fsUsedSize / 1e6).toFixed(2),

0 commit comments

Comments
 (0)