20 #include <ripple/app/misc/NetworkOPs.h>
21 #include <ripple/basics/Archive.h>
22 #include <ripple/core/ConfigSections.h>
23 #include <ripple/nodestore/DatabaseShard.h>
24 #include <ripple/rpc/ShardArchiveHandler.h>
25 #include <ripple/basics/BasicConfig.h>
26 #include <ripple/rpc/impl/Handler.h>
27 #include <ripple/protocol/ErrorCodes.h>
34 using namespace boost::filesystem;
35 using namespace std::chrono_literals;
40 boost::filesystem::path
46 "path",
"")) /
"download";
85 return instance_.get() !=
nullptr;
92 :
Stoppable(
"ShardArchiveHandler", parent)
94 , j_(app.journal(
"ShardArchiveHandler"))
95 , downloadDir_(getDownloadDirectory(app.config()))
96 , timer_(app_.getIOService())
113 sqliteDB_ = std::make_unique<DatabaseCon>(
122 <<
" in function: " << __func__;
135 using namespace boost::filesystem;
140 sqliteDB_ = std::make_unique<DatabaseCon>(
148 soci::rowset<soci::row> rs = (session.prepare
149 <<
"SELECT * FROM State;");
153 for (
auto it = rs.begin(); it != rs.end(); ++it)
159 JLOG(
j_.
error()) <<
"Failed to parse url: "
165 add(it->get<
int>(0), std::move(url), lock);
179 <<
" in function: " << __func__;
207 if (!
add(shardIndex, std::forward<parsedURL>(url.first), lock))
212 session <<
"INSERT INTO State VALUES (:index, :url);",
213 soci::use(shardIndex),
214 soci::use(url.second);
226 "Download and import already in progress";
230 auto const it {
archives_.find(shardIndex)};
232 return url == it->second;
237 archives_.emplace(shardIndex, std::move(url));
249 "No shard store available";
255 "Archives already being processed";
261 "No archives to process";
273 downloader_ = std::make_shared<DatabaseDownloader>(
280 "exception: " << e.
what();
304 auto const shardIndex {
archives_.begin()->first};
308 create_directory(dstDir);
313 "exception: " << e.
what();
321 auto const& url {
archives_.begin()->second};
331 dstDir /
"archive.tar.lz4",
333 ptr, std::placeholders::_1)))
335 std::lock_guard<std::mutex> l(m_);
352 if (!is_regular_file(dstPath))
356 "Downloading shard id " << ar->first <<
357 " form URL " << ar->second.domain << ar->second.path;
366 "exception: " << e.
what();
379 auto const mode {ptr->app_.getOPs().getOperatingMode()};
387 [=, dstPath = std::move(dstPath), ptr = std::move(ptr)]
388 (boost::system::error_code
const& ec)
390 if (ec != boost::asio::error::operation_aborted)
391 ptr->complete(std::move(dstPath));
396 ptr->process(dstPath);
413 auto const shardDir {dstPath.parent_path() /
std::to_string(shardIndex)};
420 if (!is_directory(shardDir))
423 "Shard " << shardIndex <<
424 " mismatches archive shard directory";
431 "exception: " << e.
what();
439 "Importing shard " << shardIndex;
444 "Shard " << shardIndex <<
" downloaded and imported";
450 auto const shardIndex {
archives_.begin()->first};
456 session <<
"DELETE FROM State WHERE ShardIndex = :index;",
457 soci::use(shardIndex);
467 "exception: " << e.
what();
484 session <<
"DROP TABLE State;";
497 <<
" in function: " << __func__;
static boost::filesystem::path getDownloadDirectory(Config const &config)
std::shared_ptr< DatabaseDownloader > downloader_
const boost::filesystem::path downloadDir_
bool start()
Starts downloading and importing archives.
bool add(std::uint32_t shardIndex, std::pair< parsedURL, std::string > &&url)
void stopped()
Called by derived classes to indicate that the stoppable has stopped.
static pointer recoverInstance(Application &app, Stoppable &parent)
static std::string shardDatabase()
std::shared_ptr< ShardArchiveHandler > pointer
void onStop() override
Override called when the stop notification is issued.
void doRelease(std::lock_guard< std::mutex > const &)
virtual NodeStore::DatabaseShard * getShardStore()=0
static constexpr std::array< char const *, 3 > ShardArchiveHandlerDBInit
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
void extractTarLz4(boost::filesystem::path const &src, boost::filesystem::path const &dst)
Extract a tar archive compressed with lz4.
static constexpr std::array< char const *, 2 > DownloaderDBPragma
boost::asio::basic_waitable_timer< std::chrono::steady_clock > timer_
Provides an interface for starting and stopping.
void process(boost::filesystem::path const &dstPath)
T shared_from_this(T... args)
void remove(std::lock_guard< std::mutex > &)
virtual Config & config()=0
virtual JobQueue & getJobQueue()=0
bool parseUrl(parsedURL &pUrl, std::string const &strUrl)
std::unique_ptr< DatabaseCon > sqliteDB_
void complete(boost::filesystem::path dstPath)
virtual boost::asio::io_service & getIOService()=0
static constexpr auto stateDBName
virtual bool importShard(std::uint32_t shardIndex, boost::filesystem::path const &srcDir)=0
Import a shard into the shard database.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::map< std::uint32_t, parsedURL > archives_
virtual bool prepareShard(std::uint32_t shardIndex)=0
Prepare a shard index to be imported into the database.
static bool hasInstance()
Handles the download and import one or more shard archives.
ShardArchiveHandler()=delete
static std::mutex instance_mutex_
virtual void removePreShard(std::uint32_t shardIndex)=0
Remove a previously prepared shard index for import.
static pointer getInstance()
bool next(std::lock_guard< std::mutex > &l)
T & get(EitherAmount &amt)
Section & section(std::string const &name)
Returns the section with the given name.
@ FULL
we have the ledger and can even validate