|
|
@@ -34,31 +34,28 @@ export const clearCacheCb = callbackify(clearCache)
|
|
|
/**
|
|
|
* @param {string} projectId
|
|
|
* @param {string} userId
|
|
|
+ * @param {string} cacheKey
|
|
|
* @return {Promise<void>}
|
|
|
*/
|
|
|
-export async function clearCache(projectId, userId) {
|
|
|
- const { dir } = snapshotPath(projectId, userId)
|
|
|
+export async function clearCache(projectId, userId, cacheKey) {
|
|
|
+ const { dir } = snapshotPath(cacheKey)
|
|
|
try {
|
|
|
await fs.promises.rm(dir, { recursive: true, force: true })
|
|
|
} catch (err) {
|
|
|
if (isENOENT(err)) return
|
|
|
logger.warn(
|
|
|
- { err, projectId, userId },
|
|
|
+ { err, projectId, userId, cacheKey },
|
|
|
'compile from cache: failed to clear history cache'
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * @param {string} projectId
|
|
|
- * @param {string} userId
|
|
|
+ * @param {string} cacheKey
|
|
|
* @return {{ dir: string, path: string, resyncPath: string }}
|
|
|
*/
|
|
|
-function snapshotPath(projectId, userId) {
|
|
|
- const dir = Path.join(
|
|
|
- Settings.path.clsiCacheDir,
|
|
|
- userId ? `${projectId}-${userId}` : projectId
|
|
|
- )
|
|
|
+function snapshotPath(cacheKey) {
|
|
|
+ const dir = Path.join(Settings.path.clsiCacheDir, cacheKey)
|
|
|
|
|
|
const path = Path.join(dir, 'history.json.gz')
|
|
|
const resyncPath = Path.join(dir, 'history-resync.json.gz')
|
|
|
@@ -76,6 +73,7 @@ function isENOENT(err) {
|
|
|
/**
|
|
|
* @param {string} projectId
|
|
|
* @param {string} userId
|
|
|
+ * @param {string} cacheKey
|
|
|
* @param {number} remoteBaseVersion
|
|
|
* @param {boolean} populateClsiCache
|
|
|
* @return {Promise<{rawSnapshot: import('overleaf-editor-core/lib/types.js').RawSnapshot, globalBlobs: string[], fullSync: boolean,localBaseVersion: number, dirty: string[]}>}
|
|
|
@@ -83,10 +81,11 @@ function isENOENT(err) {
|
|
|
async function loadSnapshot(
|
|
|
projectId,
|
|
|
userId,
|
|
|
+ cacheKey,
|
|
|
remoteBaseVersion,
|
|
|
populateClsiCache
|
|
|
) {
|
|
|
- const { path, resyncPath } = snapshotPath(projectId, userId)
|
|
|
+ const { path, resyncPath } = snapshotPath(cacheKey)
|
|
|
let maxLocalBaseVersion = -1
|
|
|
for (const candidate of [path, resyncPath]) {
|
|
|
try {
|
|
|
@@ -100,7 +99,7 @@ async function loadSnapshot(
|
|
|
)
|
|
|
} else if (!isENOENT(err)) {
|
|
|
logger.warn(
|
|
|
- { err, projectId, userId },
|
|
|
+ { err, projectId, userId, cacheKey },
|
|
|
'compile from cache: cannot read history from disk'
|
|
|
)
|
|
|
}
|
|
|
@@ -111,6 +110,7 @@ async function loadSnapshot(
|
|
|
return await loadSnapshotFromClsiCache(
|
|
|
projectId,
|
|
|
userId,
|
|
|
+ cacheKey,
|
|
|
remoteBaseVersion
|
|
|
)
|
|
|
} catch (err) {
|
|
|
@@ -121,7 +121,7 @@ async function loadSnapshot(
|
|
|
)
|
|
|
} else if (!isENOENT(err)) {
|
|
|
logger.warn(
|
|
|
- { err, projectId, userId },
|
|
|
+ { err, projectId, userId, cacheKey },
|
|
|
'compile from cache: cannot download from clsi-cache'
|
|
|
)
|
|
|
}
|
|
|
@@ -135,11 +135,17 @@ async function loadSnapshot(
|
|
|
/**
|
|
|
* @param {string} projectId
|
|
|
* @param {string} userId
|
|
|
+ * @param {string} cacheKey
|
|
|
* @param {number} remoteBaseVersion
|
|
|
* @return {Promise<{rawSnapshot: import('overleaf-editor-core/lib/types.js').RawSnapshot, globalBlobs: string[], fullSync: boolean,localBaseVersion: number, dirty: string[]}>}
|
|
|
*/
|
|
|
-async function loadSnapshotFromClsiCache(projectId, userId, remoteBaseVersion) {
|
|
|
- const { dir, resyncPath } = snapshotPath(projectId, userId)
|
|
|
+async function loadSnapshotFromClsiCache(
|
|
|
+ projectId,
|
|
|
+ userId,
|
|
|
+ cacheKey,
|
|
|
+ remoteBaseVersion
|
|
|
+) {
|
|
|
+ const { dir, resyncPath } = snapshotPath(cacheKey)
|
|
|
await fs.promises.mkdir(dir, { recursive: true })
|
|
|
const ok = await CLSICacheHandler.downloadHistorySnapshot(
|
|
|
projectId,
|
|
|
@@ -182,8 +188,7 @@ async function loadSnapshotFromFile(path, remoteBaseVersion, fullSync) {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * @param {string} projectId
|
|
|
- * @param {string} userId
|
|
|
+ * @param {string} cacheKey
|
|
|
* @param {Snapshot} snapshot
|
|
|
* @param {number} localBaseVersion
|
|
|
* @param {string[]} globalBlobs
|
|
|
@@ -191,14 +196,13 @@ async function loadSnapshotFromFile(path, remoteBaseVersion, fullSync) {
|
|
|
* @return {Promise<void>}
|
|
|
*/
|
|
|
async function saveSnapshot(
|
|
|
- projectId,
|
|
|
- userId,
|
|
|
+ cacheKey,
|
|
|
snapshot,
|
|
|
localBaseVersion,
|
|
|
globalBlobs,
|
|
|
dirty
|
|
|
) {
|
|
|
- const { dir, path } = snapshotPath(projectId, userId)
|
|
|
+ const { dir, path } = snapshotPath(cacheKey)
|
|
|
await fs.promises.mkdir(dir, { recursive: true })
|
|
|
const tmp = path + '~'
|
|
|
await fs.promises.writeFile(
|
|
|
@@ -221,16 +225,17 @@ async function saveSnapshot(
|
|
|
/**
|
|
|
* @param {string} projectId
|
|
|
* @param {string} userId
|
|
|
+ * @param {string} cacheKey
|
|
|
* @return {Promise<void>}
|
|
|
*/
|
|
|
-async function deleteResyncSnapshot(projectId, userId) {
|
|
|
- const { resyncPath } = snapshotPath(projectId, userId)
|
|
|
+async function deleteResyncSnapshot(projectId, userId, cacheKey) {
|
|
|
+ const { resyncPath } = snapshotPath(cacheKey)
|
|
|
try {
|
|
|
await fs.promises.unlink(resyncPath)
|
|
|
} catch (err) {
|
|
|
if (!isENOENT(err)) {
|
|
|
logger.warn(
|
|
|
- { err, projectId, userId },
|
|
|
+ { err, projectId, userId, cacheKey },
|
|
|
'compile from cache: failed to clear history-resync.json.gz'
|
|
|
)
|
|
|
}
|
|
|
@@ -367,6 +372,10 @@ export async function syncResourcesToDisk(
|
|
|
compileDir,
|
|
|
timings
|
|
|
) {
|
|
|
+ // - logged in user: <project-id>-<user-id>
|
|
|
+ // - anonymous user: <project-id>
|
|
|
+ // - conversion job: <uuid>
|
|
|
+ const cacheKey = Path.basename(compileDir)
|
|
|
const remoteBaseVersion = request.baseHistoryVersion
|
|
|
let rawSnapshot, globalBlobs, localBaseVersion, source, dirty, fullSync
|
|
|
try {
|
|
|
@@ -374,24 +383,25 @@ export async function syncResourcesToDisk(
|
|
|
await loadSnapshot(
|
|
|
projectId,
|
|
|
userId,
|
|
|
+ cacheKey,
|
|
|
remoteBaseVersion,
|
|
|
request.populateClsiCache
|
|
|
))
|
|
|
source = fullSync ? 'clsi-cache' : 'local'
|
|
|
logger.debug(
|
|
|
- { projectId, userId, localBaseVersion, remoteBaseVersion },
|
|
|
+ { projectId, userId, cacheKey, localBaseVersion, remoteBaseVersion },
|
|
|
'compile from cache: using existing snapshot'
|
|
|
)
|
|
|
} catch (err) {
|
|
|
if (!request.rawSnapshot) throw err
|
|
|
if (!(err instanceof Errors.MissingUpdatesError)) {
|
|
|
logger.warn(
|
|
|
- { err, projectId, userId },
|
|
|
+ { err, projectId, userId, cacheKey },
|
|
|
'compile from cache: bad local history state during full resync'
|
|
|
)
|
|
|
}
|
|
|
logger.debug(
|
|
|
- { projectId, userId },
|
|
|
+ { projectId, userId, cacheKey },
|
|
|
'compile from cache: using incoming snapshot'
|
|
|
)
|
|
|
source = 'remote'
|
|
|
@@ -424,7 +434,10 @@ export async function syncResourcesToDisk(
|
|
|
const changedPaths = []
|
|
|
if (fullSync) {
|
|
|
changedPaths.push(...snapshot.getFilePathnames())
|
|
|
- logger.debug({ projectId, userId }, 'compile from cache: full sync')
|
|
|
+ logger.debug(
|
|
|
+ { projectId, userId, cacheKey },
|
|
|
+ 'compile from cache: full sync'
|
|
|
+ )
|
|
|
} else {
|
|
|
const dedupe = new Set(dirty)
|
|
|
if (request.draft) {
|
|
|
@@ -448,7 +461,7 @@ export async function syncResourcesToDisk(
|
|
|
}
|
|
|
changedPaths.push(...dedupe)
|
|
|
logger.debug(
|
|
|
- { projectId, userId, changedPaths },
|
|
|
+ { projectId, userId, cacheKey, changedPaths },
|
|
|
'compile from cache: incremental sync'
|
|
|
)
|
|
|
}
|
|
|
@@ -541,8 +554,7 @@ export async function syncResourcesToDisk(
|
|
|
const baseHistoryVersion = localBaseVersion + changes.length
|
|
|
if (fullSync || changes.length || wasDirty || dirty.length) {
|
|
|
await saveSnapshot(
|
|
|
- projectId,
|
|
|
- userId,
|
|
|
+ cacheKey,
|
|
|
snapshot,
|
|
|
baseHistoryVersion,
|
|
|
globalBlobs,
|
|
|
@@ -550,7 +562,7 @@ export async function syncResourcesToDisk(
|
|
|
)
|
|
|
}
|
|
|
if (fullSync) {
|
|
|
- await deleteResyncSnapshot(projectId, userId)
|
|
|
+ await deleteResyncSnapshot(projectId, userId, cacheKey)
|
|
|
}
|
|
|
return {
|
|
|
baseHistoryVersion,
|