mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	Tonstorage: fix compilation on some platforms, minor improvements (#578)
* Fix compilation errors on some platforms * Update db after "copy inside" * Link rldp2 with blas * Add "--" flag to some commands
This commit is contained in:
		
							parent
							
								
									a1d8a5e4f3
								
							
						
					
					
						commit
						c9555615e9
					
				
					 11 changed files with 103 additions and 51 deletions
				
			
		|  | @ -7,6 +7,9 @@ endif() | |||
| if (NOT GSL_FOUND) | ||||
|   find_package(GSL) | ||||
| endif() | ||||
| if (NOT BLAS_FOUND) | ||||
|   find_package(BLAS) | ||||
| endif() | ||||
| 
 | ||||
| set(RLDP_SOURCE | ||||
|   Ack.cpp | ||||
|  | @ -50,8 +53,8 @@ target_include_directories(rldp PUBLIC | |||
|   $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/..  | ||||
|   ${OPENSSL_INCLUDE_DIR} | ||||
| ) | ||||
| if (GSL_FOUND) | ||||
|   target_link_libraries(rldp2 PRIVATE gsl) | ||||
| if (GSL_FOUND AND BLAS_FOUND) | ||||
|   target_link_libraries(rldp2 PRIVATE gsl blas) | ||||
|   target_compile_definitions(rldp2 PRIVATE -DTON_HAVE_GSL=1) | ||||
| endif() | ||||
| target_link_libraries(rldp2 PUBLIC tdutils tdactor fec adnl tl_api) | ||||
|  |  | |||
|  | @ -454,6 +454,12 @@ void NodeActor::load_from(td::optional<TorrentMeta> meta, std::string files_path | |||
|   loop(); | ||||
| } | ||||
| 
 | ||||
| void NodeActor::copy_to_new_root_dir(std::string new_root_dir, td::Promise<td::Unit> promise) { | ||||
|   TRY_STATUS_PROMISE(promise, torrent_.copy_to(new_root_dir)); | ||||
|   db_store_torrent(); | ||||
|   promise.set_result(td::Unit()); | ||||
| } | ||||
| 
 | ||||
| void NodeActor::tear_down() { | ||||
|   for (auto &promise : wait_for_completion_) { | ||||
|     promise.set_error(td::Status::Error("Torrent closed")); | ||||
|  |  | |||
|  | @ -92,6 +92,7 @@ class NodeActor : public td::actor::Actor { | |||
|   void set_file_priority_by_name(std::string name, td::uint8 priority, td::Promise<bool> promise); | ||||
| 
 | ||||
|   void load_from(td::optional<TorrentMeta> meta, std::string files_path, td::Promise<td::Unit> promise); | ||||
|   void copy_to_new_root_dir(std::string new_root_dir, td::Promise<td::Unit> promise); | ||||
| 
 | ||||
|   void wait_for_completion(td::Promise<td::Unit> promise); | ||||
|   void get_peers_info(td::Promise<tl_object_ptr<ton_api::storage_daemon_peerList>> promise); | ||||
|  |  | |||
|  | @ -21,6 +21,8 @@ | |||
| #include "td/db/RocksDb.h" | ||||
| #include "td/actor/MultiPromise.h" | ||||
| 
 | ||||
| namespace ton { | ||||
| 
 | ||||
| static overlay::OverlayIdFull get_overlay_id(td::Bits256 hash) { | ||||
|   td::BufferSlice hash_str(hash.as_slice()); | ||||
|   return overlay::OverlayIdFull(std::move(hash_str)); | ||||
|  | @ -126,11 +128,27 @@ td::unique_ptr<NodeActor::Callback> StorageManager::create_callback( | |||
|   return td::make_unique<Callback>(actor_id(this), hash, std::move(closing_state)); | ||||
| } | ||||
| 
 | ||||
| void StorageManager::add_torrent(Torrent torrent, bool start_download, bool allow_upload, | ||||
| void StorageManager::add_torrent(Torrent torrent, bool start_download, bool allow_upload, bool copy_inside, | ||||
|                                  td::Promise<td::Unit> promise) { | ||||
|   td::Bits256 hash = torrent.get_hash(); | ||||
|   TRY_STATUS_PROMISE(promise, add_torrent_impl(std::move(torrent), start_download, allow_upload)); | ||||
|   db_store_torrent_list(); | ||||
|   promise.set_result(td::Unit()); | ||||
|   if (!copy_inside) { | ||||
|     promise.set_result(td::Unit()); | ||||
|     return; | ||||
|   } | ||||
|   TorrentEntry& entry = torrents_[hash]; | ||||
|   std::string new_dir = db_root_ + "/torrent-files/" + hash.to_hex(); | ||||
|   LOG(INFO) << "Copy torrent to " << new_dir; | ||||
|   td::actor::send_closure( | ||||
|       entry.actor, &NodeActor::copy_to_new_root_dir, std::move(new_dir), | ||||
|       [SelfId = actor_id(this), hash, promise = std::move(promise)](td::Result<td::Unit> R) mutable { | ||||
|         if (R.is_error()) { | ||||
|           LOG(WARNING) << "Copy torrent: " << R.error(); | ||||
|           td::actor::send_closure(SelfId, &StorageManager::remove_torrent, hash, false, [](td::Result<td::Unit> R) {}); | ||||
|         } | ||||
|         promise.set_result(std::move(R)); | ||||
|       }); | ||||
| } | ||||
| 
 | ||||
| td::Status StorageManager::add_torrent_impl(Torrent torrent, bool start_download, bool allow_upload) { | ||||
|  | @ -156,7 +174,7 @@ void StorageManager::add_torrent_by_meta(TorrentMeta meta, std::string root_dir, | |||
|   Torrent::Options options; | ||||
|   options.root_dir = root_dir.empty() ? db_root_ + "/torrent-files/" + hash.to_hex() : root_dir; | ||||
|   TRY_RESULT_PROMISE(promise, torrent, Torrent::open(std::move(options), std::move(meta))); | ||||
|   add_torrent(std::move(torrent), start_download, allow_upload, std::move(promise)); | ||||
|   add_torrent(std::move(torrent), start_download, allow_upload, false, std::move(promise)); | ||||
| } | ||||
| 
 | ||||
| void StorageManager::add_torrent_by_hash(td::Bits256 hash, std::string root_dir, bool start_download, bool allow_upload, | ||||
|  | @ -164,7 +182,7 @@ void StorageManager::add_torrent_by_hash(td::Bits256 hash, std::string root_dir, | |||
|   Torrent::Options options; | ||||
|   options.root_dir = root_dir.empty() ? db_root_ + "/torrent-files/" + hash.to_hex() : root_dir; | ||||
|   TRY_RESULT_PROMISE(promise, torrent, Torrent::open(std::move(options), hash)); | ||||
|   add_torrent(std::move(torrent), start_download, allow_upload, std::move(promise)); | ||||
|   add_torrent(std::move(torrent), start_download, allow_upload, false, std::move(promise)); | ||||
| } | ||||
| 
 | ||||
| void StorageManager::set_active_download(td::Bits256 hash, bool active, td::Promise<td::Unit> promise) { | ||||
|  | @ -273,3 +291,5 @@ void StorageManager::get_peers_info(td::Bits256 hash, | |||
|   TRY_RESULT_PROMISE(promise, entry, get_torrent(hash)); | ||||
|   td::actor::send_closure(entry->actor, &NodeActor::get_peers_info, std::move(promise)); | ||||
| } | ||||
| 
 | ||||
| }  // namespace ton
 | ||||
|  | @ -23,7 +23,7 @@ | |||
| #include "storage/PeerManager.h" | ||||
| #include "storage/db.h" | ||||
| 
 | ||||
| using namespace ton; | ||||
| namespace ton { | ||||
| 
 | ||||
| class StorageManager : public td::actor::Actor { | ||||
|  public: | ||||
|  | @ -39,9 +39,12 @@ class StorageManager : public td::actor::Actor { | |||
| 
 | ||||
|   void start_up() override; | ||||
| 
 | ||||
|   void add_torrent(Torrent torrent, bool start_download, bool allow_upload, td::Promise<td::Unit> promise); | ||||
|   void add_torrent_by_meta(TorrentMeta meta, std::string root_dir, bool start_download, bool allow_upload, td::Promise<td::Unit> promise); | ||||
|   void add_torrent_by_hash(td::Bits256 hash, std::string root_dir, bool start_download, bool allow_upload, td::Promise<td::Unit> promise); | ||||
|   void add_torrent(Torrent torrent, bool start_download, bool allow_upload, bool copy_inside, | ||||
|                    td::Promise<td::Unit> promise); | ||||
|   void add_torrent_by_meta(TorrentMeta meta, std::string root_dir, bool start_download, bool allow_upload, | ||||
|                            td::Promise<td::Unit> promise); | ||||
|   void add_torrent_by_hash(td::Bits256 hash, std::string root_dir, bool start_download, bool allow_upload, | ||||
|                            td::Promise<td::Unit> promise); | ||||
| 
 | ||||
|   void set_active_download(td::Bits256 hash, bool active, td::Promise<td::Unit> promise); | ||||
|   void set_active_upload(td::Bits256 hash, bool active, td::Promise<td::Unit> promise); | ||||
|  | @ -105,4 +108,6 @@ class StorageManager : public td::actor::Actor { | |||
|   void db_store_torrent_list(); | ||||
| 
 | ||||
|   void on_torrent_closed(Torrent torrent, std::shared_ptr<TorrentEntry::ClosingState> closing_state); | ||||
| }; | ||||
| }; | ||||
| 
 | ||||
| }  // namespace ton
 | ||||
|  |  | |||
|  | @ -24,6 +24,8 @@ | |||
| #include "common/delay.h" | ||||
| #include "td/actor/MultiPromise.h" | ||||
| 
 | ||||
| namespace ton { | ||||
| 
 | ||||
| td::Result<ProviderParams> ProviderParams::create(const tl_object_ptr<ton_api::storage_daemon_provider_params>& obj) { | ||||
|   ProviderParams p; | ||||
|   p.accept_new_contracts = obj->accept_new_contracts_; | ||||
|  | @ -852,3 +854,5 @@ StorageProvider::Config::Config(const tl_object_ptr<ton_api::storage_daemon_prov | |||
| tl_object_ptr<ton_api::storage_daemon_providerConfig> StorageProvider::Config::tl() const { | ||||
|   return create_tl_object<ton_api::storage_daemon_providerConfig>(max_contracts, max_total_size); | ||||
| } | ||||
| 
 | ||||
| }  // namespace ton
 | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ | |||
| #include "smc-util.h" | ||||
| #include "storage/MicrochunkTree.h" | ||||
| 
 | ||||
| using namespace ton; | ||||
| namespace ton { | ||||
| 
 | ||||
| struct ProviderParams { | ||||
|   bool accept_new_contracts = false; | ||||
|  | @ -110,7 +110,7 @@ class StorageProvider : public td::actor::Actor { | |||
|   void init_new_storage_contract(ContractAddress address, StorageContract& contract); | ||||
|   void downloaded_torrent(ContractAddress address, MicrochunkTree microchunk_tree); | ||||
|   void after_contract_downloaded(ContractAddress address, td::Timestamp retry_until = td::Timestamp::in(30.0), | ||||
|                              td::Timestamp retry_false_until = td::Timestamp::never()); | ||||
|                                  td::Timestamp retry_false_until = td::Timestamp::never()); | ||||
|   void activate_contract_cont(ContractAddress address); | ||||
|   void activated_storage_contract(ContractAddress address); | ||||
|   void do_close_storage_contract(ContractAddress address); | ||||
|  | @ -125,3 +125,5 @@ class StorageProvider : public td::actor::Actor { | |||
|   void got_next_proof(ContractAddress address, td::Result<td::Ref<vm::Cell>> R); | ||||
|   void sent_next_proof(ContractAddress address); | ||||
| }; | ||||
| 
 | ||||
| }  // namespace ton
 | ||||
|  | @ -20,6 +20,8 @@ | |||
| #include "keys/encryptor.h" | ||||
| #include "smartcont/provider-code.h" | ||||
| 
 | ||||
| namespace ton { | ||||
| 
 | ||||
| static void smc_forget(td::actor::ActorId<tonlib::TonlibClientWrapper> client, td::int64 id) { | ||||
|   auto query = create_tl_object<tonlib_api::smc_forget>(id); | ||||
|   td::actor::send_closure(client, &tonlib::TonlibClientWrapper::send_request<tonlib_api::smc_forget>, std::move(query), | ||||
|  | @ -226,7 +228,7 @@ void FabricContractWrapper::loaded_last_transactions( | |||
| void FabricContractWrapper::run_get_method( | ||||
|     std::string method, std::vector<tl_object_ptr<tonlib_api::tvm_StackEntry>> args, | ||||
|     td::Promise<std::vector<tl_object_ptr<tonlib_api::tvm_StackEntry>>> promise) { | ||||
|   ::run_get_method(address_, client_, std::move(method), std::move(args), std::move(promise)); | ||||
|   ton::run_get_method(address_, client_, std::move(method), std::move(args), std::move(promise)); | ||||
| } | ||||
| 
 | ||||
| void FabricContractWrapper::send_internal_message(ContractAddress dest, td::RefInt256 coins, vm::CellSlice body, | ||||
|  | @ -485,3 +487,5 @@ void get_storage_contract_data(ContractAddress address, td::actor::ActorId<tonli | |||
|                                    rate_per_mb_day, max_span, last_proof_time, torrent_hash}; | ||||
|       })); | ||||
| } | ||||
| 
 | ||||
| }  // namespace ton
 | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ | |||
| #include <queue> | ||||
| #include "keyring/keyring.h" | ||||
| 
 | ||||
| using namespace ton; | ||||
| namespace ton { | ||||
| 
 | ||||
| struct ContractAddress { | ||||
|   WorkchainId wc = workchainIdNotYet; | ||||
|  | @ -181,4 +181,6 @@ struct StorageContractData { | |||
| }; | ||||
| 
 | ||||
| void get_storage_contract_data(ContractAddress address, td::actor::ActorId<tonlib::TonlibClientWrapper> client, | ||||
|                                td::Promise<StorageContractData> promise); | ||||
|                                td::Promise<StorageContractData> promise); | ||||
| 
 | ||||
| }  // namespace ton
 | ||||
|  | @ -39,7 +39,7 @@ | |||
| #include "common/refint.h" | ||||
| #include "crypto/block/block.h" | ||||
| 
 | ||||
| using namespace ton; | ||||
| namespace ton { | ||||
| 
 | ||||
| bool is_whitespace(char c) { | ||||
|   return strchr(" \t\n\r", c) != nullptr; | ||||
|  | @ -302,8 +302,9 @@ class StorageDaemonCli : public td::actor::Actor { | |||
|       bool copy = false; | ||||
|       std::string description; | ||||
|       bool json = false; | ||||
|       bool no_more_flags = false; | ||||
|       for (size_t i = 1; i < tokens.size(); ++i) { | ||||
|         if (!tokens[i].empty() && tokens[i][0] == '-') { | ||||
|         if (!tokens[i].empty() && tokens[i][0] == '-' && !no_more_flags) { | ||||
|           if (tokens[i] == "-d") { | ||||
|             ++i; | ||||
|             if (i == tokens.size()) { | ||||
|  | @ -324,6 +325,10 @@ class StorageDaemonCli : public td::actor::Actor { | |||
|             json = true; | ||||
|             continue; | ||||
|           } | ||||
|           if (tokens[i] == "--") { | ||||
|             no_more_flags = true; | ||||
|             continue; | ||||
|           } | ||||
|           return td::Status::Error(PSTRING() << "Unknown flag " << tokens[i]); | ||||
|         } | ||||
|         if (found_path) { | ||||
|  | @ -343,8 +348,9 @@ class StorageDaemonCli : public td::actor::Actor { | |||
|       bool upload = true; | ||||
|       bool json = false; | ||||
|       td::optional<std::vector<std::string>> partial; | ||||
|       bool no_more_flags = false; | ||||
|       for (size_t i = 1; i < tokens.size(); ++i) { | ||||
|         if (!tokens[i].empty() && tokens[i][0] == '-') { | ||||
|         if (!tokens[i].empty() && tokens[i][0] == '-' && !no_more_flags) { | ||||
|           if (tokens[i] == "-d") { | ||||
|             ++i; | ||||
|             if (i == tokens.size()) { | ||||
|  | @ -369,6 +375,10 @@ class StorageDaemonCli : public td::actor::Actor { | |||
|             partial = std::vector<std::string>(tokens.begin() + i + 1, tokens.end()); | ||||
|             break; | ||||
|           } | ||||
|           if (tokens[i] == "--") { | ||||
|             no_more_flags = true; | ||||
|             continue; | ||||
|           } | ||||
|           return td::Status::Error(PSTRING() << "Unknown flag " << tokens[i]); | ||||
|         } | ||||
|         if (param) { | ||||
|  | @ -542,8 +552,9 @@ class StorageDaemonCli : public td::actor::Actor { | |||
|       td::optional<std::string> provider_address; | ||||
|       td::optional<std::string> rate; | ||||
|       td::optional<td::uint32> max_span; | ||||
|       bool no_more_flags = false; | ||||
|       for (size_t i = 1; i < tokens.size(); ++i) { | ||||
|         if (!tokens[i].empty() && tokens[i][0] == '-') { | ||||
|         if (!tokens[i].empty() && tokens[i][0] == '-' && !no_more_flags) { | ||||
|           if (tokens[i] == "--query-id") { | ||||
|             ++i; | ||||
|             TRY_RESULT_PREFIX_ASSIGN(query_id, td::to_integer_safe<td::uint64>(tokens[i]), "Invalid query id: "); | ||||
|  | @ -564,6 +575,10 @@ class StorageDaemonCli : public td::actor::Actor { | |||
|             TRY_RESULT_PREFIX_ASSIGN(max_span, td::to_integer_safe<td::uint8>(tokens[i]), "Invalid max span: "); | ||||
|             continue; | ||||
|           } | ||||
|           if (tokens[i] == "--") { | ||||
|             no_more_flags = true; | ||||
|             continue; | ||||
|           } | ||||
|           return td::Status::Error(PSTRING() << "Unknown flag " << tokens[i]); | ||||
|         } | ||||
|         if (cnt == 0) { | ||||
|  | @ -1742,12 +1757,14 @@ class StorageDaemonCli : public td::actor::Actor { | |||
|   } | ||||
| }; | ||||
| 
 | ||||
| }  // namespace ton
 | ||||
| 
 | ||||
| int main(int argc, char* argv[]) { | ||||
|   SET_VERBOSITY_LEVEL(verbosity_INFO); | ||||
|   td::set_default_failure_signal_handler(); | ||||
|   td::IPAddress ip_addr; | ||||
|   PrivateKey client_private_key; | ||||
|   PublicKey server_public_key; | ||||
|   ton::PrivateKey client_private_key; | ||||
|   ton::PublicKey server_public_key; | ||||
|   std::vector<std::string> commands; | ||||
|   td::OptionParser p; | ||||
|   p.set_description("command-line interface for storage-daemon"); | ||||
|  | @ -1772,12 +1789,12 @@ int main(int argc, char* argv[]) { | |||
|   p.add_option('c', "cmd", "execute command", [&](td::Slice arg) { commands.push_back(arg.str()); }); | ||||
|   p.add_checked_option('k', "key", "private key", [&](td::Slice arg) { | ||||
|     TRY_RESULT_PREFIX(data, td::read_file(arg.str()), "failed to read: "); | ||||
|     TRY_RESULT_ASSIGN(client_private_key, PrivateKey::import(data)); | ||||
|     TRY_RESULT_ASSIGN(client_private_key, ton::PrivateKey::import(data)); | ||||
|     return td::Status::OK(); | ||||
|   }); | ||||
|   p.add_checked_option('p', "pub", "server public key", [&](td::Slice arg) { | ||||
|     TRY_RESULT_PREFIX(data, td::read_file(arg.str()), "failed to read: "); | ||||
|     TRY_RESULT_ASSIGN(server_public_key, PublicKey::import(data)); | ||||
|     TRY_RESULT_ASSIGN(server_public_key, ton::PublicKey::import(data)); | ||||
|     return td::Status::OK(); | ||||
|   }); | ||||
| 
 | ||||
|  | @ -1791,8 +1808,8 @@ int main(int argc, char* argv[]) { | |||
| 
 | ||||
|   td::actor::Scheduler scheduler({0}); | ||||
|   scheduler.run_in_context([&] { | ||||
|     td::actor::create_actor<StorageDaemonCli>("console", ip_addr, client_private_key, server_public_key, | ||||
|                                               std::move(commands)) | ||||
|     td::actor::create_actor<ton::StorageDaemonCli>("console", ip_addr, client_private_key, server_public_key, | ||||
|                                                    std::move(commands)) | ||||
|         .release(); | ||||
|   }); | ||||
|   scheduler.run(); | ||||
|  |  | |||
|  | @ -44,7 +44,7 @@ | |||
| #endif | ||||
| #include <iostream> | ||||
| 
 | ||||
| using namespace ton; | ||||
| namespace ton { | ||||
| 
 | ||||
| td::BufferSlice create_query_error(td::CSlice message) { | ||||
|   return create_serialize_tl_object<ton_api::storage_daemon_queryError>(message.str()); | ||||
|  | @ -293,29 +293,15 @@ class StorageDaemon : public td::actor::Actor { | |||
|           options.description = std::move(query.description_); | ||||
|           TRY_RESULT_PROMISE(promise, torrent, Torrent::Creator::create_from_path(std::move(options), query.path_)); | ||||
|           td::Bits256 hash = torrent.get_hash(); | ||||
|           td::Promise<td::Unit> P = [manager, hash, promise = std::move(promise)](td::Result<td::Unit> R) mutable { | ||||
|             TRY_RESULT_PROMISE(promise, unit, std::move(R)); | ||||
|             get_torrent_info_full_serialized(manager, hash, std::move(promise)); | ||||
|           }; | ||||
|           if (query.copy_inside_) { | ||||
|             P = [P = std::move(P), manager, hash, db_root](td::Result<td::Unit> R) mutable { | ||||
|               TRY_RESULT_PROMISE(P, unit, std::move(R)); | ||||
|               td::actor::send_closure(manager, &StorageManager::with_torrent, hash, | ||||
|                                       P.wrap([=](NodeActor::NodeState state) -> td::Status { | ||||
|                                         std::string dir = db_root + "/torrent/torrent-files/" + hash.to_hex(); | ||||
|                                         LOG(INFO) << "Copying torrent to " << dir; | ||||
|                                         auto S = state.torrent.copy_to(dir); | ||||
|                                         if (S.is_error()) { | ||||
|                                           LOG(WARNING) << "Copying torrent to " << dir << ": " << S; | ||||
|                                           td::actor::send_closure(manager, &StorageManager::remove_torrent, hash, false, | ||||
|                                                                   [](td::Result<td::Unit>) {}); | ||||
|                                         } | ||||
|                                         return S; | ||||
|                                       })); | ||||
|             }; | ||||
|           } | ||||
|           td::actor::send_closure(manager, &StorageManager::add_torrent, std::move(torrent), false, query.allow_upload_, | ||||
|                                   std::move(P)); | ||||
|                                   query.copy_inside_, | ||||
|                                   [manager, hash, promise = std::move(promise)](td::Result<td::Unit> R) mutable { | ||||
|                                     if (R.is_error()) { | ||||
|                                       promise.set_error(R.move_as_error()); | ||||
|                                       return; | ||||
|                                     } | ||||
|                                     get_torrent_info_full_serialized(manager, hash, std::move(promise)); | ||||
|                                   }); | ||||
|         }, | ||||
|         td::Timestamp::now()); | ||||
|   } | ||||
|  | @ -882,6 +868,8 @@ class StorageDaemon : public td::actor::Actor { | |||
|   } | ||||
| }; | ||||
| 
 | ||||
| }  // namespace ton
 | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
|   SET_VERBOSITY_LEVEL(verbosity_WARNING); | ||||
|   td::set_default_failure_signal_handler().ensure(); | ||||
|  | @ -954,8 +942,8 @@ int main(int argc, char *argv[]) { | |||
| 
 | ||||
|   scheduler.run_in_context([&] { | ||||
|     p.run(argc, argv).ensure(); | ||||
|     td::actor::create_actor<StorageDaemon>("storage-daemon", ip_addr, client_mode, global_config, db_root, control_port, | ||||
|                                            enable_storage_provider) | ||||
|     td::actor::create_actor<ton::StorageDaemon>("storage-daemon", ip_addr, client_mode, global_config, db_root, | ||||
|                                                 control_port, enable_storage_provider) | ||||
|         .release(); | ||||
|   }); | ||||
|   while (scheduler.run(1)) { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue