diff --git a/rai/node/node.cpp b/rai/node/node.cpp index 5feaf0b9..3ad5ddbe 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -1524,6 +1524,12 @@ rai::node::~node () stop (); } +bool rai::node::copy_with_compaction (boost::filesystem::path const & destination_file) +{ + return !mdb_env_copy2 (store.environment.environment, + destination_file.string ().c_str (), MDB_CP_COMPACT); +} + void rai::node::send_keepalive (rai::endpoint const & endpoint_a) { auto endpoint_l (endpoint_a); @@ -2935,7 +2941,7 @@ void rai::thread_runner::join () void rai::add_node_options (boost::program_options::options_description & description_a) { - description_a.add_options () ("account_create", "Insert next deterministic key in to ") ("account_get", "Get account number for the ") ("account_key", "Get the public key for ") ("data_path", boost::program_options::value (), "Use the supplied path as the data directory") ("diagnostics", "Run internal diagnostics") ("key_create", "Generates a adhoc random keypair and prints it to stdout") ("key_expand", "Derive public key and account number from ") ("wallet_add_adhoc", "Insert in to ") ("wallet_create", "Creates a new wallet and prints the ID") ("wallet_change_seed", "Changes seed for to ") ("wallet_decrypt_unsafe", "Decrypts using , !!THIS WILL PRINT YOUR PRIVATE KEY TO STDOUT!!") ("wallet_destroy", "Destroys and all keys it contains") ("wallet_import", "Imports keys in using in to ") ("wallet_list", "Dumps wallet IDs and public keys") ("wallet_remove", "Remove from ") ("wallet_representative_get", "Prints default representative for ") ("wallet_representative_set", "Set as default representative for ") ("vote_dump", "Dump most recent votes from representatives") ("account", boost::program_options::value (), "Defines for other commands") ("file", boost::program_options::value (), "Defines for other commands") ("key", boost::program_options::value (), "Defines the for other commands, hex") ("password", boost::program_options::value (), "Defines for other commands") ("wallet", boost::program_options::value (), "Defines for other commands"); + description_a.add_options () ("account_create", "Insert next deterministic key in to ") ("account_get", "Get account number for the ") ("account_key", "Get the public key for ") ("vacuum", "Compact database. If data_path is missing, the database in data directory is compacted.") ("data_path", boost::program_options::value (), "Use the supplied path as the data directory") ("diagnostics", "Run internal diagnostics") ("key_create", "Generates a adhoc random keypair and prints it to stdout") ("key_expand", "Derive public key and account number from ") ("wallet_add_adhoc", "Insert in to ") ("wallet_create", "Creates a new wallet and prints the ID") ("wallet_change_seed", "Changes seed for to ") ("wallet_decrypt_unsafe", "Decrypts using , !!THIS WILL PRINT YOUR PRIVATE KEY TO STDOUT!!") ("wallet_destroy", "Destroys and all keys it contains") ("wallet_import", "Imports keys in using in to ") ("wallet_list", "Dumps wallet IDs and public keys") ("wallet_remove", "Remove from ") ("wallet_representative_get", "Prints default representative for ") ("wallet_representative_set", "Set as default representative for ") ("vote_dump", "Dump most recent votes from representatives") ("account", boost::program_options::value (), "Defines for other commands") ("file", boost::program_options::value (), "Defines for other commands") ("key", boost::program_options::value (), "Defines the for other commands, hex") ("password", boost::program_options::value (), "Defines for other commands") ("wallet", boost::program_options::value (), "Defines for other commands"); } bool rai::handle_node_options (boost::program_options::variables_map & vm) @@ -3015,6 +3021,46 @@ bool rai::handle_node_options (boost::program_options::variables_map & vm) result = true; } } + else if (vm.count ("vacuum") > 0) + { + try + { + boost::filesystem::path data_path = vm.count ("data_path") ? boost::filesystem::path (vm["data_path"].as ()) : rai::working_path (); + + auto vacuum_path = data_path / "vacuumed.ldb"; + auto source_path = data_path / "data.ldb"; + auto backup_path = data_path / "backup.vacuum.ldb"; + + std::cout << "Vacuuming database copy in " << data_path << std::endl; + std::cout << "This may take a while..." << std::endl; + + // Scope the node so the mdb environment gets cleaned up properly before + // the original file is replaced with the vacuumed file. + bool success = false; + { + inactive_node node (data_path); + success = node.node->copy_with_compaction (vacuum_path); + } + + if (success) + { + // Note that these throw on failure + std::cout << "Finalizing" << std::endl; + boost::filesystem::remove (backup_path); + boost::filesystem::rename (source_path, backup_path); + boost::filesystem::rename (vacuum_path, source_path); + std::cout << "Vacuum completed" << std::endl; + } + } + catch (const boost::filesystem::filesystem_error & ex) + { + std::cerr << "Vacuum failed during a file operation: " << ex.what () << std::endl; + } + catch (...) + { + std::cerr << "Vacuum failed" << std::endl; + } + } else if (vm.count ("diagnostics")) { inactive_node node; @@ -3499,8 +3545,8 @@ bool rai::handle_node_options (boost::program_options::variables_map & vm) return result; } -rai::inactive_node::inactive_node () : -path (rai::working_path ()), +rai::inactive_node::inactive_node (boost::filesystem::path const & path) : +path (path), service (boost::make_shared ()), alarm (*service), work (1, nullptr) diff --git a/rai/node/node.hpp b/rai/node/node.hpp index ab0b032d..1d96f647 100644 --- a/rai/node/node.hpp +++ b/rai/node/node.hpp @@ -482,6 +482,7 @@ public: alarm.service.post (action_a); } void send_keepalive (rai::endpoint const &); + bool copy_with_compaction (boost::filesystem::path const &); void keepalive (std::string const &, uint16_t); void start (); void stop (); @@ -550,7 +551,7 @@ bool handle_node_options (boost::program_options::variables_map &); class inactive_node { public: - inactive_node (); + inactive_node (boost::filesystem::path const & path = rai::working_path ()); ~inactive_node (); boost::filesystem::path path; boost::shared_ptr service;