Skip to content

Commit

Permalink
🐛 Fix hash of binary files in cache service (#1707)
Browse files Browse the repository at this point in the history
  • Loading branch information
misode authored Jan 28, 2025
1 parent 0a1b620 commit c18a593
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 17 deletions.
34 changes: 23 additions & 11 deletions packages/core/src/service/CacheService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ interface ValidateResult {
export class CacheService {
checksums = Checksums.create()
errors: ErrorCache = {}
dirtyFiles = new Set<string>()
#hasValidatedFiles = false

/**
Expand All @@ -69,15 +70,9 @@ export class CacheService {
if (!this.#hasValidatedFiles) {
return
}
try {
// TODO: Don't update this for every single change.
this.checksums.files[doc.uri] = await this.project.externals.crypto.getSha1(
doc.getText(),
)
} catch (e) {
if (!this.project.externals.error.isKind(e, 'EISDIR')) {
this.project.logger.error(`[CacheService#hash-file] ${doc.uri}`)
}
this.dirtyFiles.add(doc.uri)
if (this.dirtyFiles.size > 100) {
await this.flushDirtyFiles()
}
})
this.project.on('rootsUpdated', async ({ roots }) => {
Expand All @@ -89,7 +84,7 @@ export class CacheService {
this.checksums.roots[root] = await this.project.fs.hash(root)
} catch (e) {
if (!this.project.externals.error.isKind(e, 'EISDIR')) {
this.project.logger.error(`[CacheService#hash-root] ${root}`)
this.project.logger.error(`[CacheService#hash-root] ${root}`, e)
}
}
}
Expand All @@ -114,6 +109,19 @@ export class CacheService {
return this.#cacheFilePath
}

private async flushDirtyFiles() {
for (const uri of this.dirtyFiles) {
try {
this.checksums.files[uri] = await this.project.fs.hash(uri)
} catch (e) {
if (!this.project.externals.error.isKind(e, 'EISDIR')) {
this.project.logger.error(`[CacheService#flushDirtyFiles] ${uri}`, e)
}
}
}
this.dirtyFiles.clear()
}

async load(): Promise<LoadResult> {
const ans: LoadResult = { symbols: {} }
if (this.project.projectRoots.length === 0) {
Expand Down Expand Up @@ -163,7 +171,7 @@ export class CacheService {
}
} catch (e) {
if (!this.project.externals.error.isKind(e, 'EISDIR')) {
this.project.logger.error(`[CacheService#hash-file] ${uri}`)
this.project.logger.error(`[CacheService#hash-file] ${uri}`, e)
}
// Failed calculating hash. Assume the root has changed.
}
Expand Down Expand Up @@ -222,6 +230,10 @@ export class CacheService {
let filePath: string | undefined
try {
filePath = await this.getCacheFileUri()

await this.flushDirtyFiles()
__profiler.task('Hash Files')

const cache: CacheFile = {
version: LatestCacheVersion,
projectRoots: this.project.projectRoots,
Expand Down
15 changes: 9 additions & 6 deletions packages/core/src/service/Project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { fileUtil } from './fileUtil.js'
import { MetaRegistry } from './MetaRegistry.js'
import { ProfilerFactory } from './Profiler.js'

const CacheAutoSaveInterval = 600_000 // 10 Minutes.
const CacheAutoSaveInterval = 300_000 // 5 Minutes.

export type ProjectInitializerContext = Pick<
Project,
Expand Down Expand Up @@ -160,7 +160,7 @@ export class Project implements ExternalEventEmitter {

/** Prevent circular binding. */
readonly #bindingInProgressUris = new Set<string>()
readonly #cacheSaverIntervalId: IntervalId
#cacheSaverIntervalId: IntervalId | undefined = undefined
readonly cacheService: CacheService
/** URI of files that are currently managed by the language client. */
readonly #clientManagedUris = new Set<string>()
Expand Down Expand Up @@ -341,10 +341,6 @@ export class Project implements ExternalEventEmitter {

this.setInitPromise()
this.setReadyPromise()
this.#cacheSaverIntervalId = setInterval(
() => this.cacheService.save(),
CacheAutoSaveInterval,
)

this.on('documentUpdated', ({ doc, node }) => {
// if (!this.#isReady) {
Expand Down Expand Up @@ -586,6 +582,13 @@ export class Project implements ExternalEventEmitter {

__profiler.finalize()
this.emit('ready', {})

// Save the cache after ready and start the auto-cache interval
await this.cacheService.save()
this.#cacheSaverIntervalId = setInterval(
() => this.cacheService.save(),
CacheAutoSaveInterval,
)
}
this.#isReady = false
this.#readyPromise = ready()
Expand Down

0 comments on commit c18a593

Please sign in to comment.