blockstore: recover from block write interrupt

This commit is contained in:
Braydon Fuller 2019-02-28 11:53:42 -08:00
parent 64fb7c1d88
commit 2d08b296f7
No known key found for this signature in database
GPG Key ID: F24F232D108B3AD4
2 changed files with 59 additions and 1 deletions

View File

@ -191,9 +191,12 @@ class FileBlockStore extends AbstractBlockStore {
const rec = await this.db.get(layout.f.encode(fileno));
let touch = false;
if (rec) {
filerecord = FileRecord.fromRaw(rec);
} else {
touch = true;
filerecord = new FileRecord({
blocks: 0,
used: 0,
@ -204,6 +207,7 @@ class FileBlockStore extends AbstractBlockStore {
if (filerecord.used + length > filerecord.length) {
fileno += 1;
filepath = this.filepath(fileno);
touch = true;
filerecord = new FileRecord({
blocks: 0,
used: 0,
@ -211,6 +215,11 @@ class FileBlockStore extends AbstractBlockStore {
});
}
if (touch) {
const fd = await fs.open(filepath, 'w');
await fs.close(fd);
}
return {fileno, filerecord, filepath};
}
@ -240,7 +249,7 @@ class FileBlockStore extends AbstractBlockStore {
bwm.writeU32(blength);
const magic = bwm.render();
const fd = await fs.open(filepath, 'a');
const fd = await fs.open(filepath, 'r+');
const mwritten = await fs.write(fd, magic, 0, mlength, mposition);
const bwritten = await fs.write(fd, data, 0, blength, bposition);

View File

@ -4,6 +4,7 @@
'use strict';
const Logger = require('blgr');
const bio = require('bufio');
const assert = require('./util/assert');
const common = require('./util/common');
const {resolve} = require('path');
@ -428,6 +429,54 @@ describe('BlockStore', function() {
}
});
it('will recover from interrupt during block write', async () => {
{
const block = random.randomBytes(128);
const hash = random.randomBytes(32);
await store.write(hash, block);
const block2 = await store.read(hash);
assert.bufferEqual(block2, block);
}
// Manually insert a partially written block to the
// end of file as would be the case of an untimely
// interrupted write of a block. The file record
// would not be updated to include the used bytes and
// thus this data should be overwritten.
{
const filepath = store.filepath(0);
const fd = await fs.open(filepath, 'a');
const bw = bio.write(8);
bw.writeU32(store.network.magic);
bw.writeU32(73);
const magic = bw.render();
const failblock = random.randomBytes(73);
const mwritten = await fs.write(fd, magic, 0, 8);
const bwritten = await fs.write(fd, failblock, 0, 73);
await fs.close(fd);
assert.equal(mwritten, 8);
assert.equal(bwritten, 73);
}
// Now check that this block has the correct position
// in the file and that it can be read correctly.
{
const block = random.randomBytes(128);
const hash = random.randomBytes(32);
await store.write(hash, block);
const block2 = await store.read(hash);
assert.bufferEqual(block2, block);
}
});
it('will return null if block not found', async () => {
const hash = random.randomBytes(32);
const block = await store.read(hash);