MongoManager.js 5.6 KB

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