delay writing disk cache until block handler completes

This commit is contained in:
Mononaut 2023-05-01 14:30:30 -06:00
parent 2773bbfd00
commit bb1ee90b0b
No known key found for this signature in database
GPG Key ID: A3F058E41374C04E
3 changed files with 39 additions and 0 deletions

View File

@ -520,6 +520,8 @@ class Blocks {
} }
public async $updateBlocks() { public async $updateBlocks() {
diskCache.lock();
let fastForwarded = false; let fastForwarded = false;
const blockHeightTip = await bitcoinApi.$getBlockHeightTip(); const blockHeightTip = await bitcoinApi.$getBlockHeightTip();
@ -658,6 +660,8 @@ class Blocks {
// wait for pending async callbacks to finish // wait for pending async callbacks to finish
await Promise.all(callbackPromises); await Promise.all(callbackPromises);
} }
diskCache.unlock();
} }
/** /**

View File

@ -18,6 +18,11 @@ class DiskCache {
private static CHUNK_FILES = 25; private static CHUNK_FILES = 25;
private isWritingCache = false; private isWritingCache = false;
private semaphore: { resume: (() => void)[], locks: number } = {
resume: [],
locks: 0,
};
constructor() { constructor() {
if (!cluster.isPrimary) { if (!cluster.isPrimary) {
return; return;
@ -73,6 +78,7 @@ class DiskCache {
fs.renameSync(DiskCache.TMP_FILE_NAMES.replace('{number}', i.toString()), DiskCache.FILE_NAMES.replace('{number}', i.toString())); fs.renameSync(DiskCache.TMP_FILE_NAMES.replace('{number}', i.toString()), DiskCache.FILE_NAMES.replace('{number}', i.toString()));
} }
} else { } else {
await this.$yield();
await fsPromises.writeFile(DiskCache.TMP_FILE_NAME, JSON.stringify({ await fsPromises.writeFile(DiskCache.TMP_FILE_NAME, JSON.stringify({
network: config.MEMPOOL.NETWORK, network: config.MEMPOOL.NETWORK,
cacheSchemaVersion: this.cacheSchemaVersion, cacheSchemaVersion: this.cacheSchemaVersion,
@ -82,6 +88,7 @@ class DiskCache {
mempoolArray: mempoolArray.splice(0, chunkSize), mempoolArray: mempoolArray.splice(0, chunkSize),
}), { flag: 'w' }); }), { flag: 'w' });
for (let i = 1; i < DiskCache.CHUNK_FILES; i++) { for (let i = 1; i < DiskCache.CHUNK_FILES; i++) {
await this.$yield();
await fsPromises.writeFile(DiskCache.TMP_FILE_NAMES.replace('{number}', i.toString()), JSON.stringify({ await fsPromises.writeFile(DiskCache.TMP_FILE_NAMES.replace('{number}', i.toString()), JSON.stringify({
mempool: {}, mempool: {},
mempoolArray: mempoolArray.splice(0, chunkSize), mempoolArray: mempoolArray.splice(0, chunkSize),
@ -175,6 +182,32 @@ class DiskCache {
logger.warn('Failed to parse mempoool and blocks cache. Skipping. Reason: ' + (e instanceof Error ? e.message : e)); logger.warn('Failed to parse mempoool and blocks cache. Skipping. Reason: ' + (e instanceof Error ? e.message : e));
} }
} }
private $yield(): Promise<void> {
if (this.semaphore.locks) {
logger.debug('Pause writing mempool and blocks data to disk cache (async)');
return new Promise((resolve) => {
this.semaphore.resume.push(resolve);
});
} else {
return Promise.resolve();
}
}
public lock(): void {
this.semaphore.locks++;
}
public unlock(): void {
this.semaphore.locks = Math.max(0, this.semaphore.locks - 1);
if (!this.semaphore.locks && this.semaphore.resume.length) {
const nextResume = this.semaphore.resume.shift();
if (nextResume) {
logger.debug('Resume writing mempool and blocks data to disk cache (async)');
nextResume();
}
}
}
} }
export default new DiskCache(); export default new DiskCache();

View File

@ -206,6 +206,8 @@ class Server {
setTimeout(this.runMainUpdateLoop.bind(this), 1000 * this.currentBackendRetryInterval); setTimeout(this.runMainUpdateLoop.bind(this), 1000 * this.currentBackendRetryInterval);
this.currentBackendRetryInterval *= 2; this.currentBackendRetryInterval *= 2;
this.currentBackendRetryInterval = Math.min(this.currentBackendRetryInterval, 60); this.currentBackendRetryInterval = Math.min(this.currentBackendRetryInterval, 60);
} finally {
diskCache.unlock();
} }
} }