MongoManager.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /* eslint-disable
  2. no-unused-vars,
  3. */
  4. // TODO: This file was created by bulk-decaffeinate.
  5. // Fix any style issues and re-enable lint.
  6. /*
  7. * decaffeinate suggestions:
  8. * DS102: Remove unnecessary code created because of implicit returns
  9. * DS207: Consider shorter variations of null checks
  10. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  11. */
  12. let MongoManager
  13. const { db, ObjectId } = require('./mongodb')
  14. const PackManager = require('./PackManager')
  15. const async = require('async')
  16. const _ = require('underscore')
  17. const metrics = require('@overleaf/metrics')
  18. const logger = require('@overleaf/logger')
  19. module.exports = MongoManager = {
  20. getLastCompressedUpdate(docId, callback) {
  21. if (callback == null) {
  22. callback = function () {}
  23. }
  24. return db.docHistory
  25. .find(
  26. { doc_id: ObjectId(docId.toString()) },
  27. // only return the last entry in a pack
  28. { projection: { pack: { $slice: -1 } } }
  29. )
  30. .sort({ v: -1 })
  31. .limit(1)
  32. .toArray(function (error, compressedUpdates) {
  33. if (error != null) {
  34. return callback(error)
  35. }
  36. return callback(null, compressedUpdates[0] || null)
  37. })
  38. },
  39. peekLastCompressedUpdate(docId, callback) {
  40. // under normal use we pass back the last update as
  41. // callback(null,update,version).
  42. //
  43. // when we have an existing last update but want to force a new one
  44. // to start, we pass it back as callback(null,null,version), just
  45. // giving the version so we can check consistency.
  46. if (callback == null) {
  47. callback = function () {}
  48. }
  49. return MongoManager.getLastCompressedUpdate(
  50. docId,
  51. function (error, update) {
  52. if (error != null) {
  53. return callback(error)
  54. }
  55. if (update != null) {
  56. if (update.broken) {
  57. // marked as broken so we will force a new op
  58. return callback(null, null)
  59. } else if (update.pack != null) {
  60. if (update.finalised) {
  61. // no more ops can be appended
  62. return callback(
  63. null,
  64. null,
  65. update.pack[0] != null ? update.pack[0].v : undefined
  66. )
  67. } else {
  68. return callback(
  69. null,
  70. update,
  71. update.pack[0] != null ? update.pack[0].v : undefined
  72. )
  73. }
  74. } else {
  75. return callback(null, update, update.v)
  76. }
  77. } else {
  78. return PackManager.getLastPackFromIndex(
  79. docId,
  80. function (error, pack) {
  81. if (error != null) {
  82. return callback(error)
  83. }
  84. if (
  85. (pack != null ? pack.inS3 : undefined) != null &&
  86. (pack != null ? pack.v_end : undefined) != null
  87. ) {
  88. return callback(null, null, pack.v_end)
  89. }
  90. return callback(null, null)
  91. }
  92. )
  93. }
  94. }
  95. )
  96. },
  97. backportProjectId(projectId, docId, callback) {
  98. if (callback == null) {
  99. callback = function () {}
  100. }
  101. return db.docHistory.updateMany(
  102. {
  103. doc_id: ObjectId(docId.toString()),
  104. project_id: { $exists: false },
  105. },
  106. {
  107. $set: { project_id: ObjectId(projectId.toString()) },
  108. },
  109. callback
  110. )
  111. },
  112. getProjectMetaData(projectId, callback) {
  113. if (callback == null) {
  114. callback = function () {}
  115. }
  116. return db.projectHistoryMetaData.findOne(
  117. {
  118. project_id: ObjectId(projectId.toString()),
  119. },
  120. callback
  121. )
  122. },
  123. setProjectMetaData(projectId, metadata, callback) {
  124. if (callback == null) {
  125. callback = function () {}
  126. }
  127. return db.projectHistoryMetaData.updateOne(
  128. {
  129. project_id: ObjectId(projectId),
  130. },
  131. {
  132. $set: metadata,
  133. },
  134. {
  135. upsert: true,
  136. },
  137. callback
  138. )
  139. },
  140. upgradeHistory(projectId, callback) {
  141. // preserve the project's existing history
  142. if (callback == null) {
  143. callback = function () {}
  144. }
  145. return db.docHistory.updateMany(
  146. {
  147. project_id: ObjectId(projectId),
  148. temporary: true,
  149. expiresAt: { $exists: true },
  150. },
  151. {
  152. $set: { temporary: false },
  153. $unset: { expiresAt: '' },
  154. },
  155. callback
  156. )
  157. },
  158. ensureIndices() {
  159. // For finding all updates that go into a diff for a doc
  160. db.docHistory.ensureIndex({ doc_id: 1, v: 1 }, { background: true })
  161. // For finding all updates that affect a project
  162. db.docHistory.ensureIndex(
  163. { project_id: 1, 'meta.end_ts': 1 },
  164. { background: true }
  165. )
  166. // For finding updates that don't yet have a project_id and need it inserting
  167. db.docHistory.ensureIndex(
  168. { doc_id: 1, project_id: 1 },
  169. { background: true }
  170. )
  171. // For finding project meta-data
  172. db.projectHistoryMetaData.ensureIndex(
  173. { project_id: 1 },
  174. { background: true }
  175. )
  176. // TTL index for auto deleting week old temporary ops
  177. db.docHistory.ensureIndex(
  178. { expiresAt: 1 },
  179. { expireAfterSeconds: 0, background: true }
  180. )
  181. // For finding packs to be checked for archiving
  182. db.docHistory.ensureIndex({ last_checked: 1 }, { background: true })
  183. // For finding archived packs
  184. return db.docHistoryIndex.ensureIndex(
  185. { project_id: 1 },
  186. { background: true }
  187. )
  188. },
  189. }
  190. ;['getLastCompressedUpdate', 'getProjectMetaData', 'setProjectMetaData'].map(
  191. method =>
  192. metrics.timeAsyncMethod(MongoManager, method, 'mongo.MongoManager', logger)
  193. )