blockstore: recover from block write interrupt
This commit is contained in:
parent
64fb7c1d88
commit
2d08b296f7
@ -191,9 +191,12 @@ class FileBlockStore extends AbstractBlockStore {
|
|||||||
|
|
||||||
const rec = await this.db.get(layout.f.encode(fileno));
|
const rec = await this.db.get(layout.f.encode(fileno));
|
||||||
|
|
||||||
|
let touch = false;
|
||||||
|
|
||||||
if (rec) {
|
if (rec) {
|
||||||
filerecord = FileRecord.fromRaw(rec);
|
filerecord = FileRecord.fromRaw(rec);
|
||||||
} else {
|
} else {
|
||||||
|
touch = true;
|
||||||
filerecord = new FileRecord({
|
filerecord = new FileRecord({
|
||||||
blocks: 0,
|
blocks: 0,
|
||||||
used: 0,
|
used: 0,
|
||||||
@ -204,6 +207,7 @@ class FileBlockStore extends AbstractBlockStore {
|
|||||||
if (filerecord.used + length > filerecord.length) {
|
if (filerecord.used + length > filerecord.length) {
|
||||||
fileno += 1;
|
fileno += 1;
|
||||||
filepath = this.filepath(fileno);
|
filepath = this.filepath(fileno);
|
||||||
|
touch = true;
|
||||||
filerecord = new FileRecord({
|
filerecord = new FileRecord({
|
||||||
blocks: 0,
|
blocks: 0,
|
||||||
used: 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};
|
return {fileno, filerecord, filepath};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,7 +249,7 @@ class FileBlockStore extends AbstractBlockStore {
|
|||||||
bwm.writeU32(blength);
|
bwm.writeU32(blength);
|
||||||
const magic = bwm.render();
|
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 mwritten = await fs.write(fd, magic, 0, mlength, mposition);
|
||||||
const bwritten = await fs.write(fd, data, 0, blength, bposition);
|
const bwritten = await fs.write(fd, data, 0, blength, bposition);
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Logger = require('blgr');
|
const Logger = require('blgr');
|
||||||
|
const bio = require('bufio');
|
||||||
const assert = require('./util/assert');
|
const assert = require('./util/assert');
|
||||||
const common = require('./util/common');
|
const common = require('./util/common');
|
||||||
const {resolve} = require('path');
|
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 () => {
|
it('will return null if block not found', async () => {
|
||||||
const hash = random.randomBytes(32);
|
const hash = random.randomBytes(32);
|
||||||
const block = await store.read(hash);
|
const block = await store.read(hash);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user