88#include < iostream>
99#include < golos/protocol/protocol.hpp>
1010#include < golos/protocol/types.hpp>
11+ #include < future>
1112
1213namespace golos {
1314namespace plugins {
@@ -31,11 +32,34 @@ namespace chain {
3132
3233 uint32_t allow_future_time = 5 ;
3334
35+ uint64_t read_wait_micro;
36+ uint32_t max_read_wait_retries;
37+
38+ uint64_t write_wait_micro;
39+ uint32_t max_write_wait_retries;
40+
41+ golos::chain::database db;
42+
43+ bool single_write_thread = false ;
44+
45+ plugin_impl () {
46+ // get default settings
47+ read_wait_micro = db.read_wait_micro ();
48+ max_read_wait_retries = db.max_read_wait_retries ();
49+
50+ write_wait_micro = db.write_wait_micro ();
51+ max_write_wait_retries = db.max_write_wait_retries ();
52+ }
53+
3454 // HELPERS
3555 golos::chain::database &database () {
3656 return db;
3757 }
3858
59+ boost::asio::io_service& io_service () {
60+ return appbase::app ().get_io_service ();
61+ }
62+
3963 constexpr const static char *plugin_name = " chain_api" ;
4064 static const std::string &name () {
4165 static std::string name = plugin_name;
@@ -45,9 +69,6 @@ namespace chain {
4569 void check_time_in_block (const protocol::signed_block &block);
4670 bool accept_block (const protocol::signed_block &block, bool currently_syncing, uint32_t skip);
4771 void accept_transaction (const protocol::signed_transaction &trx);
48-
49-
50- golos::chain::database db;
5172 };
5273
5374 void plugin::plugin_impl::check_time_in_block (const protocol::signed_block &block) {
@@ -66,11 +87,40 @@ namespace chain {
6687
6788 check_time_in_block (block);
6889
69- return db.push_block (block, skip);
90+ if (single_write_thread) {
91+ std::promise<bool > promise;
92+ auto result = promise.get_future ();
93+
94+ io_service ().post ([&]{
95+ try {
96+ promise.set_value (db.push_block (block, skip));
97+ } catch (...) {
98+ promise.set_exception (std::current_exception ());
99+ }
100+ });
101+ return result.get (); // if an exception was, it will be thrown
102+ } else {
103+ return db.push_block (block, skip);
104+ }
70105 }
71106
72107 void plugin::plugin_impl::accept_transaction (const protocol::signed_transaction &trx) {
73- db.push_transaction (trx);
108+ if (single_write_thread) {
109+ std::promise<bool > promise;
110+ auto wait = promise.get_future ();
111+
112+ io_service ().post ([&]{
113+ try {
114+ db.push_transaction (trx);
115+ promise.set_value (true );
116+ } catch (...) {
117+ promise.set_exception (std::current_exception ());
118+ }
119+ });
120+ wait.get (); // if an exception was, it will be thrown
121+ } else {
122+ db.push_transaction (trx);
123+ }
74124 }
75125
76126 plugin::plugin () {
@@ -89,23 +139,73 @@ namespace chain {
89139
90140 void plugin::set_program_options (boost::program_options::options_description &cli,
91141 boost::program_options::options_description &cfg) {
92- cfg.add_options ()(" shared-file-dir" , boost::program_options::value<boost::filesystem::path>()->default_value (" blockchain" ),
93- " the location of the chain shared memory files (absolute path or relative to application data dir)" )(
94- " shared-file-size" , boost::program_options::value<std::string>()->default_value (" 54G" ),
95- " Size of the shared memory file. Default: 54G" )(" checkpoint,c" ,
96- boost::program_options::value<std::vector<std::string>>()->composing (),
97- " Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints." )(
98- " flush-state-interval" , boost::program_options::value<uint32_t >(),
99- " flush shared memory changes to disk every N blocks" );
100- cli.add_options ()(" replay-blockchain" , boost::program_options::bool_switch ()->default_value (false ),
101- " clear chain database and replay all blocks" )(" resync-blockchain" ,
102- boost::program_options::bool_switch ()->default_value (
103- false ),
104- " clear chain database and block log" )(
105- " check-locks" , boost::program_options::bool_switch ()->default_value (false ),
106- " Check correctness of chainbase locking" )(" validate-database-invariants" ,
107- boost::program_options::bool_switch ()->default_value (false ),
108- " Validate all supply invariants check out" );
142+ cfg.add_options ()
143+ (
144+ " shared-file-dir" ,
145+ boost::program_options::value<boost::filesystem::path>()->default_value (" blockchain" ),
146+ " the location of the chain shared memory files (absolute path or relative to application data dir)"
147+ )
148+ (
149+ " shared-file-size" ,
150+ boost::program_options::value<std::string>()->default_value (" 64G" ),
151+ " Size of the shared memory file. Default: 54G"
152+ )
153+ (
154+ " checkpoint,c" ,
155+ boost::program_options::value<std::vector<std::string>>()->composing (),
156+ " Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints."
157+ )
158+ (
159+ " flush-state-interval" ,
160+ boost::program_options::value<uint32_t >(),
161+ " flush shared memory changes to disk every N blocks"
162+ )
163+ (
164+ " read-wait-micro" ,
165+ boost::program_options::value<uint64_t >(),
166+ " maximum microseconds for trying to get read lock"
167+ )
168+ (
169+ " max-read-wait-retries" ,
170+ boost::program_options::value<uint32_t >(),
171+ " maximum number of retries to get read lock"
172+ )
173+ (
174+ " write-wait-micro" ,
175+ boost::program_options::value<uint64_t >(),
176+ " maximum microseconds for trying to get write lock"
177+ )
178+ (
179+ " max-write-wait-retries" ,
180+ boost::program_options::value<uint32_t >(),
181+ " maximum number of retries to get write lock"
182+ )
183+ (
184+ " single-write-thread" ,
185+ boost::program_options::value<bool >()->default_value (false ),
186+ " push blocks and transactions from one thread"
187+ );
188+ cli.add_options ()
189+ (
190+ " replay-blockchain" ,
191+ boost::program_options::bool_switch ()->default_value (false ),
192+ " clear chain database and replay all blocks"
193+ )
194+ (
195+ " resync-blockchain" ,
196+ boost::program_options::bool_switch ()->default_value (false ),
197+ " clear chain database and block log"
198+ )
199+ (
200+ " check-locks" ,
201+ boost::program_options::bool_switch ()->default_value (false ),
202+ " Check correctness of chainbase locking"
203+ )
204+ (
205+ " validate-database-invariants" ,
206+ boost::program_options::bool_switch ()->default_value (false ),
207+ " Validate all supply invariants check out"
208+ );
109209 }
110210
111211 void plugin::plugin_initialize (const boost::program_options::variables_map &options) {
@@ -122,6 +222,24 @@ namespace chain {
122222 }
123223 }
124224
225+ if (options.count (" read-wait-micro" )) {
226+ my->read_wait_micro = options.at (" read-wait-micro" ).as <uint64_t >();
227+ }
228+
229+ if (options.count (" max-read-wait-retries" )) {
230+ my->max_read_wait_retries = options.at (" max-read-wait-retries" ).as <uint32_t >();
231+ }
232+
233+ if (options.count (" write-wait-micro" )) {
234+ my->write_wait_micro = options.at (" write-wait-micro" ).as <uint64_t >();
235+ }
236+
237+ if (options.count (" max-write-wait-retries" )) {
238+ my->max_write_wait_retries = options.at (" max-write-wait-retries" ).as <uint32_t >();
239+ }
240+
241+ my->single_write_thread = options.at (" single-write-thread" ).as <bool >();
242+
125243 my->shared_memory_size = fc::parse_size (options.at (" shared-file-size" ).as <std::string>());
126244
127245 my->replay = options.at (" replay-blockchain" ).as <bool >();
@@ -156,6 +274,11 @@ namespace chain {
156274 my->db .add_checkpoints (my->loaded_checkpoints );
157275 my->db .set_require_locking (my->check_locks );
158276
277+ my->db .read_wait_micro (my->read_wait_micro );
278+ my->db .max_read_wait_retries (my->max_read_wait_retries );
279+ my->db .write_wait_micro (my->write_wait_micro );
280+ my->db .max_write_wait_retries (my->max_write_wait_retries );
281+
159282 if (my->replay ) {
160283 ilog (" Replaying blockchain on user request." );
161284 my->db .reindex (appbase::app ().data_dir () / " blockchain" , my->shared_memory_dir , my->shared_memory_size );
0 commit comments