"Maximum call stack size exceeded" error bug fixed
-The "Maximum call stack size exceeded" error is now handled internally by the block sync script in a way which will capture the error and re-launch the sync using a larger stack size and have the sync resume from where it left off. If the re-launch still doesn't have enough memory it will continue re-launching with more and more memory until the sync can finish without errors and then it will return to sync with a lower memory footprint for future syncs -Added a new option for sync.elastic_stack_size which is used to determine how much memory should be used to increase the stack size for the block sync after encountering the "Maximum call stack size exceeded" error -Fixed an issue with the block sync when using more than 1 thread that could sometimes cause the flattened txes value in the coinstats database to be written incorrectly (Use `npm run reindex-txcount` to fix this issue without needing to reindex the entire database) -Updated the benchmark script so that it can also benefit from being able to capture the "Maximum call stack size exceeded" error even though the timing will be off so it outputs a new warning in that scenario which instructs to run the benchmark again with a higher stack size to properly capture the benchmark time -Removed the "Maximum call stack size exceeded" error notes from the "Known Issues" section of the README
This commit is contained in:
+114
-27
@@ -1,18 +1,25 @@
|
||||
const mongoose = require('mongoose');
|
||||
const Address = require('../models/address');
|
||||
const Tx = require('../models/tx');
|
||||
const blkSync = require('../lib/block_sync');
|
||||
const settings = require('../lib/settings');
|
||||
const resumeSync = process.argv[2] == '1';
|
||||
|
||||
let dbString = `mongodb://${settings.benchmark.address}:${settings.benchmark.port}/admin`
|
||||
|
||||
// prevent stopping of the sync script to be able to gracefully shut down
|
||||
process.on('SIGINT', () => {
|
||||
console.log(`${settings.localization.stopping_sync_process}.. ${settings.localization.please_wait}..`);
|
||||
if (!blkSync.getStackSizeErrorId())
|
||||
console.log(`${settings.localization.stopping_sync_process}.. ${settings.localization.please_wait}..`);
|
||||
|
||||
blkSync.setStopSync(true);
|
||||
});
|
||||
|
||||
// prevent killing of the sync script to be able to gracefully shut down
|
||||
process.on('SIGTERM', () => {
|
||||
console.log(`${settings.localization.stopping_sync_process}.. ${settings.localization.please_wait}..`);
|
||||
if (!blkSync.getStackSizeErrorId())
|
||||
console.log(`${settings.localization.stopping_sync_process}.. ${settings.localization.please_wait}..`);
|
||||
|
||||
blkSync.setStopSync(true);
|
||||
});
|
||||
|
||||
@@ -89,6 +96,74 @@ function check_create_user(cb) {
|
||||
return cb();
|
||||
}
|
||||
|
||||
function initialize_data_startup(cb) {
|
||||
console.log(`${settings.localization.initializing_database}.. ${settings.localization.please_wait}..`);
|
||||
|
||||
const db = require('../lib/database');
|
||||
|
||||
// check if stats collection is initialized
|
||||
db.check_stats(settings.coin.name, function(stats_exists) {
|
||||
let skip = true;
|
||||
|
||||
// determine if stats collection already exists
|
||||
if (stats_exists == false) {
|
||||
console.log(`${settings.localization.creating_initial_entry.replace('{1}', 'stats')}.. ${settings.localization.please_wait}..`);
|
||||
skip = false;
|
||||
}
|
||||
|
||||
// initialize the stats collection
|
||||
db.create_stats(settings.coin.name, skip, function() {
|
||||
// get the stats object from the database
|
||||
db.get_stats(settings.coin.name, function(stats) {
|
||||
// finished initializing startup data
|
||||
console.log('Database initialization complete');
|
||||
return cb(stats);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function delete_txes(cb) {
|
||||
// check if the benchmark sync is being resumed
|
||||
if (resumeSync) {
|
||||
// do not delete the list of txes for a resume sync
|
||||
return cb();
|
||||
} else {
|
||||
// delete all previous transaction records from the benchmark database
|
||||
Tx.deleteMany({}).then(() => {
|
||||
return cb();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function delete_addresses(cb) {
|
||||
// check if the benchmark sync is being resumed
|
||||
if (resumeSync) {
|
||||
// do not delete the list of addresses for a resume sync
|
||||
return cb();
|
||||
} else {
|
||||
// delete all previous address records from the benchmark database
|
||||
Address.deleteMany({}).then(() => {
|
||||
return cb();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function delete_stats(cb) {
|
||||
// check if the benchmark sync is being resumed
|
||||
if (resumeSync) {
|
||||
// do not delete the database stats for a resume sync
|
||||
return cb();
|
||||
} else {
|
||||
const Stats = require('../models/stats');
|
||||
|
||||
// delete all previous stat records from the benchmark database
|
||||
Stats.deleteMany({}).then(() => {
|
||||
return cb();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`${settings.localization.script_launched}: ${process.pid}`);
|
||||
|
||||
mongoose.set('strictQuery', true);
|
||||
@@ -104,37 +179,49 @@ check_create_user(function() {
|
||||
|
||||
// connect to the benchmark database
|
||||
mongoose.connect(dbString).then(() => {
|
||||
const Tx = require('../models/tx');
|
||||
|
||||
// delete all previous transaction records from the benchmark database
|
||||
Tx.deleteMany({}).then(() => {
|
||||
const Address = require('../models/address');
|
||||
|
||||
delete_txes(function() {
|
||||
// delete all previous address records from the benchmark database
|
||||
Address.deleteMany({}).then(() => {
|
||||
// get starting timestamp
|
||||
const s_timer = new Date().getTime();
|
||||
delete_addresses(function() {
|
||||
// delete all previous stat records from the benchmark database
|
||||
delete_stats(function() {
|
||||
// initialize the benchmark database
|
||||
initialize_data_startup(function(stats) {
|
||||
// get the last synced block index value
|
||||
const last = (stats.last ? stats.last : 0);
|
||||
|
||||
// start the block sync
|
||||
blkSync.update_tx_db(settings.coin.name, 1, settings.benchmark.block_to_sync, 0, settings.sync.update_timeout, false, function() {
|
||||
// get ending timestamp
|
||||
const e_timer = new Date().getTime();
|
||||
// get starting timestamp
|
||||
const s_timer = new Date().getTime();
|
||||
|
||||
// get count of transactions
|
||||
Tx.countDocuments({}).then((txcount) => {
|
||||
// get count of addresses
|
||||
Address.countDocuments({}).then((acount) => {
|
||||
// check if the script stopped prematurely
|
||||
if (blkSync.getStopSync())
|
||||
console.log('Block sync was stopped prematurely');
|
||||
// start the block sync
|
||||
blkSync.update_tx_db(settings.coin.name, last, settings.benchmark.block_to_sync, stats.txes, settings.sync.update_timeout, false, function() {
|
||||
// get ending timestamp
|
||||
const e_timer = new Date().getTime();
|
||||
|
||||
// output final benchmark stats
|
||||
console.log({
|
||||
tx_count: txcount,
|
||||
address_count: acount,
|
||||
seconds: (e_timer - s_timer) / 1000,
|
||||
// get count of transactions
|
||||
Tx.countDocuments({}).then((txcount) => {
|
||||
// get count of addresses
|
||||
Address.countDocuments({}).then((acount) => {
|
||||
// check if the script stopped prematurely
|
||||
if (blkSync.getStopSync())
|
||||
console.log('Block sync was stopped prematurely');
|
||||
|
||||
// output final benchmark stats
|
||||
console.log({
|
||||
tx_count: txcount,
|
||||
address_count: acount,
|
||||
seconds: (e_timer - s_timer) / 1000,
|
||||
});
|
||||
|
||||
// check if the sync needed to be resumed
|
||||
if (resumeSync) {
|
||||
// output a warning msg
|
||||
console.log(`\n${settings.localization.ex_warning}: The sync ran out of memory during processing and therefore the run time was affected. It is recommended to re-run the benchmark again using a larger stack size such as 25000 or higher with the cmd "node --stack-size=25000 scripts/benchmark.js" to help ensure an accurate benchmark time.`);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
});
|
||||
});
|
||||
exit(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+78
-43
@@ -18,14 +18,18 @@ var stopSync = false;
|
||||
|
||||
// prevent stopping of the sync script to be able to gracefully shut down
|
||||
process.on('SIGINT', () => {
|
||||
console.log(`${settings.localization.stopping_sync_process}.. ${settings.localization.please_wait}..`);
|
||||
if (!blkSync.getStackSizeErrorId())
|
||||
console.log(`${settings.localization.stopping_sync_process}.. ${settings.localization.please_wait}..`);
|
||||
|
||||
blkSync.setStopSync(true);
|
||||
stopSync = true;
|
||||
});
|
||||
|
||||
// prevent killing of the sync script to be able to gracefully shut down
|
||||
process.on('SIGTERM', () => {
|
||||
console.log(`${settings.localization.stopping_sync_process}.. ${settings.localization.please_wait}..`);
|
||||
if (!blkSync.getStackSizeErrorId())
|
||||
console.log(`${settings.localization.stopping_sync_process}.. ${settings.localization.please_wait}..`);
|
||||
|
||||
blkSync.setStopSync(true);
|
||||
stopSync = true;
|
||||
});
|
||||
@@ -202,6 +206,12 @@ function update_orphans(orphan_index, orphan_current, last_blockindex, timeout,
|
||||
tx_count = updated_tx_count2;
|
||||
|
||||
setTimeout(function() {
|
||||
// check if there was a memory error
|
||||
if (blkSync.getStackSizeErrorId() != null) {
|
||||
// stop the loop
|
||||
tx_loop.break(true);
|
||||
}
|
||||
|
||||
// move to the next tx record
|
||||
tx_loop.next();
|
||||
}, timeout);
|
||||
@@ -209,6 +219,12 @@ function update_orphans(orphan_index, orphan_current, last_blockindex, timeout,
|
||||
});
|
||||
}, function() {
|
||||
setTimeout(function() {
|
||||
// check if there was a memory error
|
||||
if (blkSync.getStackSizeErrorId() != null) {
|
||||
// stop the loop
|
||||
block_loop.break(true);
|
||||
}
|
||||
|
||||
// move to the next block record
|
||||
block_loop.next();
|
||||
}, timeout);
|
||||
@@ -216,49 +232,57 @@ function update_orphans(orphan_index, orphan_current, last_blockindex, timeout,
|
||||
});
|
||||
});
|
||||
}, function() {
|
||||
// get the most recent stats
|
||||
Stats.findOne({coin: settings.coin.name}).then((stats) => {
|
||||
// add missing txes for the current block
|
||||
blkSync.update_tx_db(settings.coin.name, current_block, current_block, (stats.txes + tx_count), timeout, 2, function(updated_tx_count) {
|
||||
// update the stats collection by removing the orphaned txes in this block from the tx count
|
||||
// and setting the orphan_index and orphan_current values in case the sync is interrupted before finishing
|
||||
Stats.updateOne({coin: settings.coin.name}, {
|
||||
orphan_index: current_block,
|
||||
orphan_current: (unresolved_forks.length == 0 ? 0 : unresolved_forks[0])
|
||||
}).then(() => {
|
||||
// clear the saved block hash data
|
||||
correct_block_data = null;
|
||||
// check if there was a memory error
|
||||
if (!blkSync.getStackSizeErrorId()) {
|
||||
// get the most recent stats
|
||||
Stats.findOne({coin: settings.coin.name}).then((stats) => {
|
||||
// add missing txes for the current block
|
||||
blkSync.update_tx_db(settings.coin.name, current_block, current_block, (stats.txes + tx_count), timeout, 2, function(updated_tx_count) {
|
||||
// update the stats collection by removing the orphaned txes in this block from the tx count
|
||||
// and setting the orphan_index and orphan_current values in case the sync is interrupted before finishing
|
||||
Stats.updateOne({coin: settings.coin.name}, {
|
||||
orphan_index: current_block,
|
||||
orphan_current: (unresolved_forks.length == 0 ? 0 : unresolved_forks[0])
|
||||
}).then(() => {
|
||||
// clear the saved block hash data
|
||||
correct_block_data = null;
|
||||
|
||||
// move to the next block
|
||||
current_block++;
|
||||
// move to the next block
|
||||
current_block++;
|
||||
|
||||
setTimeout(function() {
|
||||
// process next block
|
||||
next(null);
|
||||
}, timeout);
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
setTimeout(function() {
|
||||
// process next block
|
||||
next(null);
|
||||
}, timeout);
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
|
||||
// clear the saved block hash data
|
||||
correct_block_data = null;
|
||||
// clear the saved block hash data
|
||||
correct_block_data = null;
|
||||
|
||||
// move to the next block
|
||||
current_block++;
|
||||
// move to the next block
|
||||
current_block++;
|
||||
|
||||
setTimeout(function() {
|
||||
// process next block
|
||||
next(null);
|
||||
}, timeout);
|
||||
setTimeout(function() {
|
||||
// process next block
|
||||
next(null);
|
||||
}, timeout);
|
||||
});
|
||||
});
|
||||
});
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
|
||||
setTimeout(function() {
|
||||
// process next block
|
||||
next(null);
|
||||
}, timeout);
|
||||
});
|
||||
} else {
|
||||
setTimeout(function() {
|
||||
// process next block
|
||||
next(null);
|
||||
// stop the loop
|
||||
next('StackSizeError');
|
||||
}, timeout);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
@@ -283,11 +307,17 @@ function update_orphans(orphan_index, orphan_current, last_blockindex, timeout,
|
||||
function(err) {
|
||||
// check if there is a msg to display
|
||||
if (err != '' && err != 'stop') {
|
||||
// display the msg
|
||||
console.log(err);
|
||||
// check if this is the StackSizeError error
|
||||
if (err == 'StackSizeError') {
|
||||
// reload the sync process
|
||||
blkSync.respawnSync();
|
||||
} else {
|
||||
// display the msg
|
||||
console.log(err);
|
||||
|
||||
// stop fixing orphaned block data
|
||||
return cb();
|
||||
// stop fixing orphaned block data
|
||||
return cb();
|
||||
}
|
||||
} else {
|
||||
// check if the script is stopping
|
||||
if (!stopSync)
|
||||
@@ -514,9 +544,14 @@ function check_add_tx(txid, blockhash, tx_count, cb) {
|
||||
// save the tx to the local database
|
||||
blkSync.save_tx(txid, block.height, block, function(save_tx_err, tx_has_vout) {
|
||||
// check if there were any save errors
|
||||
if (save_tx_err)
|
||||
console.log(save_tx_err);
|
||||
else
|
||||
if (save_tx_err) {
|
||||
// check the error code
|
||||
if (save_tx_err.code == 'StackSizeError') {
|
||||
// ensure the process halts after stopping all sync threads
|
||||
blkSync.setStackSizeErrorId(txid);
|
||||
} else
|
||||
console.log(save_tx_err);
|
||||
} else
|
||||
console.log('%s: %s', block.height, txid);
|
||||
|
||||
// check if the tx was saved correctly
|
||||
|
||||
Reference in New Issue
Block a user