20 #include <ripple/app/misc/NetworkOPs.h>
21 #include <ripple/basics/Archive.h>
22 #include <ripple/basics/BasicConfig.h>
23 #include <ripple/core/ConfigSections.h>
24 #include <ripple/nodestore/DatabaseShard.h>
25 #include <ripple/protocol/ErrorCodes.h>
26 #include <ripple/rpc/ShardArchiveHandler.h>
27 #include <ripple/rpc/impl/Handler.h>
34 using namespace boost::filesystem;
35 using namespace std::chrono_literals;
40 boost::filesystem::path
87 return instance_.get() !=
nullptr;
94 :
Stoppable(
"ShardArchiveHandler", parent)
96 , j_(app.journal(
"ShardArchiveHandler"))
97 , downloadDir_(getDownloadDirectory(app.config()))
98 , timer_(app_.getIOService())
115 sqliteDB_ = std::make_unique<DatabaseCon>(
124 <<
" in function: " << __func__;
137 using namespace boost::filesystem;
143 sqliteDB_ = std::make_unique<DatabaseCon>(
151 soci::rowset<soci::row> rs =
152 (session.prepare <<
"SELECT * FROM State;");
156 for (
auto it = rs.begin(); it != rs.end(); ++it)
163 <<
"Failed to parse url: " << it->get<
std::string>(1);
168 add(it->get<
int>(0), std::move(url), lock);
182 <<
" in function: " << __func__;
211 if (!
add(shardIndex, std::forward<parsedURL>(url.first), lock))
216 session <<
"INSERT INTO State VALUES (:index, :url);",
217 soci::use(shardIndex), soci::use(url.second);
230 JLOG(
j_.
error()) <<
"Download and import already in progress";
234 auto const it{
archives_.find(shardIndex)};
236 return url == it->second;
241 archives_.emplace(shardIndex, std::move(url));
252 JLOG(
j_.
error()) <<
"No shard store available";
257 JLOG(
j_.
warn()) <<
"Archives already being processed";
262 JLOG(
j_.
warn()) <<
"No archives to process";
274 downloader_ = std::make_shared<DatabaseDownloader>(
304 auto const shardIndex{
archives_.begin()->first};
308 create_directory(dstDir);
320 auto const& url{
archives_.begin()->second};
323 "ShardArchiveHandler",
330 dstDir /
"archive.tar.lz4",
334 std::placeholders::_1)))
336 std::lock_guard<std::mutex> l(m_);
353 if (!is_regular_file(dstPath))
357 <<
"Downloading shard id " << ar->first <<
" form URL "
358 << ar->second.domain << ar->second.path;
376 "ShardArchiveHandler",
379 auto const mode{ptr->app_.getOPs().getOperatingMode()};
388 [=, dstPath = std::move(dstPath), ptr = std::move(ptr)](
389 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))
422 JLOG(
j_.
error()) <<
"Shard " << shardIndex
423 <<
" mismatches archive shard directory";
436 JLOG(
j_.
error()) <<
"Importing shard " << shardIndex;
440 JLOG(
j_.
debug()) <<
"Shard " << shardIndex <<
" downloaded and imported";
446 auto const shardIndex{
archives_.begin()->first};
452 session <<
"DELETE FROM State WHERE ShardIndex = :index;",
453 soci::use(shardIndex);
479 session <<
"DROP TABLE State;";
492 <<
" 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