Compare commits

...

5 Commits
1.0.0 ... 1.0.1

Author SHA1 Message Date
CJ Cobb
4468302852 Set version to 1.0.1 (#216) 2022-07-13 19:33:03 -04:00
Nathan Nichols
a704cf7cfe remove "this software is in a beta version" from readme (#204)
* remove "this software is in a beta version" from readme

Co-authored-by: Michael Legleux <legleux@users.noreply.github.com>
2022-07-10 20:05:13 -05:00
CJ Cobb
05d09cc352 Only fetch validated ledgers 2022-07-08 12:10:12 -04:00
ethanlabelle
ae96ac7baf removed unused LayeredCache (#199) 2022-06-29 16:10:15 -07:00
ethanlabelle
4579fa2f26 Use ledger close times for stale data warning (#194) 2022-06-29 16:10:03 -07:00
10 changed files with 33 additions and 203 deletions

View File

@@ -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

View File

@@ -1,9 +1,3 @@
[![Build Clio](https://github.com/legleux/clio/actions/workflows/build.yml/badge.svg?branch=run-tests)](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.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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);

View File

@@ -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()))