mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
switch to single get/set method for getProjectDocs
if project state hasn't changed, return the docs. Otherwise set the hash and return a 409 Conflict response.
This commit is contained in:
parent
f5f516a910
commit
9f3ec72f81
4 changed files with 57 additions and 27 deletions
|
@ -12,7 +12,14 @@ OpRangeNotAvailableError = (message) ->
|
||||||
return error
|
return error
|
||||||
OpRangeNotAvailableError.prototype.__proto__ = Error.prototype
|
OpRangeNotAvailableError.prototype.__proto__ = Error.prototype
|
||||||
|
|
||||||
|
ProjectStateChangedError = (message) ->
|
||||||
|
error = new Error(message)
|
||||||
|
error.name = "ProjectStateChangedError"
|
||||||
|
error.__proto__ = ProjectStateChangedError.prototype
|
||||||
|
return error
|
||||||
|
ProjectStateChangedError.prototype.__proto__ = Error.prototype
|
||||||
|
|
||||||
module.exports = Errors =
|
module.exports = Errors =
|
||||||
NotFoundError: NotFoundError
|
NotFoundError: NotFoundError
|
||||||
OpRangeNotAvailableError: OpRangeNotAvailableError
|
OpRangeNotAvailableError: OpRangeNotAvailableError
|
||||||
|
ProjectStateChangedError: ProjectStateChangedError
|
||||||
|
|
|
@ -39,6 +39,7 @@ module.exports = HttpController =
|
||||||
|
|
||||||
getProjectDocs: (req, res, next = (error) ->) ->
|
getProjectDocs: (req, res, next = (error) ->) ->
|
||||||
project_id = req.params.project_id
|
project_id = req.params.project_id
|
||||||
|
projectStateHash = req.query?.state
|
||||||
# exclude is string of existing docs "id:version,id:version,..."
|
# exclude is string of existing docs "id:version,id:version,..."
|
||||||
excludeItems = req.query?.exclude?.split(',') or []
|
excludeItems = req.query?.exclude?.split(',') or []
|
||||||
logger.log project_id: project_id, exclude: excludeItems, "getting docs via http"
|
logger.log project_id: project_id, exclude: excludeItems, "getting docs via http"
|
||||||
|
@ -47,12 +48,16 @@ module.exports = HttpController =
|
||||||
for item in excludeItems
|
for item in excludeItems
|
||||||
[id,version] = item?.split(':')
|
[id,version] = item?.split(':')
|
||||||
excludeVersions[id] = version
|
excludeVersions[id] = version
|
||||||
logger.log {project_id: project_id, excludeVersions: excludeVersions}, "excluding versions"
|
logger.log {project_id: project_id, projectStateHash: projectStateHash, excludeVersions: excludeVersions}, "excluding versions"
|
||||||
ProjectManager.getProjectDocs project_id, excludeVersions, (error, result) ->
|
ProjectManager.getProjectDocs project_id, projectStateHash, excludeVersions, (error, result) ->
|
||||||
timer.done()
|
timer.done()
|
||||||
return next(error) if error?
|
if error instanceof Errors.ProjectStateChangedError
|
||||||
logger.log project_id: project_id, result: ("#{doc._id}:#{doc.rev}" for doc in result), "got docs via http"
|
res.send 409 # conflict
|
||||||
res.send result
|
else if error?
|
||||||
|
return next(error)
|
||||||
|
else
|
||||||
|
logger.log project_id: project_id, result: ("#{doc._id}:#{doc.rev}" for doc in result), "got docs via http"
|
||||||
|
res.send result
|
||||||
|
|
||||||
setDoc: (req, res, next = (error) ->) ->
|
setDoc: (req, res, next = (error) ->) ->
|
||||||
doc_id = req.params.doc_id
|
doc_id = req.params.doc_id
|
||||||
|
|
|
@ -3,6 +3,7 @@ DocumentManager = require "./DocumentManager"
|
||||||
async = require "async"
|
async = require "async"
|
||||||
logger = require "logger-sharelatex"
|
logger = require "logger-sharelatex"
|
||||||
Metrics = require "./Metrics"
|
Metrics = require "./Metrics"
|
||||||
|
Errors = require "./Errors"
|
||||||
|
|
||||||
module.exports = ProjectManager =
|
module.exports = ProjectManager =
|
||||||
flushProjectWithLocks: (project_id, _callback = (error) ->) ->
|
flushProjectWithLocks: (project_id, _callback = (error) ->) ->
|
||||||
|
@ -57,29 +58,34 @@ module.exports = ProjectManager =
|
||||||
else
|
else
|
||||||
callback(null)
|
callback(null)
|
||||||
|
|
||||||
getProjectDocs: (project_id, excludeVersions = {}, _callback = (error) ->) ->
|
getProjectDocs: (project_id, projectStateHash, excludeVersions = {}, _callback = (error) ->) ->
|
||||||
timer = new Metrics.Timer("projectManager.getProjectDocs")
|
timer = new Metrics.Timer("projectManager.getProjectDocs")
|
||||||
callback = (args...) ->
|
callback = (args...) ->
|
||||||
timer.done()
|
timer.done()
|
||||||
_callback(args...)
|
_callback(args...)
|
||||||
|
|
||||||
RedisManager.getDocIdsInProject project_id, (error, doc_ids) ->
|
RedisManager.checkOrSetProjectState project_id, projectStateHash, (error, projectStateChanged) ->
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
jobs = []
|
# we can't return docs if project structure has changed
|
||||||
docs = []
|
return callback Errors.ProjectStateChangedError("project state changed") if projectStateChanged
|
||||||
for doc_id in doc_ids or []
|
# project structure hasn't changed, return doc content from redis
|
||||||
do (doc_id) ->
|
RedisManager.getDocIdsInProject project_id, (error, doc_ids) ->
|
||||||
jobs.push (cb) ->
|
|
||||||
# check the doc version first
|
|
||||||
RedisManager.getDocVersion doc_id, (error, version) ->
|
|
||||||
return cb(error) if error?
|
|
||||||
# skip getting the doc if we already have that version
|
|
||||||
return cb() if version is excludeVersions[doc_id]
|
|
||||||
# otherwise get the doc lines from redis
|
|
||||||
RedisManager.getDocLines doc_id, (error, lines) ->
|
|
||||||
return cb(error) if error?
|
|
||||||
docs.push {_id: doc_id, lines: lines, rev: version}
|
|
||||||
cb()
|
|
||||||
async.series jobs, (error) ->
|
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
callback(null, docs)
|
jobs = []
|
||||||
|
docs = []
|
||||||
|
for doc_id in doc_ids or []
|
||||||
|
do (doc_id) ->
|
||||||
|
jobs.push (cb) ->
|
||||||
|
# check the doc version first
|
||||||
|
RedisManager.getDocVersion doc_id, (error, version) ->
|
||||||
|
return cb(error) if error?
|
||||||
|
# skip getting the doc if we already have that version
|
||||||
|
return cb() if version is excludeVersions[doc_id]
|
||||||
|
# otherwise get the doc lines from redis
|
||||||
|
RedisManager.getDocLines doc_id, (error, lines) ->
|
||||||
|
return cb(error) if error?
|
||||||
|
docs.push {_id: doc_id, lines: lines, rev: version}
|
||||||
|
cb()
|
||||||
|
async.series jobs, (error) ->
|
||||||
|
return callback(error) if error?
|
||||||
|
callback(null, docs)
|
||||||
|
|
|
@ -90,10 +90,22 @@ module.exports = RedisManager =
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
multi = rclient.multi()
|
multi = rclient.multi()
|
||||||
multi.srem keys.docsInProject(project_id:project_id), doc_id
|
multi.srem keys.docsInProject(project_id:project_id), doc_id
|
||||||
if keys.clsiState?
|
if keys.projectState?
|
||||||
multi.del keys.clsiState(project_id:project_id)
|
multi.del keys.projectState(project_id:project_id)
|
||||||
multi.exec callback
|
multi.exec callback
|
||||||
|
|
||||||
|
checkOrSetProjectState: (project_id, newState, callback = (error, stateChanged) ->) ->
|
||||||
|
if keys.projectState?
|
||||||
|
multi = rclient.multi()
|
||||||
|
multi.getset keys.projectState(project_id:project_id), newState
|
||||||
|
multi.expire keys.projectState(project_id:project_id), 30 * minutes
|
||||||
|
multi.exec (error, response) ->
|
||||||
|
return callback(error) if error?
|
||||||
|
logger.log project_id: project_id, newState:newState, oldState: response[0], "checking project state"
|
||||||
|
callback(null, response[0] isnt newState)
|
||||||
|
else
|
||||||
|
callback(null,true)
|
||||||
|
|
||||||
getDoc : (project_id, doc_id, callback = (error, lines, version, ranges) ->)->
|
getDoc : (project_id, doc_id, callback = (error, lines, version, ranges) ->)->
|
||||||
timer = new metrics.Timer("redis.get-doc")
|
timer = new metrics.Timer("redis.get-doc")
|
||||||
multi = rclient.multi()
|
multi = rclient.multi()
|
||||||
|
|
Loading…
Reference in a new issue