2018-08-30 18:48:43 +00:00
|
|
|
#ifndef LLARP_NODEDB_HPP
|
|
|
|
#define LLARP_NODEDB_HPP
|
2018-12-12 01:55:30 +00:00
|
|
|
|
|
|
|
#include <router_contact.hpp>
|
2018-12-12 02:52:51 +00:00
|
|
|
#include <router_id.hpp>
|
2019-01-10 19:41:51 +00:00
|
|
|
#include <util/common.hpp>
|
|
|
|
#include <util/fs.hpp>
|
2019-09-01 13:26:16 +00:00
|
|
|
#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
2020-02-21 17:21:11 +00:00
|
|
|
#include <util/thread/annotations.hpp>
|
2020-01-22 22:30:24 +00:00
|
|
|
#include <dht/key.hpp>
|
2019-03-03 20:51:47 +00:00
|
|
|
|
2019-03-11 13:58:31 +00:00
|
|
|
#include <set>
|
2019-07-30 23:42:13 +00:00
|
|
|
#include <utility>
|
2019-03-11 13:58:31 +00:00
|
|
|
|
2018-05-31 13:08:06 +00:00
|
|
|
/**
|
2018-08-30 18:48:43 +00:00
|
|
|
* nodedb.hpp
|
2018-05-31 13:08:06 +00:00
|
|
|
*
|
|
|
|
* persistent storage API for router contacts
|
|
|
|
*/
|
2018-12-10 14:14:55 +00:00
|
|
|
namespace llarp
|
|
|
|
{
|
|
|
|
class Logic;
|
2019-01-13 16:30:07 +00:00
|
|
|
} // namespace llarp
|
2018-12-10 14:14:55 +00:00
|
|
|
|
2018-12-10 23:29:58 +00:00
|
|
|
struct llarp_nodedb
|
|
|
|
{
|
2020-06-11 11:44:02 +00:00
|
|
|
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)
|
2020-01-14 20:12:47 +00:00
|
|
|
|
2018-12-10 23:29:58 +00:00
|
|
|
{
|
|
|
|
}
|
2018-06-18 22:05:02 +00:00
|
|
|
|
2018-12-10 23:29:58 +00:00
|
|
|
~llarp_nodedb()
|
|
|
|
{
|
|
|
|
Clear();
|
|
|
|
}
|
2018-09-11 15:53:54 +00:00
|
|
|
|
2020-06-11 11:44:02 +00:00
|
|
|
const DiskCaller_t disk;
|
2019-03-03 20:51:47 +00:00
|
|
|
mutable llarp::util::Mutex access; // protects entries
|
2020-01-14 17:01:41 +00:00
|
|
|
/// time for next save to disk event, 0 if never happened
|
2020-02-24 19:40:45 +00:00
|
|
|
llarp_time_t m_NextSaveToDisk = 0s;
|
2020-01-14 17:01:41 +00:00
|
|
|
/// how often to save to disk
|
2020-02-24 19:40:45 +00:00
|
|
|
const llarp_time_t m_SaveInterval = 5min;
|
2019-06-10 12:47:21 +00:00
|
|
|
|
|
|
|
struct NetDBEntry
|
|
|
|
{
|
|
|
|
const llarp::RouterContact rc;
|
2019-06-26 21:39:29 +00:00
|
|
|
llarp_time_t inserted;
|
2019-06-10 12:47:21 +00:00
|
|
|
|
2019-07-30 23:42:13 +00:00
|
|
|
NetDBEntry(llarp::RouterContact data);
|
2019-06-10 12:47:21 +00:00
|
|
|
};
|
|
|
|
|
2020-04-07 18:38:56 +00:00
|
|
|
using NetDBMap_t = std::unordered_map<llarp::RouterID, NetDBEntry, llarp::RouterID::Hash>;
|
2019-06-10 12:47:21 +00:00
|
|
|
|
|
|
|
NetDBMap_t entries GUARDED_BY(access);
|
2018-12-10 23:29:58 +00:00
|
|
|
fs::path nodePath;
|
2018-06-19 17:11:24 +00:00
|
|
|
|
2020-01-22 22:30:24 +00:00
|
|
|
llarp::RouterContact
|
2020-04-07 18:38:56 +00:00
|
|
|
FindClosestTo(const llarp::dht::Key_t& location);
|
2020-01-22 22:30:24 +00:00
|
|
|
|
2020-02-13 22:19:12 +00:00
|
|
|
/// find the $numRouters closest routers to the given DHT key
|
2020-04-07 18:38:56 +00:00
|
|
|
std::vector<llarp::RouterContact>
|
|
|
|
FindClosestTo(const llarp::dht::Key_t& location, uint32_t numRouters);
|
2020-02-13 22:19:12 +00:00
|
|
|
|
2020-01-14 17:01:41 +00:00
|
|
|
/// return true if we should save our nodedb to disk
|
|
|
|
bool
|
2020-02-24 19:40:45 +00:00
|
|
|
ShouldSaveToDisk(llarp_time_t now = 0s) const;
|
2020-01-14 17:01:41 +00:00
|
|
|
|
2018-12-10 23:29:58 +00:00
|
|
|
bool
|
2020-04-07 18:38:56 +00:00
|
|
|
Remove(const llarp::RouterID& pk) EXCLUDES(access);
|
2018-06-18 22:05:02 +00:00
|
|
|
|
2019-03-25 13:52:22 +00:00
|
|
|
void
|
2020-04-07 18:38:56 +00:00
|
|
|
RemoveIf(std::function<bool(const llarp::RouterContact&)> filter) EXCLUDES(access);
|
2019-03-25 13:52:22 +00:00
|
|
|
|
2018-12-10 23:29:58 +00:00
|
|
|
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
2020-02-21 17:21:11 +00:00
|
|
|
Clear() EXCLUDES(access);
|
2018-06-18 22:05:02 +00:00
|
|
|
|
2018-12-10 23:29:58 +00:00
|
|
|
bool
|
2020-04-07 18:38:56 +00:00
|
|
|
Get(const llarp::RouterID& pk, llarp::RouterContact& result) EXCLUDES(access);
|
2018-12-10 23:29:58 +00:00
|
|
|
|
|
|
|
bool
|
2020-04-07 18:38:56 +00:00
|
|
|
Has(const llarp::RouterID& pk) EXCLUDES(access);
|
2018-12-10 23:29:58 +00:00
|
|
|
|
|
|
|
std::string
|
2020-04-07 18:38:56 +00:00
|
|
|
getRCFilePath(const llarp::RouterID& pubkey) const;
|
2018-12-10 23:29:58 +00:00
|
|
|
|
2020-01-16 04:44:25 +00:00
|
|
|
/// insert without writing to disk
|
2018-12-10 23:29:58 +00:00
|
|
|
bool
|
2020-04-07 18:38:56 +00:00
|
|
|
Insert(const llarp::RouterContact& rc) EXCLUDES(access);
|
2018-12-10 23:29:58 +00:00
|
|
|
|
2020-01-16 04:44:25 +00:00
|
|
|
/// invokes Insert() asynchronously with an optional completion
|
|
|
|
/// callback
|
2018-12-19 16:17:41 +00:00
|
|
|
void
|
2020-04-07 18:38:56 +00:00
|
|
|
InsertAsync(
|
|
|
|
llarp::RouterContact rc,
|
|
|
|
std::shared_ptr<llarp::Logic> l = nullptr,
|
|
|
|
std::function<void(void)> completionHandler = nullptr);
|
2018-12-19 16:17:41 +00:00
|
|
|
|
2019-06-17 14:23:38 +00:00
|
|
|
/// update rc if newer
|
|
|
|
/// return true if we started to put this rc in the database
|
|
|
|
/// retur false if not newer
|
|
|
|
bool
|
2020-04-07 18:38:56 +00:00
|
|
|
UpdateAsyncIfNewer(
|
|
|
|
llarp::RouterContact rc,
|
|
|
|
std::shared_ptr<llarp::Logic> l = nullptr,
|
|
|
|
std::function<void(void)> completionHandler = nullptr) EXCLUDES(access);
|
2019-06-17 14:23:38 +00:00
|
|
|
|
2018-12-10 23:29:58 +00:00
|
|
|
ssize_t
|
2020-04-07 18:38:56 +00:00
|
|
|
Load(const fs::path& path);
|
2018-12-10 23:29:58 +00:00
|
|
|
|
|
|
|
ssize_t
|
2020-04-07 18:38:56 +00:00
|
|
|
loadSubdir(const fs::path& dir);
|
2019-06-17 14:23:38 +00:00
|
|
|
/// save all entries to disk async
|
|
|
|
void
|
|
|
|
AsyncFlushToDisk();
|
2018-12-10 23:29:58 +00:00
|
|
|
|
|
|
|
bool
|
2020-04-07 18:38:56 +00:00
|
|
|
loadfile(const fs::path& fpath) EXCLUDES(access);
|
2018-12-10 23:29:58 +00:00
|
|
|
|
|
|
|
void
|
2020-04-07 18:38:56 +00:00
|
|
|
visit(std::function<bool(const llarp::RouterContact&)> visit) EXCLUDES(access);
|
2018-12-10 23:29:58 +00:00
|
|
|
|
|
|
|
void
|
2020-04-07 18:38:56 +00:00
|
|
|
set_dir(const char* dir);
|
2018-12-10 23:29:58 +00:00
|
|
|
|
|
|
|
ssize_t
|
2020-01-14 20:12:47 +00:00
|
|
|
LoadAll();
|
|
|
|
|
2018-12-10 23:29:58 +00:00
|
|
|
ssize_t
|
2020-04-07 18:38:56 +00:00
|
|
|
store_dir(const char* dir);
|
2018-12-10 23:29:58 +00:00
|
|
|
|
2019-06-20 14:00:04 +00:00
|
|
|
/// visit all entries inserted into nodedb cache before a timestamp
|
2019-06-10 12:47:21 +00:00
|
|
|
void
|
2020-04-07 18:38:56 +00:00
|
|
|
VisitInsertedBefore(
|
|
|
|
std::function<void(const llarp::RouterContact&)> visit, llarp_time_t insertedAfter)
|
|
|
|
EXCLUDES(access);
|
2018-12-10 23:29:58 +00:00
|
|
|
|
2019-06-26 21:39:29 +00:00
|
|
|
void
|
2020-04-07 18:38:56 +00:00
|
|
|
RemoveStaleRCs(const std::set<llarp::RouterID>& keep, llarp_time_t cutoff);
|
2019-06-26 21:39:29 +00:00
|
|
|
|
2018-12-10 23:29:58 +00:00
|
|
|
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
2020-02-21 17:21:11 +00:00
|
|
|
num_loaded() const EXCLUDES(access);
|
2018-12-10 23:29:58 +00:00
|
|
|
|
|
|
|
bool
|
2020-04-07 18:38:56 +00:00
|
|
|
select_random_exit(llarp::RouterContact& rc) EXCLUDES(access);
|
2018-12-10 23:29:58 +00:00
|
|
|
|
2019-03-11 13:58:31 +00:00
|
|
|
bool
|
2020-04-07 18:38:56 +00:00
|
|
|
select_random_hop_excluding(
|
|
|
|
llarp::RouterContact& result, const std::set<llarp::RouterID>& exclude) EXCLUDES(access);
|
2019-03-11 13:58:31 +00:00
|
|
|
|
2020-04-02 20:11:07 +00:00
|
|
|
/// 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);
|
2019-06-17 14:23:38 +00:00
|
|
|
|
|
|
|
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
2020-02-21 17:21:11 +00:00
|
|
|
SaveAll() EXCLUDES(access);
|
2018-12-10 23:29:58 +00:00
|
|
|
};
|
2018-09-13 16:41:53 +00:00
|
|
|
|
2018-06-18 22:05:02 +00:00
|
|
|
/// struct for async rc verification
|
|
|
|
struct llarp_async_verify_rc;
|
|
|
|
|
2020-04-07 18:38:56 +00:00
|
|
|
using llarp_async_verify_rc_hook_func = std::function<void(struct llarp_async_verify_rc*)>;
|
2018-06-18 22:05:02 +00:00
|
|
|
|
|
|
|
/// verify rc request
|
|
|
|
struct llarp_async_verify_rc
|
|
|
|
{
|
|
|
|
/// async_verify_context
|
2020-04-07 18:38:56 +00:00
|
|
|
void* user;
|
2018-06-18 22:05:02 +00:00
|
|
|
/// nodedb storage
|
2020-04-07 18:38:56 +00:00
|
|
|
llarp_nodedb* nodedb;
|
2018-12-10 14:14:55 +00:00
|
|
|
// llarp::Logic for queue_job
|
2020-04-07 18:38:56 +00:00
|
|
|
std::shared_ptr<llarp::Logic> logic;
|
2020-06-11 11:44:02 +00:00
|
|
|
llarp_nodedb::WorkCaller_t worker;
|
|
|
|
llarp_nodedb::DiskCaller_t disk;
|
2018-06-18 22:05:02 +00:00
|
|
|
|
2018-07-03 13:13:56 +00:00
|
|
|
/// router contact
|
2018-08-30 18:48:43 +00:00
|
|
|
llarp::RouterContact rc;
|
2018-06-18 22:05:02 +00:00
|
|
|
/// 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
|
2020-04-07 18:38:56 +00:00
|
|
|
llarp_nodedb_async_verify(struct llarp_async_verify_rc* job);
|
2018-06-18 22:05:02 +00:00
|
|
|
|
|
|
|
struct llarp_async_load_rc;
|
|
|
|
|
2020-04-07 18:38:56 +00:00
|
|
|
using llarp_async_load_rc_hook_func = std::function<void(struct llarp_async_load_rc*)>;
|
2018-06-18 22:05:02 +00:00
|
|
|
|
|
|
|
struct llarp_async_load_rc
|
|
|
|
{
|
|
|
|
/// async_verify_context
|
2020-04-07 18:38:56 +00:00
|
|
|
void* user;
|
2018-06-18 22:05:02 +00:00
|
|
|
/// nodedb storage
|
2020-04-07 18:38:56 +00:00
|
|
|
llarp_nodedb* nodedb;
|
2018-12-10 14:14:55 +00:00
|
|
|
/// llarp::Logic for calling hook
|
2020-04-07 18:38:56 +00:00
|
|
|
llarp::Logic* logic;
|
2018-06-18 22:05:02 +00:00
|
|
|
/// disk worker threadpool
|
2020-06-11 11:44:02 +00:00
|
|
|
llarp_nodedb::DiskCaller_t disk;
|
2018-06-18 22:05:02 +00:00
|
|
|
/// target pubkey
|
2018-08-30 18:48:43 +00:00
|
|
|
llarp::PubKey pubkey;
|
2018-06-18 22:05:02 +00:00
|
|
|
/// router contact result
|
2018-08-30 18:48:43 +00:00
|
|
|
llarp::RouterContact result;
|
2018-06-18 22:05:02 +00:00
|
|
|
/// 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
|
2020-04-07 18:38:56 +00:00
|
|
|
llarp_nodedb_async_load_rc(struct llarp_async_load_rc* job);
|
2018-06-13 12:58:51 +00:00
|
|
|
|
2018-04-08 12:18:16 +00:00
|
|
|
#endif
|