Skip to content

Commit

Permalink
Fix: issues with synchronization on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
zerti committed Sep 27, 2016
1 parent fdeeefb commit 024fd7f
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 13 deletions.
1 change: 1 addition & 0 deletions app/lib/dal/drivers/sqlite.js
Expand Up @@ -55,6 +55,7 @@ function SQLiteDriver(path) {
if (path !== MEMORY_PATH) {
yield qfs.remove(path);
}
logger.debug('Database removed');
});

this.closeConnection = () => co(function*() {
Expand Down
13 changes: 9 additions & 4 deletions app/lib/sync.js
Expand Up @@ -548,14 +548,14 @@ function P2PDownloader(localNumber, to, maxParallelDownloads, peers, watcher) {
try {
const start = Date.now();
handler[chunkIndex] = node;
watcher.writeStatus('Getting chunck #' + chunkIndex + '/' + numberOfChunksToDownload + ' from ' + from + ' to ' + (from + count - 1) + ' on peer ' + [node.host, node.port].join(':'));
watcher.writeStatus('Getting chunck #' + chunkIndex + '/' + (numberOfChunksToDownload - 1) + ' from ' + from + ' to ' + (from + count - 1) + ' on peer ' + [node.host, node.port].join(':'));
let blocks = yield Q.nfcall(node.blockchain.blocks, count, from);
node.ttas.push(Date.now() - start);
// Only keep a flow of 5 ttas for the node
if (node.ttas.length > 5) node.ttas.shift();
// Average time to answer
node.tta = Math.round(node.ttas.reduce((sum, tta) => sum + tta, 0) / node.ttas.length);
watcher.writeStatus('GOT chunck #' + chunkIndex + '/' + numberOfChunksToDownload + ' from ' + from + ' to ' + (from + count - 1) + ' on peer ' + [node.host, node.port].join(':'));
watcher.writeStatus('GOT chunck #' + chunkIndex + '/' + (numberOfChunksToDownload - 1) + ' from ' + from + ' to ' + (from + count - 1) + ' on peer ' + [node.host, node.port].join(':'));
return blocks;
} catch (e) {
// If a node throws an error, do not cancel the download
Expand Down Expand Up @@ -638,9 +638,10 @@ function P2PDownloader(localNumber, to, maxParallelDownloads, peers, watcher) {
*/
co(function*() {
yield downloadStarter;
let doneCount = 0;
while (doneCount < chunks.length) {
let doneCount = 0, resolvedCount = 0;
while (resolvedCount < chunks.length) {
doneCount = 0;
resolvedCount = 0;
// Add as much possible downloads as possible, and count the already done ones
for (let i = 0; i < chunks.length; i++) {
if (chunks[i] === null && !processing[i] && slots.indexOf(i) === -1 && slots.length < downloadSlots) {
Expand All @@ -650,6 +651,10 @@ function P2PDownloader(localNumber, to, maxParallelDownloads, peers, watcher) {
} else if (downloads[i] && downloads[i].isFulfilled() && processing[i]) {
doneCount++;
}
// We count the number of perfectly downloaded & validated chunks
if (chunks[i]) {
resolvedCount++;
}
}
watcher.downloadPercent(Math.round(doneCount / numberOfChunksToDownload * 100));
let races = slots.map((i) => downloads[i]);
Expand Down
12 changes: 11 additions & 1 deletion server.js
Expand Up @@ -361,20 +361,30 @@ function Server (dbConf, overrideConf) {
// JSON file?
const existsJSON = yield myFS.exists(rootPath + '/' + fName + '.json');
if (existsJSON) {
yield myFS.remove(rootPath + '/' + fName + '.json');
const theFilePath = rootPath + '/' + fName + '.json';
yield myFS.remove(theFilePath);
if (yield myFS.exists(theFilePath)) {
throw Error('Failed to delete file "' + theFilePath + '"');
}
} else {
// Normal file?
const normalFile = path.join(rootPath, fName);
const existsFile = yield myFS.exists(normalFile);
if (existsFile) {
yield myFS.remove(normalFile);
if (yield myFS.exists(normalFile)) {
throw Error('Failed to delete file "' + normalFile + '"');
}
}
}
}
for (const dirName of dirs) {
const existsDir = yield myFS.exists(rootPath + '/' + dirName);
if (existsDir) {
yield myFS.removeTree(rootPath + '/' + dirName);
if (yield myFS.exists(rootPath + '/' + dirName)) {
throw Error('Failed to delete folder "' + rootPath + '/' + dirName + '"');
}
}
}
done && done();
Expand Down
14 changes: 11 additions & 3 deletions test/fast/database.js
Expand Up @@ -6,7 +6,7 @@ const should = require('should');
const sqlite = require('../../app/lib/dal/drivers/sqlite');

const MEMORY = ':memory:';
const FILE = tmp.fileSync().name;
const FILE = tmp.fileSync().name + '.db'; // We add an suffix to avoid Windows-locking of the file by the `tmp` module

const CREATE_TABLE_SQL = 'BEGIN;' +
'CREATE TABLE IF NOT EXISTS duniter (' +
Expand Down Expand Up @@ -58,23 +58,31 @@ describe("SQLite driver", function() {

describe("File", function() {

const driver = sqlite(FILE);
let rows;

it('should be openable and closable on will, memorizing previous state', () => co(function*() {
const driver = sqlite(FILE);
it('should be able to open a new one', () => co(function*() {
yield driver.executeSql(CREATE_TABLE_SQL);
rows = yield driver.executeAll(SELECT_FROM_TABLE, []);
rows.should.have.length(0);
yield driver.closeConnection();
}));

it('should be able to reopen the file', () => co(function*() {
// Reopens the file
rows = yield driver.executeAll(SELECT_FROM_TABLE, []);
rows.should.have.length(0);
}));

it('should be able to remove the file', () => co(function*() {
// We explicitely ask for destruction
yield driver.destroyDatabase();
yield driver.executeAll(SELECT_FROM_TABLE, [])
.then(() => 'Should have thrown an exception')
.catch((err) => err.should.have.property('message').match(/^SQLITE_ERROR: no such table: duniter$/));
}));

it('should be able to open the file after being removed', () => co(function*() {
// But if we populate it again, it will work
yield driver.executeSql(CREATE_TABLE_SQL);
rows = yield driver.executeAll(SELECT_FROM_TABLE, []);
Expand Down
6 changes: 1 addition & 5 deletions test/integration/cli.js
Expand Up @@ -83,7 +83,7 @@ describe("CLI", function() {
} else if (index == 4) {

/***************
* Node with apparent good chaining, but one of the hashs if WRONG
* Node with apparent good chaining, but one of the hashs is WRONG
*/
return toolbox.fakeSyncServer((count, from) => {
// We just need to send the wrong chunk
Expand Down Expand Up @@ -119,14 +119,12 @@ describe("CLI", function() {
let res = yield execute(['config', '--autoconf']);
res.should.have.property("ipv4").not.equal("a wrong string");
res.should.have.property("ipv4").match(constants.IPV4_REGEXP);
if (process.platform === 'win32') yield new Promise((resolve) => setTimeout(resolve, 500));
}));

it('reset data', () => co(function*() {
yield execute(['reset', 'data']);
const res = yield execute(['export-bc', '--nostdout']);
res.slice(0, 1).should.have.length(0);
if (process.platform === 'win32') yield new Promise((resolve) => setTimeout(resolve, 500));
}));

it('sync 2200 blocks (fast)', () => co(function*() {
Expand All @@ -135,15 +133,13 @@ describe("CLI", function() {
const res = yield execute(['export-bc', '--nostdout']);
res[res.length - 1].should.have.property('number').equal(2200);
res.should.have.length(2200 + 1);
if (process.platform === 'win32') yield new Promise((resolve) => setTimeout(resolve, 500));
}));

it('sync 5 blocks (cautious)', () => co(function*() {
yield execute(['sync', fakeServer.host, fakeServer.port, '2204', '--nointeractive']);
const res = yield execute(['export-bc', '--nostdout']);
res[res.length - 1].should.have.property('number').equal(2204);
res.should.have.length(2204 + 1);
if (process.platform === 'win32') yield new Promise((resolve) => setTimeout(resolve, 500));
}));

it('[spawn] reset data', () => co(function*() {
Expand Down

0 comments on commit 024fd7f

Please sign in to comment.