You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lokinet/llarp/nodedb.hpp

230 lines
5.5 KiB
C++

#ifndef LLARP_NODEDB_HPP
#define LLARP_NODEDB_HPP
#include <router_contact.hpp>
#include <router_id.hpp>
#include <util/common.hpp>
#include <util/fs.hpp>
#include <util/thread/threading.hpp>
De-abseil, part 2: mutex, locks, (most) time - util::Mutex is now a std::shared_timed_mutex, which is capable of exclusive and shared locks. - util::Lock is still present as a std::lock_guard<util::Mutex>. - the locking annotations are preserved, but updated to the latest supported by clang rather than using abseil's older/deprecated ones. - ACQUIRE_LOCK macro is gone since we don't pass mutexes by pointer into locks anymore (WTF abseil). - ReleasableLock is gone. Instead there are now some llarp::util helper methods to obtain unique and/or shared locks: - `auto lock = util::unique_lock(mutex);` gets an RAII-but-also unlockable object (std::unique_lock<T>, with T inferred from `mutex`). - `auto lock = util::shared_lock(mutex);` gets an RAII shared (i.e. "reader") lock of the mutex. - `auto lock = util::unique_locks(mutex1, mutex2, mutex3);` can be used to atomically lock multiple mutexes at once (returning a tuple of the locks). This are templated on the mutex which makes them a bit more flexible than using a concrete type: they can be used for any type of lockable mutex, not only util::Mutex. (Some of the code here uses them for getting locks around a std::mutex). Until C++17, using the RAII types is painfully verbose: ```C++ // pre-C++17 - needing to figure out the mutex type here is annoying: std::unique_lock<util::Mutex> lock(mutex); // pre-C++17 and even more verbose (but at least the type isn't needed): std::unique_lock<decltype(mutex)> lock(mutex); // our compromise: auto lock = util::unique_lock(mutex); // C++17: std::unique_lock lock(mutex); ``` All of these functions will also warn (under gcc or clang) if you discard the return value. You can also do fancy things like `auto l = util::unique_lock(mutex, std::adopt_lock)` (which lets a lock take over an already-locked mutex). - metrics code is gone, which also removes a big pile of code that was only used by metrics: - llarp::util::Scheduler - llarp::thread::TimerQueue - llarp::util::Stopwatch
4 years ago
#include <util/thread/annotations.hpp>
#include <dht/key.hpp>
#include <set>
#include <utility>
/**
* nodedb.hpp
*
* persistent storage API for router contacts
*/
namespace llarp
{
class Logic;
} // namespace llarp
struct llarp_nodedb
{
using DiskJob_t = std::function<void(void)>;
using DiskCaller_t = std::function<void(DiskJob_t)>;
using WorkJob_t = std::function<void(void)>;
using WorkCaller_t = std::function<void(WorkJob_t)>;
explicit llarp_nodedb(const std::string rootdir, DiskCaller_t diskCaller)
: disk(std::move(diskCaller)), nodePath(rootdir)
{
}
6 years ago
~llarp_nodedb()
{
Clear();
}
const DiskCaller_t disk;
mutable llarp::util::Mutex access; // protects entries
/// time for next save to disk event, 0 if never happened
llarp_time_t m_NextSaveToDisk = 0s;
/// how often to save to disk
const llarp_time_t m_SaveInterval = 5min;
struct NetDBEntry
{
const llarp::RouterContact rc;
llarp_time_t inserted;
NetDBEntry(llarp::RouterContact data);
};
using NetDBMap_t = std::unordered_map<llarp::RouterID, NetDBEntry, llarp::RouterID::Hash>;
NetDBMap_t entries GUARDED_BY(access);
fs::path nodePath;
llarp::RouterContact
FindClosestTo(const llarp::dht::Key_t& location);
/// find the $numRouters closest routers to the given DHT key
std::vector<llarp::RouterContact>
FindClosestTo(const llarp::dht::Key_t& location, uint32_t numRouters);
/// return true if we should save our nodedb to disk
bool
ShouldSaveToDisk(llarp_time_t now = 0s) const;
bool
Remove(const llarp::RouterID& pk) EXCLUDES(access);
6 years ago
void
RemoveIf(std::function<bool(const llarp::RouterContact&)> filter) EXCLUDES(access);
void
De-abseil, part 2: mutex, locks, (most) time - util::Mutex is now a std::shared_timed_mutex, which is capable of exclusive and shared locks. - util::Lock is still present as a std::lock_guard<util::Mutex>. - the locking annotations are preserved, but updated to the latest supported by clang rather than using abseil's older/deprecated ones. - ACQUIRE_LOCK macro is gone since we don't pass mutexes by pointer into locks anymore (WTF abseil). - ReleasableLock is gone. Instead there are now some llarp::util helper methods to obtain unique and/or shared locks: - `auto lock = util::unique_lock(mutex);` gets an RAII-but-also unlockable object (std::unique_lock<T>, with T inferred from `mutex`). - `auto lock = util::shared_lock(mutex);` gets an RAII shared (i.e. "reader") lock of the mutex. - `auto lock = util::unique_locks(mutex1, mutex2, mutex3);` can be used to atomically lock multiple mutexes at once (returning a tuple of the locks). This are templated on the mutex which makes them a bit more flexible than using a concrete type: they can be used for any type of lockable mutex, not only util::Mutex. (Some of the code here uses them for getting locks around a std::mutex). Until C++17, using the RAII types is painfully verbose: ```C++ // pre-C++17 - needing to figure out the mutex type here is annoying: std::unique_lock<util::Mutex> lock(mutex); // pre-C++17 and even more verbose (but at least the type isn't needed): std::unique_lock<decltype(mutex)> lock(mutex); // our compromise: auto lock = util::unique_lock(mutex); // C++17: std::unique_lock lock(mutex); ``` All of these functions will also warn (under gcc or clang) if you discard the return value. You can also do fancy things like `auto l = util::unique_lock(mutex, std::adopt_lock)` (which lets a lock take over an already-locked mutex). - metrics code is gone, which also removes a big pile of code that was only used by metrics: - llarp::util::Scheduler - llarp::thread::TimerQueue - llarp::util::Stopwatch
4 years ago
Clear() EXCLUDES(access);
6 years ago
bool
Get(const llarp::RouterID& pk, llarp::RouterContact& result) EXCLUDES(access);
bool
Has(const llarp::RouterID& pk) EXCLUDES(access);
std::string
getRCFilePath(const llarp::RouterID& pubkey) const;
/// insert without writing to disk
bool
Insert(const llarp::RouterContact& rc) EXCLUDES(access);
/// invokes Insert() asynchronously with an optional completion
/// callback
void
InsertAsync(
llarp::RouterContact rc,
std::shared_ptr<llarp::Logic> l = nullptr,
std::function<void(void)> completionHandler = nullptr);
/// update rc if newer
/// return true if we started to put this rc in the database
/// retur false if not newer
bool
UpdateAsyncIfNewer(
llarp::RouterContact rc,
std::shared_ptr<llarp::Logic> l = nullptr,
std::function<void(void)> completionHandler = nullptr) EXCLUDES(access);
ssize_t
Load(const fs::path& path);
ssize_t
loadSubdir(const fs::path& dir);
/// save all entries to disk async
void
AsyncFlushToDisk();
bool
loadfile(const fs::path& fpath) EXCLUDES(access);
void
visit(std::function<bool(const llarp::RouterContact&)> visit) EXCLUDES(access);
void
set_dir(const char* dir);
ssize_t
LoadAll();
ssize_t
store_dir(const char* dir);
5 years ago
/// visit all entries inserted into nodedb cache before a timestamp
void
VisitInsertedBefore(
std::function<void(const llarp::RouterContact&)> visit, llarp_time_t insertedAfter)
EXCLUDES(access);
void
RemoveStaleRCs(const std::set<llarp::RouterID>& keep, llarp_time_t cutoff);
size_t
De-abseil, part 2: mutex, locks, (most) time - util::Mutex is now a std::shared_timed_mutex, which is capable of exclusive and shared locks. - util::Lock is still present as a std::lock_guard<util::Mutex>. - the locking annotations are preserved, but updated to the latest supported by clang rather than using abseil's older/deprecated ones. - ACQUIRE_LOCK macro is gone since we don't pass mutexes by pointer into locks anymore (WTF abseil). - ReleasableLock is gone. Instead there are now some llarp::util helper methods to obtain unique and/or shared locks: - `auto lock = util::unique_lock(mutex);` gets an RAII-but-also unlockable object (std::unique_lock<T>, with T inferred from `mutex`). - `auto lock = util::shared_lock(mutex);` gets an RAII shared (i.e. "reader") lock of the mutex. - `auto lock = util::unique_locks(mutex1, mutex2, mutex3);` can be used to atomically lock multiple mutexes at once (returning a tuple of the locks). This are templated on the mutex which makes them a bit more flexible than using a concrete type: they can be used for any type of lockable mutex, not only util::Mutex. (Some of the code here uses them for getting locks around a std::mutex). Until C++17, using the RAII types is painfully verbose: ```C++ // pre-C++17 - needing to figure out the mutex type here is annoying: std::unique_lock<util::Mutex> lock(mutex); // pre-C++17 and even more verbose (but at least the type isn't needed): std::unique_lock<decltype(mutex)> lock(mutex); // our compromise: auto lock = util::unique_lock(mutex); // C++17: std::unique_lock lock(mutex); ``` All of these functions will also warn (under gcc or clang) if you discard the return value. You can also do fancy things like `auto l = util::unique_lock(mutex, std::adopt_lock)` (which lets a lock take over an already-locked mutex). - metrics code is gone, which also removes a big pile of code that was only used by metrics: - llarp::util::Scheduler - llarp::thread::TimerQueue - llarp::util::Stopwatch
4 years ago
num_loaded() const EXCLUDES(access);
bool
select_random_exit(llarp::RouterContact& rc) EXCLUDES(access);
bool
select_random_hop_excluding(
llarp::RouterContact& result, const std::set<llarp::RouterID>& exclude) EXCLUDES(access);
/// Ensures that the given nodedb 'dir' exists
///
/// @param nodedbDir should be the desired nodedb directory
/// @throws on any filesistem error or if `nodedbDir` exists and is not a directory
static void
ensure_dir(const fs::path& nodedbDir);
void
De-abseil, part 2: mutex, locks, (most) time - util::Mutex is now a std::shared_timed_mutex, which is capable of exclusive and shared locks. - util::Lock is still present as a std::lock_guard<util::Mutex>. - the locking annotations are preserved, but updated to the latest supported by clang rather than using abseil's older/deprecated ones. - ACQUIRE_LOCK macro is gone since we don't pass mutexes by pointer into locks anymore (WTF abseil). - ReleasableLock is gone. Instead there are now some llarp::util helper methods to obtain unique and/or shared locks: - `auto lock = util::unique_lock(mutex);` gets an RAII-but-also unlockable object (std::unique_lock<T>, with T inferred from `mutex`). - `auto lock = util::shared_lock(mutex);` gets an RAII shared (i.e. "reader") lock of the mutex. - `auto lock = util::unique_locks(mutex1, mutex2, mutex3);` can be used to atomically lock multiple mutexes at once (returning a tuple of the locks). This are templated on the mutex which makes them a bit more flexible than using a concrete type: they can be used for any type of lockable mutex, not only util::Mutex. (Some of the code here uses them for getting locks around a std::mutex). Until C++17, using the RAII types is painfully verbose: ```C++ // pre-C++17 - needing to figure out the mutex type here is annoying: std::unique_lock<util::Mutex> lock(mutex); // pre-C++17 and even more verbose (but at least the type isn't needed): std::unique_lock<decltype(mutex)> lock(mutex); // our compromise: auto lock = util::unique_lock(mutex); // C++17: std::unique_lock lock(mutex); ``` All of these functions will also warn (under gcc or clang) if you discard the return value. You can also do fancy things like `auto l = util::unique_lock(mutex, std::adopt_lock)` (which lets a lock take over an already-locked mutex). - metrics code is gone, which also removes a big pile of code that was only used by metrics: - llarp::util::Scheduler - llarp::thread::TimerQueue - llarp::util::Stopwatch
4 years ago
SaveAll() EXCLUDES(access);
};
6 years ago
/// struct for async rc verification
struct llarp_async_verify_rc;
using llarp_async_verify_rc_hook_func = std::function<void(struct llarp_async_verify_rc*)>;
6 years ago
/// verify rc request
struct llarp_async_verify_rc
{
/// async_verify_context
void* user;
6 years ago
/// nodedb storage
llarp_nodedb* nodedb;
// llarp::Logic for queue_job
std::shared_ptr<llarp::Logic> logic;
llarp_nodedb::WorkCaller_t worker;
llarp_nodedb::DiskCaller_t disk;
6 years ago
/// router contact
llarp::RouterContact rc;
6 years ago
/// result
bool valid;
/// hook
llarp_async_verify_rc_hook_func hook;
};
/**
struct for async rc verification
data is loaded in disk io threadpool
crypto is done on the crypto worker threadpool
result is called on the logic thread
*/
void
llarp_nodedb_async_verify(struct llarp_async_verify_rc* job);
6 years ago
struct llarp_async_load_rc;
using llarp_async_load_rc_hook_func = std::function<void(struct llarp_async_load_rc*)>;
6 years ago
struct llarp_async_load_rc
{
/// async_verify_context
void* user;
6 years ago
/// nodedb storage
llarp_nodedb* nodedb;
/// llarp::Logic for calling hook
llarp::Logic* logic;
6 years ago
/// disk worker threadpool
llarp_nodedb::DiskCaller_t disk;
6 years ago
/// target pubkey
llarp::PubKey pubkey;
6 years ago
/// router contact result
llarp::RouterContact result;
6 years ago
/// set to true if we loaded the rc
bool loaded;
/// hook function called in logic thread
llarp_async_load_rc_hook_func hook;
};
/// asynchronously load an rc from disk
void
llarp_nodedb_async_load_rc(struct llarp_async_load_rc* job);
6 years ago
6 years ago
#endif