| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- /* eslint-disable
- camelcase,
- handle-callback-err,
- */
- // TODO: This file was created by bulk-decaffeinate.
- // Fix any style issues and re-enable lint.
- /*
- * decaffeinate suggestions:
- * DS101: Remove unnecessary use of Array.from
- * DS102: Remove unnecessary code created because of implicit returns
- * DS205: Consider reworking code to avoid use of IIFEs
- * DS207: Consider shorter variations of null checks
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
- let RedisManager
- const Settings = require('@overleaf/settings')
- const redis = require('@overleaf/redis-wrapper')
- const rclient = redis.createClient(Settings.redis.history)
- const Keys = Settings.redis.history.key_schema
- const async = require('async')
- module.exports = RedisManager = {
- getOldestDocUpdates(doc_id, batchSize, callback) {
- if (callback == null) {
- callback = function (error, jsonUpdates) {}
- }
- const key = Keys.uncompressedHistoryOps({ doc_id })
- return rclient.lrange(key, 0, batchSize - 1, callback)
- },
- expandDocUpdates(jsonUpdates, callback) {
- let rawUpdates
- if (callback == null) {
- callback = function (error, rawUpdates) {}
- }
- try {
- rawUpdates = Array.from(jsonUpdates || []).map(update =>
- JSON.parse(update)
- )
- } catch (e) {
- return callback(e)
- }
- return callback(null, rawUpdates)
- },
- deleteAppliedDocUpdates(project_id, doc_id, docUpdates, callback) {
- if (callback == null) {
- callback = function (error) {}
- }
- const multi = rclient.multi()
- // Delete all the updates which have been applied (exact match)
- for (const update of Array.from(docUpdates || [])) {
- multi.lrem(Keys.uncompressedHistoryOps({ doc_id }), 1, update)
- }
- return multi.exec(function (error, results) {
- if (error != null) {
- return callback(error)
- }
- // It's ok to delete the doc_id from the set here. Even though the list
- // of updates may not be empty, we will continue to process it until it is.
- return rclient.srem(
- Keys.docsWithHistoryOps({ project_id }),
- doc_id,
- function (error) {
- if (error != null) {
- return callback(error)
- }
- return callback(null)
- }
- )
- })
- },
- getDocIdsWithHistoryOps(project_id, callback) {
- if (callback == null) {
- callback = function (error, doc_ids) {}
- }
- return rclient.smembers(Keys.docsWithHistoryOps({ project_id }), callback)
- },
- // iterate over keys asynchronously using redis scan (non-blocking)
- // handle all the cluster nodes or single redis server
- _getKeys(pattern, callback) {
- const nodes = (typeof rclient.nodes === 'function'
- ? rclient.nodes('master')
- : undefined) || [rclient]
- const doKeyLookupForNode = (node, cb) =>
- RedisManager._getKeysFromNode(node, pattern, cb)
- return async.concatSeries(nodes, doKeyLookupForNode, callback)
- },
- _getKeysFromNode(node, pattern, callback) {
- let cursor = 0 // redis iterator
- const keySet = {} // use hash to avoid duplicate results
- // scan over all keys looking for pattern
- var doIteration = cb =>
- node.scan(
- cursor,
- 'MATCH',
- pattern,
- 'COUNT',
- 1000,
- function (error, reply) {
- let keys
- if (error != null) {
- return callback(error)
- }
- ;[cursor, keys] = Array.from(reply)
- for (const key of Array.from(keys)) {
- keySet[key] = true
- }
- if (cursor === '0') {
- // note redis returns string result not numeric
- return callback(null, Object.keys(keySet))
- } else {
- return doIteration()
- }
- }
- )
- return doIteration()
- },
- // extract ids from keys like DocsWithHistoryOps:57fd0b1f53a8396d22b2c24b
- // or DocsWithHistoryOps:{57fd0b1f53a8396d22b2c24b} (for redis cluster)
- _extractIds(keyList) {
- const ids = (() => {
- const result = []
- for (const key of Array.from(keyList)) {
- const m = key.match(/:\{?([0-9a-f]{24})\}?/) // extract object id
- result.push(m[1])
- }
- return result
- })()
- return ids
- },
- getProjectIdsWithHistoryOps(callback) {
- if (callback == null) {
- callback = function (error, project_ids) {}
- }
- return RedisManager._getKeys(
- Keys.docsWithHistoryOps({ project_id: '*' }),
- function (error, project_keys) {
- if (error != null) {
- return callback(error)
- }
- const project_ids = RedisManager._extractIds(project_keys)
- return callback(error, project_ids)
- }
- )
- },
- getAllDocIdsWithHistoryOps(callback) {
- // return all the docids, to find dangling history entries after
- // everything is flushed.
- if (callback == null) {
- callback = function (error, doc_ids) {}
- }
- return RedisManager._getKeys(
- Keys.uncompressedHistoryOps({ doc_id: '*' }),
- function (error, doc_keys) {
- if (error != null) {
- return callback(error)
- }
- const doc_ids = RedisManager._extractIds(doc_keys)
- return callback(error, doc_ids)
- }
- )
- },
- }
|