| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- /**
- * Compress changes for projects that have too many text operations.
- *
- * Usage:
- *
- * node tasks/compress_changes.js CSV_FILE
- *
- * where CSV_FILE contains a list of project ids in the first column
- */
- const fs = require('node:fs')
- const BPromise = require('bluebird')
- const { History } = require('overleaf-editor-core')
- const { historyStore, chunkStore } = require('..')
- const CONCURRENCY = 10
- async function main() {
- const filename = process.argv[2]
- const projectIds = await readCsv(filename)
- const chunks = []
- for (const projectId of projectIds) {
- const chunkIds = await chunkStore.getProjectChunkIds(projectId)
- chunks.push(...chunkIds.map(id => ({ id, projectId })))
- }
- let totalCompressed = 0
- await BPromise.map(
- chunks,
- async chunk => {
- try {
- const history = await getHistory(chunk)
- const numCompressed = compressChanges(history)
- if (numCompressed > 0) {
- await storeHistory(chunk, history)
- console.log(
- `Compressed project ${chunk.projectId}, chunk ${chunk.id}`
- )
- }
- totalCompressed += numCompressed
- } catch (err) {
- console.log(err)
- }
- },
- { concurrency: CONCURRENCY }
- )
- console.log('CHANGES:', totalCompressed)
- }
- async function readCsv(filename) {
- const csv = await fs.promises.readFile(filename, 'utf-8')
- const lines = csv.trim().split('\n')
- const projectIds = lines.map(line => line.split(',')[0])
- return projectIds
- }
- async function getHistory(chunk) {
- const rawHistory = await historyStore.loadRaw(chunk.projectId, chunk.id)
- const history = History.fromRaw(rawHistory)
- return history
- }
- async function storeHistory(chunk, history) {
- const rawHistory = history.toRaw()
- await historyStore.storeRaw(chunk.projectId, chunk.id, rawHistory)
- }
- function compressChanges(history) {
- let numCompressed = 0
- for (const change of history.getChanges()) {
- const newOperations = compressOperations(change.operations)
- if (newOperations.length !== change.operations.length) {
- numCompressed++
- }
- change.setOperations(newOperations)
- }
- return numCompressed
- }
- function compressOperations(operations) {
- if (!operations.length) return []
- const newOperations = []
- let currentOperation = operations[0]
- for (let operationId = 1; operationId < operations.length; operationId++) {
- const nextOperation = operations[operationId]
- if (currentOperation.canBeComposedWith(nextOperation)) {
- currentOperation = currentOperation.compose(nextOperation)
- } else {
- // currentOperation and nextOperation cannot be composed. Push the
- // currentOperation and start over with nextOperation.
- newOperations.push(currentOperation)
- currentOperation = nextOperation
- }
- }
- newOperations.push(currentOperation)
- return newOperations
- }
- main()
- .then(() => {
- process.exit()
- })
- .catch(err => {
- console.error(err)
- process.exit(1)
- })
|