2015-12-31 06:37:27 +00:00
// Copyright (c) 2014-2016, The Monero Project
2014-10-21 20:33:43 +00:00
// All rights reserved.
2015-12-14 04:54:39 +00:00
//
2014-10-21 20:33:43 +00:00
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
2015-12-14 04:54:39 +00:00
//
2014-10-21 20:33:43 +00:00
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
2015-12-14 04:54:39 +00:00
//
2014-10-21 20:33:43 +00:00
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
2015-12-14 04:54:39 +00:00
//
2014-10-21 20:33:43 +00:00
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
2015-12-14 04:54:39 +00:00
//
2014-10-21 20:33:43 +00:00
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# include "db_lmdb.h"
2014-10-23 19:37:10 +00:00
# include <boost/filesystem.hpp>
2015-08-04 21:59:42 +00:00
# include <boost/format.hpp>
2015-12-14 18:47:13 +00:00
# include <boost/current_function.hpp>
2014-10-23 19:37:10 +00:00
# include <memory> // std::unique_ptr
# include <cstring> // memcpy
2015-07-12 04:24:42 +00:00
# include <random>
2014-10-23 19:37:10 +00:00
# include "cryptonote_core/cryptonote_format_utils.h"
2014-10-28 00:45:33 +00:00
# include "crypto/crypto.h"
2015-02-11 23:55:53 +00:00
# include "profile_tools.h"
2014-10-23 19:37:10 +00:00
2016-02-25 13:55:49 +00:00
# if defined(__i386) || defined(__x86_64)
# define MISALIGNED_OK 1
# endif
2014-10-29 02:25:03 +00:00
using epee : : string_tools : : pod_to_hex ;
2015-10-26 15:52:07 +00:00
// Increase when the DB changes in a non backward compatible way, and there
// is no automatic conversion, so that a full resync is needed.
# define VERSION 0
2014-10-28 00:45:33 +00:00
namespace
{
2015-01-09 12:29:05 +00:00
template < typename T >
inline void throw0 ( const T & e )
2014-12-12 21:34:45 +00:00
{
LOG_PRINT_L0 ( e . what ( ) ) ;
throw e ;
}
2015-01-09 12:29:05 +00:00
template < typename T >
inline void throw1 ( const T & e )
2014-12-12 21:34:45 +00:00
{
LOG_PRINT_L1 ( e . what ( ) ) ;
throw e ;
}
2014-10-28 00:45:33 +00:00
// cursor needs to be closed when it goes out of scope,
// this helps if the function using it throws
struct lmdb_cur
2014-10-21 20:33:43 +00:00
{
2014-10-28 00:45:33 +00:00
lmdb_cur ( MDB_txn * txn , MDB_dbi dbi )
{
if ( mdb_cursor_open ( txn , dbi , & m_cur ) )
2014-12-12 21:34:45 +00:00
throw0 ( cryptonote : : DB_ERROR ( " Error opening db cursor " ) ) ;
2014-10-28 00:45:33 +00:00
done = false ;
}
2015-12-14 04:54:39 +00:00
~ lmdb_cur ( )
{
close ( ) ;
}
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2015-12-14 04:54:39 +00:00
operator MDB_cursor * ( )
{
return m_cur ;
}
operator MDB_cursor * * ( )
{
return & m_cur ;
}
2014-10-28 00:45:33 +00:00
void close ( )
{
if ( ! done )
{
mdb_cursor_close ( m_cur ) ;
done = true ;
}
}
2014-12-07 11:23:40 +00:00
private :
2014-10-28 00:45:33 +00:00
MDB_cursor * m_cur ;
bool done ;
} ;
2014-10-21 20:33:43 +00:00
2014-12-12 13:27:05 +00:00
template < typename T >
struct MDB_val_copy : public MDB_val
{
2015-12-14 04:54:39 +00:00
MDB_val_copy ( const T & t ) :
t_copy ( t )
2014-12-12 13:27:05 +00:00
{
mv_size = sizeof ( T ) ;
mv_data = & t_copy ;
}
private :
T t_copy ;
} ;
template < >
struct MDB_val_copy < cryptonote : : blobdata > : public MDB_val
{
2015-12-14 04:54:39 +00:00
MDB_val_copy ( const cryptonote : : blobdata & bd ) :
data ( new char [ bd . size ( ) ] )
2014-12-12 13:27:05 +00:00
{
memcpy ( data . get ( ) , bd . data ( ) , bd . size ( ) ) ;
mv_size = bd . size ( ) ;
mv_data = data . get ( ) ;
}
private :
std : : unique_ptr < char [ ] > data ;
} ;
2015-10-26 15:52:07 +00:00
template < >
struct MDB_val_copy < const char * > : public MDB_val
{
2015-12-28 19:22:37 +00:00
MDB_val_copy ( const char * s ) :
2015-12-29 00:09:10 +00:00
size ( strlen ( s ) + 1 ) , // include the NUL, makes it easier for compares
data ( new char [ size ] )
2015-10-26 15:52:07 +00:00
{
2015-12-29 00:09:10 +00:00
mv_size = size ;
2015-10-26 15:52:07 +00:00
mv_data = data . get ( ) ;
2015-12-29 00:09:10 +00:00
memcpy ( mv_data , s , size ) ;
2015-10-26 15:52:07 +00:00
}
private :
2015-12-29 00:09:10 +00:00
size_t size ;
2015-10-26 15:52:07 +00:00
std : : unique_ptr < char [ ] > data ;
} ;
2016-02-25 13:55:49 +00:00
int compare_uint8 ( const MDB_val * a , const MDB_val * b )
2015-09-20 17:41:38 +00:00
{
const uint8_t va = * ( const uint8_t * ) a - > mv_data ;
const uint8_t vb = * ( const uint8_t * ) b - > mv_data ;
2016-02-25 13:55:49 +00:00
return va - vb ;
2015-09-20 17:41:38 +00:00
} ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
int compare_hash32 ( const MDB_val * a , const MDB_val * b )
{
2015-12-14 04:54:39 +00:00
uint32_t * va = ( uint32_t * ) a - > mv_data ;
uint32_t * vb = ( uint32_t * ) b - > mv_data ;
for ( int n = 7 ; n > = 0 ; n - - )
{
if ( va [ n ] = = vb [ n ] )
continue ;
return va [ n ] < vb [ n ] ? - 1 : 1 ;
}
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2015-12-14 04:54:39 +00:00
return 0 ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
}
2015-10-26 15:52:07 +00:00
int compare_string ( const MDB_val * a , const MDB_val * b )
{
const char * va = ( const char * ) a - > mv_data ;
const char * vb = ( const char * ) b - > mv_data ;
return strcmp ( va , vb ) ;
}
2014-12-06 21:37:22 +00:00
const char * const LMDB_BLOCKS = " blocks " ;
const char * const LMDB_BLOCK_TIMESTAMPS = " block_timestamps " ;
const char * const LMDB_BLOCK_HEIGHTS = " block_heights " ;
const char * const LMDB_BLOCK_HASHES = " block_hashes " ;
const char * const LMDB_BLOCK_SIZES = " block_sizes " ;
const char * const LMDB_BLOCK_DIFFS = " block_diffs " ;
const char * const LMDB_BLOCK_COINS = " block_coins " ;
const char * const LMDB_TXS = " txs " ;
const char * const LMDB_TX_UNLOCKS = " tx_unlocks " ;
const char * const LMDB_TX_HEIGHTS = " tx_heights " ;
const char * const LMDB_TX_OUTPUTS = " tx_outputs " ;
const char * const LMDB_OUTPUT_TXS = " output_txs " ;
const char * const LMDB_OUTPUT_INDICES = " output_indices " ;
const char * const LMDB_OUTPUT_AMOUNTS = " output_amounts " ;
const char * const LMDB_OUTPUT_KEYS = " output_keys " ;
const char * const LMDB_SPENT_KEYS = " spent_keys " ;
2014-10-21 20:33:43 +00:00
2015-09-20 17:41:38 +00:00
const char * const LMDB_HF_STARTING_HEIGHTS = " hf_starting_heights " ;
const char * const LMDB_HF_VERSIONS = " hf_versions " ;
2015-10-26 15:52:07 +00:00
const char * const LMDB_PROPERTIES = " properties " ;
2014-10-28 00:45:33 +00:00
inline void lmdb_db_open ( MDB_txn * txn , const char * name , int flags , MDB_dbi & dbi , const std : : string & error_string )
{
if ( mdb_dbi_open ( txn , name , flags , & dbi ) )
2014-12-12 21:34:45 +00:00
throw0 ( cryptonote : : DB_OPEN_FAILURE ( error_string . c_str ( ) ) ) ;
2014-10-28 00:45:33 +00:00
}
2015-12-13 16:45:03 +00:00
const std : : string lmdb_error ( const std : : string & error_string , int mdb_res )
{
const std : : string full_string = error_string + mdb_strerror ( mdb_res ) ;
return full_string ;
}
2014-10-28 00:45:33 +00:00
} // anonymous namespace
2016-01-07 06:33:22 +00:00
# define CURSOR(name) \
if ( ! m_cur_ # # name ) { \
int result = mdb_cursor_open ( * m_write_txn , m_ # # name , & m_cur_ # # name ) ; \
if ( result ) \
throw0 ( DB_ERROR ( std : : string ( " Failed to open cursor: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ; \
}
2016-02-18 12:09:57 +00:00
# define RCURSOR(name) \
if ( ! m_cur_ # # name ) { \
int result = mdb_cursor_open ( m_txn , m_ # # name , ( MDB_cursor * * ) & m_cur_ # # name ) ; \
if ( result ) \
throw0 ( DB_ERROR ( std : : string ( " Failed to open cursor: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ; \
if ( ! m_write_txn ) \
m_tinfo - > m_ti_rflags . m_rf_ # # name = true ; \
} else if ( ! m_write_txn & & ! m_tinfo - > m_ti_rflags . m_rf_ # # name ) { \
mdb_cursor_renew ( m_txn , m_cur_ # # name ) ; \
m_tinfo - > m_ti_rflags . m_rf_ # # name = true ; \
}
2014-10-28 00:45:33 +00:00
namespace cryptonote
{
2015-05-17 02:05:54 +00:00
std : : atomic < uint64_t > mdb_txn_safe : : num_active_txns { 0 } ;
std : : atomic_flag mdb_txn_safe : : creation_gate = ATOMIC_FLAG_INIT ;
2014-10-28 00:45:33 +00:00
2016-02-18 12:09:57 +00:00
mdb_threadinfo : : ~ mdb_threadinfo ( )
{
MDB_cursor * * cur = & m_ti_rcursors . m_txc_blocks ;
unsigned i ;
for ( i = 0 ; i < sizeof ( mdb_txn_cursors ) / sizeof ( MDB_cursor * ) ; i + + )
if ( cur [ i ] )
mdb_cursor_close ( cur [ i ] ) ;
if ( m_ti_rtxn )
mdb_txn_abort ( m_ti_rtxn ) ;
}
2015-05-17 02:05:54 +00:00
mdb_txn_safe : : mdb_txn_safe ( ) : m_txn ( NULL )
{
while ( creation_gate . test_and_set ( ) ) ;
num_active_txns + + ;
creation_gate . clear ( ) ;
}
mdb_txn_safe : : ~ mdb_txn_safe ( )
{
LOG_PRINT_L3 ( " mdb_txn_safe: destructor " ) ;
2016-02-13 11:35:48 +00:00
if ( m_txn ! = nullptr )
2015-05-16 00:42:47 +00:00
{
2015-05-17 02:05:54 +00:00
if ( m_batch_txn ) // this is a batch txn and should have been handled before this point for safety
2015-05-16 00:42:47 +00:00
{
2015-05-17 02:05:54 +00:00
LOG_PRINT_L0 ( " WARNING: mdb_txn_safe: m_txn is a batch txn and it's not NULL in destructor - calling mdb_txn_abort() " ) ;
}
else
{
// Example of when this occurs: a lookup fails, so a read-only txn is
// aborted through this destructor. However, successful read-only txns
// ideally should have been committed when done and not end up here.
//
// NOTE: not sure if this is ever reached for a non-batch write
// transaction, but it's probably not ideal if it did.
LOG_PRINT_L3 ( " mdb_txn_safe: m_txn not NULL in destructor - calling mdb_txn_abort() " ) ;
2015-05-16 00:42:47 +00:00
}
2015-05-17 02:05:54 +00:00
mdb_txn_abort ( m_txn ) ;
2015-05-16 00:42:47 +00:00
}
2015-05-17 02:05:54 +00:00
num_active_txns - - ;
}
2015-05-16 00:42:47 +00:00
2015-05-17 02:05:54 +00:00
void mdb_txn_safe : : commit ( std : : string message )
{
if ( message . size ( ) = = 0 )
2015-05-16 00:42:47 +00:00
{
2015-05-17 02:05:54 +00:00
message = " Failed to commit a transaction to the db " ;
}
2015-05-16 00:42:47 +00:00
2015-05-30 04:07:54 +00:00
if ( auto result = mdb_txn_commit ( m_txn ) )
2015-05-17 02:05:54 +00:00
{
2016-02-13 11:35:48 +00:00
m_txn = nullptr ;
2015-05-30 04:07:54 +00:00
throw0 ( DB_ERROR ( ( message + " : " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2015-05-16 00:42:47 +00:00
}
2016-02-13 11:35:48 +00:00
m_txn = nullptr ;
2015-05-17 02:05:54 +00:00
}
2015-05-16 00:42:47 +00:00
2015-05-17 02:05:54 +00:00
void mdb_txn_safe : : abort ( )
{
LOG_PRINT_L3 ( " mdb_txn_safe: abort() " ) ;
2016-02-13 11:35:48 +00:00
if ( m_txn ! = nullptr )
2015-05-16 00:42:47 +00:00
{
2015-05-17 02:05:54 +00:00
mdb_txn_abort ( m_txn ) ;
2016-02-13 11:35:48 +00:00
m_txn = nullptr ;
2015-05-17 02:05:54 +00:00
}
else
{
LOG_PRINT_L0 ( " WARNING: mdb_txn_safe: abort() called, but m_txn is NULL " ) ;
}
}
2015-05-27 18:03:46 +00:00
uint64_t mdb_txn_safe : : num_active_tx ( ) const
2015-05-17 02:05:54 +00:00
{
return num_active_txns ;
}
void mdb_txn_safe : : prevent_new_txns ( )
{
while ( creation_gate . test_and_set ( ) ) ;
}
void mdb_txn_safe : : wait_no_active_txns ( )
{
while ( num_active_txns > 0 ) ;
}
void mdb_txn_safe : : allow_new_txns ( )
{
creation_gate . clear ( ) ;
}
2015-07-12 05:46:16 +00:00
void BlockchainLMDB : : do_resize ( uint64_t increase_size )
2015-05-17 02:05:54 +00:00
{
2015-08-04 21:59:42 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
CRITICAL_REGION_LOCAL ( m_synchronization_lock ) ;
const uint64_t add_size = 1LL < < 30 ;
// check disk capacity
try
{
2015-12-14 04:54:39 +00:00
boost : : filesystem : : path path ( m_folder ) ;
boost : : filesystem : : space_info si = boost : : filesystem : : space ( path ) ;
if ( si . available < add_size )
{
LOG_PRINT_RED_L0 ( " !! WARNING: Insufficient free space to extend database !!: " < < si . available / 1LL < < 20L ) ;
return ;
}
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
}
catch ( . . . )
{
2015-12-14 04:54:39 +00:00
// print something but proceed.
LOG_PRINT_YELLOW ( " Unable to query free disk space. " , LOG_LEVEL_0 ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
}
2015-05-17 02:05:54 +00:00
MDB_envinfo mei ;
mdb_env_info ( m_env , & mei ) ;
MDB_stat mst ;
mdb_env_stat ( m_env , & mst ) ;
2015-07-15 05:47:07 +00:00
// add 1Gb per resize, instead of doing a percentage increase
uint64_t new_mapsize = ( double ) mei . me_mapsize + add_size ;
2015-07-12 05:46:16 +00:00
// If given, use increase_size intead of above way of resizing.
// This is currently used for increasing by an estimated size at start of new
// batch txn.
if ( increase_size > 0 )
new_mapsize = mei . me_mapsize + increase_size ;
2015-05-17 02:05:54 +00:00
new_mapsize + = ( new_mapsize % mst . ms_psize ) ;
mdb_txn_safe : : prevent_new_txns ( ) ;
if ( m_write_txn ! = nullptr )
{
if ( m_batch_active )
2015-05-16 00:42:47 +00:00
{
2015-05-17 02:05:54 +00:00
throw0 ( DB_ERROR ( " lmdb resizing not yet supported when batch transactions enabled! " ) ) ;
2015-05-16 00:42:47 +00:00
}
else
{
2015-05-17 02:05:54 +00:00
throw0 ( DB_ERROR ( " attempting resize with write transaction in progress, this should not happen! " ) ) ;
2015-05-16 00:42:47 +00:00
}
}
2014-10-28 00:45:33 +00:00
2015-05-17 02:05:54 +00:00
mdb_txn_safe : : wait_no_active_txns ( ) ;
mdb_env_set_mapsize ( m_env , new_mapsize ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
LOG_PRINT_GREEN ( " LMDB Mapsize increased. " < < " Old: " < < mei . me_mapsize / ( 1024 * 1024 ) < < " MiB " < < " , New: " < < new_mapsize / ( 1024 * 1024 ) < < " MiB " , LOG_LEVEL_0 ) ;
2015-05-17 02:05:54 +00:00
mdb_txn_safe : : allow_new_txns ( ) ;
}
2015-07-12 05:46:16 +00:00
// threshold_size is used for batch transactions
bool BlockchainLMDB : : need_resize ( uint64_t threshold_size ) const
2015-05-17 02:05:54 +00:00
{
2015-08-04 21:59:42 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
# if defined(ENABLE_AUTO_RESIZE)
2015-05-17 02:05:54 +00:00
MDB_envinfo mei ;
mdb_env_info ( m_env , & mei ) ;
MDB_stat mst ;
mdb_env_stat ( m_env , & mst ) ;
2015-07-12 05:46:16 +00:00
// size_used doesn't include data yet to be committed, which can be
// significant size during batch transactions. For that, we estimate the size
// needed at the beginning of the batch transaction and pass in the
// additional size needed.
2015-05-17 02:05:54 +00:00
uint64_t size_used = mst . ms_psize * mei . me_last_pgno ;
2015-07-12 05:46:16 +00:00
LOG_PRINT_L1 ( " DB map size: " < < mei . me_mapsize ) ;
LOG_PRINT_L1 ( " Space used: " < < size_used ) ;
LOG_PRINT_L1 ( " Space remaining: " < < mei . me_mapsize - size_used ) ;
LOG_PRINT_L1 ( " Size threshold: " < < threshold_size ) ;
2015-08-04 21:59:42 +00:00
float resize_percent_old = RESIZE_PERCENT ;
LOG_PRINT_L1 ( boost : : format ( " Percent used: %.04f Percent threshold: %.04f " ) % ( ( double ) size_used / mei . me_mapsize ) % resize_percent_old ) ;
2015-07-12 05:46:16 +00:00
if ( threshold_size > 0 )
{
if ( mei . me_mapsize - size_used < threshold_size )
{
LOG_PRINT_L1 ( " Threshold met (size-based) " ) ;
return true ;
}
else
return false ;
}
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
std : : mt19937 engine ( std : : random_device { } ( ) ) ;
std : : uniform_real_distribution < double > fdis ( 0.6 , 0.9 ) ;
double resize_percent = fdis ( engine ) ;
if ( ( double ) size_used / mei . me_mapsize > resize_percent )
2015-05-17 02:05:54 +00:00
{
2015-07-12 05:46:16 +00:00
LOG_PRINT_L1 ( " Threshold met (percent-based) " ) ;
2015-05-17 02:05:54 +00:00
return true ;
}
return false ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
# else
2015-12-14 04:54:39 +00:00
return false ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
# endif
2015-05-17 02:05:54 +00:00
}
2015-03-03 21:09:49 +00:00
2015-07-12 05:46:16 +00:00
void BlockchainLMDB : : check_and_resize_for_batch ( uint64_t batch_num_blocks )
{
2015-08-04 21:59:42 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
LOG_PRINT_L1 ( " [ " < < __func__ < < " ] " < < " checking DB size " ) ;
2016-02-14 19:31:52 +00:00
const uint64_t min_increase_size = 512 * ( 1 < < 20 ) ;
2015-07-12 05:46:16 +00:00
uint64_t threshold_size = 0 ;
uint64_t increase_size = 0 ;
if ( batch_num_blocks > 0 )
{
threshold_size = get_estimated_batch_size ( batch_num_blocks ) ;
LOG_PRINT_L1 ( " calculated batch size: " < < threshold_size ) ;
// The increased DB size could be a multiple of threshold_size, a fixed
// size increase (> threshold_size), or other variations.
//
// Currently we use the greater of threshold size and a minimum size. The
// minimum size increase is used to avoid frequent resizes when the batch
// size is set to a very small numbers of blocks.
increase_size = ( threshold_size > min_increase_size ) ? threshold_size : min_increase_size ;
LOG_PRINT_L1 ( " increase size: " < < increase_size ) ;
}
// if threshold_size is 0 (i.e. number of blocks for batch not passed in), it
// will fall back to the percent-based threshold check instead of the
// size-based check
if ( need_resize ( threshold_size ) )
{
LOG_PRINT_L0 ( " [batch] DB resize needed " ) ;
do_resize ( increase_size ) ;
}
}
uint64_t BlockchainLMDB : : get_estimated_batch_size ( uint64_t batch_num_blocks ) const
{
2015-08-04 21:59:42 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2015-07-12 05:46:16 +00:00
uint64_t threshold_size = 0 ;
// batch size estimate * batch safety factor = final size estimate
// Takes into account "reasonable" block size increases in batch.
float batch_safety_factor = 1.7f ;
2016-02-14 19:31:52 +00:00
float batch_fudge_factor = batch_safety_factor * batch_num_blocks ;
2015-07-12 05:46:16 +00:00
// estimate of stored block expanded from raw block, including denormalization and db overhead.
// Note that this probably doesn't grow linearly with block size.
float db_expand_factor = 4.5f ;
uint64_t num_prev_blocks = 500 ;
// For resizing purposes, allow for at least 4k average block size.
uint64_t min_block_size = 4 * 1024 ;
2015-08-04 21:59:42 +00:00
uint64_t block_stop = 0 ;
if ( m_height > 1 )
block_stop = m_height - 1 ;
2015-07-12 05:46:16 +00:00
uint64_t block_start = 0 ;
if ( block_stop > = num_prev_blocks )
block_start = block_stop - num_prev_blocks + 1 ;
uint32_t num_blocks_used = 0 ;
uint64_t total_block_size = 0 ;
2015-08-04 21:59:42 +00:00
LOG_PRINT_L1 ( " [ " < < __func__ < < " ] " < < " m_height: " < < m_height < < " block_start: " < < block_start < < " block_stop: " < < block_stop ) ;
size_t avg_block_size = 0 ;
if ( m_height = = 0 )
2015-07-12 05:46:16 +00:00
{
2015-08-04 21:59:42 +00:00
LOG_PRINT_L1 ( " No existing blocks to check for average block size " ) ;
}
2016-02-14 20:27:43 +00:00
else if ( m_cum_count )
{
avg_block_size = m_cum_size / m_cum_count ;
LOG_PRINT_L1 ( " average block size across recent " < < m_cum_count < < " blocks: " < < avg_block_size ) ;
m_cum_size = 0 ;
m_cum_count = 0 ;
}
2015-08-04 21:59:42 +00:00
else
{
for ( uint64_t block_num = block_start ; block_num < = block_stop ; + + block_num )
{
uint32_t block_size = get_block_size ( block_num ) ;
total_block_size + = block_size ;
// Track number of blocks being totalled here instead of assuming, in case
// some blocks were to be skipped for being outliers.
+ + num_blocks_used ;
}
avg_block_size = total_block_size / num_blocks_used ;
LOG_PRINT_L1 ( " average block size across recent " < < num_blocks_used < < " blocks: " < < avg_block_size ) ;
2015-07-12 05:46:16 +00:00
}
if ( avg_block_size < min_block_size )
avg_block_size = min_block_size ;
LOG_PRINT_L1 ( " estimated average block size for batch: " < < avg_block_size ) ;
2016-02-14 19:31:52 +00:00
// bigger safety margin on smaller block sizes
if ( batch_fudge_factor < 5000.0 )
batch_fudge_factor = 5000.0 ;
threshold_size = avg_block_size * db_expand_factor * batch_fudge_factor ;
2015-07-12 05:46:16 +00:00
return threshold_size ;
}
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
void BlockchainLMDB : : add_block ( const block & blk , const size_t & block_size , const difficulty_type & cumulative_difficulty , const uint64_t & coins_generated ,
2015-12-14 04:54:39 +00:00
const crypto : : hash & blk_hash )
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2016-02-18 12:09:57 +00:00
mdb_txn_cursors * m_cursors = & m_wcursors ;
2014-10-23 19:37:10 +00:00
2016-01-07 06:33:22 +00:00
CURSOR ( block_heights )
2015-02-11 23:55:53 +00:00
MDB_val_copy < crypto : : hash > val_h ( blk_hash ) ;
2016-01-07 06:33:22 +00:00
if ( mdb_cursor_get ( m_cur_block_heights , & val_h , NULL , MDB_SET ) = = 0 )
2014-12-12 21:34:45 +00:00
throw1 ( BLOCK_EXISTS ( " Attempting to add block that's already in the db " ) ) ;
2014-10-23 19:37:10 +00:00
if ( m_height > 0 )
{
2014-12-12 13:27:05 +00:00
MDB_val_copy < crypto : : hash > parent_key ( blk . prev_id ) ;
2014-10-23 19:37:10 +00:00
MDB_val parent_h ;
2016-01-07 06:33:22 +00:00
if ( mdb_cursor_get ( m_cur_block_heights , & parent_key , & parent_h , MDB_SET ) )
2015-02-11 23:55:53 +00:00
{
LOG_PRINT_L3 ( " m_height: " < < m_height ) ;
LOG_PRINT_L3 ( " parent_key: " < < blk . prev_id ) ;
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " Failed to get top block hash to check for new block's parent " ) ) ;
2015-02-11 23:55:53 +00:00
}
2014-12-11 19:30:55 +00:00
uint64_t parent_height = * ( const uint64_t * ) parent_h . mv_data ;
2014-10-23 19:37:10 +00:00
if ( parent_height ! = m_height - 1 )
2014-12-12 21:34:45 +00:00
throw0 ( BLOCK_PARENT_DNE ( " Top block is not new block's parent " ) ) ;
2014-10-23 19:37:10 +00:00
}
2015-05-30 04:07:54 +00:00
int result = 0 ;
2014-12-12 13:27:05 +00:00
MDB_val_copy < uint64_t > key ( m_height ) ;
2014-10-23 19:37:10 +00:00
2016-01-07 06:33:22 +00:00
CURSOR ( blocks )
CURSOR ( block_sizes )
CURSOR ( block_timestamps )
CURSOR ( block_diffs )
CURSOR ( block_coins )
CURSOR ( block_hashes )
2014-12-12 13:27:05 +00:00
MDB_val_copy < blobdata > blob ( block_to_blob ( blk ) ) ;
2016-01-07 06:33:22 +00:00
result = mdb_cursor_put ( m_cur_blocks , & key , & blob , MDB_APPEND ) ;
2015-05-30 04:07:54 +00:00
if ( result )
throw0 ( DB_ERROR ( std : : string ( " Failed to add block blob to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2014-10-23 19:37:10 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < size_t > sz ( block_size ) ;
2016-01-07 06:33:22 +00:00
result = mdb_cursor_put ( m_cur_block_sizes , & key , & sz , MDB_APPEND ) ;
2015-05-30 04:07:54 +00:00
if ( result )
throw0 ( DB_ERROR ( std : : string ( " Failed to add block size to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2014-10-23 19:37:10 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < uint64_t > ts ( blk . timestamp ) ;
2016-01-07 06:33:22 +00:00
result = mdb_cursor_put ( m_cur_block_timestamps , & key , & ts , MDB_APPEND ) ;
2015-05-30 04:07:54 +00:00
if ( result )
throw0 ( DB_ERROR ( std : : string ( " Failed to add block timestamp to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2014-10-28 00:45:33 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < difficulty_type > diff ( cumulative_difficulty ) ;
2016-01-07 06:33:22 +00:00
result = mdb_cursor_put ( m_cur_block_diffs , & key , & diff , MDB_APPEND ) ;
2015-05-30 04:07:54 +00:00
if ( result )
throw0 ( DB_ERROR ( std : : string ( " Failed to add block cumulative difficulty to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2014-10-28 00:45:33 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < uint64_t > coinsgen ( coins_generated ) ;
2016-01-07 06:33:22 +00:00
result = mdb_cursor_put ( m_cur_block_coins , & key , & coinsgen , MDB_APPEND ) ;
2015-05-30 04:07:54 +00:00
if ( result )
throw0 ( DB_ERROR ( std : : string ( " Failed to add block total generated coins to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2014-10-28 00:45:33 +00:00
2016-01-07 06:33:22 +00:00
result = mdb_cursor_put ( m_cur_block_heights , & val_h , & key , 0 ) ;
2015-05-30 04:07:54 +00:00
if ( result )
throw0 ( DB_ERROR ( std : : string ( " Failed to add block height by hash to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2014-10-28 00:45:33 +00:00
2016-01-07 06:33:22 +00:00
result = mdb_cursor_put ( m_cur_block_hashes , & key , & val_h , MDB_APPEND ) ;
2015-05-30 04:07:54 +00:00
if ( result )
throw0 ( DB_ERROR ( std : : string ( " Failed to add block hash to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2014-10-23 19:37:10 +00:00
2016-02-14 20:27:43 +00:00
m_cum_size + = block_size ;
m_cum_count + + ;
2014-10-21 20:33:43 +00:00
}
2014-10-23 19:37:10 +00:00
void BlockchainLMDB : : remove_block ( )
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
2014-12-12 23:20:41 +00:00
if ( m_height = = 0 )
throw0 ( BLOCK_DNE ( " Attempting to remove block from an empty blockchain " ) ) ;
2014-12-12 13:27:05 +00:00
MDB_val_copy < uint64_t > k ( m_height - 1 ) ;
2014-10-28 00:45:33 +00:00
MDB_val h ;
if ( mdb_get ( * m_write_txn , m_block_hashes , & k , & h ) )
2014-12-12 21:34:45 +00:00
throw1 ( BLOCK_DNE ( " Attempting to remove block that's not in the db " ) ) ;
2014-10-28 00:45:33 +00:00
if ( mdb_del ( * m_write_txn , m_blocks , & k , NULL ) )
2014-12-12 21:34:45 +00:00
throw1 ( DB_ERROR ( " Failed to add removal of block to db transaction " ) ) ;
2014-10-28 00:45:33 +00:00
if ( mdb_del ( * m_write_txn , m_block_sizes , & k , NULL ) )
2014-12-12 21:34:45 +00:00
throw1 ( DB_ERROR ( " Failed to add removal of block size to db transaction " ) ) ;
2014-10-28 00:45:33 +00:00
if ( mdb_del ( * m_write_txn , m_block_diffs , & k , NULL ) )
2014-12-12 21:34:45 +00:00
throw1 ( DB_ERROR ( " Failed to add removal of block cumulative difficulty to db transaction " ) ) ;
2014-10-28 00:45:33 +00:00
if ( mdb_del ( * m_write_txn , m_block_coins , & k , NULL ) )
2014-12-12 21:34:45 +00:00
throw1 ( DB_ERROR ( " Failed to add removal of block total generated coins to db transaction " ) ) ;
2014-10-28 00:45:33 +00:00
2014-12-11 19:36:27 +00:00
if ( mdb_del ( * m_write_txn , m_block_timestamps , & k , NULL ) )
2014-12-12 21:34:45 +00:00
throw1 ( DB_ERROR ( " Failed to add removal of block timestamp to db transaction " ) ) ;
2014-12-11 19:36:27 +00:00
2014-10-28 00:45:33 +00:00
if ( mdb_del ( * m_write_txn , m_block_heights , & h , NULL ) )
2014-12-12 21:34:45 +00:00
throw1 ( DB_ERROR ( " Failed to add removal of block height by hash to db transaction " ) ) ;
2014-10-28 00:45:33 +00:00
if ( mdb_del ( * m_write_txn , m_block_hashes , & k , NULL ) )
2014-12-12 21:34:45 +00:00
throw1 ( DB_ERROR ( " Failed to add removal of block hash to db transaction " ) ) ;
2014-10-21 20:33:43 +00:00
}
2015-02-11 23:55:53 +00:00
void BlockchainLMDB : : add_transaction_data ( const crypto : : hash & blk_hash , const transaction & tx , const crypto : : hash & tx_hash )
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2016-02-18 12:09:57 +00:00
mdb_txn_cursors * m_cursors = & m_wcursors ;
2014-10-23 23:47:36 +00:00
2015-05-30 04:07:54 +00:00
int result = 0 ;
2016-01-07 06:33:22 +00:00
CURSOR ( txs )
CURSOR ( tx_heights )
CURSOR ( tx_unlocks )
2015-02-11 23:55:53 +00:00
MDB_val_copy < crypto : : hash > val_h ( tx_hash ) ;
2014-10-23 23:47:36 +00:00
MDB_val unused ;
2016-01-07 06:33:22 +00:00
if ( mdb_cursor_get ( m_cur_txs , & val_h , & unused , MDB_SET ) = = 0 )
2014-12-12 21:34:45 +00:00
throw1 ( TX_EXISTS ( " Attempting to add transaction that's already in the db " ) ) ;
2014-10-23 23:47:36 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < blobdata > blob ( tx_to_blob ( tx ) ) ;
2016-01-07 06:33:22 +00:00
result = mdb_cursor_put ( m_cur_txs , & val_h , & blob , 0 ) ;
2015-05-30 04:07:54 +00:00
if ( result )
throw0 ( DB_ERROR ( std : : string ( " Failed to add tx blob to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2014-10-23 23:47:36 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < uint64_t > height ( m_height ) ;
2016-01-07 06:33:22 +00:00
result = mdb_cursor_put ( m_cur_tx_heights , & val_h , & height , 0 ) ;
2015-05-30 04:07:54 +00:00
if ( result )
throw0 ( DB_ERROR ( std : : string ( " Failed to add tx block height to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2014-10-28 00:45:33 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < uint64_t > unlock_time ( tx . unlock_time ) ;
2016-01-07 06:33:22 +00:00
result = mdb_cursor_put ( m_cur_tx_unlocks , & val_h , & unlock_time , 0 ) ;
2015-05-30 04:07:54 +00:00
if ( result )
throw0 ( DB_ERROR ( std : : string ( " Failed to add tx unlock time to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2014-10-21 20:33:43 +00:00
}
2015-01-12 02:04:04 +00:00
void BlockchainLMDB : : remove_transaction_data ( const crypto : : hash & tx_hash , const transaction & tx )
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < crypto : : hash > val_h ( tx_hash ) ;
2014-10-28 00:45:33 +00:00
MDB_val unused ;
if ( mdb_get ( * m_write_txn , m_txs , & val_h , & unused ) )
2014-12-12 21:34:45 +00:00
throw1 ( TX_DNE ( " Attempting to remove transaction that isn't in the db " ) ) ;
2014-10-28 00:45:33 +00:00
if ( mdb_del ( * m_write_txn , m_txs , & val_h , NULL ) )
2014-12-12 21:34:45 +00:00
throw1 ( DB_ERROR ( " Failed to add removal of tx to db transaction " ) ) ;
2014-10-28 00:45:33 +00:00
if ( mdb_del ( * m_write_txn , m_tx_unlocks , & val_h , NULL ) )
2014-12-12 21:34:45 +00:00
throw1 ( DB_ERROR ( " Failed to add removal of tx unlock time to db transaction " ) ) ;
2014-10-28 00:45:33 +00:00
if ( mdb_del ( * m_write_txn , m_tx_heights , & val_h , NULL ) )
2014-12-12 21:34:45 +00:00
throw1 ( DB_ERROR ( " Failed to add removal of tx block height to db transaction " ) ) ;
2014-10-30 22:33:35 +00:00
2015-01-12 02:04:04 +00:00
remove_tx_outputs ( tx_hash , tx ) ;
2014-10-30 22:33:35 +00:00
2016-01-20 00:46:38 +00:00
auto result = mdb_del ( * m_write_txn , m_tx_outputs , & val_h , NULL ) ;
if ( result = = MDB_NOTFOUND )
LOG_PRINT_L1 ( " tx has no outputs to remove: " < < tx_hash ) ;
else if ( result )
throw1 ( DB_ERROR ( std : : string ( " Failed to add removal of tx outputs to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2014-10-21 20:33:43 +00:00
}
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
void BlockchainLMDB : : add_output ( const crypto : : hash & tx_hash , const tx_out & tx_output , const uint64_t & local_index , const uint64_t unlock_time )
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2016-02-18 12:09:57 +00:00
mdb_txn_cursors * m_cursors = & m_wcursors ;
2014-10-23 23:47:36 +00:00
2015-05-30 04:07:54 +00:00
int result = 0 ;
2016-01-07 06:33:22 +00:00
CURSOR ( output_txs )
CURSOR ( tx_outputs )
CURSOR ( output_indices )
CURSOR ( output_amounts )
CURSOR ( output_keys )
2014-12-12 13:27:05 +00:00
MDB_val_copy < uint64_t > k ( m_num_outputs ) ;
MDB_val_copy < crypto : : hash > v ( tx_hash ) ;
2014-10-23 23:47:36 +00:00
2016-01-07 13:23:12 +00:00
result = mdb_cursor_put ( m_cur_output_txs , & k , & v , MDB_APPEND ) ;
2015-05-30 04:07:54 +00:00
if ( result )
throw0 ( DB_ERROR ( std : : string ( " Failed to add output tx hash to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2016-01-07 06:33:22 +00:00
result = mdb_cursor_put ( m_cur_tx_outputs , & v , & k , 0 ) ;
2015-05-30 04:07:54 +00:00
if ( result )
throw0 ( DB_ERROR ( std : : string ( " Failed to add <tx hash, global output index> to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2014-10-23 23:47:36 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < uint64_t > val_local_index ( local_index ) ;
2016-01-07 13:23:12 +00:00
result = mdb_cursor_put ( m_cur_output_indices , & k , & val_local_index , MDB_APPEND ) ;
2015-05-30 04:07:54 +00:00
if ( result )
throw0 ( DB_ERROR ( std : : string ( " Failed to add tx output index to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2014-10-23 23:47:36 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < uint64_t > val_amount ( tx_output . amount ) ;
2016-01-07 06:33:22 +00:00
result = mdb_cursor_put ( m_cur_output_amounts , & val_amount , & k , 0 ) ;
2015-05-30 04:07:54 +00:00
if ( result )
throw0 ( DB_ERROR ( std : : string ( " Failed to add output amount to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2014-10-23 23:47:36 +00:00
2014-10-31 21:34:15 +00:00
if ( tx_output . target . type ( ) = = typeid ( txout_to_key ) )
{
2015-12-14 04:54:39 +00:00
output_data_t od ;
od . pubkey = boost : : get < txout_to_key > ( tx_output . target ) . key ;
od . unlock_time = unlock_time ;
od . height = m_height ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2015-12-14 04:54:39 +00:00
MDB_val_copy < output_data_t > data ( od ) ;
//MDB_val_copy<crypto::public_key> val_pubkey(boost::get<txout_to_key>(tx_output.target).key);
2016-01-07 13:23:12 +00:00
if ( mdb_cursor_put ( m_cur_output_keys , & k , & data , MDB_APPEND ) )
2015-12-14 04:54:39 +00:00
throw0 ( DB_ERROR ( " Failed to add output pubkey to db transaction " ) ) ;
2014-10-31 21:34:15 +00:00
}
2015-12-25 21:56:37 +00:00
else
{
throw0 ( DB_ERROR ( " Wrong output type: expected txout_to_key " ) ) ;
}
2014-10-31 21:34:15 +00:00
2014-10-29 02:25:03 +00:00
m_num_outputs + + ;
2014-10-21 20:33:43 +00:00
}
2015-01-12 02:04:04 +00:00
void BlockchainLMDB : : remove_tx_outputs ( const crypto : : hash & tx_hash , const transaction & tx )
2014-10-30 22:33:35 +00:00
{
2015-01-12 02:04:04 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-30 22:33:35 +00:00
lmdb_cur cur ( * m_write_txn , m_tx_outputs ) ;
2014-12-12 13:27:05 +00:00
MDB_val_copy < crypto : : hash > k ( tx_hash ) ;
2014-10-30 22:33:35 +00:00
MDB_val v ;
auto result = mdb_cursor_get ( cur , & k , & v , MDB_SET ) ;
if ( result = = MDB_NOTFOUND )
{
2016-01-20 00:46:38 +00:00
LOG_PRINT_L2 ( " tx has no outputs, so no global output indices " ) ;
2014-10-30 22:33:35 +00:00
}
else if ( result )
{
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " DB error attempting to get an output " ) ) ;
2014-10-30 22:33:35 +00:00
}
else
{
2016-02-17 16:12:38 +00:00
mdb_size_t num_elems = 0 ;
2014-10-30 22:33:35 +00:00
mdb_cursor_count ( cur , & num_elems ) ;
2015-12-24 20:22:09 +00:00
mdb_cursor_get ( cur , & k , & v , MDB_LAST_DUP ) ;
2014-10-30 22:33:35 +00:00
2015-12-24 20:22:09 +00:00
for ( uint64_t i = num_elems ; i > 0 ; - - i )
2014-10-30 22:33:35 +00:00
{
2015-12-24 20:22:09 +00:00
const tx_out tx_output = tx . vout [ i - 1 ] ;
2015-01-12 02:04:04 +00:00
remove_output ( * ( const uint64_t * ) v . mv_data , tx_output . amount ) ;
2015-12-24 20:22:09 +00:00
if ( i > 1 )
2014-10-30 22:33:35 +00:00
{
2015-12-24 20:22:09 +00:00
mdb_cursor_get ( cur , & k , & v , MDB_PREV_DUP ) ;
2014-10-30 22:33:35 +00:00
}
}
}
cur . close ( ) ;
}
2015-01-12 02:04:04 +00:00
// TODO: probably remove this function
2014-10-21 20:33:43 +00:00
void BlockchainLMDB : : remove_output ( const tx_out & tx_output )
2014-10-30 22:33:35 +00:00
{
2015-01-12 02:04:04 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ < < " (unused version - does nothing) " ) ;
2014-10-30 22:33:35 +00:00
return ;
}
2015-01-12 02:04:04 +00:00
void BlockchainLMDB : : remove_output ( const uint64_t & out_index , const uint64_t amount )
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-24 00:32:31 +00:00
2015-01-12 02:04:04 +00:00
MDB_val_copy < uint64_t > k ( out_index ) ;
2014-10-24 00:32:31 +00:00
2015-01-12 02:04:04 +00:00
auto result = mdb_del ( * m_write_txn , m_output_indices , & k , NULL ) ;
if ( result = = MDB_NOTFOUND )
{
LOG_PRINT_L0 ( " Unexpected: global output index not found in m_output_indices " ) ;
}
else if ( result )
{
throw1 ( DB_ERROR ( " Error adding removal of output tx index to db transaction " ) ) ;
}
2014-10-24 00:32:31 +00:00
2015-01-12 02:04:04 +00:00
result = mdb_del ( * m_write_txn , m_output_txs , & k , NULL ) ;
// if (result != 0 && result != MDB_NOTFOUND)
// throw1(DB_ERROR("Error adding removal of output tx hash to db transaction"));
if ( result = = MDB_NOTFOUND )
{
LOG_PRINT_L0 ( " Unexpected: global output index not found in m_output_txs " ) ;
}
else if ( result )
{
throw1 ( DB_ERROR ( " Error adding removal of output tx hash to db transaction " ) ) ;
}
2014-10-24 00:32:31 +00:00
2015-01-12 02:04:04 +00:00
result = mdb_del ( * m_write_txn , m_output_keys , & k , NULL ) ;
2014-10-31 21:34:15 +00:00
if ( result = = MDB_NOTFOUND )
{
2015-01-12 02:04:04 +00:00
LOG_PRINT_L0 ( " Unexpected: global output index not found in m_output_keys " ) ;
2014-10-31 21:34:15 +00:00
}
else if ( result )
2014-12-12 21:34:45 +00:00
throw1 ( DB_ERROR ( " Error adding removal of output pubkey to db transaction " ) ) ;
2014-10-31 21:34:15 +00:00
2015-01-12 02:04:04 +00:00
remove_amount_output_index ( amount , out_index ) ;
2014-10-30 22:33:35 +00:00
m_num_outputs - - ;
2014-10-21 20:33:43 +00:00
}
2015-01-12 02:04:04 +00:00
void BlockchainLMDB : : remove_amount_output_index ( const uint64_t amount , const uint64_t global_output_index )
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
lmdb_cur cur ( * m_write_txn , m_output_amounts ) ;
MDB_val_copy < uint64_t > k ( amount ) ;
MDB_val v ;
auto result = mdb_cursor_get ( cur , & k , & v , MDB_SET ) ;
if ( result = = MDB_NOTFOUND )
throw1 ( OUTPUT_DNE ( " Attempting to get an output index by amount and amount index, but amount not found " ) ) ;
else if ( result )
throw0 ( DB_ERROR ( " DB error attempting to get an output " ) ) ;
2016-02-17 16:12:38 +00:00
mdb_size_t num_elems = 0 ;
2015-01-12 02:04:04 +00:00
mdb_cursor_count ( cur , & num_elems ) ;
2015-12-24 20:25:07 +00:00
mdb_cursor_get ( cur , & k , & v , MDB_LAST_DUP ) ;
2015-01-12 02:04:04 +00:00
uint64_t amount_output_index = 0 ;
uint64_t goi = 0 ;
bool found_index = false ;
2015-12-24 20:25:07 +00:00
for ( uint64_t i = num_elems ; i > 0 ; - - i )
2015-01-12 02:04:04 +00:00
{
mdb_cursor_get ( cur , & k , & v , MDB_GET_CURRENT ) ;
goi = * ( const uint64_t * ) v . mv_data ;
if ( goi = = global_output_index )
{
2015-12-24 20:25:07 +00:00
amount_output_index = i - 1 ;
2015-01-12 02:04:04 +00:00
found_index = true ;
break ;
}
2015-12-24 20:25:07 +00:00
if ( i > 1 )
mdb_cursor_get ( cur , & k , & v , MDB_PREV_DUP ) ;
2015-01-12 02:04:04 +00:00
}
if ( found_index )
{
// found the amount output index
// now delete it
result = mdb_cursor_del ( cur , 0 ) ;
if ( result )
throw0 ( DB_ERROR ( std : : string ( " Error deleting amount output index " ) . append ( boost : : lexical_cast < std : : string > ( amount_output_index ) ) . c_str ( ) ) ) ;
}
else
{
// not found
cur . close ( ) ;
throw1 ( OUTPUT_DNE ( " Failed to find amount output index " ) ) ;
}
cur . close ( ) ;
}
2014-10-21 20:33:43 +00:00
void BlockchainLMDB : : add_spent_key ( const crypto : : key_image & k_image )
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2016-02-18 12:09:57 +00:00
mdb_txn_cursors * m_cursors = & m_wcursors ;
2014-10-23 23:47:36 +00:00
2016-01-07 06:33:22 +00:00
CURSOR ( spent_keys )
2014-12-12 13:27:05 +00:00
MDB_val_copy < crypto : : key_image > val_key ( k_image ) ;
2014-10-23 23:47:36 +00:00
MDB_val unused ;
2016-01-07 06:33:22 +00:00
if ( mdb_cursor_get ( m_cur_spent_keys , & val_key , & unused , MDB_SET ) = = 0 )
2014-12-12 21:34:45 +00:00
throw1 ( KEY_IMAGE_EXISTS ( " Attempting to add spent key image that's already in the db " ) ) ;
2014-10-23 23:47:36 +00:00
char anything = ' \0 ' ;
unused . mv_size = sizeof ( char ) ;
unused . mv_data = & anything ;
2016-01-07 06:33:22 +00:00
if ( auto result = mdb_cursor_put ( m_cur_spent_keys , & val_key , & unused , 0 ) )
2015-02-11 23:55:53 +00:00
throw1 ( DB_ERROR ( std : : string ( " Error adding spent key image to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2014-10-21 20:33:43 +00:00
}
void BlockchainLMDB : : remove_spent_key ( const crypto : : key_image & k_image )
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-24 00:32:31 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < crypto : : key_image > k ( k_image ) ;
2014-10-28 00:45:33 +00:00
auto result = mdb_del ( * m_write_txn , m_spent_keys , & k , NULL ) ;
2014-10-24 00:32:31 +00:00
if ( result ! = 0 & & result ! = MDB_NOTFOUND )
2014-12-12 21:34:45 +00:00
throw1 ( DB_ERROR ( " Error adding removal of key image to db transaction " ) ) ;
2014-10-23 19:37:10 +00:00
}
2015-05-27 18:03:46 +00:00
blobdata BlockchainLMDB : : output_to_blob ( const tx_out & output ) const
2014-10-28 00:45:33 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-28 00:45:33 +00:00
blobdata b ;
if ( ! t_serializable_object_to_blob ( output , b ) )
2014-12-12 21:34:45 +00:00
throw1 ( DB_ERROR ( " Error serializing output to blob " ) ) ;
2014-10-28 00:45:33 +00:00
return b ;
}
2014-12-06 21:37:22 +00:00
tx_out BlockchainLMDB : : output_from_blob ( const blobdata & blob ) const
2014-10-28 00:45:33 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-28 00:45:33 +00:00
std : : stringstream ss ;
ss < < blob ;
binary_archive < false > ba ( ss ) ;
tx_out o ;
if ( ! ( : : serialization : : serialize ( ba , o ) ) )
2014-12-12 21:34:45 +00:00
throw1 ( DB_ERROR ( " Error deserializing tx output blob " ) ) ;
2014-10-28 00:45:33 +00:00
return o ;
}
2015-12-14 04:54:39 +00:00
uint64_t BlockchainLMDB : : get_output_global_index ( const uint64_t & amount , const uint64_t & index )
2014-10-28 00:45:33 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2015-12-14 04:54:39 +00:00
std : : vector < uint64_t > offsets ;
std : : vector < uint64_t > global_indices ;
offsets . push_back ( index ) ;
get_output_global_indices ( amount , offsets , global_indices ) ;
if ( ! global_indices . size ( ) )
2015-01-09 21:01:22 +00:00
throw1 ( OUTPUT_DNE ( " Attempting to get an output index by amount and amount index, but amount not found " ) ) ;
2015-12-14 04:54:39 +00:00
return global_indices [ 0 ] ;
2014-10-28 00:45:33 +00:00
}
2014-12-06 21:37:22 +00:00
void BlockchainLMDB : : check_open ( ) const
2014-10-23 19:37:10 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
if ( ! m_open )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " DB operation attempted on a not-open DB instance " ) ) ;
2014-10-21 20:33:43 +00:00
}
BlockchainLMDB : : ~ BlockchainLMDB ( )
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2015-02-11 23:55:53 +00:00
// batch transaction shouldn't be active at this point. If it is, consider it aborted.
if ( m_batch_active )
batch_abort ( ) ;
2015-12-28 19:23:02 +00:00
if ( m_open )
close ( ) ;
2014-10-21 20:33:43 +00:00
}
2015-02-11 23:55:53 +00:00
BlockchainLMDB : : BlockchainLMDB ( bool batch_transactions )
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
// initialize folder to something "safe" just in case
// someone accidentally misuses this class...
m_folder = " thishsouldnotexistbecauseitisgibberish " ;
m_open = false ;
2015-02-11 23:55:53 +00:00
m_batch_transactions = batch_transactions ;
m_write_txn = nullptr ;
2015-05-18 09:45:15 +00:00
m_write_batch_txn = nullptr ;
2015-02-11 23:55:53 +00:00
m_batch_active = false ;
2014-10-28 19:30:16 +00:00
m_height = 0 ;
2016-02-14 20:27:43 +00:00
m_cum_size = 0 ;
m_cum_count = 0 ;
2016-02-08 15:51:57 +00:00
m_hardfork = nullptr ;
2014-10-21 20:33:43 +00:00
}
2015-02-12 00:02:20 +00:00
void BlockchainLMDB : : open ( const std : : string & filename , const int mdb_flags )
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
if ( m_open )
2014-12-12 21:34:45 +00:00
throw0 ( DB_OPEN_FAILURE ( " Attempted to open db, but it's already open " ) ) ;
2014-10-23 19:37:10 +00:00
boost : : filesystem : : path direc ( filename ) ;
if ( boost : : filesystem : : exists ( direc ) )
{
if ( ! boost : : filesystem : : is_directory ( direc ) )
2014-12-12 21:34:45 +00:00
throw0 ( DB_OPEN_FAILURE ( " LMDB needs a directory path, but a file was passed " ) ) ;
2014-10-23 19:37:10 +00:00
}
else
2014-10-21 20:33:43 +00:00
{
2015-12-13 11:09:43 +00:00
if ( ! boost : : filesystem : : create_directories ( direc ) )
2014-12-12 21:34:45 +00:00
throw0 ( DB_OPEN_FAILURE ( std : : string ( " Failed to create directory " ) . append ( filename ) . c_str ( ) ) ) ;
2014-10-23 19:37:10 +00:00
}
2015-02-19 14:37:00 +00:00
// check for existing LMDB files in base directory
boost : : filesystem : : path old_files = direc . parent_path ( ) ;
2015-12-14 04:54:39 +00:00
if ( boost : : filesystem : : exists ( old_files / " data.mdb " ) | | boost : : filesystem : : exists ( old_files / " lock.mdb " ) )
2015-02-19 14:37:00 +00:00
{
2015-05-08 18:32:20 +00:00
LOG_PRINT_L0 ( " Found existing LMDB files in " < < old_files . string ( ) ) ;
2015-02-19 14:37:00 +00:00
LOG_PRINT_L0 ( " Move data.mdb and/or lock.mdb to " < < filename < < " , or delete them, and then restart " ) ;
throw DB_ERROR ( " Database could not be opened " ) ;
}
2014-10-23 19:37:10 +00:00
m_folder = filename ;
// set up lmdb environment
if ( mdb_env_create ( & m_env ) )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " Failed to create lmdb environment " ) ) ;
2014-10-28 00:45:33 +00:00
if ( mdb_env_set_maxdbs ( m_env , 20 ) )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " Failed to set max number of dbs " ) ) ;
2015-05-17 02:05:54 +00:00
size_t mapsize = DEFAULT_MAPSIZE ;
2015-05-30 14:48:16 +00:00
2015-02-11 23:55:53 +00:00
if ( auto result = mdb_env_open ( m_env , filename . c_str ( ) , mdb_flags , 0644 ) )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( std : : string ( " Failed to open lmdb environment: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2014-10-23 19:37:10 +00:00
2015-05-30 14:48:16 +00:00
MDB_envinfo mei ;
mdb_env_info ( m_env , & mei ) ;
uint64_t cur_mapsize = ( double ) mei . me_mapsize ;
if ( cur_mapsize < mapsize )
{
if ( auto result = mdb_env_set_mapsize ( m_env , mapsize ) )
throw0 ( DB_ERROR ( std : : string ( " Failed to set max memory map size: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
mdb_env_info ( m_env , & mei ) ;
cur_mapsize = ( double ) mei . me_mapsize ;
LOG_PRINT_L1 ( " LMDB memory map size: " < < cur_mapsize ) ;
}
if ( need_resize ( ) )
{
LOG_PRINT_L0 ( " LMDB memory map needs resized, doing that now. " ) ;
do_resize ( ) ;
}
2015-05-16 08:29:02 +00:00
int txn_flags = 0 ;
if ( mdb_flags & MDB_RDONLY )
txn_flags | = MDB_RDONLY ;
// get a read/write MDB_txn, depending on mdb_flags
2015-03-14 21:24:51 +00:00
mdb_txn_safe txn ;
2015-12-13 16:45:03 +00:00
if ( auto mdb_res = mdb_txn_begin ( m_env , NULL , txn_flags , txn ) )
throw0 ( DB_ERROR ( lmdb_error ( " Failed to create a transaction for the db: " , mdb_res ) . c_str ( ) ) ) ;
2014-10-21 20:33:43 +00:00
2014-10-23 19:37:10 +00:00
// open necessary databases, and set properties as needed
// uses macros to avoid having to change things too many places
2014-10-28 00:45:33 +00:00
lmdb_db_open ( txn , LMDB_BLOCKS , MDB_INTEGERKEY | MDB_CREATE , m_blocks , " Failed to open db handle for m_blocks " ) ;
2014-10-23 19:37:10 +00:00
2014-10-28 00:45:33 +00:00
lmdb_db_open ( txn , LMDB_BLOCK_TIMESTAMPS , MDB_INTEGERKEY | MDB_CREATE , m_block_timestamps , " Failed to open db handle for m_block_timestamps " ) ;
lmdb_db_open ( txn , LMDB_BLOCK_HEIGHTS , MDB_CREATE , m_block_heights , " Failed to open db handle for m_block_heights " ) ;
lmdb_db_open ( txn , LMDB_BLOCK_HASHES , MDB_INTEGERKEY | MDB_CREATE , m_block_hashes , " Failed to open db handle for m_block_hashes " ) ;
lmdb_db_open ( txn , LMDB_BLOCK_SIZES , MDB_INTEGERKEY | MDB_CREATE , m_block_sizes , " Failed to open db handle for m_block_sizes " ) ;
lmdb_db_open ( txn , LMDB_BLOCK_DIFFS , MDB_INTEGERKEY | MDB_CREATE , m_block_diffs , " Failed to open db handle for m_block_diffs " ) ;
lmdb_db_open ( txn , LMDB_BLOCK_COINS , MDB_INTEGERKEY | MDB_CREATE , m_block_coins , " Failed to open db handle for m_block_coins " ) ;
2014-10-23 23:47:36 +00:00
2014-10-28 00:45:33 +00:00
lmdb_db_open ( txn , LMDB_TXS , MDB_CREATE , m_txs , " Failed to open db handle for m_txs " ) ;
lmdb_db_open ( txn , LMDB_TX_UNLOCKS , MDB_CREATE , m_tx_unlocks , " Failed to open db handle for m_tx_unlocks " ) ;
lmdb_db_open ( txn , LMDB_TX_HEIGHTS , MDB_CREATE , m_tx_heights , " Failed to open db handle for m_tx_heights " ) ;
2016-02-25 13:55:49 +00:00
lmdb_db_open ( txn , LMDB_TX_OUTPUTS , MDB_DUPSORT | MDB_INTEGERDUP | MDB_CREATE , m_tx_outputs , " Failed to open db handle for m_tx_outputs " ) ;
2014-10-23 23:47:36 +00:00
2014-10-28 00:45:33 +00:00
lmdb_db_open ( txn , LMDB_OUTPUT_TXS , MDB_INTEGERKEY | MDB_CREATE , m_output_txs , " Failed to open db handle for m_output_txs " ) ;
lmdb_db_open ( txn , LMDB_OUTPUT_INDICES , MDB_INTEGERKEY | MDB_CREATE , m_output_indices , " Failed to open db handle for m_output_indices " ) ;
2016-02-25 13:55:49 +00:00
lmdb_db_open ( txn , LMDB_OUTPUT_AMOUNTS , MDB_INTEGERKEY | MDB_INTEGERDUP | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE , m_output_amounts , " Failed to open db handle for m_output_amounts " ) ;
2014-10-31 21:34:15 +00:00
lmdb_db_open ( txn , LMDB_OUTPUT_KEYS , MDB_INTEGERKEY | MDB_CREATE , m_output_keys , " Failed to open db handle for m_output_keys " ) ;
2014-10-30 22:33:35 +00:00
2015-02-11 23:55:53 +00:00
lmdb_db_open ( txn , LMDB_SPENT_KEYS , MDB_CREATE , m_spent_keys , " Failed to open db handle for m_spent_keys " ) ;
2014-10-21 20:33:43 +00:00
2015-09-20 17:41:38 +00:00
lmdb_db_open ( txn , LMDB_HF_STARTING_HEIGHTS , MDB_CREATE , m_hf_starting_heights , " Failed to open db handle for m_hf_starting_heights " ) ;
2016-02-25 13:55:49 +00:00
lmdb_db_open ( txn , LMDB_HF_VERSIONS , MDB_INTEGERKEY | MDB_CREATE , m_hf_versions , " Failed to open db handle for m_hf_versions " ) ;
2015-09-20 17:41:38 +00:00
2015-10-26 15:52:07 +00:00
lmdb_db_open ( txn , LMDB_PROPERTIES , MDB_CREATE , m_properties , " Failed to open db handle for m_properties " ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
mdb_set_compare ( txn , m_spent_keys , compare_hash32 ) ;
mdb_set_compare ( txn , m_block_heights , compare_hash32 ) ;
mdb_set_compare ( txn , m_txs , compare_hash32 ) ;
mdb_set_compare ( txn , m_tx_unlocks , compare_hash32 ) ;
mdb_set_compare ( txn , m_tx_heights , compare_hash32 ) ;
2015-09-20 17:41:38 +00:00
mdb_set_compare ( txn , m_hf_starting_heights , compare_uint8 ) ;
2015-10-26 15:52:07 +00:00
mdb_set_compare ( txn , m_properties , compare_string ) ;
2014-10-29 02:25:03 +00:00
2014-10-23 19:37:10 +00:00
// get and keep current height
MDB_stat db_stats ;
if ( mdb_stat ( txn , m_blocks , & db_stats ) )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " Failed to query m_blocks " ) ) ;
2014-10-28 19:30:16 +00:00
LOG_PRINT_L2 ( " Setting m_height to: " < < db_stats . ms_entries ) ;
2014-10-23 19:37:10 +00:00
m_height = db_stats . ms_entries ;
2014-10-23 23:47:36 +00:00
// get and keep current number of outputs
2014-10-31 21:34:15 +00:00
if ( mdb_stat ( txn , m_output_indices , & db_stats ) )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " Failed to query m_output_indices " ) ) ;
2014-10-23 23:47:36 +00:00
m_num_outputs = db_stats . ms_entries ;
2015-10-26 15:52:07 +00:00
bool compatible = true ;
2015-12-14 04:54:39 +00:00
// ND: This "new" version of the lmdb database is incompatible with
// the previous version. Ensure that the output_keys database is
// sizeof(output_data_t) in length. Otherwise, inform user and
// terminate.
if ( m_height > 0 )
{
MDB_val_copy < uint64_t > k ( 0 ) ;
MDB_val v ;
auto get_result = mdb_get ( txn , m_output_keys , & k , & v ) ;
if ( get_result ! = MDB_SUCCESS )
{
txn . abort ( ) ;
m_open = false ;
return ;
}
// LOG_PRINT_L0("Output keys size: " << v.mv_size);
if ( v . mv_size ! = sizeof ( output_data_t ) )
compatible = false ;
}
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2015-10-26 15:52:07 +00:00
MDB_val_copy < const char * > k ( " version " ) ;
MDB_val v ;
auto get_result = mdb_get ( txn , m_properties , & k , & v ) ;
if ( get_result = = MDB_SUCCESS )
{
if ( * ( const uint32_t * ) v . mv_data > VERSION )
{
LOG_PRINT_RED_L0 ( " Existing lmdb database was made by a later version. We don't know how it will change yet. " ) ;
compatible = false ;
}
2016-02-17 04:05:39 +00:00
# if VERSION > 0
else if ( * ( const uint32_t * ) v . mv_data < VERSION )
2015-10-26 15:52:07 +00:00
{
compatible = false ;
}
2016-02-17 04:05:39 +00:00
# endif
2015-10-26 15:52:07 +00:00
}
else
{
// if not found, but we're on version 0, it's fine. If the DB's empty, it's fine too.
if ( VERSION > 0 & & m_height > 0 )
compatible = false ;
}
if ( ! compatible )
{
txn . abort ( ) ;
mdb_env_close ( m_env ) ;
m_open = false ;
LOG_PRINT_RED_L0 ( " Existing lmdb database is incompatible with this version. " ) ;
LOG_PRINT_RED_L0 ( " Please delete the existing database and resync. " ) ;
return ;
}
if ( ! ( mdb_flags & MDB_RDONLY ) )
{
// only write version on an empty DB
if ( m_height = = 0 )
{
MDB_val_copy < const char * > k ( " version " ) ;
MDB_val_copy < uint32_t > v ( VERSION ) ;
auto put_result = mdb_put ( txn , m_properties , & k , & v , 0 ) ;
if ( put_result ! = MDB_SUCCESS )
{
txn . abort ( ) ;
mdb_env_close ( m_env ) ;
m_open = false ;
LOG_PRINT_RED_L0 ( " Failed to write version to database. " ) ;
return ;
}
}
}
2014-10-23 19:37:10 +00:00
// commit the transaction
txn . commit ( ) ;
2014-10-21 20:33:43 +00:00
2014-10-23 19:37:10 +00:00
m_open = true ;
2014-10-21 20:33:43 +00:00
// from here, init should be finished
}
void BlockchainLMDB : : close ( )
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2015-02-11 23:55:53 +00:00
if ( m_batch_active )
{
LOG_PRINT_L3 ( " close() first calling batch_abort() due to active batch transaction " ) ;
batch_abort ( ) ;
}
this - > sync ( ) ;
2016-02-18 12:09:57 +00:00
m_tinfo . reset ( ) ;
2015-02-11 23:55:53 +00:00
2014-10-28 00:45:33 +00:00
// FIXME: not yet thread safe!!! Use with care.
mdb_env_close ( m_env ) ;
2015-12-28 19:23:02 +00:00
m_open = false ;
2014-10-21 20:33:43 +00:00
}
void BlockchainLMDB : : sync ( )
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2015-02-19 04:52:44 +00:00
check_open ( ) ;
2015-02-11 23:55:53 +00:00
// Does nothing unless LMDB environment was opened with MDB_NOSYNC or in part
// MDB_NOMETASYNC. Force flush to be synchronous.
if ( auto result = mdb_env_sync ( m_env , true ) )
{
2015-05-30 04:07:54 +00:00
throw0 ( DB_ERROR ( std : : string ( " Failed to sync database: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2015-02-11 23:55:53 +00:00
}
2014-10-21 20:33:43 +00:00
}
void BlockchainLMDB : : reset ( )
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2015-12-13 11:12:34 +00:00
check_open ( ) ;
mdb_txn_safe txn ;
if ( mdb_txn_begin ( m_env , NULL , 0 , txn ) )
throw0 ( DB_ERROR ( " Failed to create a transaction for the db " ) ) ;
mdb_drop ( txn , m_blocks , 0 ) ;
mdb_drop ( txn , m_block_timestamps , 0 ) ;
mdb_drop ( txn , m_block_heights , 0 ) ;
mdb_drop ( txn , m_block_hashes , 0 ) ;
mdb_drop ( txn , m_block_sizes , 0 ) ;
mdb_drop ( txn , m_block_diffs , 0 ) ;
mdb_drop ( txn , m_block_coins , 0 ) ;
mdb_drop ( txn , m_txs , 0 ) ;
mdb_drop ( txn , m_tx_unlocks , 0 ) ;
mdb_drop ( txn , m_tx_heights , 0 ) ;
mdb_drop ( txn , m_tx_outputs , 0 ) ;
mdb_drop ( txn , m_output_txs , 0 ) ;
mdb_drop ( txn , m_output_indices , 0 ) ;
mdb_drop ( txn , m_output_amounts , 0 ) ;
mdb_drop ( txn , m_output_keys , 0 ) ;
mdb_drop ( txn , m_spent_keys , 0 ) ;
mdb_drop ( txn , m_hf_starting_heights , 0 ) ;
mdb_drop ( txn , m_hf_versions , 0 ) ;
mdb_drop ( txn , m_properties , 0 ) ;
txn . commit ( ) ;
m_height = 0 ;
m_num_outputs = 0 ;
2016-02-14 20:27:43 +00:00
m_cum_size = 0 ;
m_cum_count = 0 ;
2014-10-21 20:33:43 +00:00
}
2014-12-06 21:37:22 +00:00
std : : vector < std : : string > BlockchainLMDB : : get_filenames ( ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
std : : vector < std : : string > filenames ;
boost : : filesystem : : path datafile ( m_folder ) ;
datafile / = " data.mdb " ;
boost : : filesystem : : path lockfile ( m_folder ) ;
lockfile / = " lock.mdb " ;
filenames . push_back ( datafile . string ( ) ) ;
filenames . push_back ( lockfile . string ( ) ) ;
return filenames ;
2014-10-21 20:33:43 +00:00
}
2015-03-14 01:39:27 +00:00
std : : string BlockchainLMDB : : get_db_name ( ) const
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
return std : : string ( " lmdb " ) ;
}
2014-10-28 00:45:33 +00:00
// TODO: this?
2014-10-21 20:33:43 +00:00
bool BlockchainLMDB : : lock ( )
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-21 20:33:43 +00:00
return false ;
}
2014-10-28 00:45:33 +00:00
// TODO: this?
2014-10-21 20:33:43 +00:00
void BlockchainLMDB : : unlock ( )
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-21 20:33:43 +00:00
}
2015-12-14 18:47:13 +00:00
# define TXN_PREFIX(flags); \
mdb_txn_safe auto_txn ; \
mdb_txn_safe * txn_ptr = & auto_txn ; \
if ( m_batch_active ) \
txn_ptr = m_write_txn ; \
else \
{ \
if ( auto mdb_res = mdb_txn_begin ( m_env , NULL , flags , auto_txn ) ) \
throw0 ( DB_ERROR ( lmdb_error ( std : : string ( " Failed to create a transaction for the db in " ) + __FUNCTION__ + " : " , mdb_res ) . c_str ( ) ) ) ; \
} \
2016-02-18 12:09:57 +00:00
# define TXN_PREFIX_RDONLY() \
bool my_rtxn = block_rtxn_start ( ) ; \
MDB_txn * m_txn = m_write_txn ? m_write_txn - > m_txn : m_tinfo - > m_ti_rtxn
# define TXN_POSTFIX_RDONLY() \
if ( my_rtxn ) block_rtxn_stop ( )
2015-12-14 18:47:13 +00:00
# define TXN_POSTFIX_SUCCESS() \
do { \
if ( ! m_batch_active ) \
auto_txn . commit ( ) ; \
} while ( 0 )
2016-02-08 12:57:16 +00:00
// The below two macros are for DB access within block add/remove, whether
// regular batch txn is in use or not. m_write_txn is used as a batch txn, even
// if it's only within block add/remove.
//
// DB access functions that may be called both within block add/remove and
// without should use these. If the function will be called ONLY within block
// add/remove, m_write_txn alone may be used instead of these macros.
# define TXN_BLOCK_PREFIX(flags); \
mdb_txn_safe auto_txn ; \
mdb_txn_safe * txn_ptr = & auto_txn ; \
if ( m_batch_active | | m_write_txn ) \
txn_ptr = m_write_txn ; \
else \
{ \
if ( auto mdb_res = mdb_txn_begin ( m_env , NULL , flags , auto_txn ) ) \
throw0 ( DB_ERROR ( lmdb_error ( std : : string ( " Failed to create a transaction for the db in " ) + __FUNCTION__ + " : " , mdb_res ) . c_str ( ) ) ) ; \
} \
# define TXN_BLOCK_POSTFIX_SUCCESS() \
do { \
if ( ! m_batch_active & & ! m_write_txn ) \
auto_txn . commit ( ) ; \
} while ( 0 )
2014-12-06 21:37:22 +00:00
bool BlockchainLMDB : : block_exists ( const crypto : : hash & h ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( block_heights ) ;
2014-10-23 19:37:10 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < crypto : : hash > key ( h ) ;
2016-02-18 12:09:57 +00:00
auto get_result = mdb_cursor_get ( m_cur_block_heights , & key , NULL , MDB_SET ) ;
2014-10-23 19:37:10 +00:00
if ( get_result = = MDB_NOTFOUND )
{
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-02-23 23:28:20 +00:00
LOG_PRINT_L3 ( " Block with hash " < < epee : : string_tools : : pod_to_hex ( h ) < < " not found in db " ) ;
2014-10-23 19:37:10 +00:00
return false ;
}
else if ( get_result )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " DB error attempting to fetch block index from hash " ) ) ;
2014-10-23 19:37:10 +00:00
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2014-10-23 19:37:10 +00:00
return true ;
2014-10-21 20:33:43 +00:00
}
2014-12-06 21:37:22 +00:00
block BlockchainLMDB : : get_block ( const crypto : : hash & h ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
return get_block_from_height ( get_block_height ( h ) ) ;
}
2014-12-06 21:37:22 +00:00
uint64_t BlockchainLMDB : : get_block_height ( const crypto : : hash & h ) const
2014-10-28 00:45:33 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-28 00:45:33 +00:00
check_open ( ) ;
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( block_heights ) ;
2014-10-23 19:37:10 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < crypto : : hash > key ( h ) ;
2014-10-23 19:37:10 +00:00
MDB_val result ;
2016-02-18 12:09:57 +00:00
auto get_result = mdb_cursor_get ( m_cur_block_heights , & key , & result , MDB_SET ) ;
2014-10-23 19:37:10 +00:00
if ( get_result = = MDB_NOTFOUND )
2014-12-12 21:34:45 +00:00
throw1 ( BLOCK_DNE ( " Attempted to retrieve non-existent block height " ) ) ;
2014-10-23 19:37:10 +00:00
else if ( get_result )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " Error attempting to retrieve a block height from the db " ) ) ;
2014-10-23 19:37:10 +00:00
2015-12-14 18:47:13 +00:00
uint64_t ret = * ( const uint64_t * ) result . mv_data ;
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-12-10 01:42:36 +00:00
return ret ;
2014-10-21 20:33:43 +00:00
}
2014-12-06 21:37:22 +00:00
block_header BlockchainLMDB : : get_block_header ( const crypto : : hash & h ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
// block_header object is automatically cast from block object
return get_block ( h ) ;
2014-10-21 20:33:43 +00:00
}
2014-12-06 21:37:22 +00:00
block BlockchainLMDB : : get_block_from_height ( const uint64_t & height ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( blocks ) ;
2014-10-23 19:37:10 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < uint64_t > key ( height ) ;
2014-10-23 19:37:10 +00:00
MDB_val result ;
2016-02-18 12:09:57 +00:00
auto get_result = mdb_cursor_get ( m_cur_blocks , & key , & result , MDB_SET ) ;
2014-10-23 19:37:10 +00:00
if ( get_result = = MDB_NOTFOUND )
{
2015-10-25 10:36:12 +00:00
throw0 ( BLOCK_DNE ( std : : string ( " Attempt to get block from height " ) . append ( boost : : lexical_cast < std : : string > ( height ) ) . append ( " failed -- block not in db " ) . c_str ( ) ) ) ;
2014-10-23 19:37:10 +00:00
}
else if ( get_result )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " Error attempting to retrieve a block from the db " ) ) ;
2014-10-23 19:37:10 +00:00
blobdata bd ;
bd . assign ( reinterpret_cast < char * > ( result . mv_data ) , result . mv_size ) ;
2014-10-21 20:33:43 +00:00
block b ;
2014-10-23 19:37:10 +00:00
if ( ! parse_and_validate_block_from_blob ( bd , b ) )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " Failed to parse block from blob retrieved from the db " ) ) ;
2014-10-23 19:37:10 +00:00
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-12-10 01:42:36 +00:00
2014-10-21 20:33:43 +00:00
return b ;
}
2014-12-06 21:37:22 +00:00
uint64_t BlockchainLMDB : : get_block_timestamp ( const uint64_t & height ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( block_timestamps ) ;
2015-12-14 18:47:13 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < uint64_t > key ( height ) ;
2014-10-28 00:45:33 +00:00
MDB_val result ;
2016-02-18 12:09:57 +00:00
auto get_result = mdb_cursor_get ( m_cur_block_timestamps , & key , & result , MDB_SET ) ;
2014-10-28 00:45:33 +00:00
if ( get_result = = MDB_NOTFOUND )
{
2015-10-25 10:36:12 +00:00
throw0 ( BLOCK_DNE ( std : : string ( " Attempt to get timestamp from height " ) . append ( boost : : lexical_cast < std : : string > ( height ) ) . append ( " failed -- timestamp not in db " ) . c_str ( ) ) ) ;
2014-10-28 00:45:33 +00:00
}
else if ( get_result )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " Error attempting to retrieve a timestamp from the db " ) ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
uint64_t ret = * ( const uint64_t * ) result . mv_data ;
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-12-10 01:42:36 +00:00
return ret ;
2014-10-21 20:33:43 +00:00
}
2014-12-06 21:37:22 +00:00
uint64_t BlockchainLMDB : : get_top_block_timestamp ( ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
// if no blocks, return 0
if ( m_height = = 0 )
{
return 0 ;
}
return get_block_timestamp ( m_height - 1 ) ;
2014-10-21 20:33:43 +00:00
}
2014-12-06 21:37:22 +00:00
size_t BlockchainLMDB : : get_block_size ( const uint64_t & height ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( block_sizes ) ;
2014-10-28 00:45:33 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < uint64_t > key ( height ) ;
2014-10-28 00:45:33 +00:00
MDB_val result ;
2016-02-18 12:09:57 +00:00
auto get_result = mdb_cursor_get ( m_cur_block_sizes , & key , & result , MDB_SET ) ;
2014-10-28 00:45:33 +00:00
if ( get_result = = MDB_NOTFOUND )
{
2015-10-25 10:36:12 +00:00
throw0 ( BLOCK_DNE ( std : : string ( " Attempt to get block size from height " ) . append ( boost : : lexical_cast < std : : string > ( height ) ) . append ( " failed -- block size not in db " ) . c_str ( ) ) ) ;
2014-10-28 00:45:33 +00:00
}
else if ( get_result )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " Error attempting to retrieve a block size from the db " ) ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
size_t ret = * ( const size_t * ) result . mv_data ;
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-12-10 01:42:36 +00:00
return ret ;
2014-10-21 20:33:43 +00:00
}
2014-12-06 21:37:22 +00:00
difficulty_type BlockchainLMDB : : get_block_cumulative_difficulty ( const uint64_t & height ) const
2014-10-21 20:33:43 +00:00
{
2015-02-11 23:55:53 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ < < " height: " < < height ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( block_diffs ) ;
2015-12-14 18:47:13 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < uint64_t > key ( height ) ;
2014-10-28 00:45:33 +00:00
MDB_val result ;
2016-02-18 12:09:57 +00:00
auto get_result = mdb_cursor_get ( m_cur_block_diffs , & key , & result , MDB_SET ) ;
2014-10-28 00:45:33 +00:00
if ( get_result = = MDB_NOTFOUND )
{
2015-10-25 10:36:12 +00:00
throw0 ( BLOCK_DNE ( std : : string ( " Attempt to get cumulative difficulty from height " ) . append ( boost : : lexical_cast < std : : string > ( height ) ) . append ( " failed -- difficulty not in db " ) . c_str ( ) ) ) ;
2014-10-28 00:45:33 +00:00
}
else if ( get_result )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " Error attempting to retrieve a cumulative difficulty from the db " ) ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
difficulty_type ret = * ( const difficulty_type * ) result . mv_data ;
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-12-10 01:42:36 +00:00
return ret ;
2014-10-21 20:33:43 +00:00
}
2014-12-06 21:37:22 +00:00
difficulty_type BlockchainLMDB : : get_block_difficulty ( const uint64_t & height ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
difficulty_type diff1 = 0 ;
difficulty_type diff2 = 0 ;
diff1 = get_block_cumulative_difficulty ( height ) ;
if ( height ! = 0 )
{
diff2 = get_block_cumulative_difficulty ( height - 1 ) ;
}
return diff1 - diff2 ;
2014-10-21 20:33:43 +00:00
}
2014-12-06 21:37:22 +00:00
uint64_t BlockchainLMDB : : get_block_already_generated_coins ( const uint64_t & height ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( block_coins ) ;
2014-10-28 00:45:33 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < uint64_t > key ( height ) ;
2014-10-28 00:45:33 +00:00
MDB_val result ;
2016-02-18 12:09:57 +00:00
auto get_result = mdb_cursor_get ( m_cur_block_coins , & key , & result , MDB_SET ) ;
2014-10-28 00:45:33 +00:00
if ( get_result = = MDB_NOTFOUND )
{
2015-10-25 10:36:12 +00:00
throw0 ( BLOCK_DNE ( std : : string ( " Attempt to get generated coins from height " ) . append ( boost : : lexical_cast < std : : string > ( height ) ) . append ( " failed -- block size not in db " ) . c_str ( ) ) ) ;
2014-10-28 00:45:33 +00:00
}
else if ( get_result )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " Error attempting to retrieve a total generated coins from the db " ) ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
uint64_t ret = * ( const uint64_t * ) result . mv_data ;
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-12-10 01:42:36 +00:00
return ret ;
2014-10-21 20:33:43 +00:00
}
2014-12-06 21:37:22 +00:00
crypto : : hash BlockchainLMDB : : get_block_hash_from_height ( const uint64_t & height ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-21 20:33:43 +00:00
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( block_hashes ) ;
2014-10-28 00:45:33 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < uint64_t > key ( height ) ;
2014-10-28 00:45:33 +00:00
MDB_val result ;
2016-02-18 12:09:57 +00:00
auto get_result = mdb_cursor_get ( m_cur_block_hashes , & key , & result , MDB_SET ) ;
2014-10-28 00:45:33 +00:00
if ( get_result = = MDB_NOTFOUND )
{
2014-12-12 21:34:45 +00:00
throw0 ( BLOCK_DNE ( std : : string ( " Attempt to get hash from height " ) . append ( boost : : lexical_cast < std : : string > ( height ) ) . append ( " failed -- hash not in db " ) . c_str ( ) ) ) ;
2014-10-28 00:45:33 +00:00
}
else if ( get_result )
2015-02-11 23:55:53 +00:00
throw0 ( DB_ERROR ( std : : string ( " Error attempting to retrieve a block hash from the db: " ) .
append ( mdb_strerror ( get_result ) ) . c_str ( ) ) ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
crypto : : hash ret = * ( const crypto : : hash * ) result . mv_data ;
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-12-10 01:42:36 +00:00
return ret ;
2014-10-28 00:45:33 +00:00
}
2014-12-06 21:37:22 +00:00
std : : vector < block > BlockchainLMDB : : get_blocks_range ( const uint64_t & h1 , const uint64_t & h2 ) const
2014-10-28 00:45:33 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-21 20:33:43 +00:00
std : : vector < block > v ;
2014-10-28 00:45:33 +00:00
for ( uint64_t height = h1 ; height < = h2 ; + + height )
{
v . push_back ( get_block_from_height ( height ) ) ;
}
2014-10-21 20:33:43 +00:00
return v ;
}
2014-12-06 21:37:22 +00:00
std : : vector < crypto : : hash > BlockchainLMDB : : get_hashes_range ( const uint64_t & h1 , const uint64_t & h2 ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-21 20:33:43 +00:00
std : : vector < crypto : : hash > v ;
2014-10-28 00:45:33 +00:00
for ( uint64_t height = h1 ; height < = h2 ; + + height )
{
v . push_back ( get_block_hash_from_height ( height ) ) ;
}
2014-10-21 20:33:43 +00:00
return v ;
}
2014-12-06 21:37:22 +00:00
crypto : : hash BlockchainLMDB : : top_block_hash ( ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
if ( m_height ! = 0 )
{
return get_block_hash_from_height ( m_height - 1 ) ;
}
return null_hash ;
2014-10-21 20:33:43 +00:00
}
2014-12-06 21:37:22 +00:00
block BlockchainLMDB : : get_top_block ( ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
if ( m_height ! = 0 )
{
return get_block_from_height ( m_height - 1 ) ;
}
2014-10-21 20:33:43 +00:00
block b ;
return b ;
}
2014-12-06 21:37:22 +00:00
uint64_t BlockchainLMDB : : height ( ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-23 23:47:36 +00:00
2015-02-22 18:31:11 +00:00
return m_height ;
2014-10-21 20:33:43 +00:00
}
2014-12-06 21:37:22 +00:00
bool BlockchainLMDB : : tx_exists ( const crypto : : hash & h ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( txs ) ;
2014-10-28 00:45:33 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < crypto : : hash > key ( h ) ;
2014-10-28 00:45:33 +00:00
MDB_val result ;
2015-02-11 04:01:02 +00:00
TIME_MEASURE_START ( time1 ) ;
2016-02-18 12:09:57 +00:00
auto get_result = mdb_cursor_get ( m_cur_txs , & key , & result , MDB_SET ) ;
2015-02-11 04:01:02 +00:00
TIME_MEASURE_FINISH ( time1 ) ;
time_tx_exists + = time1 ;
2015-12-14 18:47:13 +00:00
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-12-14 18:47:13 +00:00
2014-10-28 00:45:33 +00:00
if ( get_result = = MDB_NOTFOUND )
{
2015-02-11 23:55:53 +00:00
LOG_PRINT_L1 ( " transaction with hash " < < epee : : string_tools : : pod_to_hex ( h ) < < " not found in db " ) ;
2014-10-28 00:45:33 +00:00
return false ;
}
else if ( get_result )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " DB error attempting to fetch transaction from hash " ) ) ;
2014-10-28 00:45:33 +00:00
return true ;
2014-10-21 20:33:43 +00:00
}
2014-12-06 21:37:22 +00:00
uint64_t BlockchainLMDB : : get_tx_unlock_time ( const crypto : : hash & h ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( tx_unlocks ) ;
2014-10-28 00:45:33 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < crypto : : hash > key ( h ) ;
2014-10-28 00:45:33 +00:00
MDB_val result ;
2016-02-18 12:09:57 +00:00
auto get_result = mdb_cursor_get ( m_cur_tx_unlocks , & key , & result , MDB_SET ) ;
2014-10-28 00:45:33 +00:00
if ( get_result = = MDB_NOTFOUND )
2015-02-11 23:55:53 +00:00
throw1 ( TX_DNE ( std : : string ( " tx unlock time with hash " ) . append ( epee : : string_tools : : pod_to_hex ( h ) ) . append ( " not found in db " ) . c_str ( ) ) ) ;
2014-10-28 00:45:33 +00:00
else if ( get_result )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " DB error attempting to fetch tx unlock time from hash " ) ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
uint64_t ret = * ( const uint64_t * ) result . mv_data ;
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-12-10 01:42:36 +00:00
return ret ;
2014-10-21 20:33:43 +00:00
}
2014-12-06 21:37:22 +00:00
transaction BlockchainLMDB : : get_tx ( const crypto : : hash & h ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( txs ) ;
2014-10-28 00:45:33 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < crypto : : hash > key ( h ) ;
2014-10-28 00:45:33 +00:00
MDB_val result ;
2016-02-18 12:09:57 +00:00
auto get_result = mdb_cursor_get ( m_cur_txs , & key , & result , MDB_SET ) ;
2014-10-28 00:45:33 +00:00
if ( get_result = = MDB_NOTFOUND )
2015-02-11 23:55:53 +00:00
throw1 ( TX_DNE ( std : : string ( " tx with hash " ) . append ( epee : : string_tools : : pod_to_hex ( h ) ) . append ( " not found in db " ) . c_str ( ) ) ) ;
2014-10-28 00:45:33 +00:00
else if ( get_result )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " DB error attempting to fetch tx from hash " ) ) ;
2014-10-28 00:45:33 +00:00
blobdata bd ;
bd . assign ( reinterpret_cast < char * > ( result . mv_data ) , result . mv_size ) ;
transaction tx ;
if ( ! parse_and_validate_tx_from_blob ( bd , tx ) )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " Failed to parse tx from blob retrieved from the db " ) ) ;
2015-12-14 18:47:13 +00:00
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2014-10-28 00:45:33 +00:00
return tx ;
2014-10-21 20:33:43 +00:00
}
2014-12-06 21:37:22 +00:00
uint64_t BlockchainLMDB : : get_tx_count ( ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2014-10-28 00:45:33 +00:00
MDB_stat db_stats ;
2016-02-18 12:09:57 +00:00
if ( mdb_stat ( m_txn , m_txs , & db_stats ) )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " Failed to query m_txs " ) ) ;
2014-10-28 00:45:33 +00:00
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2014-10-28 00:45:33 +00:00
return db_stats . ms_entries ;
2014-10-21 20:33:43 +00:00
}
2014-12-06 21:37:22 +00:00
std : : vector < transaction > BlockchainLMDB : : get_tx_list ( const std : : vector < crypto : : hash > & hlist ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-21 20:33:43 +00:00
std : : vector < transaction > v ;
2014-10-28 00:45:33 +00:00
for ( auto & h : hlist )
{
v . push_back ( get_tx ( h ) ) ;
}
2014-10-21 20:33:43 +00:00
return v ;
}
2014-12-06 21:37:22 +00:00
uint64_t BlockchainLMDB : : get_tx_block_height ( const crypto : : hash & h ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( tx_heights ) ;
2014-10-28 00:45:33 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < crypto : : hash > key ( h ) ;
2014-10-28 00:45:33 +00:00
MDB_val result ;
2016-02-18 12:09:57 +00:00
auto get_result = mdb_cursor_get ( m_cur_tx_heights , & key , & result , MDB_SET ) ;
2014-10-28 00:45:33 +00:00
if ( get_result = = MDB_NOTFOUND )
{
2015-02-11 23:55:53 +00:00
throw1 ( TX_DNE ( std : : string ( " tx height with hash " ) . append ( epee : : string_tools : : pod_to_hex ( h ) ) . append ( " not found in db " ) . c_str ( ) ) ) ;
2014-10-28 00:45:33 +00:00
}
else if ( get_result )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " DB error attempting to fetch tx height from hash " ) ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
uint64_t ret = * ( const uint64_t * ) result . mv_data ;
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-12-10 01:42:36 +00:00
return ret ;
2014-10-21 20:33:43 +00:00
}
2014-12-06 21:37:22 +00:00
uint64_t BlockchainLMDB : : get_num_outputs ( const uint64_t & amount ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( output_amounts ) ;
2014-10-28 00:45:33 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < uint64_t > k ( amount ) ;
2014-10-28 00:45:33 +00:00
MDB_val v ;
2016-02-18 12:09:57 +00:00
auto result = mdb_cursor_get ( m_cur_output_amounts , & k , & v , MDB_SET ) ;
2014-10-28 00:45:33 +00:00
if ( result = = MDB_NOTFOUND )
{
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2014-10-28 00:45:33 +00:00
return 0 ;
}
else if ( result )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " DB error attempting to get number of outputs of an amount " ) ) ;
2014-10-28 00:45:33 +00:00
2016-02-17 16:12:38 +00:00
mdb_size_t num_elems = 0 ;
2016-02-18 12:09:57 +00:00
mdb_cursor_count ( m_cur_output_amounts , & num_elems ) ;
2014-10-28 00:45:33 +00:00
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2014-10-28 00:45:33 +00:00
return num_elems ;
2014-10-21 20:33:43 +00:00
}
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
output_data_t BlockchainLMDB : : get_output_key ( const uint64_t & global_index ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( output_keys ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 18:47:13 +00:00
MDB_val_copy < uint64_t > k ( global_index ) ;
2014-10-31 21:34:15 +00:00
MDB_val v ;
2016-02-18 12:09:57 +00:00
auto get_result = mdb_cursor_get ( m_cur_output_keys , & k , & v , MDB_SET ) ;
2014-10-31 21:34:15 +00:00
if ( get_result = = MDB_NOTFOUND )
2015-10-25 10:36:12 +00:00
throw1 ( OUTPUT_DNE ( " Attempting to get output pubkey by global index, but key does not exist " ) ) ;
2014-10-31 21:34:15 +00:00
else if ( get_result )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " Error attempting to retrieve an output pubkey from the db " ) ) ;
2015-12-14 18:47:13 +00:00
output_data_t ret = * ( const output_data_t * ) v . mv_data ;
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-12-14 18:47:13 +00:00
return ret ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
}
output_data_t BlockchainLMDB : : get_output_key ( const uint64_t & amount , const uint64_t & index )
{
2015-12-14 04:54:39 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 04:54:39 +00:00
uint64_t glob_index = get_output_global_index ( amount , index ) ;
return get_output_key ( glob_index ) ;
2014-10-21 20:33:43 +00:00
}
2014-12-14 20:20:41 +00:00
tx_out_index BlockchainLMDB : : get_output_tx_and_index_from_global ( const uint64_t & index ) const
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( output_txs ) ;
RCURSOR ( output_indices ) ;
2015-12-14 18:47:13 +00:00
2014-12-14 20:20:41 +00:00
MDB_val_copy < uint64_t > k ( index ) ;
MDB_val v ;
2016-02-18 12:09:57 +00:00
auto get_result = mdb_cursor_get ( m_cur_output_txs , & k , & v , MDB_SET ) ;
2014-12-14 20:20:41 +00:00
if ( get_result = = MDB_NOTFOUND )
throw1 ( OUTPUT_DNE ( " output with given index not in db " ) ) ;
else if ( get_result )
throw0 ( DB_ERROR ( " DB error attempting to fetch output tx hash " ) ) ;
2015-12-14 18:47:13 +00:00
crypto : : hash tx_hash = * ( const crypto : : hash * ) v . mv_data ;
2014-12-14 20:20:41 +00:00
2016-02-18 12:09:57 +00:00
get_result = mdb_cursor_get ( m_cur_output_indices , & k , & v , MDB_SET ) ;
2014-12-14 20:20:41 +00:00
if ( get_result = = MDB_NOTFOUND )
throw1 ( OUTPUT_DNE ( " output with given index not in db " ) ) ;
else if ( get_result )
throw0 ( DB_ERROR ( " DB error attempting to fetch output tx index " ) ) ;
2015-12-10 01:42:36 +00:00
2015-12-14 18:47:13 +00:00
tx_out_index ret = tx_out_index ( tx_hash , * ( const uint64_t * ) v . mv_data ) ;
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-12-10 01:42:36 +00:00
return ret ;
2014-12-14 20:20:41 +00:00
}
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
tx_out_index BlockchainLMDB : : get_output_tx_and_index ( const uint64_t & amount , const uint64_t & index )
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2015-12-14 04:54:39 +00:00
std : : vector < uint64_t > offsets ;
std : : vector < tx_out_index > indices ;
offsets . push_back ( index ) ;
get_output_tx_and_index ( amount , offsets , indices ) ;
if ( ! indices . size ( ) )
2014-12-12 21:34:45 +00:00
throw1 ( OUTPUT_DNE ( " Attempting to get an output index by amount and amount index, but amount not found " ) ) ;
2014-10-28 00:45:33 +00:00
2015-12-14 04:54:39 +00:00
return indices [ 0 ] ;
2014-10-21 20:33:43 +00:00
}
2014-12-06 21:37:22 +00:00
std : : vector < uint64_t > BlockchainLMDB : : get_tx_output_indices ( const crypto : : hash & h ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-28 00:45:33 +00:00
std : : vector < uint64_t > index_vec ;
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( tx_outputs ) ;
2014-10-28 00:45:33 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < crypto : : hash > k ( h ) ;
2014-10-28 00:45:33 +00:00
MDB_val v ;
2016-02-18 12:09:57 +00:00
auto result = mdb_cursor_get ( m_cur_tx_outputs , & k , & v , MDB_SET ) ;
2014-10-28 00:45:33 +00:00
if ( result = = MDB_NOTFOUND )
2014-12-12 21:34:45 +00:00
throw1 ( OUTPUT_DNE ( " Attempting to get an output by tx hash and tx index, but output not found " ) ) ;
2014-10-28 00:45:33 +00:00
else if ( result )
2014-12-12 21:34:45 +00:00
throw0 ( DB_ERROR ( " DB error attempting to get an output " ) ) ;
2014-10-28 00:45:33 +00:00
2016-02-17 16:12:38 +00:00
mdb_size_t num_elems = 0 ;
2016-02-18 12:09:57 +00:00
mdb_cursor_count ( m_cur_tx_outputs , & num_elems ) ;
2014-10-28 00:45:33 +00:00
2016-02-18 12:09:57 +00:00
mdb_cursor_get ( m_cur_tx_outputs , & k , & v , MDB_FIRST_DUP ) ;
2014-10-28 00:45:33 +00:00
for ( uint64_t i = 0 ; i < num_elems ; + + i )
{
2016-02-18 12:09:57 +00:00
mdb_cursor_get ( m_cur_tx_outputs , & k , & v , MDB_GET_CURRENT ) ;
2014-12-11 19:30:55 +00:00
index_vec . push_back ( * ( const uint64_t * ) v . mv_data ) ;
2016-02-18 12:09:57 +00:00
mdb_cursor_get ( m_cur_tx_outputs , & k , & v , MDB_NEXT_DUP ) ;
2014-10-28 00:45:33 +00:00
}
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2014-10-28 00:45:33 +00:00
return index_vec ;
2014-10-21 20:33:43 +00:00
}
2015-01-09 20:57:33 +00:00
std : : vector < uint64_t > BlockchainLMDB : : get_tx_amount_output_indices ( const crypto : : hash & h ) const
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
std : : vector < uint64_t > index_vec ;
std : : vector < uint64_t > index_vec2 ;
// get the transaction's global output indices first
index_vec = get_tx_output_indices ( h ) ;
// these are next used to obtain the amount output indices
transaction tx = get_tx ( h ) ;
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( output_amounts ) ;
2015-01-09 20:57:33 +00:00
uint64_t i = 0 ;
uint64_t global_index ;
BOOST_FOREACH ( const auto & vout , tx . vout )
{
uint64_t amount = vout . amount ;
global_index = index_vec [ i ] ;
MDB_val_copy < uint64_t > k ( amount ) ;
MDB_val v ;
2016-02-18 12:09:57 +00:00
auto result = mdb_cursor_get ( m_cur_output_amounts , & k , & v , MDB_SET ) ;
2015-01-09 20:57:33 +00:00
if ( result = = MDB_NOTFOUND )
throw1 ( OUTPUT_DNE ( " Attempting to get an output index by amount and amount index, but amount not found " ) ) ;
else if ( result )
throw0 ( DB_ERROR ( " DB error attempting to get an output " ) ) ;
2016-02-17 16:12:38 +00:00
mdb_size_t num_elems = 0 ;
2016-02-18 12:09:57 +00:00
mdb_cursor_count ( m_cur_output_amounts , & num_elems ) ;
2015-01-09 20:57:33 +00:00
2016-02-18 12:09:57 +00:00
mdb_cursor_get ( m_cur_output_amounts , & k , & v , MDB_FIRST_DUP ) ;
2015-01-09 20:57:33 +00:00
uint64_t amount_output_index = 0 ;
uint64_t output_index = 0 ;
bool found_index = false ;
for ( uint64_t j = 0 ; j < num_elems ; + + j )
{
2016-02-18 12:09:57 +00:00
mdb_cursor_get ( m_cur_output_amounts , & k , & v , MDB_GET_CURRENT ) ;
2015-01-09 20:57:33 +00:00
output_index = * ( const uint64_t * ) v . mv_data ;
if ( output_index = = global_index )
{
amount_output_index = j ;
found_index = true ;
break ;
}
2016-02-18 12:09:57 +00:00
mdb_cursor_get ( m_cur_output_amounts , & k , & v , MDB_NEXT_DUP ) ;
2015-01-09 20:57:33 +00:00
}
if ( found_index )
{
index_vec2 . push_back ( amount_output_index ) ;
}
else
{
// not found
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-01-09 20:57:33 +00:00
throw1 ( OUTPUT_DNE ( " specified output not found in db " ) ) ;
}
+ + i ;
}
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-01-09 20:57:33 +00:00
return index_vec2 ;
}
2014-12-06 21:37:22 +00:00
bool BlockchainLMDB : : has_key_image ( const crypto : : key_image & img ) const
2014-10-21 20:33:43 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2014-10-23 23:47:36 +00:00
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( spent_keys ) ;
2014-10-23 23:47:36 +00:00
2014-12-12 13:27:05 +00:00
MDB_val_copy < crypto : : key_image > val_key ( img ) ;
2016-02-18 12:09:57 +00:00
if ( mdb_cursor_get ( m_cur_spent_keys , & val_key , NULL , MDB_SET ) = = 0 )
2014-10-23 23:47:36 +00:00
{
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2014-10-23 23:47:36 +00:00
return true ;
}
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2014-10-21 20:33:43 +00:00
return false ;
}
2015-10-25 10:45:25 +00:00
bool BlockchainLMDB : : for_all_key_images ( std : : function < bool ( const crypto : : key_image & ) > f ) const
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( spent_keys ) ;
2015-10-25 10:45:25 +00:00
MDB_val k ;
MDB_val v ;
bool ret = true ;
MDB_cursor_op op = MDB_FIRST ;
while ( 1 )
{
2016-02-18 12:09:57 +00:00
int ret = mdb_cursor_get ( m_cur_spent_keys , & k , & v , op ) ;
2015-10-25 10:45:25 +00:00
op = MDB_NEXT ;
if ( ret = = MDB_NOTFOUND )
break ;
if ( ret < 0 )
throw0 ( DB_ERROR ( " Failed to enumerate key images " ) ) ;
2015-12-14 18:47:13 +00:00
const crypto : : key_image k_image = * ( const crypto : : key_image * ) k . mv_data ;
2015-10-25 10:45:25 +00:00
if ( ! f ( k_image ) ) {
ret = false ;
break ;
}
}
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-10-25 10:45:25 +00:00
return ret ;
}
bool BlockchainLMDB : : for_all_blocks ( std : : function < bool ( uint64_t , const crypto : : hash & , const cryptonote : : block & ) > f ) const
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( blocks ) ;
2015-10-25 10:45:25 +00:00
MDB_val k ;
MDB_val v ;
bool ret = true ;
MDB_cursor_op op = MDB_FIRST ;
while ( 1 )
{
2016-02-18 12:09:57 +00:00
int ret = mdb_cursor_get ( m_cur_blocks , & k , & v , op ) ;
2015-10-25 10:45:25 +00:00
op = MDB_NEXT ;
if ( ret = = MDB_NOTFOUND )
break ;
if ( ret )
throw0 ( DB_ERROR ( " Failed to enumerate blocks " ) ) ;
2015-12-14 18:47:13 +00:00
uint64_t height = * ( const uint64_t * ) k . mv_data ;
2015-10-25 10:45:25 +00:00
blobdata bd ;
bd . assign ( reinterpret_cast < char * > ( v . mv_data ) , v . mv_size ) ;
block b ;
if ( ! parse_and_validate_block_from_blob ( bd , b ) )
throw0 ( DB_ERROR ( " Failed to parse block from blob retrieved from the db " ) ) ;
crypto : : hash hash ;
if ( ! get_block_hash ( b , hash ) )
throw0 ( DB_ERROR ( " Failed to get block hash from blob retrieved from the db " ) ) ;
if ( ! f ( height , hash , b ) ) {
ret = false ;
break ;
}
}
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-10-25 10:45:25 +00:00
return ret ;
}
bool BlockchainLMDB : : for_all_transactions ( std : : function < bool ( const crypto : : hash & , const cryptonote : : transaction & ) > f ) const
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( txs ) ;
2015-10-25 10:45:25 +00:00
MDB_val k ;
MDB_val v ;
bool ret = true ;
MDB_cursor_op op = MDB_FIRST ;
while ( 1 )
{
2016-02-18 12:09:57 +00:00
int ret = mdb_cursor_get ( m_cur_txs , & k , & v , op ) ;
2015-10-25 10:45:25 +00:00
op = MDB_NEXT ;
if ( ret = = MDB_NOTFOUND )
break ;
if ( ret )
throw0 ( DB_ERROR ( " Failed to enumerate transactions " ) ) ;
2015-12-14 18:47:13 +00:00
const crypto : : hash hash = * ( const crypto : : hash * ) k . mv_data ;
2015-10-25 10:45:25 +00:00
blobdata bd ;
bd . assign ( reinterpret_cast < char * > ( v . mv_data ) , v . mv_size ) ;
transaction tx ;
if ( ! parse_and_validate_tx_from_blob ( bd , tx ) )
throw0 ( DB_ERROR ( " Failed to parse tx from blob retrieved from the db " ) ) ;
if ( ! f ( hash , tx ) ) {
ret = false ;
break ;
}
}
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-10-25 10:45:25 +00:00
return ret ;
}
bool BlockchainLMDB : : for_all_outputs ( std : : function < bool ( uint64_t amount , const crypto : : hash & tx_hash , size_t tx_idx ) > f ) const
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( output_amounts ) ;
2015-10-25 10:45:25 +00:00
MDB_val k ;
MDB_val v ;
bool ret = true ;
MDB_cursor_op op = MDB_FIRST ;
while ( 1 )
{
2016-02-18 12:09:57 +00:00
int ret = mdb_cursor_get ( m_cur_output_amounts , & k , & v , op ) ;
2015-10-25 10:45:25 +00:00
op = MDB_NEXT ;
if ( ret = = MDB_NOTFOUND )
break ;
if ( ret )
throw0 ( DB_ERROR ( " Failed to enumerate outputs " ) ) ;
2015-12-14 18:47:13 +00:00
uint64_t amount = * ( const uint64_t * ) k . mv_data ;
uint64_t global_index = * ( const uint64_t * ) v . mv_data ;
2015-10-25 10:45:25 +00:00
tx_out_index toi = get_output_tx_and_index_from_global ( global_index ) ;
if ( ! f ( amount , toi . first , toi . second ) ) {
ret = false ;
break ;
}
}
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-10-25 10:45:25 +00:00
return ret ;
}
2015-07-12 05:46:16 +00:00
// batch_num_blocks: (optional) Used to check if resize needed before batch transaction starts.
2015-07-11 19:28:20 +00:00
void BlockchainLMDB : : batch_start ( uint64_t batch_num_blocks )
2015-02-11 23:55:53 +00:00
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
if ( ! m_batch_transactions )
throw0 ( DB_ERROR ( " batch transactions not enabled " ) ) ;
if ( m_batch_active )
throw0 ( DB_ERROR ( " batch transaction already in progress " ) ) ;
2015-05-17 02:05:54 +00:00
if ( m_write_batch_txn ! = nullptr )
throw0 ( DB_ERROR ( " batch transaction already in progress " ) ) ;
2015-02-11 23:55:53 +00:00
if ( m_write_txn )
throw0 ( DB_ERROR ( " batch transaction attempted, but m_write_txn already in use " ) ) ;
check_open ( ) ;
2015-05-17 02:05:54 +00:00
2015-07-12 05:46:16 +00:00
check_and_resize_for_batch ( batch_num_blocks ) ;
2015-05-18 09:45:15 +00:00
m_write_batch_txn = new mdb_txn_safe ( ) ;
2015-02-11 23:55:53 +00:00
// NOTE: need to make sure it's destroyed properly when done
2015-12-13 16:45:03 +00:00
if ( auto mdb_res = mdb_txn_begin ( m_env , NULL , 0 , * m_write_batch_txn ) )
2016-02-13 11:41:22 +00:00
{
delete m_write_batch_txn ;
m_write_batch_txn = nullptr ;
2015-12-13 16:45:03 +00:00
throw0 ( DB_ERROR ( lmdb_error ( " Failed to create a transaction for the db: " , mdb_res ) . c_str ( ) ) ) ;
2016-02-13 11:41:22 +00:00
}
2015-02-11 23:55:53 +00:00
// indicates this transaction is for batch transactions, but not whether it's
// active
2015-05-17 02:05:54 +00:00
m_write_batch_txn - > m_batch_txn = true ;
m_write_txn = m_write_batch_txn ;
2016-02-18 12:09:57 +00:00
2015-02-11 23:55:53 +00:00
m_batch_active = true ;
2016-02-18 12:09:57 +00:00
memset ( & m_wcursors , 0 , sizeof ( m_wcursors ) ) ;
2016-01-07 06:33:22 +00:00
2015-02-11 23:55:53 +00:00
LOG_PRINT_L3 ( " batch transaction: begin " ) ;
}
void BlockchainLMDB : : batch_commit ( )
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
if ( ! m_batch_transactions )
throw0 ( DB_ERROR ( " batch transactions not enabled " ) ) ;
if ( ! m_batch_active )
throw0 ( DB_ERROR ( " batch transaction not in progress " ) ) ;
2015-05-17 02:05:54 +00:00
if ( m_write_batch_txn = = nullptr )
throw0 ( DB_ERROR ( " batch transaction not in progress " ) ) ;
2015-02-11 23:55:53 +00:00
check_open ( ) ;
2015-05-17 02:05:54 +00:00
2015-02-11 23:55:53 +00:00
LOG_PRINT_L3 ( " batch transaction: committing... " ) ;
2015-02-11 23:55:53 +00:00
TIME_MEASURE_START ( time1 ) ;
2015-02-11 23:55:53 +00:00
m_write_txn - > commit ( ) ;
2015-02-11 23:55:53 +00:00
TIME_MEASURE_FINISH ( time1 ) ;
time_commit1 + = time1 ;
2015-02-11 23:55:53 +00:00
LOG_PRINT_L3 ( " batch transaction: committed " ) ;
2015-05-17 02:05:54 +00:00
m_write_txn = nullptr ;
delete m_write_batch_txn ;
2016-02-18 12:09:57 +00:00
memset ( & m_wcursors , 0 , sizeof ( m_wcursors ) ) ;
2015-02-11 23:55:53 +00:00
}
void BlockchainLMDB : : batch_stop ( )
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
if ( ! m_batch_transactions )
throw0 ( DB_ERROR ( " batch transactions not enabled " ) ) ;
if ( ! m_batch_active )
throw0 ( DB_ERROR ( " batch transaction not in progress " ) ) ;
2015-05-17 02:05:54 +00:00
if ( m_write_batch_txn = = nullptr )
throw0 ( DB_ERROR ( " batch transaction not in progress " ) ) ;
2015-02-11 23:55:53 +00:00
check_open ( ) ;
LOG_PRINT_L3 ( " batch transaction: committing... " ) ;
2015-02-11 23:55:53 +00:00
TIME_MEASURE_START ( time1 ) ;
2015-02-11 23:55:53 +00:00
m_write_txn - > commit ( ) ;
2015-02-11 23:55:53 +00:00
TIME_MEASURE_FINISH ( time1 ) ;
time_commit1 + = time1 ;
2015-02-11 23:55:53 +00:00
// for destruction of batch transaction
m_write_txn = nullptr ;
2015-05-17 02:05:54 +00:00
delete m_write_batch_txn ;
2015-05-18 09:45:15 +00:00
m_write_batch_txn = nullptr ;
2015-02-11 23:55:53 +00:00
m_batch_active = false ;
2016-02-18 12:09:57 +00:00
memset ( & m_wcursors , 0 , sizeof ( m_wcursors ) ) ;
2015-02-11 23:55:53 +00:00
LOG_PRINT_L3 ( " batch transaction: end " ) ;
}
void BlockchainLMDB : : batch_abort ( )
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
if ( ! m_batch_transactions )
throw0 ( DB_ERROR ( " batch transactions not enabled " ) ) ;
if ( ! m_batch_active )
throw0 ( DB_ERROR ( " batch transaction not in progress " ) ) ;
check_open ( ) ;
// for destruction of batch transaction
m_write_txn = nullptr ;
// explicitly call in case mdb_env_close() (BlockchainLMDB::close()) called before BlockchainLMDB destructor called.
2015-05-17 02:05:54 +00:00
m_write_batch_txn - > abort ( ) ;
2015-02-11 23:55:53 +00:00
m_batch_active = false ;
2015-05-18 09:45:15 +00:00
m_write_batch_txn = nullptr ;
2016-02-18 12:09:57 +00:00
memset ( & m_wcursors , 0 , sizeof ( m_wcursors ) ) ;
2015-02-11 23:55:53 +00:00
LOG_PRINT_L3 ( " batch transaction: aborted " ) ;
}
void BlockchainLMDB : : set_batch_transactions ( bool batch_transactions )
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
m_batch_transactions = batch_transactions ;
LOG_PRINT_L3 ( " batch transactions " < < ( m_batch_transactions ? " enabled " : " disabled " ) ) ;
}
2016-02-18 12:09:57 +00:00
// return true if we started the txn, false if already started
bool BlockchainLMDB : : block_rtxn_start ( ) const
{
if ( m_write_txn )
return false ;
if ( ! m_tinfo . get ( ) )
{
m_tinfo . reset ( new mdb_threadinfo ) ;
memset ( & m_tinfo - > m_ti_rcursors , 0 , sizeof ( m_tinfo - > m_ti_rcursors ) ) ;
memset ( & m_tinfo - > m_ti_rflags , 0 , sizeof ( m_tinfo - > m_ti_rflags ) ) ;
if ( auto mdb_res = mdb_txn_begin ( m_env , NULL , MDB_RDONLY , & m_tinfo - > m_ti_rtxn ) )
throw0 ( DB_ERROR_TXN_START ( lmdb_error ( " Failed to create a read transaction for the db: " , mdb_res ) . c_str ( ) ) ) ;
} else if ( ! m_tinfo - > m_ti_rflags . m_rf_txn )
{
if ( auto mdb_res = mdb_txn_renew ( m_tinfo - > m_ti_rtxn ) )
throw0 ( DB_ERROR_TXN_START ( lmdb_error ( " Failed to renew a read transaction for the db: " , mdb_res ) . c_str ( ) ) ) ;
} else
{
return false ;
}
m_tinfo - > m_ti_rflags . m_rf_txn = true ;
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
return true ;
}
void BlockchainLMDB : : block_rtxn_stop ( ) const
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
mdb_txn_reset ( m_tinfo - > m_ti_rtxn ) ;
memset ( & m_tinfo - > m_ti_rflags , 0 , sizeof ( m_tinfo - > m_ti_rflags ) ) ;
}
void BlockchainLMDB : : block_txn_start ( bool readonly )
2016-02-08 16:32:19 +00:00
{
2016-02-18 12:09:57 +00:00
if ( readonly )
{
bool didit = false ;
if ( m_write_txn )
return ;
if ( ! m_tinfo . get ( ) )
{
m_tinfo . reset ( new mdb_threadinfo ) ;
memset ( & m_tinfo - > m_ti_rcursors , 0 , sizeof ( m_tinfo - > m_ti_rcursors ) ) ;
memset ( & m_tinfo - > m_ti_rflags , 0 , sizeof ( m_tinfo - > m_ti_rflags ) ) ;
if ( auto mdb_res = mdb_txn_begin ( m_env , NULL , MDB_RDONLY , & m_tinfo - > m_ti_rtxn ) )
throw0 ( DB_ERROR_TXN_START ( lmdb_error ( " Failed to create a read transaction for the db: " , mdb_res ) . c_str ( ) ) ) ;
didit = true ;
} else if ( ! m_tinfo - > m_ti_rflags . m_rf_txn )
{
if ( auto mdb_res = mdb_txn_renew ( m_tinfo - > m_ti_rtxn ) )
throw0 ( DB_ERROR_TXN_START ( lmdb_error ( " Failed to renew a read transaction for the db: " , mdb_res ) . c_str ( ) ) ) ;
didit = true ;
}
if ( didit )
{
m_tinfo - > m_ti_rflags . m_rf_txn = true ;
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ < < " RO " ) ;
}
return ;
}
2016-02-08 16:32:19 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2016-02-13 12:10:27 +00:00
// Distinguish the exceptions here from exceptions that would be thrown while
// using the txn and committing it.
//
// If an exception is thrown in this setup, we don't want the caller to catch
// it and proceed as if there were an existing write txn, such as trying to
// call block_txn_abort(). It also indicates a serious issue which will
// probably be thrown up another layer.
2016-02-08 16:32:19 +00:00
if ( ! m_batch_active & & m_write_txn )
2016-02-13 12:10:27 +00:00
throw0 ( DB_ERROR_TXN_START ( ( std : : string ( " Attempted to start new write txn when write txn already exists in " ) + __FUNCTION__ ) . c_str ( ) ) ) ;
2016-02-08 16:32:19 +00:00
if ( ! m_batch_active )
{
m_write_txn = new mdb_txn_safe ( ) ;
if ( auto mdb_res = mdb_txn_begin ( m_env , NULL , 0 , * m_write_txn ) )
2016-02-13 11:41:22 +00:00
{
delete m_write_txn ;
m_write_txn = nullptr ;
2016-02-13 12:10:27 +00:00
throw0 ( DB_ERROR_TXN_START ( lmdb_error ( " Failed to create a transaction for the db: " , mdb_res ) . c_str ( ) ) ) ;
2016-02-13 11:41:22 +00:00
}
2016-02-18 12:09:57 +00:00
memset ( & m_wcursors , 0 , sizeof ( m_wcursors ) ) ;
2016-02-08 16:32:19 +00:00
}
}
void BlockchainLMDB : : block_txn_stop ( )
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
if ( ! m_batch_active )
{
2016-02-18 12:09:57 +00:00
if ( m_write_txn )
{
TIME_MEASURE_START ( time1 ) ;
m_write_txn - > commit ( ) ;
TIME_MEASURE_FINISH ( time1 ) ;
time_commit1 + = time1 ;
2016-02-08 16:32:19 +00:00
2016-02-18 12:09:57 +00:00
delete m_write_txn ;
m_write_txn = nullptr ;
memset ( & m_wcursors , 0 , sizeof ( m_wcursors ) ) ;
}
else if ( m_tinfo - > m_ti_rtxn )
{
mdb_txn_reset ( m_tinfo - > m_ti_rtxn ) ;
memset ( & m_tinfo - > m_ti_rflags , 0 , sizeof ( m_tinfo - > m_ti_rflags ) ) ;
}
2016-02-08 16:32:19 +00:00
}
}
void BlockchainLMDB : : block_txn_abort ( )
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
if ( ! m_batch_active )
{
2016-02-13 11:50:42 +00:00
if ( m_write_txn ! = nullptr )
{
delete m_write_txn ;
m_write_txn = nullptr ;
2016-02-18 12:09:57 +00:00
memset ( & m_wcursors , 0 , sizeof ( m_wcursors ) ) ;
2016-02-13 11:50:42 +00:00
}
2016-02-18 12:09:57 +00:00
else if ( m_tinfo - > m_ti_rtxn )
{
mdb_txn_reset ( m_tinfo - > m_ti_rtxn ) ;
memset ( & m_tinfo - > m_ti_rflags , 0 , sizeof ( m_tinfo - > m_ti_rflags ) ) ;
}
2016-02-13 11:50:42 +00:00
else
{
// This would probably mean an earlier exception was caught, but then we
// proceeded further than we should have.
throw0 ( DB_ERROR ( ( std : : string ( " BlockchainLMDB:: " ) + __func__ +
std : : string ( " : block-level DB transaction abort called when write txn doesn't exist " )
) . c_str ( ) ) ) ;
}
2016-02-08 16:32:19 +00:00
}
}
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
uint64_t BlockchainLMDB : : add_block ( const block & blk , const size_t & block_size , const difficulty_type & cumulative_difficulty , const uint64_t & coins_generated ,
2015-12-14 04:54:39 +00:00
const std : : vector < transaction > & txs )
2014-10-23 19:37:10 +00:00
{
2014-10-30 04:58:14 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2014-10-23 19:37:10 +00:00
check_open ( ) ;
2015-02-11 23:55:53 +00:00
2015-05-18 10:18:31 +00:00
if ( m_height % 1000 = = 0 )
2015-05-17 02:05:54 +00:00
{
2015-07-12 05:46:16 +00:00
// for batch mode, DB resize check is done at start of batch transaction
if ( ! m_batch_active & & need_resize ( ) )
2015-05-17 02:05:54 +00:00
{
LOG_PRINT_L0 ( " LMDB memory map needs resized, doing that now. " ) ;
do_resize ( ) ;
}
}
2014-10-23 23:47:36 +00:00
uint64_t num_outputs = m_num_outputs ;
try
{
BlockchainDB : : add_block ( blk , block_size , cumulative_difficulty , coins_generated , txs ) ;
}
2016-02-13 12:10:27 +00:00
catch ( DB_ERROR_TXN_START & e )
{
throw ;
}
2014-10-23 23:47:36 +00:00
catch ( . . . )
{
m_num_outputs = num_outputs ;
2016-02-08 16:32:36 +00:00
block_txn_abort ( ) ;
2014-10-23 23:47:36 +00:00
throw ;
}
2014-10-23 19:37:10 +00:00
2014-10-23 23:47:36 +00:00
return + + m_height ;
2014-10-23 19:37:10 +00:00
}
2014-10-30 22:33:35 +00:00
void BlockchainLMDB : : pop_block ( block & blk , std : : vector < transaction > & txs )
{
2015-02-11 23:55:53 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2015-02-19 04:52:44 +00:00
check_open ( ) ;
2016-02-18 12:09:57 +00:00
block_txn_start ( false ) ;
2014-10-30 22:33:35 +00:00
uint64_t num_outputs = m_num_outputs ;
try
{
BlockchainDB : : pop_block ( blk , txs ) ;
2016-02-18 12:09:57 +00:00
block_txn_stop ( ) ;
2014-10-30 22:33:35 +00:00
}
catch ( . . . )
{
m_num_outputs = num_outputs ;
2016-02-18 12:09:57 +00:00
block_txn_abort ( ) ;
2014-10-30 22:33:35 +00:00
throw ;
}
- - m_height ;
}
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
void BlockchainLMDB : : get_output_tx_and_index_from_global ( const std : : vector < uint64_t > & global_indices ,
2015-12-14 04:54:39 +00:00
std : : vector < tx_out_index > & tx_out_indices ) const
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
{
2015-12-14 04:54:39 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
tx_out_indices . clear ( ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2015-12-14 04:54:39 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( output_txs ) ;
RCURSOR ( output_indices ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2015-12-14 04:54:39 +00:00
for ( const uint64_t & index : global_indices )
{
MDB_val_copy < uint64_t > k ( index ) ;
MDB_val v ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2016-02-18 12:09:57 +00:00
auto get_result = mdb_cursor_get ( m_cur_output_txs , & k , & v , MDB_SET ) ;
2015-12-14 04:54:39 +00:00
if ( get_result = = MDB_NOTFOUND )
throw1 ( OUTPUT_DNE ( " output with given index not in db " ) ) ;
else if ( get_result )
throw0 ( DB_ERROR ( " DB error attempting to fetch output tx hash " ) ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2015-12-14 04:54:39 +00:00
crypto : : hash tx_hash = * ( const crypto : : hash * ) v . mv_data ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2016-02-18 12:09:57 +00:00
get_result = mdb_cursor_get ( m_cur_output_indices , & k , & v , MDB_SET ) ;
2015-12-14 04:54:39 +00:00
if ( get_result = = MDB_NOTFOUND )
throw1 ( OUTPUT_DNE ( " output with given index not in db " ) ) ;
else if ( get_result )
throw0 ( DB_ERROR ( " DB error attempting to fetch output tx index " ) ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2015-12-14 04:54:39 +00:00
auto result = tx_out_index ( tx_hash , * ( const uint64_t * ) v . mv_data ) ;
tx_out_indices . push_back ( result ) ;
}
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
}
void BlockchainLMDB : : get_output_global_indices ( const uint64_t & amount , const std : : vector < uint64_t > & offsets ,
2015-12-14 04:54:39 +00:00
std : : vector < uint64_t > & global_indices )
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
TIME_MEASURE_START ( txx ) ;
check_open ( ) ;
global_indices . clear ( ) ;
uint64_t max = 0 ;
for ( const uint64_t & index : offsets )
{
if ( index > max )
max = index ;
}
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( output_amounts ) ;
2015-12-14 04:54:39 +00:00
MDB_val_copy < uint64_t > k ( amount ) ;
MDB_val v ;
2016-02-18 12:09:57 +00:00
auto result = mdb_cursor_get ( m_cur_output_amounts , & k , & v , MDB_SET ) ;
2015-12-14 04:54:39 +00:00
if ( result = = MDB_NOTFOUND )
throw1 ( OUTPUT_DNE ( " Attempting to get an output index by amount and amount index, but amount not found " ) ) ;
else if ( result )
throw0 ( DB_ERROR ( " DB error attempting to get an output " ) ) ;
2016-02-17 16:12:38 +00:00
mdb_size_t num_elems = 0 ;
2016-02-18 12:09:57 +00:00
mdb_cursor_count ( m_cur_output_amounts , & num_elems ) ;
2015-12-14 04:54:39 +00:00
if ( max < = 1 & & num_elems < = max )
throw1 ( OUTPUT_DNE ( " Attempting to get an output index by amount and amount index, but output not found " ) ) ;
uint64_t t_dbmul = 0 ;
uint64_t t_dbscan = 0 ;
if ( max < = 1 )
{
for ( const uint64_t & index : offsets )
{
2016-02-18 12:09:57 +00:00
mdb_cursor_get ( m_cur_output_amounts , & k , & v , MDB_FIRST_DUP ) ;
2015-12-14 04:54:39 +00:00
for ( uint64_t i = 0 ; i < index ; + + i )
{
2016-02-18 12:09:57 +00:00
mdb_cursor_get ( m_cur_output_amounts , & k , & v , MDB_NEXT_DUP ) ;
2015-12-14 04:54:39 +00:00
}
2016-02-18 12:09:57 +00:00
mdb_cursor_get ( m_cur_output_amounts , & k , & v , MDB_GET_CURRENT ) ;
2015-12-14 04:54:39 +00:00
uint64_t glob_index = * ( const uint64_t * ) v . mv_data ;
LOG_PRINT_L3 ( " Amount: " < < amount < < " M0->v: " < < glob_index ) ;
global_indices . push_back ( glob_index ) ;
}
}
else
{
uint32_t curcount = 0 ;
uint32_t blockstart = 0 ;
for ( const uint64_t & index : offsets )
{
if ( index > = num_elems )
{
LOG_PRINT_L1 ( " Index: " < < index < < " Elems: " < < num_elems < < " partial results found for get_output_tx_and_index " ) ;
break ;
}
2016-01-07 18:29:19 +00:00
if ( ! curcount & & index > num_elems / 2 )
2015-12-14 04:54:39 +00:00
{
2016-02-18 12:09:57 +00:00
mdb_cursor_get ( m_cur_output_amounts , & k , & v , MDB_LAST_DUP ) ;
mdb_cursor_get ( m_cur_output_amounts , & k , & v , MDB_PREV ) ; /* kludge to unset C_EOF */
mdb_cursor_get ( m_cur_output_amounts , & k , & v , MDB_NEXT ) ;
mdb_cursor_get ( m_cur_output_amounts , & k , & v , MDB_GET_MULTIPLE ) ;
2016-01-07 18:29:19 +00:00
curcount = num_elems ;
while ( 1 )
2015-12-14 04:54:39 +00:00
{
2016-01-07 18:29:19 +00:00
TIME_MEASURE_START ( db1 ) ;
int count = v . mv_size / sizeof ( uint64_t ) ;
curcount - = count ;
if ( curcount > index )
{
2016-02-18 12:09:57 +00:00
mdb_cursor_get ( m_cur_output_amounts , & k , & v , MDB_PREV_MULTIPLE ) ;
2016-01-07 18:29:19 +00:00
} else
{
blockstart = curcount ;
curcount + = count ;
break ;
}
TIME_MEASURE_FINISH ( db1 ) ;
t_dbmul + = db1 ;
2015-12-14 04:54:39 +00:00
}
2016-01-07 18:29:19 +00:00
} else
{
while ( index > = curcount )
{
TIME_MEASURE_START ( db1 ) ;
2016-02-18 12:09:57 +00:00
if ( mdb_cursor_get ( m_cur_output_amounts , & k , & v , curcount = = 0 ? MDB_GET_MULTIPLE : MDB_NEXT_MULTIPLE ) ! = 0 )
2016-01-07 18:29:19 +00:00
{
// allow partial results
result = false ;
break ;
}
int count = v . mv_size / sizeof ( uint64_t ) ;
blockstart = curcount ;
curcount + = count ;
TIME_MEASURE_FINISH ( db1 ) ;
t_dbmul + = db1 ;
}
2015-12-14 04:54:39 +00:00
}
LOG_PRINT_L3 ( " Records returned: " < < curcount < < " Index: " < < index ) ;
TIME_MEASURE_START ( db2 ) ;
uint64_t actual_index = index - blockstart ;
uint64_t glob_index = ( ( const uint64_t * ) v . mv_data ) [ actual_index ] ;
LOG_PRINT_L3 ( " Amount: " < < amount < < " M1->v: " < < glob_index ) ;
global_indices . push_back ( glob_index ) ;
TIME_MEASURE_FINISH ( db2 ) ;
t_dbscan + = db2 ;
}
}
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-12-14 04:54:39 +00:00
TIME_MEASURE_FINISH ( txx ) ;
LOG_PRINT_L3 ( " txx: " < < txx < < " db1: " < < t_dbmul < < " db2: " < < t_dbscan ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
}
void BlockchainLMDB : : get_output_key ( const uint64_t & amount , const std : : vector < uint64_t > & offsets , std : : vector < output_data_t > & outputs )
{
2015-12-14 04:54:39 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
TIME_MEASURE_START ( db3 ) ;
check_open ( ) ;
outputs . clear ( ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2016-02-18 12:09:57 +00:00
TXN_PREFIX_RDONLY ( ) ;
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
2015-12-14 04:54:39 +00:00
std : : vector < uint64_t > global_indices ;
get_output_global_indices ( amount , offsets , global_indices ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2015-12-14 04:54:39 +00:00
if ( global_indices . size ( ) > 0 )
{
2016-02-18 12:09:57 +00:00
RCURSOR ( output_keys ) ;
2015-12-14 18:47:13 +00:00
2015-12-14 04:54:39 +00:00
for ( const uint64_t & index : global_indices )
{
MDB_val_copy < uint64_t > k ( index ) ;
MDB_val v ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2016-02-18 12:09:57 +00:00
auto get_result = mdb_cursor_get ( m_cur_output_keys , & k , & v , MDB_SET ) ;
2015-12-14 04:54:39 +00:00
if ( get_result = = MDB_NOTFOUND )
throw1 ( OUTPUT_DNE ( " Attempting to get output pubkey by global index, but key does not exist " ) ) ;
else if ( get_result )
throw0 ( DB_ERROR ( " Error attempting to retrieve an output pubkey from the db " ) ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2015-12-14 04:54:39 +00:00
output_data_t data = * ( const output_data_t * ) v . mv_data ;
outputs . push_back ( data ) ;
}
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2015-12-14 04:54:39 +00:00
}
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2015-12-14 04:54:39 +00:00
TIME_MEASURE_FINISH ( db3 ) ;
LOG_PRINT_L3 ( " db3: " < < db3 ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
}
void BlockchainLMDB : : get_output_tx_and_index ( const uint64_t & amount , const std : : vector < uint64_t > & offsets , std : : vector < tx_out_index > & indices )
{
2015-12-14 04:54:39 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
indices . clear ( ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2015-12-14 04:54:39 +00:00
std : : vector < uint64_t > global_indices ;
get_output_global_indices ( amount , offsets , global_indices ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
2015-12-14 04:54:39 +00:00
TIME_MEASURE_START ( db3 ) ;
if ( global_indices . size ( ) > 0 )
{
get_output_tx_and_index_from_global ( global_indices , indices ) ;
}
TIME_MEASURE_FINISH ( db3 ) ;
LOG_PRINT_L3 ( " db3: " < < db3 ) ;
** CHANGES ARE EXPERIMENTAL (FOR TESTING ONLY)
Bockchain:
1. Optim: Multi-thread long-hash computation when encountering groups of blocks.
2. Optim: Cache verified txs and return result from cache instead of re-checking whenever possible.
3. Optim: Preload output-keys when encoutering groups of blocks. Sort by amount and global-index before bulk querying database and multi-thread when possible.
4. Optim: Disable double spend check on block verification, double spend is already detected when trying to add blocks.
5. Optim: Multi-thread signature computation whenever possible.
6. Patch: Disable locking (recursive mutex) on called functions from check_tx_inputs which causes slowdowns (only seems to happen on ubuntu/VMs??? Reason: TBD)
7. Optim: Removed looped full-tx hash computation when retrieving transactions from pool (???).
8. Optim: Cache difficulty/timestamps (735 blocks) for next-difficulty calculations so that only 2 db reads per new block is needed when a new block arrives (instead of 1470 reads).
Berkeley-DB:
1. Fix: 32-bit data errors causing wrong output global indices and failure to send blocks to peers (etc).
2. Fix: Unable to pop blocks on reorganize due to transaction errors.
3. Patch: Large number of transaction aborts when running multi-threaded bulk queries.
4. Patch: Insufficient locks error when running full sync.
5. Patch: Incorrect db stats when returning from an immediate exit from "pop block" operation.
6. Optim: Add bulk queries to get output global indices.
7. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
8. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
9. Optim: Added thread-safe buffers used when multi-threading bulk queries.
10. Optim: Added support for nosync/write_nosync options for improved performance (*see --db-sync-mode option for details)
11. Mod: Added checkpoint thread and auto-remove-logs option.
12. *Now usable on 32-bit systems like RPI2.
LMDB:
1. Optim: Added custom comparison for 256-bit key tables (minor speed-up, TBD: get actual effect)
2. Optim: Modified output_keys table to store public_key+unlock_time+height for single transaction lookup (vs 3)
3. Optim: Used output_keys table retrieve public_keys instead of going through output_amounts->output_txs+output_indices->txs->output:public_key
4. Optim: Added support for sync/writemap options for improved performance (*see --db-sync-mode option for details)
5. Mod: Auto resize to +1GB instead of multiplier x1.5
ETC:
1. Minor optimizations for slow-hash for ARM (RPI2). Incomplete.
2. Fix: 32-bit saturation bug when computing next difficulty on large blocks.
[PENDING ISSUES]
1. Berkely db has a very slow "pop-block" operation. This is very noticeable on the RPI2 as it sometimes takes > 10 MINUTES to pop a block during reorganization.
This does not happen very often however, most reorgs seem to take a few seconds but it possibly depends on the number of outputs present. TBD.
2. Berkeley db, possible bug "unable to allocate memory". TBD.
[NEW OPTIONS] (*Currently all enabled for testing purposes)
1. --fast-block-sync arg=[0:1] (default: 1)
a. 0 = Compute long hash per block (may take a while depending on CPU)
b. 1 = Skip long-hash and verify blocks based on embedded known good block hashes (faster, minimal CPU dependence)
2. --db-sync-mode arg=[[safe|fast|fastest]:[sync|async]:[nblocks_per_sync]] (default: fastest:async:1000)
a. safe = fdatasync/fsync (or equivalent) per stored block. Very slow, but safest option to protect against power-out/crash conditions.
b. fast/fastest = Enables asynchronous fdatasync/fsync (or equivalent). Useful for battery operated devices or STABLE systems with UPS and/or systems with battery backed write cache/solid state cache.
Fast - Write meta-data but defer data flush.
Fastest - Defer meta-data and data flush.
Sync - Flush data after nblocks_per_sync and wait.
Async - Flush data after nblocks_per_sync but do not wait for the operation to finish.
3. --prep-blocks-threads arg=[n] (default: 4 or system max threads, whichever is lower)
Max number of threads to use when computing long-hash in groups.
4. --show-time-stats arg=[0:1] (default: 1)
Show benchmark related time stats.
5. --db-auto-remove-logs arg=[0:1] (default: 1)
For berkeley-db only. Auto remove logs if enabled.
**Note: lmdb and berkeley-db have changes to the tables and are not compatible with official git head version.
At the moment, you need a full resync to use this optimized version.
[PERFORMANCE COMPARISON]
**Some figures are approximations only.
Using a baseline machine of an i7-2600K+SSD+(with full pow computation):
1. The optimized lmdb/blockhain core can process blocks up to 585K for ~1.25 hours + download time, so it usually takes 2.5 hours to sync the full chain.
2. The current head with memory can process blocks up to 585K for ~4.2 hours + download time, so it usually takes 5.5 hours to sync the full chain.
3. The current head with lmdb can process blocks up to 585K for ~32 hours + download time and usually takes 36 hours to sync the full chain.
Averate procesing times (with full pow computation):
lmdb-optimized:
1. tx_ave = 2.5 ms / tx
2. block_ave = 5.87 ms / block
memory-official-repo:
1. tx_ave = 8.85 ms / tx
2. block_ave = 19.68 ms / block
lmdb-official-repo (0f4a036437fd41a5498ee5e74e2422ea6177aa3e)
1. tx_ave = 47.8 ms / tx
2. block_ave = 64.2 ms / block
**Note: The following data denotes processing times only (does not include p2p download time)
lmdb-optimized processing times (with full pow computation):
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.25 hours processing time (--db-sync-mode=fastest:async:1000).
2. Laptop, Dual-core / 4-threads U4200 (3Mb) - 4.90 hours processing time (--db-sync-mode=fastest:async:1000).
3. Embedded, Quad-core / 4-threads Z3735F (2x1Mb) - 12.0 hours processing time (--db-sync-mode=fastest:async:1000).
lmdb-optimized processing times (with per-block-checkpoint)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 10 minutes processing time (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with full pow computation)
1. Desktop, Quad-core / 8-threads 2600k (8Mb) - 1.8 hours processing time (--db-sync-mode=fastest:async:1000).
2. RPI2. Improved from estimated 3 months(???) into 2.5 days (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
berkeley-db optimized processing times (with per-block-checkpoint)
1. RPI2. 12-15 hours (*Need 2AMP supply + Clock:1Ghz + [usb+ssd] to achieve this speed) (--db-sync-mode=fastest:async:1000).
2015-07-10 20:09:32 +00:00
}
2016-01-15 14:00:58 +00:00
void BlockchainLMDB : : check_hard_fork_info ( )
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
TXN_PREFIX ( 0 ) ;
MDB_stat db_stat1 , db_stat2 ;
if ( mdb_stat ( * txn_ptr , m_blocks , & db_stat1 ) )
throw0 ( DB_ERROR ( " Failed to query m_blocks " ) ) ;
if ( mdb_stat ( * txn_ptr , m_hf_versions , & db_stat2 ) )
throw0 ( DB_ERROR ( " Failed to query m_hf_starting_heights " ) ) ;
if ( db_stat1 . ms_entries ! = db_stat2 . ms_entries )
{
2016-02-05 04:09:51 +00:00
// Empty, but don't delete. This allows this function to be called after
// startup, after the subdbs have already been created, and rest of startup
// can proceed. If these don't exist, hard fork's init() will fail.
//
// If these are empty, hard fork's init() will repopulate the hard fork
// data.
mdb_drop ( * txn_ptr , m_hf_starting_heights , 0 ) ;
mdb_drop ( * txn_ptr , m_hf_versions , 0 ) ;
2016-01-15 14:00:58 +00:00
}
TXN_POSTFIX_SUCCESS ( ) ;
}
2016-02-05 01:15:37 +00:00
void BlockchainLMDB : : drop_hard_fork_info ( )
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
TXN_PREFIX ( 0 ) ;
mdb_drop ( * txn_ptr , m_hf_starting_heights , 1 ) ;
mdb_drop ( * txn_ptr , m_hf_versions , 1 ) ;
TXN_POSTFIX_SUCCESS ( ) ;
}
2015-09-20 17:41:38 +00:00
void BlockchainLMDB : : set_hard_fork_starting_height ( uint8_t version , uint64_t height )
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
2016-02-08 12:58:08 +00:00
TXN_BLOCK_PREFIX ( 0 ) ;
2015-09-20 17:41:38 +00:00
MDB_val_copy < uint8_t > val_key ( version ) ;
MDB_val_copy < uint64_t > val_value ( height ) ;
2016-01-07 13:23:12 +00:00
if ( auto result = mdb_put ( * txn_ptr , m_hf_starting_heights , & val_key , & val_value , MDB_APPEND ) )
2015-09-20 17:41:38 +00:00
throw1 ( DB_ERROR ( std : : string ( " Error adding hard fork starting height to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2016-02-08 12:58:08 +00:00
TXN_BLOCK_POSTFIX_SUCCESS ( ) ;
2015-09-20 17:41:38 +00:00
}
uint64_t BlockchainLMDB : : get_hard_fork_starting_height ( uint8_t version ) const
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2015-09-20 17:41:38 +00:00
MDB_val_copy < uint8_t > val_key ( version ) ;
MDB_val val_ret ;
2016-02-18 12:09:57 +00:00
auto result = mdb_get ( m_txn , m_hf_starting_heights , & val_key , & val_ret ) ;
2015-09-20 17:41:38 +00:00
if ( result = = MDB_NOTFOUND )
return std : : numeric_limits < uint64_t > : : max ( ) ;
if ( result )
throw0 ( DB_ERROR ( " Error attempting to retrieve a hard fork starting height from the db " ) ) ;
2016-02-25 13:55:49 +00:00
uint64_t ret ;
# ifdef MISALIGNED_OK
ret = * ( const uint64_t * ) val_ret . mv_data ;
# else
memcpy ( & ret , val_ret . mv_data , sizeof ( uint64_t ) ) ;
# endif
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-12-10 01:42:36 +00:00
return ret ;
2015-09-20 17:41:38 +00:00
}
void BlockchainLMDB : : set_hard_fork_version ( uint64_t height , uint8_t version )
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
2016-02-08 12:58:08 +00:00
TXN_BLOCK_PREFIX ( 0 ) ;
2015-09-20 17:41:38 +00:00
MDB_val_copy < uint64_t > val_key ( height ) ;
MDB_val_copy < uint8_t > val_value ( version ) ;
2016-01-07 13:23:12 +00:00
int result ;
result = mdb_put ( * txn_ptr , m_hf_versions , & val_key , & val_value , MDB_APPEND ) ;
if ( result = = MDB_KEYEXIST )
result = mdb_put ( * txn_ptr , m_hf_versions , & val_key , & val_value , 0 ) ;
if ( result )
2015-09-20 17:41:38 +00:00
throw1 ( DB_ERROR ( std : : string ( " Error adding hard fork version to db transaction: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2016-02-08 12:58:08 +00:00
TXN_BLOCK_POSTFIX_SUCCESS ( ) ;
2015-09-20 17:41:38 +00:00
}
uint8_t BlockchainLMDB : : get_hard_fork_version ( uint64_t height ) const
{
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
check_open ( ) ;
2015-12-14 18:47:13 +00:00
TXN_PREFIX_RDONLY ( ) ;
2016-02-18 12:09:57 +00:00
const mdb_txn_cursors * m_cursors = m_write_txn ? & m_wcursors : & m_tinfo - > m_ti_rcursors ;
RCURSOR ( hf_versions ) ;
2015-09-20 17:41:38 +00:00
MDB_val_copy < uint64_t > val_key ( height ) ;
MDB_val val_ret ;
2016-02-18 12:09:57 +00:00
auto result = mdb_cursor_get ( m_cur_hf_versions , & val_key , & val_ret , MDB_SET ) ;
2015-09-20 17:41:38 +00:00
if ( result = = MDB_NOTFOUND | | result )
2016-03-01 01:51:21 +00:00
throw0 ( DB_ERROR ( std : : string ( " Error attempting to retrieve a hard fork version at height " ) . append ( boost : : lexical_cast < std : : string > ( height ) ) . append ( " from the db: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
2015-09-20 17:41:38 +00:00
2015-12-14 18:47:13 +00:00
uint8_t ret = * ( const uint8_t * ) val_ret . mv_data ;
2016-02-18 12:09:57 +00:00
TXN_POSTFIX_RDONLY ( ) ;
2015-12-10 01:42:36 +00:00
return ret ;
2015-09-20 17:41:38 +00:00
}
2015-12-26 22:27:35 +00:00
bool BlockchainLMDB : : is_read_only ( ) const
{
unsigned int flags ;
auto result = mdb_env_get_flags ( m_env , & flags ) ;
if ( result )
throw0 ( DB_ERROR ( std : : string ( " Error getting database environment info: " ) . append ( mdb_strerror ( result ) ) . c_str ( ) ) ) ;
if ( flags & MDB_RDONLY )
return true ;
return false ;
}
2015-12-06 20:48:17 +00:00
void BlockchainLMDB : : fixup ( )
{
2015-12-26 22:27:35 +00:00
LOG_PRINT_L3 ( " BlockchainLMDB:: " < < __func__ ) ;
2015-12-06 20:48:17 +00:00
// Always call parent as well
BlockchainDB : : fixup ( ) ;
}
2014-10-21 20:33:43 +00:00
} // namespace cryptonote