mirror of
https://github.com/XRPLF/clio.git
synced 2025-11-10 06:45:50 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4468302852 | ||
|
|
a704cf7cfe | ||
|
|
05d09cc352 | ||
|
|
ae96ac7baf | ||
|
|
4579fa2f26 |
@@ -45,7 +45,6 @@ target_sources(clio PRIVATE
|
||||
## Backend
|
||||
src/backend/BackendInterface.cpp
|
||||
src/backend/CassandraBackend.cpp
|
||||
src/backend/LayeredCache.cpp
|
||||
src/backend/Pg.cpp
|
||||
src/backend/PostgresBackend.cpp
|
||||
src/backend/SimpleCache.cpp
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
[](https://github.com/legleux/clio/actions/workflows/build.yml)
|
||||
|
||||
|
||||
**Status:** This software is in beta mode. We encourage anyone to try it out and
|
||||
report any issues they discover. Version 1.0 coming soon.
|
||||
|
||||
# Clio
|
||||
Clio is an XRP Ledger API server. Clio is optimized for RPC calls, over WebSocket or JSON-RPC. Validated
|
||||
historical ledger and transaction data are stored in a more space-efficient format,
|
||||
@@ -167,4 +161,4 @@ deleted to free up space.
|
||||
rotate the current log file.
|
||||
|
||||
Note, time-based log rotation occurs dependently on size-based log rotation, where if a
|
||||
size-based log rotation occurs, the timer for the time-based rotation will reset.
|
||||
size-based log rotation occurs, the timer for the time-based rotation will reset.
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
#include <backend/LayeredCache.h>
|
||||
namespace Backend {
|
||||
|
||||
void
|
||||
LayeredCache::insert(
|
||||
ripple::uint256 const& key,
|
||||
Blob const& value,
|
||||
uint32_t seq)
|
||||
{
|
||||
auto entry = map_[key];
|
||||
// stale insert, do nothing
|
||||
if (seq <= entry.recent.seq)
|
||||
return;
|
||||
entry.old = entry.recent;
|
||||
entry.recent = {seq, value};
|
||||
if (value.empty())
|
||||
pendingDeletes_.push_back(key);
|
||||
if (!entry.old.blob.empty())
|
||||
pendingSweeps_.push_back(key);
|
||||
}
|
||||
|
||||
std::optional<Blob>
|
||||
LayeredCache::select(CacheEntry const& entry, uint32_t seq) const
|
||||
{
|
||||
if (seq < entry.old.seq)
|
||||
return {};
|
||||
if (seq < entry.recent.seq && !entry.old.blob.empty())
|
||||
return entry.old.blob;
|
||||
if (!entry.recent.blob.empty())
|
||||
return entry.recent.blob;
|
||||
return {};
|
||||
}
|
||||
void
|
||||
LayeredCache::update(std::vector<LedgerObject> const& blobs, uint32_t seq)
|
||||
{
|
||||
std::unique_lock lck{mtx_};
|
||||
if (seq > mostRecentSequence_)
|
||||
mostRecentSequence_ = seq;
|
||||
for (auto const& k : pendingSweeps_)
|
||||
{
|
||||
auto e = map_[k];
|
||||
e.old = {};
|
||||
}
|
||||
for (auto const& k : pendingDeletes_)
|
||||
{
|
||||
map_.erase(k);
|
||||
}
|
||||
for (auto const& b : blobs)
|
||||
{
|
||||
insert(b.key, b.blob, seq);
|
||||
}
|
||||
}
|
||||
std::optional<LedgerObject>
|
||||
LayeredCache::getSuccessor(ripple::uint256 const& key, uint32_t seq) const
|
||||
{
|
||||
ripple::uint256 curKey = key;
|
||||
while (true)
|
||||
{
|
||||
std::shared_lock lck{mtx_};
|
||||
if (seq < mostRecentSequence_ - 1)
|
||||
return {};
|
||||
auto e = map_.upper_bound(curKey);
|
||||
if (e == map_.end())
|
||||
return {};
|
||||
auto const& entry = e->second;
|
||||
auto blob = select(entry, seq);
|
||||
if (!blob)
|
||||
{
|
||||
curKey = e->first;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
return {{e->first, *blob}};
|
||||
}
|
||||
}
|
||||
std::optional<LedgerObject>
|
||||
LayeredCache::getPredecessor(ripple::uint256 const& key, uint32_t seq) const
|
||||
{
|
||||
ripple::uint256 curKey = key;
|
||||
std::shared_lock lck{mtx_};
|
||||
while (true)
|
||||
{
|
||||
if (seq < mostRecentSequence_ - 1)
|
||||
return {};
|
||||
auto e = map_.lower_bound(curKey);
|
||||
--e;
|
||||
if (e == map_.begin())
|
||||
return {};
|
||||
auto const& entry = e->second;
|
||||
auto blob = select(entry, seq);
|
||||
if (!blob)
|
||||
{
|
||||
curKey = e->first;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
return {{e->first, *blob}};
|
||||
}
|
||||
}
|
||||
std::optional<Blob>
|
||||
LayeredCache::get(ripple::uint256 const& key, uint32_t seq) const
|
||||
{
|
||||
std::shared_lock lck{mtx_};
|
||||
auto e = map_.find(key);
|
||||
if (e == map_.end())
|
||||
return {};
|
||||
auto const& entry = e->second;
|
||||
return select(entry, seq);
|
||||
}
|
||||
} // namespace Backend
|
||||
@@ -1,73 +0,0 @@
|
||||
#ifndef CLIO_LAYEREDCACHE_H_INCLUDED
|
||||
#define CLIO_LAYEREDCACHE_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/base_uint.h>
|
||||
#include <backend/Types.h>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
namespace Backend {
|
||||
class LayeredCache
|
||||
{
|
||||
struct SeqBlobPair
|
||||
{
|
||||
uint32_t seq;
|
||||
Blob blob;
|
||||
};
|
||||
struct CacheEntry
|
||||
{
|
||||
SeqBlobPair recent;
|
||||
SeqBlobPair old;
|
||||
};
|
||||
|
||||
std::map<ripple::uint256, CacheEntry> map_;
|
||||
std::vector<ripple::uint256> pendingDeletes_;
|
||||
std::vector<ripple::uint256> pendingSweeps_;
|
||||
mutable std::shared_mutex mtx_;
|
||||
uint32_t mostRecentSequence_;
|
||||
|
||||
void
|
||||
insert(ripple::uint256 const& key, Blob const& value, uint32_t seq);
|
||||
|
||||
/*
|
||||
void
|
||||
insert(ripple::uint256 const& key, Blob const& value, uint32_t seq)
|
||||
{
|
||||
map_.emplace(key,{{seq,value,{}});
|
||||
}
|
||||
void
|
||||
update(ripple::uint256 const& key, Blob const& value, uint32_t seq)
|
||||
{
|
||||
auto& entry = map_.find(key);
|
||||
entry.old = entry.recent;
|
||||
entry.recent = {seq, value};
|
||||
pendingSweeps_.push_back(key);
|
||||
}
|
||||
void
|
||||
erase(ripple::uint256 const& key, uint32_t seq)
|
||||
{
|
||||
update(key, {}, seq);
|
||||
pendingDeletes_.push_back(key);
|
||||
}
|
||||
*/
|
||||
std::optional<Blob>
|
||||
select(CacheEntry const& entry, uint32_t seq) const;
|
||||
|
||||
public:
|
||||
void
|
||||
update(std::vector<LedgerObject> const& blobs, uint32_t seq);
|
||||
|
||||
std::optional<Blob>
|
||||
get(ripple::uint256 const& key, uint32_t seq) const;
|
||||
|
||||
std::optional<LedgerObject>
|
||||
getSuccessor(ripple::uint256 const& key, uint32_t seq) const;
|
||||
|
||||
std::optional<LedgerObject>
|
||||
getPredecessor(ripple::uint256 const& key, uint32_t seq) const;
|
||||
};
|
||||
|
||||
} // namespace Backend
|
||||
#endif
|
||||
@@ -1032,7 +1032,7 @@ ETLLoadBalancer::fetchLedger(
|
||||
auto [status, data] = source->fetchLedger(
|
||||
ledgerSequence, getObjects, getObjectNeighbors);
|
||||
response = std::move(data);
|
||||
if (status.ok() && (response.validated() || true))
|
||||
if (status.ok() && response.validated())
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info)
|
||||
<< "Successfully fetched ledger = " << ledgerSequence
|
||||
|
||||
@@ -147,11 +147,9 @@ ReportingETL::publishLedger(ripple::LedgerInfo const& lgrInfo)
|
||||
backend_->cache().update(diff, lgrInfo.seq);
|
||||
backend_->updateRange(lgrInfo.seq);
|
||||
}
|
||||
auto now = std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count();
|
||||
auto closeTime = lgrInfo.closeTime.time_since_epoch().count();
|
||||
auto age = now - (rippleEpochStart + closeTime);
|
||||
|
||||
setLastClose(lgrInfo.closeTime);
|
||||
auto age = lastCloseAgeSeconds();
|
||||
// if the ledger closed over 10 minutes ago, assume we are still
|
||||
// catching up and don't publish
|
||||
if (age < 600)
|
||||
|
||||
@@ -139,6 +139,18 @@ private:
|
||||
lastPublish_ = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
/// The time that the most recently published ledger was closed.
|
||||
std::chrono::time_point<ripple::NetClock> lastCloseTime_;
|
||||
|
||||
mutable std::shared_mutex closeTimeMtx_;
|
||||
|
||||
void
|
||||
setLastClose(std::chrono::time_point<ripple::NetClock> lastCloseTime)
|
||||
{
|
||||
std::unique_lock lck(closeTimeMtx_);
|
||||
lastCloseTime_ = lastCloseTime;
|
||||
}
|
||||
|
||||
/// Download a ledger with specified sequence in full, via GetLedgerData,
|
||||
/// and write the data to the databases. This takes several minutes or
|
||||
/// longer.
|
||||
@@ -334,6 +346,17 @@ public:
|
||||
std::chrono::system_clock::now() - getLastPublish())
|
||||
.count();
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
lastCloseAgeSeconds() const
|
||||
{
|
||||
std::shared_lock lck(closeTimeMtx_);
|
||||
auto now = std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count();
|
||||
auto closeTime = lastCloseTime_.time_since_epoch().count();
|
||||
return now - (rippleEpochStart + closeTime);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Build {
|
||||
// and follow the format described at http://semver.org/
|
||||
//------------------------------------------------------------------------------
|
||||
// clang-format off
|
||||
char const* const versionString = "1.0.0"
|
||||
char const* const versionString = "1.0.1"
|
||||
// clang-format on
|
||||
|
||||
#if defined(DEBUG) || defined(SANITIZER)
|
||||
|
||||
@@ -422,8 +422,8 @@ handle_request(
|
||||
"This is a clio server. clio only serves validated data. If you "
|
||||
"want to talk to rippled, include 'ledger_index':'current' in your "
|
||||
"request");
|
||||
auto lastPublishAge = context->etl->lastPublishAgeSeconds();
|
||||
if (lastPublishAge >= 60)
|
||||
auto lastCloseAge = context->etl->lastCloseAgeSeconds();
|
||||
if (lastCloseAge >= 60)
|
||||
warnings.emplace_back("This server may be out of date");
|
||||
result["warnings"] = warnings;
|
||||
responseStr = boost::json::serialize(response);
|
||||
|
||||
@@ -351,10 +351,9 @@ public:
|
||||
"want to talk to rippled, include 'ledger_index':'current' in your "
|
||||
"request");
|
||||
|
||||
auto lastPublishAge = etl_->lastPublishAgeSeconds();
|
||||
if (lastPublishAge >= 60)
|
||||
auto lastCloseAge = etl_->lastCloseAgeSeconds();
|
||||
if (lastCloseAge >= 60)
|
||||
warnings.emplace_back("This server may be out of date");
|
||||
|
||||
response["warnings"] = warnings;
|
||||
std::string responseStr = boost::json::serialize(response);
|
||||
if (!dosGuard_.add(*ip, responseStr.size()))
|
||||
|
||||
Reference in New Issue
Block a user