count_project_size.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. const readline = require('readline')
  2. const { waitForDb, ObjectId, db } = require('../app/src/infrastructure/mongodb')
  3. const ProjectEntityHandler = require('../app/src/Features/Project/ProjectEntityHandler')
  4. const ProjectGetter = require('../app/src/Features/Project/ProjectGetter')
  5. const Errors = require('../app/src/Features/Errors/Errors')
  6. const FileStoreHandler = require('../app/src/Features/FileStore/FileStoreHandler')
  7. /* eslint-disable no-console */
  8. // Handles a list of project IDs from stdin, one per line, and outputs the count of files and docs
  9. // in the project, along with the aggregated size in bytes for all files and docs.
  10. //
  11. // It outputs to stderr, so that the logging junk can be piped elsewhere - e.g., running like:
  12. // node scripts/count_project_size.js < /tmp/project_ids.txt /dev/null 2> /tmp/output.txt
  13. //
  14. // The output format is line-per-project with data separated by a single space, containing:
  15. // - projectId
  16. // - file count
  17. // - deleted files count
  18. // - doc count
  19. // - deleted docs count
  20. // - total size in bytes of (non deleted) files
  21. // - total size in bytes of (non deleted) docs
  22. async function countProjectFiles() {
  23. const rl = readline.createInterface({
  24. input: process.stdin,
  25. })
  26. for await (const projectId of rl) {
  27. try {
  28. const project = await ProjectGetter.promises.getProject(projectId)
  29. if (!project) {
  30. throw new Errors.NotFoundError('project not found')
  31. }
  32. const { files, docs } =
  33. ProjectEntityHandler.getAllEntitiesFromProject(project)
  34. const [fileSize, docSize] = await Promise.all([
  35. countFilesSize(files, projectId),
  36. countDocsSizes(docs),
  37. ])
  38. console.error(
  39. projectId,
  40. files.length,
  41. (project.deletedFiles && project.deletedFiles.length) || 0,
  42. docs.length,
  43. (project.deletedDocs && project.deletedDocs.length) || 0,
  44. fileSize,
  45. docSize
  46. )
  47. } catch (err) {
  48. if (err instanceof Errors.NotFoundError) {
  49. console.error(projectId, 'NOTFOUND')
  50. } else {
  51. console.log(projectId, 'ERROR', err.name, err.message)
  52. }
  53. }
  54. }
  55. }
  56. async function countFilesSize(files, projectId) {
  57. if (!files?.length > 0) {
  58. return 0
  59. }
  60. const ids = files.map(fileObject => fileObject.file._id)
  61. let totalFileSize = 0
  62. for (const fileId of ids) {
  63. const contentLength = await FileStoreHandler.promises.getFileSize(
  64. projectId,
  65. fileId
  66. )
  67. const size = parseInt(contentLength, 10)
  68. if (isNaN(size)) {
  69. throw new Error(
  70. `Unable to fetch file size for fileId=${fileId} and projectId=${projectId}`
  71. )
  72. }
  73. totalFileSize += size
  74. }
  75. return totalFileSize
  76. }
  77. async function countDocsSizes(docs) {
  78. if (!docs?.length > 0) {
  79. return 0
  80. }
  81. const ids = docs.map(docObject => docObject.doc._id)
  82. let totalDocSize = 0
  83. for (const docId of ids) {
  84. const result = await db.docs.aggregate([
  85. {
  86. $match: { _id: new ObjectId(docId) },
  87. },
  88. {
  89. $project: {
  90. lineSizeInBytes: {
  91. $reduce: {
  92. input: { $ifNull: ['$lines', []] },
  93. initialValue: 0,
  94. in: {
  95. $add: ['$$value', { $strLenBytes: '$$this' }],
  96. },
  97. },
  98. },
  99. },
  100. },
  101. ])
  102. const { lineSizeInBytes } = await result.next()
  103. if (isNaN(lineSizeInBytes)) {
  104. throw new Error(`Unable to fetch 'lineSizeInBytes' for docId=${docId}`)
  105. }
  106. totalDocSize += lineSizeInBytes
  107. }
  108. return totalDocSize
  109. }
  110. waitForDb()
  111. .then(countProjectFiles)
  112. .then(() => {
  113. process.exit(0)
  114. })
  115. .catch(err => {
  116. console.log('Aiee, something went wrong!', err)
  117. process.exit(1)
  118. })