Compare commits
36 Commits
c6ce4d3229
...
4ecf1ef037
Author | SHA1 | Date |
---|---|---|
Jason Volk | 4ecf1ef037 | |
Jason Volk | 3ec562ce0b | |
Jason Volk | a8c16e0fd0 | |
Jason Volk | 66629046e1 | |
Jason Volk | 4339639732 | |
Jason Volk | 95d5361c20 | |
Jason Volk | 95274dd0cd | |
Jason Volk | bffa445d37 | |
Jason Volk | 1b8ad3e160 | |
Jason Volk | 04acaabf91 | |
Jason Volk | 575211d37e | |
Jason Volk | 6d73a65867 | |
Jason Volk | b3832541ff | |
Jason Volk | 14f55f6110 | |
Jason Volk | 82482278fb | |
Jason Volk | fc495f06ef | |
Jason Volk | 1973e2c086 | |
Jason Volk | 63c70ecdfc | |
Jason Volk | 13f3d1ebc6 | |
Jason Volk | b07fa8c110 | |
Jason Volk | 4d2478f814 | |
Jason Volk | f2626d39a7 | |
Jason Volk | c3c73fcbe7 | |
Jason Volk | 19462b5fae | |
Jason Volk | 96b1d68933 | |
Jason Volk | c807550ca7 | |
Jason Volk | 3709cda233 | |
Jason Volk | eca02723b3 | |
Jason Volk | ee31b5a59f | |
Jason Volk | 4e16f1849b | |
Jason Volk | 3fcfaddc3e | |
Jason Volk | abf1ed47c6 | |
Jason Volk | cc36c17c03 | |
Jason Volk | 1e4f44f41d | |
Jason Volk | 5994475542 | |
Jason Volk | eff25f45f1 |
18
README.md
18
README.md
|
@ -1,10 +1,10 @@
|
|||
# This — is The **Construct**
|
||||
|
||||
#### Federated Messaging Server
|
||||
#### FEDERATED MESSAGING SERVER
|
||||
|
||||
[![Chat in #construct:zemos.net](https://img.shields.io/matrix/construct:zemos.net.svg?label=Chat%20in%20%23construct%3Azemos.net&logo=matrix&server_fqdn=matrix.org&style=for-the-badge&color=5965AF)](https://matrix.to/#/#construct:zemos.net) [![](https://img.shields.io/badge/License-BSD-5965AF.svg?label=%20license&style=for-the-badge)]()
|
||||
|
||||
### 📦 RUN YOUR OWN
|
||||
### 🚚 GET CONSTRUCT
|
||||
|
||||
- `git clone https://github.com/matrix-construct/construct`
|
||||
|
||||
|
@ -13,19 +13,17 @@
|
|||
[![](https://img.shields.io/github/directory-file-count/matrix-construct/construct.svg?type=dir&label=directories&logo=GitHub&style=flat-square&color=5965AF)](https://github.com/matrix-construct/construct)
|
||||
[![](https://img.shields.io/github/directory-file-count/matrix-construct/construct.svg?type=file&label=files&logo=GitHub&style=flat-square&color=5965AF)](https://github.com/matrix-construct/construct)
|
||||
|
||||
| Fully Featured Builds | Minimal Dependencies |
|
||||
|:---|:---|
|
||||
| [![](https://img.shields.io/docker/image-size/jevolk/construct/ubuntu-22.04-full-built-clang-15-amd64.svg?logoWidth=25&label=ubuntu%2022.04%20amd64&logo=Docker&style=flat-square&color=5965AF)](https://registry.hub.docker.com/r/jevolk/construct/tags) | [![](https://img.shields.io/docker/image-size/jevolk/construct/ubuntu-22.04-base-built-gcc-12-amd64.svg?logoWidth=25&label=ubuntu%2022.04%20amd64&logo=Docker&style=flat-square&color=5965AF)](https://registry.hub.docker.com/r/jevolk/construct/tags)
|
||||
| [![](https://img.shields.io/docker/image-size/jevolk/construct/alpine-3.16-full-built-clang-amd64.svg?logoWidth=25&label=alpine%203.16%20clang%20amd64&logo=Docker&style=flat-square&color=5965AF)](https://registry.hub.docker.com/r/jevolk/construct/tags) | [![](https://img.shields.io/docker/image-size/jevolk/construct/alpine-3.16-base-built-clang-amd64.svg?logoWidth=25&label=alpine%203.16%20clang%20amd64&logo=Docker&style=flat-square&color=5965AF)](https://registry.hub.docker.com/r/jevolk/construct/tags)
|
||||
| [![](https://img.shields.io/docker/image-size/jevolk/construct/alpine-3.16-full-built-gcc-amd64.svg?logoWidth=25&label=alpine%203.16%20gcc%20amd64&logo=Docker&style=flat-square&color=5965AF)](https://registry.hub.docker.com/r/jevolk/construct/tags) | [![](https://img.shields.io/docker/image-size/jevolk/construct/alpine-3.16-base-built-gcc-amd64.svg?logoWidth=25&label=alpine%203.16%20gcc%20amd64&logo=Docker&style=flat-square&color=5965AF)](https://registry.hub.docker.com/r/jevolk/construct/tags)
|
||||
- 📦 [**DISTRIBUTION PACKAGES**](https://github.com/matrix-construct/construct/wiki/PACKAGE)
|
||||
|
||||
- 🐋 [**DOCKER IMAGES**](https://github.com/matrix-construct/construct/wiki/DOCKER)
|
||||
|
||||
### 🗒️ INSTRUCTIONS
|
||||
|
||||
1. 🏗️ [BUILD](https://github.com/matrix-construct/construct/wiki/BUILD) instructions to compile Construct from source.
|
||||
1. 🏗️ [**BUILD**](https://github.com/matrix-construct/construct/wiki/BUILD) to compile Construct from source.
|
||||
|
||||
2. 🪛 [SETUP](https://github.com/matrix-construct/construct/wiki/SETUP) instructions to run Construct for the first time.
|
||||
2. 🪛 [**SETUP**](https://github.com/matrix-construct/construct/wiki/SETUP) to run Construct for the first time.
|
||||
|
||||
3. ⚡ [TUNING](https://github.com/matrix-construct/construct/wiki/TUNING) guide to optimize Construct for your deployment.
|
||||
3. ⚡ [**TUNING**](https://github.com/matrix-construct/construct/wiki/TUNING) to optimize Construct for your deployment.
|
||||
|
||||
- 🙋 [TROUBLESHOOTING](https://github.com/matrix-construct/construct/wiki/Troubleshooting-problems) guide for solutions to possible problems.
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ bool yes6;
|
|||
bool norun;
|
||||
bool nomain;
|
||||
bool read_only;
|
||||
bool write_avoid;
|
||||
bool slave;
|
||||
std::array<bool, 6> smoketest;
|
||||
bool megatest;
|
||||
|
@ -51,6 +50,7 @@ const char *diagnostic;
|
|||
bool nobanner;
|
||||
bool silentmode;
|
||||
bool noiouct;
|
||||
bool noioust;
|
||||
|
||||
lgetopt opts[]
|
||||
{
|
||||
|
@ -76,7 +76,6 @@ lgetopt opts[]
|
|||
{ "norun", &norun, lgetopt::BOOL, "[debug] Initialize but never run the event loop" },
|
||||
{ "nomain", &nomain, lgetopt::BOOL, "[debug] Initialize and run without entering ircd::main()" },
|
||||
{ "ro", &read_only, lgetopt::BOOL, "Read-only mode. No writes to database allowed" },
|
||||
{ "wa", &write_avoid, lgetopt::BOOL, "Like read-only mode, but writes permitted if triggered" },
|
||||
{ "slave", &slave, lgetopt::BOOL, "Like read-only mode; allows multiple instances of server" },
|
||||
{ "smoketest", &smoketest[0], lgetopt::BOOL, "Starts and stops the daemon to return success" },
|
||||
{ "megatest", &megatest, lgetopt::BOOL, "Trap execution every millionth tick for diagnostic and statistics." },
|
||||
|
@ -89,6 +88,7 @@ lgetopt opts[]
|
|||
{ "nobanner", &nobanner, lgetopt::BOOL, "Terminal log enabled only in runlevel RUN" },
|
||||
{ "silent", &silentmode, lgetopt::BOOL, "Like quiet mode without console output either" },
|
||||
{ "noiouct", &noiouct, lgetopt::BOOL, "Disable experimental IORING_SETUP_COOP_TASKRUN" },
|
||||
{ "noioust", &noioust, lgetopt::BOOL, "Disable experimental IORING_SETUP_SINGLE_ISSUER" },
|
||||
{ nullptr, nullptr, lgetopt::STRING, nullptr },
|
||||
};
|
||||
|
||||
|
@ -558,10 +558,11 @@ applyargs()
|
|||
ircd::db::auto_deletion.set("false");
|
||||
}
|
||||
|
||||
if(single && !bootstrap)
|
||||
if(single)
|
||||
{
|
||||
ircd::write_avoid.set("true");
|
||||
ircd::maintenance.set("true");
|
||||
cmdline = !debugmode;
|
||||
nobackfill = true;
|
||||
}
|
||||
|
||||
if(bootstrap)
|
||||
|
@ -572,21 +573,12 @@ applyargs()
|
|||
|
||||
if(slave)
|
||||
{
|
||||
ircd::db::open_slave.set("true");
|
||||
ircd::slave.set("true");
|
||||
read_only = true; // slave implies read_only
|
||||
}
|
||||
|
||||
if(read_only)
|
||||
{
|
||||
ircd::read_only.set("true");
|
||||
write_avoid = true; // read_only implies write_avoid.
|
||||
}
|
||||
|
||||
if(write_avoid)
|
||||
{
|
||||
ircd::write_avoid.set("true");
|
||||
nobackfill = true;
|
||||
}
|
||||
|
||||
if(debugmode)
|
||||
ircd::debugmode.set("true");
|
||||
|
@ -693,17 +685,28 @@ __wrap_io_uring_queue_init(unsigned entries,
|
|||
{
|
||||
namespace info = ircd::info;
|
||||
|
||||
#if defined(IORING_SETUP_COOP_TASKRUN)
|
||||
const bool have_coop_taskrun
|
||||
{
|
||||
info::kernel_version[0] > 5 ||
|
||||
(info::kernel_version[0] >= 5 && info::kernel_version[1] >= 19)
|
||||
};
|
||||
|
||||
#if defined(IORING_SETUP_COOP_TASKRUN)
|
||||
if(have_coop_taskrun && !noiouct)
|
||||
flags |= IORING_SETUP_COOP_TASKRUN;
|
||||
#endif
|
||||
|
||||
#if defined(IORING_SETUP_SINGLE_ISSUER)
|
||||
const bool have_single_issuer
|
||||
{
|
||||
info::kernel_version[0] > 6 ||
|
||||
(info::kernel_version[0] >= 6 && info::kernel_version[1] >= 0)
|
||||
};
|
||||
|
||||
if(have_single_issuer && !noioust)
|
||||
flags |= IORING_SETUP_SINGLE_ISSUER;
|
||||
#endif
|
||||
|
||||
struct io_uring_params params
|
||||
{
|
||||
.flags = flags,
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
namespace fs = ircd::fs;
|
||||
using ircd::string_view;
|
||||
|
||||
decltype(construct::homeserver::primary)
|
||||
construct::homeserver::primary;
|
||||
|
||||
construct::homeserver::homeserver(struct ircd::m::homeserver::opts opts)
|
||||
try
|
||||
:opts
|
||||
|
@ -45,6 +48,8 @@ try
|
|||
}
|
||||
}
|
||||
{
|
||||
assert(!primary);
|
||||
primary = this;
|
||||
}
|
||||
catch(const std::exception &e)
|
||||
{
|
||||
|
@ -59,4 +64,6 @@ catch(const std::exception &e)
|
|||
construct::homeserver::~homeserver()
|
||||
noexcept
|
||||
{
|
||||
assert(primary);
|
||||
primary = nullptr;
|
||||
}
|
||||
|
|
|
@ -23,4 +23,6 @@ struct construct::homeserver
|
|||
public:
|
||||
homeserver(struct ircd::m::homeserver::opts);
|
||||
~homeserver() noexcept;
|
||||
|
||||
static homeserver *primary;
|
||||
};
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
// copyright notice and this permission notice is present in all copies. The
|
||||
// full license for this software is available in the LICENSE file.
|
||||
|
||||
#include <ircd/ircd.h> // must include because asio.h.gch is fPIC
|
||||
#include <ircd/matrix.h>
|
||||
#include <ircd/asio.h>
|
||||
#include "construct.h"
|
||||
#include "homeserver.h"
|
||||
#include "signals.h"
|
||||
#include "console.h"
|
||||
|
||||
|
@ -19,6 +20,7 @@ namespace construct
|
|||
namespace ph = std::placeholders;
|
||||
|
||||
static void handle_cont();
|
||||
static void handle_usr2();
|
||||
static void handle_usr1();
|
||||
static void handle_quit();
|
||||
static void handle_interrupt();
|
||||
|
@ -41,6 +43,7 @@ construct::signals::signals(boost::asio::io_context &ios)
|
|||
signal_set->add(SIGQUIT);
|
||||
signal_set->add(SIGTERM);
|
||||
signal_set->add(SIGUSR1);
|
||||
signal_set->add(SIGUSR2);
|
||||
signal_set->add(SIGCONT);
|
||||
set_handle();
|
||||
}
|
||||
|
@ -132,6 +135,7 @@ construct::handle_signal(const int &signum)
|
|||
case SIGQUIT: return handle_quit();
|
||||
case SIGTERM: return handle_quit();
|
||||
case SIGUSR1: return handle_usr1();
|
||||
case SIGUSR2: return handle_usr2();
|
||||
case SIGCONT: return handle_cont();
|
||||
default: break;
|
||||
}
|
||||
|
@ -225,24 +229,73 @@ try
|
|||
return;
|
||||
}
|
||||
|
||||
if(!homeserver::primary || !homeserver::primary->module[0])
|
||||
return;
|
||||
|
||||
// This signal handler (though not a *real* signal handler) is still
|
||||
// running on the main async stack and not an ircd::ctx. The reload
|
||||
// function does a lot of IO so it requires an ircd::ctx.
|
||||
ircd::context{[]
|
||||
{
|
||||
ircd::mods::import<void ()> reload_conf
|
||||
static ircd::mods::import<void (ircd::m::homeserver *)> rehash
|
||||
{
|
||||
"s_conf", "reload_conf"
|
||||
homeserver::primary->module[0], "ircd::m::homeserver::rehash"
|
||||
};
|
||||
|
||||
reload_conf();
|
||||
assert(homeserver::primary->hs);
|
||||
rehash(homeserver::primary->hs.get());
|
||||
}};
|
||||
}
|
||||
catch(const std::exception &e)
|
||||
{
|
||||
ircd::log::error
|
||||
{
|
||||
"SIGUSR1 handler: %s", e.what()
|
||||
"SIGUSR1 handler :%s",
|
||||
e.what()
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
construct::handle_usr2()
|
||||
try
|
||||
{
|
||||
if(ircd::run::level != ircd::run::level::RUN)
|
||||
{
|
||||
ircd::log::warning
|
||||
{
|
||||
"Not synchronizing database from SIGUSR2 in runlevel %s",
|
||||
reflect(ircd::run::level)
|
||||
};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(!ircd::slave)
|
||||
return;
|
||||
|
||||
if(!homeserver::primary || !homeserver::primary->module[0])
|
||||
return;
|
||||
|
||||
ircd::context{[]
|
||||
{
|
||||
static ircd::mods::import<bool (ircd::m::homeserver *)> refresh
|
||||
{
|
||||
homeserver::primary->module[0], "ircd::m::homeserver::refresh"
|
||||
};
|
||||
|
||||
assert(homeserver::primary->hs);
|
||||
const bool refreshed
|
||||
{
|
||||
refresh(homeserver::primary->hs.get())
|
||||
};
|
||||
}};
|
||||
}
|
||||
catch(const std::exception &e)
|
||||
{
|
||||
ircd::log::error
|
||||
{
|
||||
"SIGUSR2 handler :%s",
|
||||
e.what()
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace boost
|
|||
|
||||
// In boost 1.79+ asio implements some filesystem operations we can use. While
|
||||
// these are available in 1.78 they were buggy for our purposes until 1.79.
|
||||
#if BOOST_VERSION >= 107900
|
||||
#if IRCD_USE_ASIO_IO_URING && BOOST_VERSION >= 107900
|
||||
#define IRCD_USE_ASIO_READ 1
|
||||
#define IRCD_USE_ASIO_WRITE 1
|
||||
#else
|
||||
|
|
|
@ -56,7 +56,9 @@ struct ircd::client
|
|||
size_t write_all(const net::const_buffers &);
|
||||
size_t write_all(const const_buffer &);
|
||||
void close(const net::close_opts &, net::close_callback);
|
||||
ctx::future<void> close(const net::close_opts & = {});
|
||||
void close(const net::dc, net::close_callback);
|
||||
ctx::future<void> close(const net::close_opts &);
|
||||
ctx::future<void> close(const net::dc);
|
||||
|
||||
private:
|
||||
void discard_unconsumed(const http::request::head &);
|
||||
|
|
|
@ -38,9 +38,9 @@ namespace ircd::db
|
|||
template<> prop_map property(const column &, const string_view &name);
|
||||
|
||||
// Access to the column's caches (see cache.h interface)
|
||||
const rocksdb::Cache *cache_compressed(const column &);
|
||||
[[gnu::deprecated]] const rocksdb::Cache *cache_compressed(const column &);
|
||||
const rocksdb::Cache *cache(const column &);
|
||||
rocksdb::Cache *cache_compressed(column &);
|
||||
[[gnu::deprecated]] rocksdb::Cache *cache_compressed(column &);
|
||||
rocksdb::Cache *cache(column &);
|
||||
|
||||
// [GET] Tests if key exists
|
||||
|
|
|
@ -18,9 +18,16 @@ namespace ircd::db
|
|||
// Broad conf items
|
||||
extern conf::item<std::string> open_recover;
|
||||
extern conf::item<bool> open_repair;
|
||||
extern conf::item<bool> open_slave;
|
||||
extern conf::item<bool> auto_compact;
|
||||
extern conf::item<bool> auto_deletion;
|
||||
extern conf::item<bool> open_stats;
|
||||
extern conf::item<bool> paranoid;
|
||||
extern conf::item<bool> paranoid_checks;
|
||||
extern conf::item<bool> paranoid_size;
|
||||
extern conf::item<bool> paranoid_uuid;
|
||||
extern conf::item<bool> paranoid_wal;
|
||||
extern conf::item<bool> paranoid_sst;
|
||||
extern conf::item<bool> paranoid_lsm;
|
||||
|
||||
// General information
|
||||
const std::string &name(const database &);
|
||||
|
|
|
@ -29,14 +29,14 @@ struct ircd::ios::descriptor
|
|||
|
||||
static uint64_t ids;
|
||||
|
||||
static void *default_allocator(handler &, const size_t &);
|
||||
static void default_deallocator(handler &, void *const &, const size_t &) noexcept;
|
||||
static void *default_allocator(handler &, const size_t);
|
||||
static void default_deallocator(handler &, void *, const size_t) noexcept;
|
||||
|
||||
string_view name;
|
||||
uint64_t id {++ids};
|
||||
std::unique_ptr<struct stats> stats;
|
||||
void *(*allocator)(handler &, const size_t &);
|
||||
void (*deallocator)(handler &, void *const &, const size_t &);
|
||||
void *(*allocator)(handler &, const size_t);
|
||||
void (*deallocator)(handler &, void *, const size_t);
|
||||
std::vector<std::array<uint64_t, 2>> history; // epoch, cycles
|
||||
uint8_t history_pos {0};
|
||||
bool continuation {false};
|
||||
|
@ -72,10 +72,10 @@ struct ircd::ios::descriptor::stats
|
|||
item alloc_bytes;
|
||||
item frees;
|
||||
item free_bytes;
|
||||
item slice_total;
|
||||
item slice_last;
|
||||
item latency_total;
|
||||
item slice_total;
|
||||
item latency_last;
|
||||
item latency_total;
|
||||
|
||||
stats(descriptor &);
|
||||
stats() = delete;
|
||||
|
@ -87,8 +87,8 @@ struct ircd::ios::descriptor::stats
|
|||
[[gnu::hot]]
|
||||
inline void
|
||||
ircd::ios::descriptor::default_deallocator(handler &handler,
|
||||
void *const &ptr,
|
||||
const size_t &size)
|
||||
void *const ptr,
|
||||
const size_t size)
|
||||
noexcept
|
||||
{
|
||||
#ifdef __clang__
|
||||
|
@ -101,7 +101,7 @@ noexcept
|
|||
[[gnu::hot]]
|
||||
inline void *
|
||||
ircd::ios::descriptor::default_allocator(handler &handler,
|
||||
const size_t &size)
|
||||
const size_t size)
|
||||
{
|
||||
return ::operator new(size);
|
||||
}
|
||||
|
|
|
@ -28,13 +28,13 @@ struct ircd::ios::handler
|
|||
static thread_local handler *current;
|
||||
static thread_local uint64_t epoch;
|
||||
|
||||
static void enqueue(handler *const &) noexcept;
|
||||
static void *allocate(handler *const &, const size_t &);
|
||||
static void deallocate(handler *const &, void *const &, const size_t &) noexcept;
|
||||
static bool continuation(handler *const &) noexcept;
|
||||
static void enter(handler *const &) noexcept;
|
||||
static void leave(handler *const &) noexcept;
|
||||
static bool fault(handler *const &) noexcept;
|
||||
static void enqueue(handler *) noexcept;
|
||||
static void *allocate(handler *, const size_t);
|
||||
static void deallocate(handler *, void *, const size_t) noexcept;
|
||||
static bool continuation(handler *) noexcept;
|
||||
static void enter(handler *) noexcept;
|
||||
static void leave(handler *) noexcept;
|
||||
static bool fault(handler *) noexcept;
|
||||
|
||||
ios::descriptor *descriptor {nullptr};
|
||||
uint64_t ts {0}; // last tsc sample; for profiling each phase
|
||||
|
@ -91,9 +91,9 @@ const
|
|||
|
||||
[[gnu::hot]]
|
||||
inline void
|
||||
ircd::ios::handler::deallocate(handler *const &handler,
|
||||
void *const &ptr,
|
||||
const size_t &size)
|
||||
ircd::ios::handler::deallocate(handler *const handler,
|
||||
void *const ptr,
|
||||
const size_t size)
|
||||
noexcept
|
||||
{
|
||||
assert(handler && handler->descriptor);
|
||||
|
@ -110,8 +110,8 @@ noexcept
|
|||
|
||||
[[gnu::hot]]
|
||||
inline void *
|
||||
ircd::ios::handler::allocate(handler *const &handler,
|
||||
const size_t &size)
|
||||
ircd::ios::handler::allocate(handler *const handler,
|
||||
const size_t size)
|
||||
{
|
||||
assert(handler && handler->descriptor);
|
||||
auto &descriptor(*handler->descriptor);
|
||||
|
@ -127,7 +127,7 @@ ircd::ios::handler::allocate(handler *const &handler,
|
|||
|
||||
[[gnu::hot]]
|
||||
inline void
|
||||
ircd::ios::handler::enqueue(handler *const &handler)
|
||||
ircd::ios::handler::enqueue(handler *const handler)
|
||||
noexcept
|
||||
{
|
||||
assert(handler && handler->descriptor);
|
||||
|
@ -152,7 +152,7 @@ noexcept
|
|||
|
||||
[[gnu::hot]]
|
||||
inline bool
|
||||
ircd::ios::handler::continuation(handler *const &handler)
|
||||
ircd::ios::handler::continuation(handler *const handler)
|
||||
noexcept
|
||||
{
|
||||
assert(handler && handler->descriptor);
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace ircd::ios
|
|||
extern asio::executor user, main;
|
||||
extern std::thread::id main_thread_id;
|
||||
extern thread_local bool is_main_thread;
|
||||
extern bool user_available, main_available;
|
||||
|
||||
bool available() noexcept;
|
||||
const uint64_t &epoch() noexcept;
|
||||
|
@ -64,3 +65,11 @@ noexcept
|
|||
{
|
||||
return handler::epoch;
|
||||
}
|
||||
|
||||
inline bool
|
||||
__attribute__((always_inline))
|
||||
ircd::ios::available()
|
||||
noexcept
|
||||
{
|
||||
return main_available;
|
||||
}
|
||||
|
|
|
@ -129,10 +129,10 @@ namespace ircd
|
|||
|
||||
// Operating Mode Selectors
|
||||
extern conf::item<bool> debugmode;
|
||||
extern conf::item<bool> maintenance;
|
||||
extern conf::item<bool> soft_assert;
|
||||
extern conf::item<bool> write_avoid; // implies maintenance
|
||||
extern conf::item<bool> read_only; // implies write_avoid
|
||||
extern conf::item<bool> maintenance;
|
||||
extern conf::item<bool> slave;
|
||||
extern conf::item<bool> read_only;
|
||||
extern conf::item<bool> defaults;
|
||||
}
|
||||
|
||||
|
|
|
@ -83,6 +83,8 @@ struct ircd::m::homeserver
|
|||
/// Factory to create homeserver with single procedure for shlib purposes.
|
||||
static homeserver *init(const struct opts *);
|
||||
static void fini(homeserver *) noexcept;
|
||||
static bool rehash(homeserver *);
|
||||
static bool refresh(homeserver *);
|
||||
};
|
||||
|
||||
struct ircd::m::homeserver::key
|
||||
|
|
|
@ -63,7 +63,8 @@ struct ircd::m::keys
|
|||
static bool get(const queries &, const closure_bool &);
|
||||
static bool get(const string_view &server_name, const closure &);
|
||||
static bool get(const string_view &server_name, const string_view &key_id, const closure &);
|
||||
static bool query(const string_view &query_server, const queries &, const closure_bool &);
|
||||
static bool query(const string_view &remote, const queries &, const closure_bool &, const mutable_buffer &, const bool dynamic = false);
|
||||
static bool query(const string_view &remote, const queries &, const closure_bool &);
|
||||
static size_t fetch(const queries &);
|
||||
static size_t fetch(const pdus &);
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace ircd::m::vm
|
|||
enum phase :uint;
|
||||
|
||||
string_view reflect(const phase &);
|
||||
phase phase_reflect(const string_view &) noexcept; // default NONE
|
||||
}
|
||||
|
||||
/// Evaluation phases
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
namespace ircd::m::vm::sequence
|
||||
{
|
||||
struct refresh;
|
||||
|
||||
extern ctx::dock dock;
|
||||
extern uint64_t retired; // already written; always monotonic
|
||||
extern uint64_t committed; // pending write; usually monotonic
|
||||
|
@ -25,3 +27,12 @@ namespace ircd::m::vm::sequence
|
|||
uint64_t max();
|
||||
uint64_t min();
|
||||
}
|
||||
|
||||
struct ircd::m::vm::sequence::refresh
|
||||
{
|
||||
uint64_t database[2] {0, 0};
|
||||
uint64_t retired[2] {0, 0};
|
||||
m::event::id::buf event_id;
|
||||
|
||||
refresh();
|
||||
};
|
||||
|
|
|
@ -61,17 +61,22 @@ ircd::net::acceptor
|
|||
ip::tcp::acceptor a;
|
||||
size_t accepting {0};
|
||||
sockets handshaking;
|
||||
bool secure {false};
|
||||
bool interrupting {false};
|
||||
ctx::dock joining;
|
||||
|
||||
// Internal configuration
|
||||
void configure_dh(const json::object &);
|
||||
void configure_certs(const json::object &);
|
||||
bool configure_certs(const json::object &);
|
||||
void configure_curves(const json::object &);
|
||||
void configure_ciphers(const json::object &);
|
||||
void configure_flags(const json::object &);
|
||||
void configure_password(const json::object &);
|
||||
void configure(const json::object &opts);
|
||||
void configure_sni(const json::object &);
|
||||
bool configure(const json::object &opts);
|
||||
|
||||
// Completion stack
|
||||
void accepted(const std::shared_ptr<socket> &);
|
||||
|
||||
// Handshake stack
|
||||
bool handle_sni(socket &, int &ad);
|
||||
|
|
|
@ -17,11 +17,15 @@ namespace ircd::net
|
|||
struct close_opts extern const close_opts_default;
|
||||
using close_callback = std::function<void (std::exception_ptr)>;
|
||||
|
||||
string_view reflect(const dc) noexcept;
|
||||
|
||||
// Callback-based closer.
|
||||
void close(socket &, const close_opts &, close_callback);
|
||||
void close(socket &, const dc &, close_callback);
|
||||
|
||||
// Future-based closer.
|
||||
ctx::future<void> close(socket &, const close_opts & = close_opts_default);
|
||||
ctx::future<void> close(socket &, const dc &);
|
||||
|
||||
// Fire-and-forget helper callback for close().
|
||||
extern const close_callback close_ignore;
|
||||
|
@ -44,9 +48,6 @@ struct ircd::net::close_opts
|
|||
{
|
||||
static conf::item<milliseconds> default_timeout;
|
||||
|
||||
close_opts() = default;
|
||||
close_opts(const net::dc &);
|
||||
|
||||
/// The type of close() to be conducted is specified here.
|
||||
net::dc type { dc::SSL_NOTIFY };
|
||||
|
||||
|
@ -56,11 +57,10 @@ struct ircd::net::close_opts
|
|||
/// If specified, these socket options will be applied when conducting
|
||||
/// the disconnect (useful for adding an SO_LINGER time etc).
|
||||
const sock_opts *sopts { nullptr };
|
||||
};
|
||||
|
||||
/// Allows for implicit construction of close_opts in arguments to close()
|
||||
/// without requiring brackets for the close_opts& argument.
|
||||
inline
|
||||
ircd::net::close_opts::close_opts(const net::dc &type)
|
||||
:type{type}
|
||||
{}
|
||||
/// For portable clean disconnection shutdown(2) might be called prior to
|
||||
/// close(2). Setting this option to dc::RST skips the shutdown(2) when
|
||||
/// the caller deems it unnecessary. At this time it only affects non-SSL
|
||||
/// sockets and in the future we will have io_uring(7) fuse these calls.
|
||||
net::dc shutdown { dc::FIN };
|
||||
};
|
||||
|
|
|
@ -65,6 +65,9 @@ struct ircd::net::open_opts
|
|||
/// if given. Defaults to null; no application is made.
|
||||
const sock_opts *sopts { nullptr };
|
||||
|
||||
/// Option to disable SSL. Use false for plaintext socket.
|
||||
bool secure { true };
|
||||
|
||||
/// Option to toggle whether to perform the SSL handshake; you want true.
|
||||
bool handshake { true };
|
||||
|
||||
|
|
|
@ -16,8 +16,9 @@ namespace ircd::net
|
|||
using mutable_buffers = vector_view<const mutable_buffer>;
|
||||
|
||||
// Observers
|
||||
size_t readable(const socket &);
|
||||
size_t available(const socket &) noexcept;
|
||||
size_t readable(const socket &); // don't use w/ ssl
|
||||
size_t available(const socket &) noexcept; // don't use w/ ssl
|
||||
size_t pending(const socket &) noexcept; // use with either.
|
||||
|
||||
// Non-blocking; read into buffers in a single syscall
|
||||
size_t read_one(socket &, const mutable_buffers &);
|
||||
|
|
|
@ -14,10 +14,13 @@
|
|||
namespace ircd::net
|
||||
{
|
||||
struct sock_opts;
|
||||
IRCD_OVERLOAD(system);
|
||||
|
||||
bool v6only(const socket &);
|
||||
bool blocking(const socket &, system_t);
|
||||
bool blocking(const socket &);
|
||||
bool nopush(const socket &);
|
||||
bool nodelay(const socket &, system_t);
|
||||
bool nodelay(const socket &);
|
||||
bool quickack(const socket &);
|
||||
bool keepalive(const socket &);
|
||||
|
@ -29,21 +32,23 @@ namespace ircd::net
|
|||
int attach(const socket &);
|
||||
|
||||
// returns true if supported, false if unsupported; failures will throw.
|
||||
bool v6only(socket &, const bool &);
|
||||
bool blocking(socket &, const bool &);
|
||||
bool nopush(socket &, const bool &);
|
||||
bool nodelay(socket &, const bool &);
|
||||
bool quickack(socket &, const bool &);
|
||||
bool keepalive(socket &, const bool &);
|
||||
bool linger(socket &, const time_t &); // -1 is OFF; >= 0 is ON
|
||||
bool read_bufsz(socket &, const size_t &bytes);
|
||||
bool write_bufsz(socket &, const size_t &bytes);
|
||||
bool read_lowat(socket &, const size_t &bytes);
|
||||
bool write_lowat(socket &, const size_t &bytes);
|
||||
bool attach(const int &sd, const int &fd);
|
||||
bool attach(socket &, const int &fd);
|
||||
bool detach(const int &sd, const int &fd);
|
||||
bool detach(socket &, const int &fd);
|
||||
bool v6only(socket &, const bool);
|
||||
bool blocking(socket &, const bool, system_t);
|
||||
bool blocking(socket &, const bool);
|
||||
bool nopush(socket &, const bool);
|
||||
bool nodelay(socket &, const bool, system_t);
|
||||
bool nodelay(socket &, const bool);
|
||||
bool quickack(socket &, const bool);
|
||||
bool keepalive(socket &, const bool);
|
||||
bool linger(socket &, const time_t); // -1 is OFF; >= 0 is ON
|
||||
bool read_bufsz(socket &, const size_t bytes);
|
||||
bool write_bufsz(socket &, const size_t bytes);
|
||||
bool read_lowat(socket &, const size_t bytes);
|
||||
bool write_lowat(socket &, const size_t bytes);
|
||||
bool attach(const int sd, const int fd);
|
||||
bool attach(socket &, const int fd);
|
||||
bool detach(const int sd, const int fd);
|
||||
bool detach(socket &, const int fd);
|
||||
|
||||
void set(socket &, const sock_opts &);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace ircd::net
|
|||
}
|
||||
|
||||
/// Internal socket interface
|
||||
///
|
||||
/// Socket cannot be copied or moved; must be constructed as shared ptr.
|
||||
struct [[gnu::visibility("protected")]]
|
||||
ircd::net::socket
|
||||
:std::enable_shared_from_this<ircd::net::socket>
|
||||
|
@ -40,6 +40,7 @@ ircd::net::socket
|
|||
using endpoint = ip::tcp::endpoint;
|
||||
using wait_type = ip::tcp::socket::wait_type;
|
||||
using message_flags = asio::socket_base::message_flags;
|
||||
using ssl_stream = asio::ssl::stream<ip::tcp::socket &>;
|
||||
using handshake_type = asio::ssl::stream<ip::tcp::socket>::handshake_type;
|
||||
using ec_handler = std::function<void (const error_code &)>;
|
||||
using eptr_handler = std::function<void (std::exception_ptr)>;
|
||||
|
@ -64,7 +65,7 @@ ircd::net::socket
|
|||
|
||||
uint64_t id {++count};
|
||||
ip::tcp::socket sd;
|
||||
asio::ssl::stream<ip::tcp::socket &> ssl;
|
||||
std::optional<ssl_stream> ssl;
|
||||
endpoint local, remote;
|
||||
stat in, out;
|
||||
deadline_timer timer;
|
||||
|
@ -73,6 +74,7 @@ ircd::net::socket
|
|||
bool timer_set {false}; // boolean lockout
|
||||
bool timedout {false};
|
||||
bool fini {false};
|
||||
mutable bool _nodelay {false}; // userspace tracking only
|
||||
|
||||
void call_user(const eptr_handler &, const error_code &) noexcept;
|
||||
void call_user(const ec_handler &, const error_code &) noexcept;
|
||||
|
@ -120,9 +122,8 @@ ircd::net::socket
|
|||
void connect(const endpoint &, const open_opts &, eptr_handler);
|
||||
bool cancel() noexcept;
|
||||
|
||||
socket(asio::ssl::context & = sslv23_client);
|
||||
|
||||
// Socket cannot be copied or moved; must be constructed as shared ptr
|
||||
socket(asio::ssl::context &);
|
||||
socket();
|
||||
socket(socket &&) = delete;
|
||||
socket(const socket &) = delete;
|
||||
socket &operator=(socket &&) = delete;
|
||||
|
|
|
@ -39,7 +39,7 @@ struct ircd::resource::response
|
|||
static const size_t HEAD_BUF_SZ;
|
||||
static conf::item<std::string> access_control_allow_origin;
|
||||
|
||||
response(client &, const http::code &, const string_view &content_type, const size_t &content_length, const string_view &headers = {});
|
||||
response(client &, const http::code &, const string_view &content_type, const size_t &content_length, const string_view &headers = {}, const string_view &content = {});
|
||||
response(client &, const string_view &str, const string_view &content_type, const http::code &, const vector_view<const http::header> &);
|
||||
response(client &, const string_view &str, const string_view &content_type, const http::code & = http::OK, const string_view &headers = {});
|
||||
response(client &, const json::object &str, const http::code & = http::OK);
|
||||
|
|
|
@ -93,7 +93,8 @@ struct ircd::server::link
|
|||
void submit(request &);
|
||||
|
||||
// control panel
|
||||
bool close(const net::close_opts & = net::close_opts_default);
|
||||
bool close(const net::close_opts &);
|
||||
bool close(const net::dc = net::dc::SSL_NOTIFY);
|
||||
bool open(const net::open_opts &);
|
||||
|
||||
link(server::peer &);
|
||||
|
|
|
@ -587,7 +587,13 @@ try
|
|||
loghead(client),
|
||||
};
|
||||
|
||||
client.close(net::dc::SSL_NOTIFY, net::close_ignore);
|
||||
const net::close_opts opts
|
||||
{
|
||||
.type = net::dc::SSL_NOTIFY,
|
||||
.shutdown = net::dc::RST,
|
||||
};
|
||||
|
||||
client.close(opts, net::close_ignore);
|
||||
return false;
|
||||
}
|
||||
catch(const std::exception &e)
|
||||
|
@ -1048,6 +1054,15 @@ ircd::client::discard_unconsumed(const http::request::head &head)
|
|||
assert(content_consumed == head.content_length);
|
||||
}
|
||||
|
||||
ircd::ctx::future<void>
|
||||
ircd::client::close(const net::dc type)
|
||||
{
|
||||
return close(net::close_opts
|
||||
{
|
||||
.type = type,
|
||||
});
|
||||
}
|
||||
|
||||
ircd::ctx::future<void>
|
||||
ircd::client::close(const net::close_opts &opts)
|
||||
{
|
||||
|
@ -1056,6 +1071,18 @@ ircd::client::close(const net::close_opts &opts)
|
|||
ctx::already;
|
||||
}
|
||||
|
||||
void
|
||||
ircd::client::close(const net::dc type,
|
||||
net::close_callback callback)
|
||||
{
|
||||
const net::close_opts opts
|
||||
{
|
||||
.type = type,
|
||||
};
|
||||
|
||||
close(opts, std::move(callback));
|
||||
}
|
||||
|
||||
void
|
||||
ircd::client::close(const net::close_opts &opts,
|
||||
net::close_callback callback)
|
||||
|
|
125
ircd/db.cc
125
ircd/db.cc
|
@ -179,10 +179,10 @@ try
|
|||
fs::base::db
|
||||
};
|
||||
|
||||
if(!fs::is_dir(dbdir) && (ircd::read_only || ircd::write_avoid))
|
||||
if(!fs::is_dir(dbdir) && (ircd::read_only || ircd::maintenance))
|
||||
log::warning
|
||||
{
|
||||
log, "Not creating database directory `%s' in read-only/write-avoid mode.", dbdir
|
||||
log, "Not creating database directory `%s' in read-only/maintenance mode.", dbdir
|
||||
};
|
||||
else if(fs::mkdir(dbdir))
|
||||
log::notice
|
||||
|
@ -3204,7 +3204,7 @@ rocksdb::Cache *
|
|||
ircd::db::cache_compressed(column &column)
|
||||
{
|
||||
database::column &c(column);
|
||||
return c.table_opts.block_cache_compressed.get();
|
||||
return nullptr; // c.table_opts.block_cache_compressed.get();
|
||||
}
|
||||
|
||||
[[gnu::hot]]
|
||||
|
@ -3219,7 +3219,7 @@ const rocksdb::Cache *
|
|||
ircd::db::cache_compressed(const column &column)
|
||||
{
|
||||
const database::column &c(column);
|
||||
return c.table_opts.block_cache_compressed.get();
|
||||
return nullptr; // c.table_opts.block_cache_compressed.get();
|
||||
}
|
||||
|
||||
template<>
|
||||
|
@ -3852,9 +3852,16 @@ ircd::db::options::operator rocksdb::PlainTableOptions()
|
|||
const
|
||||
{
|
||||
rocksdb::PlainTableOptions ret;
|
||||
#ifdef IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
rocksdb::ConfigOptions opts;
|
||||
#endif
|
||||
throw_on_error
|
||||
{
|
||||
#ifdef IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
rocksdb::GetPlainTableOptionsFromString(opts, ret, *this, &ret)
|
||||
#else
|
||||
rocksdb::GetPlainTableOptionsFromString(ret, *this, &ret)
|
||||
#endif
|
||||
};
|
||||
|
||||
return ret;
|
||||
|
@ -3864,9 +3871,16 @@ ircd::db::options::operator rocksdb::BlockBasedTableOptions()
|
|||
const
|
||||
{
|
||||
rocksdb::BlockBasedTableOptions ret;
|
||||
#ifdef IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
rocksdb::ConfigOptions opts;
|
||||
#endif
|
||||
throw_on_error
|
||||
{
|
||||
#ifdef IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
rocksdb::GetBlockBasedTableOptionsFromString(opts, ret, *this, &ret)
|
||||
#else
|
||||
rocksdb::GetBlockBasedTableOptionsFromString(ret, *this, &ret)
|
||||
#endif
|
||||
};
|
||||
|
||||
return ret;
|
||||
|
@ -3876,9 +3890,16 @@ ircd::db::options::operator rocksdb::ColumnFamilyOptions()
|
|||
const
|
||||
{
|
||||
rocksdb::ColumnFamilyOptions ret;
|
||||
#ifdef IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
rocksdb::ConfigOptions opts;
|
||||
#endif
|
||||
throw_on_error
|
||||
{
|
||||
#ifdef IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
rocksdb::GetColumnFamilyOptionsFromString(opts, ret, *this, &ret)
|
||||
#else
|
||||
rocksdb::GetColumnFamilyOptionsFromString(ret, *this, &ret)
|
||||
#endif
|
||||
};
|
||||
|
||||
return ret;
|
||||
|
@ -3888,9 +3909,16 @@ ircd::db::options::operator rocksdb::DBOptions()
|
|||
const
|
||||
{
|
||||
rocksdb::DBOptions ret;
|
||||
#ifdef IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
rocksdb::ConfigOptions opts;
|
||||
#endif
|
||||
throw_on_error
|
||||
{
|
||||
#ifdef IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
rocksdb::GetDBOptionsFromString(opts, ret, *this, &ret)
|
||||
#else
|
||||
rocksdb::GetDBOptionsFromString(ret, *this, &ret)
|
||||
#endif
|
||||
};
|
||||
|
||||
return ret;
|
||||
|
@ -3900,9 +3928,16 @@ ircd::db::options::operator rocksdb::Options()
|
|||
const
|
||||
{
|
||||
rocksdb::Options ret;
|
||||
#ifdef IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
rocksdb::ConfigOptions opts;
|
||||
#endif
|
||||
throw_on_error
|
||||
{
|
||||
#ifdef IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
rocksdb::GetOptionsFromString(opts, ret, *this, &ret)
|
||||
#else
|
||||
rocksdb::GetOptionsFromString(ret, *this, &ret)
|
||||
#endif
|
||||
};
|
||||
|
||||
return ret;
|
||||
|
@ -3949,52 +3984,88 @@ const
|
|||
}
|
||||
|
||||
rocksdb::BlockBasedTableOptions
|
||||
ircd::db::options::map::merge(const rocksdb::BlockBasedTableOptions &opts)
|
||||
ircd::db::options::map::merge(const rocksdb::BlockBasedTableOptions &in)
|
||||
const
|
||||
{
|
||||
#ifdef IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
rocksdb::ConfigOptions opts;
|
||||
opts.ignore_unknown_options = true;
|
||||
#endif
|
||||
|
||||
rocksdb::BlockBasedTableOptions ret;
|
||||
throw_on_error
|
||||
{
|
||||
rocksdb::GetBlockBasedTableOptionsFromMap(opts, *this, &ret, true, true)
|
||||
#ifdef IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
rocksdb::GetBlockBasedTableOptionsFromMap(opts, in, *this, &ret)
|
||||
#else
|
||||
rocksdb::GetBlockBasedTableOptionsFromMap(in, *this, &ret, true, true)
|
||||
#endif
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rocksdb::PlainTableOptions
|
||||
ircd::db::options::map::merge(const rocksdb::PlainTableOptions &opts)
|
||||
ircd::db::options::map::merge(const rocksdb::PlainTableOptions &in)
|
||||
const
|
||||
{
|
||||
#ifdef IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
rocksdb::ConfigOptions opts;
|
||||
opts.ignore_unknown_options = true;
|
||||
#endif
|
||||
|
||||
rocksdb::PlainTableOptions ret;
|
||||
throw_on_error
|
||||
{
|
||||
rocksdb::GetPlainTableOptionsFromMap(opts, *this, &ret, true, true)
|
||||
#ifdef IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
rocksdb::GetPlainTableOptionsFromMap(opts, in, *this, &ret)
|
||||
#else
|
||||
rocksdb::GetPlainTableOptionsFromMap(in, *this, &ret, true, true)
|
||||
#endif
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rocksdb::ColumnFamilyOptions
|
||||
ircd::db::options::map::merge(const rocksdb::ColumnFamilyOptions &opts)
|
||||
ircd::db::options::map::merge(const rocksdb::ColumnFamilyOptions &in)
|
||||
const
|
||||
{
|
||||
#ifdef IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
rocksdb::ConfigOptions opts;
|
||||
opts.ignore_unknown_options = true;
|
||||
#endif
|
||||
|
||||
rocksdb::ColumnFamilyOptions ret;
|
||||
throw_on_error
|
||||
{
|
||||
rocksdb::GetColumnFamilyOptionsFromMap(opts, *this, &ret, true, true)
|
||||
#ifdef IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
rocksdb::GetColumnFamilyOptionsFromMap(opts, in, *this, &ret)
|
||||
#else
|
||||
rocksdb::GetColumnFamilyOptionsFromMap(in, *this, &ret, true, true)
|
||||
#endif
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rocksdb::DBOptions
|
||||
ircd::db::options::map::merge(const rocksdb::DBOptions &opts)
|
||||
ircd::db::options::map::merge(const rocksdb::DBOptions &in)
|
||||
const
|
||||
{
|
||||
#ifdef IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
rocksdb::ConfigOptions opts;
|
||||
opts.ignore_unknown_options = true;
|
||||
#endif
|
||||
|
||||
rocksdb::DBOptions ret;
|
||||
throw_on_error
|
||||
{
|
||||
rocksdb::GetDBOptionsFromMap(opts, *this, &ret, true, true)
|
||||
#ifdef IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
rocksdb::GetDBOptionsFromMap(opts, in, *this, &ret)
|
||||
#else
|
||||
rocksdb::GetDBOptionsFromMap(in, *this, &ret, true, true)
|
||||
#endif
|
||||
};
|
||||
|
||||
return ret;
|
||||
|
@ -4053,11 +4124,19 @@ ircd::db::insert(rocksdb::Cache &cache,
|
|||
// the argument execution doesn't throw after release()
|
||||
throw_on_error
|
||||
{
|
||||
#ifdef IRCD_DB_HAS_CACHE_ITEMHELPER
|
||||
cache.Insert(slice(key),
|
||||
mutable_cast(data(value.release())),
|
||||
cache.GetCacheItemHelper(nullptr), // ???
|
||||
value_size,
|
||||
nullptr)
|
||||
#else
|
||||
cache.Insert(slice(key),
|
||||
mutable_cast(data(value.release())),
|
||||
value_size,
|
||||
deleter,
|
||||
nullptr)
|
||||
#endif
|
||||
};
|
||||
|
||||
return true;
|
||||
|
@ -4066,6 +4145,24 @@ ircd::db::insert(rocksdb::Cache &cache,
|
|||
void
|
||||
ircd::db::for_each(const rocksdb::Cache &cache,
|
||||
const cache_closure &closure)
|
||||
#ifdef IRCD_DB_HAS_CACHE_ITEMHELPER
|
||||
{
|
||||
const auto _closure{[&closure]
|
||||
(const auto &slice, void *const value, size_t size, const auto *const helper)
|
||||
noexcept
|
||||
{
|
||||
const const_buffer buf
|
||||
{
|
||||
reinterpret_cast<const char *>(value), size
|
||||
};
|
||||
|
||||
closure(buf);
|
||||
}};
|
||||
|
||||
rocksdb::Cache::ApplyToAllEntriesOptions opts;
|
||||
mutable_cast(cache).ApplyToAllEntries(_closure, opts);
|
||||
}
|
||||
#else
|
||||
{
|
||||
// Due to the use of the global variables which are required when using a
|
||||
// C-style callback for RocksDB, we have to make use of this function
|
||||
|
@ -4094,6 +4191,7 @@ ircd::db::for_each(const rocksdb::Cache &cache,
|
|||
},
|
||||
true);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IRCD_DB_HAS_CACHE_GETCHARGE
|
||||
size_t
|
||||
|
@ -5825,6 +5923,9 @@ ircd::db::reflect(const rocksdb::CompactionReason &r)
|
|||
#ifdef IRCD_DB_HAS_ROUND_ROBIN_TTL
|
||||
case Reason::kRoundRobinTtl: return "kRoundRobinTtl";
|
||||
#endif
|
||||
#ifdef IRCD_DB_HAS_REFIT_LEVEL
|
||||
case Reason::kRefitLevel: return "RefitLevel";
|
||||
#endif
|
||||
|
||||
case Reason::kNumOfReasons:
|
||||
break;
|
||||
|
|
23
ircd/db.h
23
ircd/db.h
|
@ -61,6 +61,9 @@
|
|||
#include <rocksdb/compaction_filter.h>
|
||||
#include <rocksdb/wal_filter.h>
|
||||
#include <rocksdb/rate_limiter.h>
|
||||
#if __has_include(<rocksdb/advanced_cache.h>)
|
||||
#include <rocksdb/advanced_cache.h>
|
||||
#endif
|
||||
#pragma clang attribute pop
|
||||
|
||||
#include "db_has.h"
|
||||
|
@ -218,8 +221,16 @@ ircd::db::database::cache final
|
|||
std::shared_ptr<rocksdb::Cache> c;
|
||||
|
||||
const char *Name() const noexcept override;
|
||||
#ifdef IRCD_DB_HAS_CACHE_ITEMHELPER
|
||||
Status Insert(const Slice &key, ObjectPtr, const CacheItemHelper *, size_t charge, Handle **, Priority) noexcept override;
|
||||
#else
|
||||
Status Insert(const Slice &key, void *value, size_t charge, deleter, Handle **, Priority) noexcept override;
|
||||
#endif
|
||||
#ifdef IRCD_DB_HAS_CACHE_ITEMHELPER
|
||||
Handle *Lookup(const Slice &key, const CacheItemHelper *, CreateContext *, Priority, bool, Statistics *) noexcept override;
|
||||
#else
|
||||
Handle *Lookup(const Slice &key, Statistics *) noexcept override;
|
||||
#endif
|
||||
bool Ref(Handle *) noexcept override;
|
||||
bool Release(Handle *, bool force_erase) noexcept override;
|
||||
void *Value(Handle *) noexcept override;
|
||||
|
@ -233,19 +244,27 @@ ircd::db::database::cache final
|
|||
size_t GetUsage(Handle *) const noexcept override;
|
||||
size_t GetPinnedUsage() const noexcept override;
|
||||
void DisownData() noexcept override;
|
||||
#ifndef IRCD_DB_HAS_CACHE_ITEMHELPER
|
||||
void ApplyToAllCacheEntries(callback, bool thread_safe) noexcept override;
|
||||
#endif
|
||||
void EraseUnRefEntries() noexcept override;
|
||||
std::string GetPrintableOptions() const noexcept override;
|
||||
#ifdef IRCD_DB_HAS_CACHE_GETCHARGE
|
||||
size_t GetCharge(Handle *) const noexcept override;
|
||||
#endif
|
||||
#ifdef IRCD_DB_HAS_CACHE_GETDELETER
|
||||
#if defined(IRCD_DB_HAS_CACHE_GETDELETER) && !defined(IRCD_DB_HAS_CACHE_ITEMHELPER)
|
||||
DeleterFn GetDeleter(Handle *) const noexcept override;
|
||||
#endif
|
||||
#ifdef IRCD_DB_HAS_CACHE_APPLYTOALL
|
||||
#ifdef IRCD_DB_HAS_CACHE_ITEMHELPER
|
||||
using callbackstd = std::function<void (const Slice &, ObjectPtr, size_t, const CacheItemHelper *)>;
|
||||
void ApplyToAllEntries(const callbackstd &, const ApplyToAllEntriesOptions &) noexcept override;
|
||||
#elif defined(IRCD_DB_HAS_CACHE_APPLYTOALL)
|
||||
using callbackstd = std::function<void (const Slice &, void *, size_t, DeleterFn)>;
|
||||
void ApplyToAllEntries(const callbackstd &, const ApplyToAllEntriesOptions &) noexcept override;
|
||||
#endif
|
||||
#ifdef IRCD_DB_HAS_CACHE_ITEMHELPER
|
||||
const CacheItemHelper *GetCacheItemHelper(Handle *) const noexcept override;
|
||||
#endif
|
||||
|
||||
cache(database *const &,
|
||||
std::shared_ptr<struct database::stats>,
|
||||
|
|
|
@ -81,17 +81,87 @@ ircd::db::auto_deletion
|
|||
{ "persist", false },
|
||||
};
|
||||
|
||||
/// Conf item dictates whether databases will be opened in slave mode; this
|
||||
/// is a recent feature of RocksDB which may not be available. It allows two
|
||||
/// instances of a database, so long as only one is not opened as a slave.
|
||||
decltype(ircd::db::open_slave)
|
||||
ircd::db::open_slave
|
||||
/// Gather statistics about files on open to inform the compaction algorithm.
|
||||
/// This can be disabled to prevent touching a lot of files on open, but it's
|
||||
/// unclear when/if that information will be gathered to ever inform compactor.
|
||||
decltype(ircd::db::open_stats)
|
||||
ircd::db::open_stats
|
||||
{
|
||||
{ "name", "ircd.db.open.slave" },
|
||||
{ "default", false },
|
||||
{ "name", "ircd.db.open.stats" },
|
||||
{ "default", true },
|
||||
{ "persist", false },
|
||||
};
|
||||
|
||||
/// Paranoid suite toggle. This allows coarse control over the rest of the
|
||||
/// configuration from here. If this is set to false, all other paranoid confs
|
||||
/// will default to false; note that each conf can still be explicitly set.
|
||||
decltype(ircd::db::paranoid)
|
||||
ircd::db::paranoid
|
||||
{
|
||||
{ "name", "ircd.db.paranoid.enable" },
|
||||
{ "default", true },
|
||||
{ "persist", false },
|
||||
};
|
||||
|
||||
/// General paranoid checks; enabled by rocksdb by default. Disabling this
|
||||
/// might implicitly override some of the other paranoid features configurable
|
||||
/// here and disable them within rocksdb.
|
||||
decltype(ircd::db::paranoid_checks)
|
||||
ircd::db::paranoid_checks
|
||||
{
|
||||
{ "name", "ircd.db.paranoid.checks" },
|
||||
{ "default", bool(paranoid) },
|
||||
{ "persist", false },
|
||||
};
|
||||
|
||||
/// Check file sizes on open. This is expensive because it opens every file
|
||||
/// with only mediocre value for finding corruption in practice.
|
||||
decltype(ircd::db::paranoid_size)
|
||||
ircd::db::paranoid_size
|
||||
{
|
||||
{ "name", "ircd.db.paranoid.size" },
|
||||
{ "default", false },
|
||||
{ "persist", false },
|
||||
};
|
||||
|
||||
/// Check UUIDs of SST files against the manifest.
|
||||
decltype(ircd::db::paranoid_uuid)
|
||||
ircd::db::paranoid_uuid
|
||||
{
|
||||
{ "name", "ircd.db.paranoid.uuid" },
|
||||
{ "default", bool(paranoid) },
|
||||
{ "persist", false },
|
||||
};
|
||||
|
||||
/// Check WAL against the manifest for corruption.
|
||||
decltype(ircd::db::paranoid_wal)
|
||||
ircd::db::paranoid_wal
|
||||
{
|
||||
{ "name", "ircd.db.paranoid.wal" },
|
||||
{ "default", bool(paranoid) },
|
||||
{ "persist", false },
|
||||
};
|
||||
|
||||
/// Check every SST after writing it. This is expensive and rocksdb doesn't
|
||||
/// enable it in their own defaults.
|
||||
decltype(ircd::db::paranoid_sst)
|
||||
ircd::db::paranoid_sst
|
||||
{
|
||||
{ "name", "ircd.db.paranoid.sst" },
|
||||
{ "default", false },
|
||||
{ "persist", false },
|
||||
};
|
||||
|
||||
/// Check LSM after changing it. This is claimed to be cheap by rocksdb and
|
||||
/// they enable it by default.
|
||||
decltype(ircd::db::paranoid_lsm)
|
||||
ircd::db::paranoid_lsm
|
||||
{
|
||||
{ "name", "ircd.db.paranoid.lsm" },
|
||||
{ "default", bool(paranoid) },
|
||||
{ "persist", false },
|
||||
};
|
||||
|
||||
void
|
||||
ircd::db::sync(database &d)
|
||||
{
|
||||
|
@ -859,7 +929,7 @@ try
|
|||
}
|
||||
,slave
|
||||
{
|
||||
db::open_slave
|
||||
ircd::slave
|
||||
}
|
||||
,read_only
|
||||
{
|
||||
|
@ -968,8 +1038,9 @@ try
|
|||
opts->bytes_per_sync = 0;
|
||||
opts->wal_bytes_per_sync = 0;
|
||||
|
||||
// This prevents the creation of additional SST files and lots of I/O on
|
||||
// either DB open and close.
|
||||
// We need flush during shutdown or data which bypasses the WAL might get
|
||||
// desynchronized from data which doesn't (or simply lost). Flush during
|
||||
// recovery seems to happen anyway but setting to avoid is probably better.
|
||||
opts->avoid_flush_during_recovery = true;
|
||||
opts->avoid_flush_during_shutdown = false;
|
||||
|
||||
|
@ -994,6 +1065,19 @@ try
|
|||
// Use the determined direct io value for writes as well.
|
||||
//opts->use_direct_io_for_flush_and_compaction = opts->use_direct_reads;
|
||||
|
||||
// Additional optimizations at the cost of trading some added risk.
|
||||
opts->skip_stats_update_on_db_open = !open_stats;
|
||||
opts->paranoid_checks = bool(paranoid_checks);
|
||||
#ifdef IRCD_DB_HAS_SKIP_CHECKSIZE
|
||||
opts->skip_checking_sst_file_sizes_on_db_open = !paranoid_size;
|
||||
#endif
|
||||
#ifdef IRCD_DB_HAS_MANIFEST_WALS
|
||||
opts->track_and_verify_wals_in_manifest = bool(paranoid_wal);
|
||||
#endif
|
||||
#ifdef IRCD_DB_HAS_MANIFEST_UUIDS
|
||||
opts->verify_sst_unique_id_in_manifest = bool(paranoid_uuid);
|
||||
#endif
|
||||
|
||||
// Default corruption tolerance is zero-tolerance; db fails to open with
|
||||
// error by default to inform the user. The rest of the options are
|
||||
// various relaxations for how to proceed.
|
||||
|
@ -1202,7 +1286,7 @@ try
|
|||
|
||||
// If the directory does not exist, though rocksdb will create it, we can
|
||||
// avoid scaring the user with an error log message if we just do that..
|
||||
if(opts->create_if_missing && !fs::is_dir(path) && !ircd::write_avoid)
|
||||
if(opts->create_if_missing && !fs::is_dir(path) && !ircd::maintenance && !ircd::read_only)
|
||||
fs::mkdir(path);
|
||||
|
||||
// Announce attempt before usual point where exceptions are thrown
|
||||
|
@ -1745,6 +1829,11 @@ ircd::db::database::column::column(database &d,
|
|||
}
|
||||
,options_preconfiguration{[this]
|
||||
{
|
||||
// Setup sundry
|
||||
this->options.report_bg_io_stats = true;
|
||||
this->options.paranoid_file_checks = bool(paranoid_sst);
|
||||
this->options.force_consistency_checks = bool(paranoid_lsm);
|
||||
|
||||
// If possible, deduce comparator based on type given in descriptor
|
||||
if(!this->descriptor->cmp.less)
|
||||
{
|
||||
|
@ -1780,11 +1869,6 @@ ircd::db::database::column::column(database &d,
|
|||
// Set the compaction filter
|
||||
this->options.compaction_filter = &this->cfilter;
|
||||
|
||||
//this->options.paranoid_file_checks = true;
|
||||
|
||||
// More stats reported by the rocksdb.stats property.
|
||||
this->options.report_bg_io_stats = true;
|
||||
|
||||
// Set filter reductions for this column. This means we expect a key to exist.
|
||||
this->options.optimize_filters_for_hits = this->descriptor->expect_queries_hit;
|
||||
|
||||
|
@ -1985,7 +2069,7 @@ ircd::db::database::column::column(database &d,
|
|||
// Setup the cache for compressed assets.
|
||||
const auto &cache_size_comp(this->descriptor->cache_size_comp);
|
||||
if(cache_size_comp != 0)
|
||||
table_opts.block_cache_compressed = std::make_shared<database::cache>(this->d, this->stats, this->allocator, this->name, cache_size_comp);
|
||||
; //table_opts.block_cache_compressed = std::make_shared<database::cache>(this->d, this->stats, this->allocator, this->name, cache_size_comp);
|
||||
|
||||
// Setup the bloom filter.
|
||||
const auto &bloom_bits(this->descriptor->bloom_bits);
|
||||
|
@ -2059,7 +2143,7 @@ ircd::db::database::column::column(database &d,
|
|||
this->cmp.Name(),
|
||||
this->options.prefix_extractor? this->prefix.Name() : "none",
|
||||
table_opts.block_cache? "YES": "NO",
|
||||
table_opts.block_cache_compressed? "YES": "NO",
|
||||
"NO", //table_opts.block_cache_compressed? "YES": "NO",
|
||||
this->descriptor->bloom_bits,
|
||||
int(this->options.compression),
|
||||
this->descriptor->name
|
||||
|
@ -3182,6 +3266,15 @@ const noexcept
|
|||
c->Name();
|
||||
}
|
||||
|
||||
#ifdef IRCD_DB_HAS_CACHE_ITEMHELPER
|
||||
rocksdb::Status
|
||||
ircd::db::database::cache::Insert(const Slice &key,
|
||||
ObjectPtr value,
|
||||
const CacheItemHelper *const helper,
|
||||
size_t charge,
|
||||
Handle **const handle,
|
||||
Priority priority)
|
||||
#else
|
||||
rocksdb::Status
|
||||
ircd::db::database::cache::Insert(const Slice &key,
|
||||
void *const value,
|
||||
|
@ -3189,6 +3282,7 @@ ircd::db::database::cache::Insert(const Slice &key,
|
|||
deleter del,
|
||||
Handle **const handle,
|
||||
Priority priority)
|
||||
#endif
|
||||
noexcept
|
||||
{
|
||||
using rocksdb::Tickers;
|
||||
|
@ -3198,7 +3292,11 @@ noexcept
|
|||
|
||||
const rocksdb::Status &ret
|
||||
{
|
||||
#ifdef IRCD_DB_HAS_CACHE_ITEMHELPER
|
||||
c->Insert(key, value, helper, charge, handle, priority)
|
||||
#else
|
||||
c->Insert(key, value, charge, del, handle, priority)
|
||||
#endif
|
||||
};
|
||||
|
||||
stats->recordTick(Tickers::BLOCK_CACHE_ADD, ret.ok());
|
||||
|
@ -3223,9 +3321,19 @@ noexcept
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef IRCD_DB_HAS_CACHE_ITEMHELPER
|
||||
rocksdb::Cache::Handle *
|
||||
ircd::db::database::cache::Lookup(const Slice &key,
|
||||
const CacheItemHelper *const helper,
|
||||
CreateContext *const cc,
|
||||
Priority pri,
|
||||
bool wait,
|
||||
Statistics *const statistics)
|
||||
#else
|
||||
rocksdb::Cache::Handle *
|
||||
ircd::db::database::cache::Lookup(const Slice &key,
|
||||
Statistics *const statistics)
|
||||
#endif
|
||||
noexcept
|
||||
{
|
||||
using rocksdb::Tickers;
|
||||
|
@ -3247,7 +3355,11 @@ noexcept
|
|||
|
||||
auto *const &ret
|
||||
{
|
||||
#ifdef IRCD_DB_HAS_CACHE_ITEMHELPER
|
||||
c->Lookup(key, helper, cc, pri, wait, statistics)
|
||||
#else
|
||||
c->Lookup(key, s)
|
||||
#endif
|
||||
};
|
||||
|
||||
// Rocksdb's LRUCache stats are broke. The statistics ptr is null and
|
||||
|
@ -3379,6 +3491,7 @@ noexcept
|
|||
return c->DisownData();
|
||||
}
|
||||
|
||||
#ifndef IRCD_DB_HAS_CACHE_ITEMHELPER
|
||||
void
|
||||
ircd::db::database::cache::ApplyToAllCacheEntries(callback cb,
|
||||
bool thread_safe)
|
||||
|
@ -3387,6 +3500,7 @@ noexcept
|
|||
assert(bool(c));
|
||||
return c->ApplyToAllCacheEntries(cb, thread_safe);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
ircd::db::database::cache::EraseUnRefEntries()
|
||||
|
@ -3414,7 +3528,7 @@ const noexcept
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef IRCD_DB_HAS_CACHE_GETDELETER
|
||||
#if defined(IRCD_DB_HAS_CACHE_GETDELETER) && !defined(IRCD_DB_HAS_CACHE_ITEMHELPER)
|
||||
rocksdb::Cache::DeleterFn
|
||||
ircd::db::database::cache::GetDeleter(Handle *const h)
|
||||
const noexcept
|
||||
|
@ -3435,6 +3549,16 @@ noexcept
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef IRCD_DB_HAS_CACHE_ITEMHELPER
|
||||
const rocksdb::Cache::CacheItemHelper *
|
||||
ircd::db::database::cache::GetCacheItemHelper(Handle *const h)
|
||||
const noexcept
|
||||
{
|
||||
assert(bool(c));
|
||||
return c->GetCacheItemHelper(h);
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// database::compaction_filter
|
||||
|
|
|
@ -73,12 +73,24 @@
|
|||
#define IRCD_DB_HAS_ENV_FILESYSTEM
|
||||
#endif
|
||||
|
||||
#if ROCKSDB_MAJOR > 6 \
|
||||
|| (ROCKSDB_MAJOR == 6 && ROCKSDB_MINOR > 8) \
|
||||
|| (ROCKSDB_MAJOR == 6 && ROCKSDB_MINOR == 8 && ROCKSDB_PATCH >= 1)
|
||||
#define IRCD_DB_HAS_SKIP_CHECKSIZE
|
||||
#endif
|
||||
|
||||
#if ROCKSDB_MAJOR > 6 \
|
||||
|| (ROCKSDB_MAJOR == 6 && ROCKSDB_MINOR > 10) \
|
||||
|| (ROCKSDB_MAJOR == 6 && ROCKSDB_MINOR == 10 && ROCKSDB_PATCH >= 0)
|
||||
#define IRCD_DB_HAS_MULTIGET_DIRECT
|
||||
#endif
|
||||
|
||||
#if ROCKSDB_MAJOR > 6 \
|
||||
|| (ROCKSDB_MAJOR == 6 && ROCKSDB_MINOR > 10) \
|
||||
|| (ROCKSDB_MAJOR == 6 && ROCKSDB_MINOR == 10 && ROCKSDB_PATCH >= 1)
|
||||
#define IRCD_DB_HAS_CONFIG_OPTIONS
|
||||
#endif
|
||||
|
||||
#if ROCKSDB_MAJOR > 6 \
|
||||
|| (ROCKSDB_MAJOR == 6 && ROCKSDB_MINOR > 12) \
|
||||
|| (ROCKSDB_MAJOR == 6 && ROCKSDB_MINOR == 12 && ROCKSDB_PATCH >= 6)
|
||||
|
@ -92,9 +104,15 @@
|
|||
#endif
|
||||
|
||||
#if ROCKSDB_MAJOR > 6 \
|
||||
|| (ROCKSDB_MAJOR == 6 && ROCKSDB_MINOR > 16) \
|
||||
|| (ROCKSDB_MAJOR == 6 && ROCKSDB_MINOR == 16 && ROCKSDB_PATCH >= 3)
|
||||
#define IRCD_DB_HAS_MANIFEST_WRITE_NOWAL
|
||||
|| (ROCKSDB_MAJOR == 6 && ROCKSDB_MINOR > 14) \
|
||||
|| (ROCKSDB_MAJOR == 6 && ROCKSDB_MINOR == 14 && ROCKSDB_PATCH >= 5)
|
||||
#define IRCD_DB_HAS_FLUSH_RETRY
|
||||
#endif
|
||||
|
||||
#if ROCKSDB_MAJOR > 6 \
|
||||
|| (ROCKSDB_MAJOR == 6 && ROCKSDB_MINOR > 15) \
|
||||
|| (ROCKSDB_MAJOR == 6 && ROCKSDB_MINOR == 15 && ROCKSDB_PATCH >= 2)
|
||||
#define IRCD_DB_HAS_MANIFEST_WALS
|
||||
#endif
|
||||
|
||||
#if ROCKSDB_MAJOR > 6 \
|
||||
|
@ -140,8 +158,38 @@
|
|||
#define IRCD_DB_HAS_FORCED_BLOBGC
|
||||
#endif
|
||||
|
||||
#if ROCKSDB_MAJOR > 7 \
|
||||
|| (ROCKSDB_MAJOR == 7 && ROCKSDB_MINOR > 2) \
|
||||
|| (ROCKSDB_MAJOR == 7 && ROCKSDB_MINOR == 2 && ROCKSDB_PATCH >= 0)
|
||||
#define IRCD_DB_HAS_SECONDARY_CACHE
|
||||
#endif
|
||||
|
||||
#if ROCKSDB_MAJOR > 7 \
|
||||
|| (ROCKSDB_MAJOR == 7 && ROCKSDB_MINOR > 7) \
|
||||
|| (ROCKSDB_MAJOR == 7 && ROCKSDB_MINOR == 7 && ROCKSDB_PATCH >= 2)
|
||||
#define IRCD_DB_HAS_MANIFEST_UUIDS
|
||||
#endif
|
||||
|
||||
#if ROCKSDB_MAJOR > 7 \
|
||||
|| (ROCKSDB_MAJOR == 7 && ROCKSDB_MINOR > 8) \
|
||||
|| (ROCKSDB_MAJOR == 7 && ROCKSDB_MINOR == 8 && ROCKSDB_PATCH >= 3)
|
||||
#define IRCD_DB_HAS_ROUND_ROBIN_TTL
|
||||
#endif
|
||||
|
||||
#if ROCKSDB_MAJOR > 7 \
|
||||
|| (ROCKSDB_MAJOR == 7 && ROCKSDB_MINOR > 10) \
|
||||
|| (ROCKSDB_MAJOR == 7 && ROCKSDB_MINOR == 10 && ROCKSDB_PATCH >= 0)
|
||||
#define IRCD_DB_HAS_CACHE_ITEMHELPER
|
||||
#endif
|
||||
|
||||
#if ROCKSDB_MAJOR > 7 \
|
||||
|| (ROCKSDB_MAJOR == 7 && ROCKSDB_MINOR > 10) \
|
||||
|| (ROCKSDB_MAJOR == 7 && ROCKSDB_MINOR == 10 && ROCKSDB_PATCH >= 2)
|
||||
#define IRCD_DB_HAS_REFIT_LEVEL
|
||||
#endif
|
||||
|
||||
#if ROCKSDB_MAJOR > 8 \
|
||||
|| (ROCKSDB_MAJOR == 8 && ROCKSDB_MINOR > 0) \
|
||||
|| (ROCKSDB_MAJOR == 8 && ROCKSDB_MINOR == 0 && ROCKSDB_PATCH >= 0)
|
||||
#define IRCD_DB_HAS_CACHE_WRAPPER
|
||||
#endif
|
||||
|
|
|
@ -689,7 +689,7 @@ ircd::fs::aio::system::handle_descriptor
|
|||
// appears to excessively allocate and deallocate 120 bytes; this
|
||||
// is a simple asynchronous operation, we can do better (and perhaps
|
||||
// even better than this below).
|
||||
[](ios::handler &handler, const size_t &size) -> void *
|
||||
[](ios::handler &handler, const size_t size) -> void *
|
||||
{
|
||||
assert(ircd::fs::aio::system);
|
||||
auto &system(*ircd::fs::aio::system);
|
||||
|
@ -705,7 +705,7 @@ ircd::fs::aio::system::handle_descriptor
|
|||
},
|
||||
|
||||
// no deallocation; satisfied by class member unique_ptr
|
||||
[](ios::handler &handler, void *const &ptr, const size_t &size) {},
|
||||
[](ios::handler &handler, void *const ptr, const size_t size) {},
|
||||
|
||||
// continuation
|
||||
true,
|
||||
|
|
53
ircd/ios.cc
53
ircd/ios.cc
|
@ -39,6 +39,14 @@ ircd::ios::primary;
|
|||
decltype(ircd::ios::main)
|
||||
ircd::ios::main;
|
||||
|
||||
/// Indicates the user asio::executor is initialized.
|
||||
decltype(ircd::ios::user_available)
|
||||
ircd::ios::user_available;
|
||||
|
||||
/// Indicates the main asio::executor is initialized.
|
||||
decltype(ircd::ios::main_available)
|
||||
ircd::ios::main_available;
|
||||
|
||||
decltype(ircd::boost_version_api)
|
||||
ircd::boost_version_api
|
||||
{
|
||||
|
@ -71,12 +79,14 @@ ircd::ios::init(asio::executor &&user)
|
|||
|
||||
// Save a reference handle to the user's executor.
|
||||
ios::user = user;
|
||||
ios::user_available = bool(ios::user);
|
||||
|
||||
// Create our strand instance.
|
||||
ios::primary.emplace(static_cast<asio::io_context &>(user.context()));
|
||||
|
||||
// Set the reference handle to our executor.
|
||||
ios::main = *ios::primary;
|
||||
ios::main_available = bool(ios::main);
|
||||
}
|
||||
|
||||
[[using gnu: cold]]
|
||||
|
@ -180,13 +190,6 @@ ircd::ios::forked_parent()
|
|||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::ios::available()
|
||||
noexcept
|
||||
{
|
||||
return bool(main);
|
||||
}
|
||||
|
||||
//
|
||||
// emption
|
||||
//
|
||||
|
@ -480,13 +483,6 @@ ircd::ios::descriptor::stats::stats(descriptor &d)
|
|||
{ "name", stats_name(d, "free_bytes") },
|
||||
},
|
||||
}
|
||||
,slice_total
|
||||
{
|
||||
value + items++,
|
||||
{
|
||||
{ "name", stats_name(d, "slice_total") },
|
||||
},
|
||||
}
|
||||
,slice_last
|
||||
{
|
||||
value + items++,
|
||||
|
@ -494,11 +490,11 @@ ircd::ios::descriptor::stats::stats(descriptor &d)
|
|||
{ "name", stats_name(d, "slice_last") },
|
||||
},
|
||||
}
|
||||
,latency_total
|
||||
,slice_total
|
||||
{
|
||||
value + items++,
|
||||
{
|
||||
{ "name", stats_name(d, "latency_total") },
|
||||
{ "name", stats_name(d, "slice_total") },
|
||||
},
|
||||
}
|
||||
,latency_last
|
||||
|
@ -508,6 +504,13 @@ ircd::ios::descriptor::stats::stats(descriptor &d)
|
|||
{ "name", stats_name(d, "latency_last") },
|
||||
},
|
||||
}
|
||||
,latency_total
|
||||
{
|
||||
value + items++,
|
||||
{
|
||||
{ "name", stats_name(d, "latency_total") },
|
||||
},
|
||||
}
|
||||
{
|
||||
assert(items <= (sizeof(value) / sizeof(value[0])));
|
||||
}
|
||||
|
@ -531,7 +534,7 @@ ircd::ios::handler::epoch;
|
|||
|
||||
[[gnu::cold]]
|
||||
bool
|
||||
ircd::ios::handler::fault(handler *const &handler)
|
||||
ircd::ios::handler::fault(handler *const handler)
|
||||
noexcept
|
||||
{
|
||||
assert(handler && handler->descriptor);
|
||||
|
@ -568,7 +571,7 @@ noexcept
|
|||
|
||||
[[gnu::hot]]
|
||||
void
|
||||
ircd::ios::handler::leave(handler *const &handler)
|
||||
ircd::ios::handler::leave(handler *const handler)
|
||||
noexcept
|
||||
{
|
||||
assert(handler && handler->descriptor);
|
||||
|
@ -619,19 +622,14 @@ noexcept
|
|||
|
||||
[[gnu::hot]]
|
||||
void
|
||||
ircd::ios::handler::enter(handler *const &handler)
|
||||
ircd::ios::handler::enter(handler *const handler)
|
||||
noexcept
|
||||
{
|
||||
assert(!handler::current);
|
||||
handler::current = handler;
|
||||
++handler::epoch;
|
||||
|
||||
assert(handler && handler->descriptor);
|
||||
auto &descriptor(*handler->descriptor);
|
||||
|
||||
assert(descriptor.stats);
|
||||
auto &stats(*descriptor.stats);
|
||||
++stats.calls;
|
||||
|
||||
const auto last_ts
|
||||
{
|
||||
|
@ -640,6 +638,11 @@ noexcept
|
|||
|
||||
stats.latency_last = handler->ts - last_ts;
|
||||
stats.latency_total += stats.latency_last;
|
||||
++stats.calls;
|
||||
|
||||
assert(!handler::current);
|
||||
handler::current = handler;
|
||||
++handler::epoch;
|
||||
|
||||
if constexpr(profile::logging)
|
||||
log::logf
|
||||
|
@ -696,7 +699,6 @@ ircd::ios::dispatch::dispatch(descriptor &descriptor,
|
|||
latch.wait();
|
||||
}
|
||||
|
||||
[[gnu::hot]]
|
||||
ircd::ios::dispatch::dispatch(descriptor &descriptor,
|
||||
defer_t,
|
||||
std::function<void ()> function)
|
||||
|
@ -725,7 +727,6 @@ ircd::ios::dispatch::dispatch(descriptor &descriptor,
|
|||
};
|
||||
}
|
||||
|
||||
[[gnu::hot]]
|
||||
ircd::ios::dispatch::dispatch(descriptor &descriptor,
|
||||
std::function<void ()> function)
|
||||
{
|
||||
|
|
38
ircd/ircd.cc
38
ircd/ircd.cc
|
@ -107,25 +107,21 @@ ircd::maintenance
|
|||
}
|
||||
};
|
||||
|
||||
/// Coarse mode indicator for degraded operation known as "write-avoid" which
|
||||
/// is similar to read_only but not hard-enforced. Writes may still occur,
|
||||
/// such as those manually triggered by an admin. All subsystems and background
|
||||
/// tasks otherwise depart from normal operation to avoid writes.
|
||||
decltype(ircd::write_avoid)
|
||||
ircd::write_avoid
|
||||
/// Conf item dictates whether databases will be opened in slave mode; this
|
||||
/// is a recent feature of RocksDB which may not be available. It allows
|
||||
/// multiple processes to open the same database in a single-writer multiple
|
||||
/// reader configuration.
|
||||
///
|
||||
/// Originally this was intended as a maintenance mode to explore another live
|
||||
/// running server's database. However it now allows listeners which can serve
|
||||
/// as load-balanced mirrors and caches over a database shared at the fs level
|
||||
/// locally or with nfs/ceph/intermezzo etc.
|
||||
decltype(ircd::slave)
|
||||
ircd::slave
|
||||
{
|
||||
{
|
||||
{ "name", "ircd.write_avoid" },
|
||||
{ "default", false },
|
||||
{ "persist", false },
|
||||
},
|
||||
[](conf::item<void> &)
|
||||
{
|
||||
if(!write_avoid)
|
||||
return;
|
||||
|
||||
maintenance.set("true");
|
||||
}
|
||||
{ "name", "ircd.slave" },
|
||||
{ "default", false },
|
||||
{ "persist", false },
|
||||
};
|
||||
|
||||
/// Coarse mode declaration for read-only behavior. All subsystems and feature
|
||||
|
@ -145,7 +141,11 @@ ircd::read_only
|
|||
if(!read_only)
|
||||
return;
|
||||
|
||||
write_avoid.set("true");
|
||||
// Not implict maintenance mode when slave mode is set.
|
||||
if(slave)
|
||||
return;
|
||||
|
||||
maintenance.set("true");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -4138,7 +4138,7 @@ ircd::json::value::value(const json::members &members)
|
|||
|
||||
ircd::json::value::value(const value &other)
|
||||
:integer{other.integer}
|
||||
,len{other.len}
|
||||
,len{other.serial? serialized(other): other.len}
|
||||
,type{other.type}
|
||||
,serial{other.serial}
|
||||
,alloc{other.alloc}
|
||||
|
|
|
@ -138,7 +138,7 @@ ircd::log::init()
|
|||
console_disable(level::DWARNING);
|
||||
}
|
||||
|
||||
if(!ircd::write_avoid)
|
||||
if(!ircd::read_only && !ircd::maintenance)
|
||||
{
|
||||
mkdir();
|
||||
open();
|
||||
|
|
318
ircd/net.cc
318
ircd/net.cc
|
@ -488,6 +488,22 @@ ircd::net::read_one(socket &socket,
|
|||
return socket.read_one(buffers);
|
||||
}
|
||||
|
||||
/// Bytes available for reading (SSL; w/ fallback).
|
||||
/// @returns 0 for socket errors, unsupported, or nothing available.
|
||||
size_t
|
||||
ircd::net::pending(const socket &socket)
|
||||
noexcept
|
||||
{
|
||||
if(!socket.ssl)
|
||||
return available(socket);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
return SSL_pending(mutable_cast(socket).ssl->native_handle());
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Bytes available for reading (userspace)
|
||||
size_t
|
||||
ircd::net::available(const socket &socket)
|
||||
|
@ -656,6 +672,11 @@ ircd::net::reflect(const ready &type)
|
|||
// net/close.h
|
||||
//
|
||||
|
||||
namespace ircd::net
|
||||
{
|
||||
static asio::ip::tcp::socket::shutdown_type translate(const dc &) noexcept;
|
||||
}
|
||||
|
||||
decltype(ircd::net::close_opts::default_timeout)
|
||||
ircd::net::close_opts::default_timeout
|
||||
{
|
||||
|
@ -664,10 +685,8 @@ ircd::net::close_opts::default_timeout
|
|||
};
|
||||
|
||||
/// Static instance of default close options.
|
||||
ircd::net::close_opts
|
||||
const ircd::net::close_opts_default
|
||||
{
|
||||
};
|
||||
decltype(ircd::net::close_opts_default)
|
||||
ircd::net::close_opts_default;
|
||||
|
||||
/// Static helper callback which may be passed to the callback-based overload
|
||||
/// of close(). This callback does nothing.
|
||||
|
@ -678,6 +697,16 @@ const ircd::net::close_ignore{[]
|
|||
return;
|
||||
}};
|
||||
|
||||
ircd::ctx::future<void>
|
||||
ircd::net::close(socket &s,
|
||||
const dc &type)
|
||||
{
|
||||
return close(s, close_opts
|
||||
{
|
||||
.type = type,
|
||||
});
|
||||
}
|
||||
|
||||
ircd::ctx::future<void>
|
||||
ircd::net::close(socket &socket,
|
||||
const close_opts &opts)
|
||||
|
@ -697,6 +726,19 @@ ircd::net::close(socket &socket,
|
|||
return f;
|
||||
}
|
||||
|
||||
void
|
||||
ircd::net::close(socket &s,
|
||||
const dc &type,
|
||||
close_callback cb)
|
||||
{
|
||||
const close_opts opts
|
||||
{
|
||||
.type = type,
|
||||
};
|
||||
|
||||
return close(s, opts, std::move(cb));
|
||||
}
|
||||
|
||||
void
|
||||
ircd::net::close(socket &socket,
|
||||
const close_opts &opts,
|
||||
|
@ -705,6 +747,46 @@ ircd::net::close(socket &socket,
|
|||
socket.disconnect(opts, std::move(callback));
|
||||
}
|
||||
|
||||
boost::asio::ip::tcp::socket::shutdown_type
|
||||
ircd::net::translate(const dc &val)
|
||||
noexcept
|
||||
{
|
||||
using type = asio::ip::tcp::socket::shutdown_type;
|
||||
|
||||
switch(val)
|
||||
{
|
||||
case dc::SSL_NOTIFY: assert(0); [[fallthrough]];
|
||||
case dc::RST: assert(0); [[fallthrough]];
|
||||
case dc::FIN:
|
||||
return type::shutdown_both;
|
||||
|
||||
case dc::FIN_SEND:
|
||||
return type::shutdown_send;
|
||||
|
||||
case dc::FIN_RECV:
|
||||
return type::shutdown_receive;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
ircd::string_view
|
||||
ircd::net::reflect(const dc type)
|
||||
noexcept
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case dc::RST: return "RST";
|
||||
case dc::FIN: return "FIN";
|
||||
case dc::FIN_SEND: return "FIN_SEND";
|
||||
case dc::FIN_RECV: return "FIN_RECV";
|
||||
case dc::SSL_NOTIFY: return "SSL_NOTIFY";
|
||||
}
|
||||
|
||||
return "????"_sv;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// net/open.h
|
||||
|
@ -759,7 +841,13 @@ ircd::net::open(const open_opts &opts)
|
|||
{
|
||||
ctx::promise<std::shared_ptr<socket>> p;
|
||||
ctx::future<std::shared_ptr<socket>> f(p);
|
||||
auto s{std::make_shared<socket>()};
|
||||
auto s
|
||||
{
|
||||
opts.secure?
|
||||
std::make_shared<socket>(sslv23_client):
|
||||
std::make_shared<socket>()
|
||||
};
|
||||
|
||||
open(*s, opts, [s, p(std::move(p))]
|
||||
(std::exception_ptr eptr)
|
||||
mutable
|
||||
|
@ -779,7 +867,13 @@ std::shared_ptr<ircd::net::socket>
|
|||
ircd::net::open(const open_opts &opts,
|
||||
open_callback handler)
|
||||
{
|
||||
auto s{std::make_shared<socket>()};
|
||||
auto s
|
||||
{
|
||||
opts.secure?
|
||||
std::make_shared<socket>(sslv23_client):
|
||||
std::make_shared<socket>()
|
||||
};
|
||||
|
||||
open(*s, opts, std::move(handler));
|
||||
return s;
|
||||
}
|
||||
|
@ -882,7 +976,7 @@ ircd::net::set(socket &socket,
|
|||
|
||||
bool
|
||||
ircd::net::detach(socket &socket,
|
||||
const int &prog_fd)
|
||||
const int prog_fd)
|
||||
{
|
||||
ip::tcp::socket &sd(socket);
|
||||
const auto &fd
|
||||
|
@ -895,8 +989,8 @@ ircd::net::detach(socket &socket,
|
|||
}
|
||||
|
||||
bool
|
||||
ircd::net::detach(const int &sd,
|
||||
const int &prog_fd)
|
||||
ircd::net::detach(const int sd,
|
||||
const int prog_fd)
|
||||
#if defined(SO_DETACH_BPF) && defined(SOL_SOCKET)
|
||||
{
|
||||
const socklen_t len(sizeof(prog_fd));
|
||||
|
@ -912,7 +1006,7 @@ ircd::net::detach(const int &sd,
|
|||
|
||||
bool
|
||||
ircd::net::attach(socket &socket,
|
||||
const int &prog_fd)
|
||||
const int prog_fd)
|
||||
{
|
||||
ip::tcp::socket &sd(socket);
|
||||
const auto &fd
|
||||
|
@ -925,8 +1019,8 @@ ircd::net::attach(socket &socket,
|
|||
}
|
||||
|
||||
bool
|
||||
ircd::net::attach(const int &sd,
|
||||
const int &prog_fd)
|
||||
ircd::net::attach(const int sd,
|
||||
const int prog_fd)
|
||||
#if defined(SO_ATTACH_BPF) && defined(SOL_SOCKET)
|
||||
{
|
||||
const socklen_t len(sizeof(prog_fd));
|
||||
|
@ -942,7 +1036,7 @@ ircd::net::attach(const int &sd,
|
|||
|
||||
bool
|
||||
ircd::net::write_lowat(socket &socket,
|
||||
const size_t &bytes)
|
||||
const size_t bytes)
|
||||
{
|
||||
assert(bytes <= std::numeric_limits<int>::max());
|
||||
const ip::tcp::socket::send_low_watermark option
|
||||
|
@ -957,7 +1051,7 @@ ircd::net::write_lowat(socket &socket,
|
|||
|
||||
bool
|
||||
ircd::net::read_lowat(socket &socket,
|
||||
const size_t &bytes)
|
||||
const size_t bytes)
|
||||
{
|
||||
assert(bytes <= std::numeric_limits<int>::max());
|
||||
const ip::tcp::socket::receive_low_watermark option
|
||||
|
@ -972,7 +1066,7 @@ ircd::net::read_lowat(socket &socket,
|
|||
|
||||
bool
|
||||
ircd::net::write_bufsz(socket &socket,
|
||||
const size_t &bytes)
|
||||
const size_t bytes)
|
||||
{
|
||||
assert(bytes <= std::numeric_limits<int>::max());
|
||||
const ip::tcp::socket::send_buffer_size option
|
||||
|
@ -987,7 +1081,7 @@ ircd::net::write_bufsz(socket &socket,
|
|||
|
||||
bool
|
||||
ircd::net::read_bufsz(socket &socket,
|
||||
const size_t &bytes)
|
||||
const size_t bytes)
|
||||
{
|
||||
assert(bytes <= std::numeric_limits<int>::max());
|
||||
const ip::tcp::socket::receive_buffer_size option
|
||||
|
@ -1002,7 +1096,7 @@ ircd::net::read_bufsz(socket &socket,
|
|||
|
||||
bool
|
||||
ircd::net::linger(socket &socket,
|
||||
const time_t &t)
|
||||
const time_t t)
|
||||
{
|
||||
assert(t >= std::numeric_limits<int>::min());
|
||||
assert(t <= std::numeric_limits<int>::max());
|
||||
|
@ -1019,7 +1113,7 @@ ircd::net::linger(socket &socket,
|
|||
|
||||
bool
|
||||
ircd::net::keepalive(socket &socket,
|
||||
const bool &b)
|
||||
const bool b)
|
||||
{
|
||||
const ip::tcp::socket::keep_alive option{b};
|
||||
ip::tcp::socket &sd(socket);
|
||||
|
@ -1029,7 +1123,7 @@ ircd::net::keepalive(socket &socket,
|
|||
|
||||
bool
|
||||
ircd::net::quickack(socket &socket,
|
||||
const bool &b)
|
||||
const bool b)
|
||||
#if defined(TCP_QUICKACK) && defined(SOL_SOCKET)
|
||||
{
|
||||
ip::tcp::socket &sd(socket);
|
||||
|
@ -1052,17 +1146,29 @@ ircd::net::quickack(socket &socket,
|
|||
|
||||
bool
|
||||
ircd::net::nodelay(socket &socket,
|
||||
const bool &b)
|
||||
const bool b)
|
||||
{
|
||||
if(likely(nodelay(socket) != b))
|
||||
nodelay(socket, b, system);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::nodelay(socket &socket,
|
||||
const bool b,
|
||||
system_t)
|
||||
{
|
||||
const ip::tcp::no_delay option{b};
|
||||
ip::tcp::socket &sd(socket);
|
||||
sd.set_option(option);
|
||||
socket._nodelay = b;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::nopush(socket &socket,
|
||||
const bool &b)
|
||||
const bool b)
|
||||
#if defined(TCP_CORK) && defined(SOL_SOCKET)
|
||||
{
|
||||
ip::tcp::socket &sd(socket);
|
||||
|
@ -1086,8 +1192,11 @@ ircd::net::nopush(socket &socket,
|
|||
/// Toggles the behavior of non-async asio calls.
|
||||
///
|
||||
/// This option affects very little in practice and only sets a flag in
|
||||
/// userspace in asio, not an actual ioctl(). Specifically:
|
||||
/// userspace in asio, not an actual ioctl(2) (XXX this is not true anymore,
|
||||
/// sd.non_blocking() and sd.native_non_blocking() both seem to ioctl(2)).
|
||||
/// See below the deprecated section.
|
||||
///
|
||||
/// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
|
||||
/// * All sockets are already set by asio to FIONBIO=1 no matter what, thus
|
||||
/// nothing really blocks the event loop ever by default unless you try hard.
|
||||
///
|
||||
|
@ -1106,19 +1215,41 @@ ircd::net::nopush(socket &socket,
|
|||
/// in this project there is never a reason to ever set this to true,
|
||||
/// however, sockets do get constructed by asio in blocking mode by default
|
||||
/// so we mostly use this function to set it to non-blocking.
|
||||
/// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
|
||||
///
|
||||
/// The kern argument has been added to decide between native_non_blocking()
|
||||
/// (when kern=true) or non_blocking() (when kern=false). These both set
|
||||
/// different flags in asio but they both result in the same ioctl(FIONBIO)
|
||||
/// probably due to third-party libraries flipping FIONBIO outside of asio's
|
||||
/// knowledge and naive users complaining too much to the maintainer.
|
||||
///
|
||||
/// To deal with this we have added a query to the sd.non_blocking() getter
|
||||
/// which AT LEAST FOR NOW only reads asio's flags without a syscall and
|
||||
/// won't call the sd.non_blocking() setter if it's superfluous.
|
||||
bool
|
||||
ircd::net::blocking(socket &socket,
|
||||
const bool &b)
|
||||
const bool b)
|
||||
{
|
||||
ip::tcp::socket &sd(socket);
|
||||
sd.non_blocking(!b);
|
||||
if(likely(sd.non_blocking() == b))
|
||||
sd.non_blocking(!b);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::blocking(socket &socket,
|
||||
const bool b,
|
||||
system_t)
|
||||
{
|
||||
ip::tcp::socket &sd(socket);
|
||||
sd.native_non_blocking(!b);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::v6only(socket &socket,
|
||||
const bool &b)
|
||||
const bool b)
|
||||
{
|
||||
const ip::v6_only option{b};
|
||||
ip::tcp::socket &sd(socket);
|
||||
|
@ -1226,12 +1357,20 @@ ircd::net::quickack(const socket &socket)
|
|||
#endif
|
||||
|
||||
bool
|
||||
ircd::net::nodelay(const socket &socket)
|
||||
ircd::net::nodelay(const socket &socket,
|
||||
system_t)
|
||||
{
|
||||
const ip::tcp::socket &sd(socket);
|
||||
ip::tcp::no_delay option;
|
||||
sd.get_option(option);
|
||||
return option.value();
|
||||
mutable_cast(socket)._nodelay = option.value();
|
||||
return socket._nodelay;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::nodelay(const socket &socket)
|
||||
{
|
||||
return socket._nodelay;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1264,6 +1403,14 @@ ircd::net::blocking(const socket &socket)
|
|||
return !sd.non_blocking();
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::blocking(const socket &socket,
|
||||
system_t)
|
||||
{
|
||||
const ip::tcp::socket &sd(socket);
|
||||
return !sd.native_non_blocking();
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::v6only(const socket &socket)
|
||||
{
|
||||
|
@ -1475,9 +1622,22 @@ ircd::net::socket::total_calls_out
|
|||
};
|
||||
|
||||
//
|
||||
// socket
|
||||
// socket::socket
|
||||
//
|
||||
|
||||
ircd::net::socket::socket()
|
||||
:sd
|
||||
{
|
||||
ios::get()
|
||||
}
|
||||
,timer
|
||||
{
|
||||
ios::get()
|
||||
}
|
||||
{
|
||||
++instances;
|
||||
}
|
||||
|
||||
ircd::net::socket::socket(asio::ssl::context &ssl)
|
||||
:sd
|
||||
{
|
||||
|
@ -1485,7 +1645,7 @@ ircd::net::socket::socket(asio::ssl::context &ssl)
|
|||
}
|
||||
,ssl
|
||||
{
|
||||
this->sd, ssl
|
||||
std::in_place, this->sd, ssl
|
||||
}
|
||||
,timer
|
||||
{
|
||||
|
@ -1568,6 +1728,7 @@ ircd::net::socket::handshake(const open_opts &opts,
|
|||
{
|
||||
assert(!fini);
|
||||
assert(sd.is_open());
|
||||
assert(ssl);
|
||||
|
||||
log::debug
|
||||
{
|
||||
|
@ -1596,8 +1757,8 @@ ircd::net::socket::handshake(const open_opts &opts,
|
|||
if(opts.send_sni && server_name(opts))
|
||||
openssl::server_name(*this, server_name(opts));
|
||||
|
||||
ssl.set_verify_callback(std::move(verify_handler));
|
||||
ssl.async_handshake(handshake_type::client, ios::handle(desc_handshake, std::move(handshake_handler)));
|
||||
ssl->set_verify_callback(std::move(verify_handler));
|
||||
ssl->async_handshake(handshake_type::client, ios::handle(desc_handshake, std::move(handshake_handler)));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1614,9 +1775,10 @@ try
|
|||
assert(!fini);
|
||||
log::debug
|
||||
{
|
||||
log, "%s disconnect type:%d user: in:%zu out:%zu",
|
||||
log, "%s disconnect type:%s shut:%s user[in:%zu out:%zu]",
|
||||
loghead(*this),
|
||||
uint(opts.type),
|
||||
reflect(opts.type),
|
||||
!ssl? reflect(opts.shutdown): "--"_sv,
|
||||
in.bytes,
|
||||
out.bytes
|
||||
};
|
||||
|
@ -1635,26 +1797,30 @@ try
|
|||
break;
|
||||
|
||||
case dc::FIN:
|
||||
sd.shutdown(ip::tcp::socket::shutdown_both);
|
||||
break;
|
||||
|
||||
case dc::FIN_SEND:
|
||||
sd.shutdown(ip::tcp::socket::shutdown_send);
|
||||
break;
|
||||
|
||||
case dc::FIN_RECV:
|
||||
sd.shutdown(ip::tcp::socket::shutdown_receive);
|
||||
sd.shutdown(translate(opts.type));
|
||||
break;
|
||||
|
||||
case dc::SSL_NOTIFY:
|
||||
{
|
||||
if(!ssl)
|
||||
{
|
||||
// Redirect SSL_NOTIFY to another strategy for non-SSL sockets.
|
||||
if(opts.shutdown != dc::RST)
|
||||
sd.shutdown(translate(opts.shutdown));
|
||||
|
||||
sd.close();
|
||||
break;
|
||||
}
|
||||
|
||||
auto disconnect_handler
|
||||
{
|
||||
std::bind(&socket::handle_disconnect, this, shared_from(*this), std::move(callback), ph::_1)
|
||||
};
|
||||
|
||||
set_timeout(opts.timeout);
|
||||
ssl.async_shutdown(ios::handle(desc_disconnect, std::move(disconnect_handler)));
|
||||
ssl->async_shutdown(ios::handle(desc_disconnect, std::move(disconnect_handler)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1796,7 +1962,7 @@ try
|
|||
// real socket wait.
|
||||
static char buf[64];
|
||||
static const ilist<mutable_buffer> bufs{buf};
|
||||
if(SSL_peek(ssl.native_handle(), buf, sizeof(buf)) > 0)
|
||||
if(ssl && SSL_peek(ssl->native_handle(), buf, sizeof(buf)) > 0)
|
||||
{
|
||||
ircd::dispatch{desc_wait[1], ios::defer, [handle(std::move(handle))]
|
||||
{
|
||||
|
@ -1868,7 +2034,7 @@ noexcept
|
|||
return make_error_code(std::errc::not_connected);
|
||||
|
||||
std::error_code ret;
|
||||
if(SSL_peek(ssl.native_handle(), buf, sizeof(buf)) > 0)
|
||||
if(ssl && SSL_peek(ssl->native_handle(), buf, sizeof(buf)) > 0)
|
||||
return ret;
|
||||
|
||||
assert(!blocking(*this));
|
||||
|
@ -1914,7 +2080,9 @@ try
|
|||
continuation::asio_predicate, interruption, [this, &ret, &bufs]
|
||||
(auto &yield)
|
||||
{
|
||||
ret = asio::async_read(ssl, bufs, completion, yield);
|
||||
ret = ssl?
|
||||
asio::async_read(*ssl, bufs, completion, yield):
|
||||
asio::async_read(sd, bufs, completion, yield);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1954,7 +2122,9 @@ try
|
|||
continuation::asio_predicate, interruption, [this, &ret, &bufs]
|
||||
(auto &yield)
|
||||
{
|
||||
ret = ssl.async_read_some(bufs, yield);
|
||||
ret = ssl?
|
||||
ssl->async_read_some(bufs, yield):
|
||||
sd.async_read_some(bufs, yield);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1990,7 +2160,9 @@ ircd::net::socket::read_any(const mutable_buffers &bufs)
|
|||
boost::system::error_code ec;
|
||||
const size_t ret
|
||||
{
|
||||
asio::read(ssl, bufs, completion, ec)
|
||||
ssl?
|
||||
asio::read(*ssl, bufs, completion, ec):
|
||||
asio::read(sd, bufs, completion, ec)
|
||||
};
|
||||
|
||||
++in.calls;
|
||||
|
@ -2018,7 +2190,9 @@ ircd::net::socket::read_one(const mutable_buffers &bufs)
|
|||
boost::system::error_code ec;
|
||||
const size_t ret
|
||||
{
|
||||
ssl.read_some(bufs, ec)
|
||||
ssl?
|
||||
ssl->read_some(bufs, ec):
|
||||
sd.read_some(bufs, ec)
|
||||
};
|
||||
|
||||
++in.calls;
|
||||
|
@ -2061,7 +2235,9 @@ try
|
|||
continuation::asio_predicate, interruption, [this, &ret, &bufs]
|
||||
(auto &yield)
|
||||
{
|
||||
ret = asio::async_write(ssl, bufs, completion, yield);
|
||||
ret = ssl?
|
||||
asio::async_write(*ssl, bufs, completion, yield):
|
||||
asio::async_write(sd, bufs, completion, yield);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2096,7 +2272,9 @@ try
|
|||
continuation::asio_predicate, interruption, [this, &ret, &bufs]
|
||||
(auto &yield)
|
||||
{
|
||||
ret = ssl.async_write_some(bufs, yield);
|
||||
ret = ssl?
|
||||
ssl->async_write_some(bufs, yield):
|
||||
sd.async_write_some(bufs, yield);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2126,7 +2304,9 @@ try
|
|||
assert(!blocking(*this));
|
||||
const size_t ret
|
||||
{
|
||||
asio::write(ssl, bufs, completion)
|
||||
ssl?
|
||||
asio::write(*ssl, bufs, completion):
|
||||
asio::write(sd, bufs, completion)
|
||||
};
|
||||
|
||||
++out.calls;
|
||||
|
@ -2150,7 +2330,9 @@ try
|
|||
assert(!blocking(*this));
|
||||
const size_t ret
|
||||
{
|
||||
ssl.write_some(bufs)
|
||||
ssl?
|
||||
ssl->write_some(bufs):
|
||||
sd.write_some(bufs)
|
||||
};
|
||||
|
||||
++out.calls;
|
||||
|
@ -2190,26 +2372,15 @@ noexcept try
|
|||
|
||||
if constexpr((false)) // manual debug; large nr syscalls
|
||||
{
|
||||
const auto has_pending
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
SSL_has_pending(ssl.native_handle())
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
};
|
||||
|
||||
char ecbuf[64];
|
||||
log::debug
|
||||
{
|
||||
log, "%s ready %s %s avail:%zu:%zu:%d:%d",
|
||||
log, "%s ready %s %s avail:%zu:%zu",
|
||||
loghead(*this),
|
||||
reflect(type),
|
||||
string(ecbuf, ec),
|
||||
type == ready::READ? bytes : 0UL,
|
||||
type == ready::READ? available(*this) : 0UL,
|
||||
has_pending,
|
||||
SSL_pending(ssl.native_handle()),
|
||||
type == ready::READ? pending(*this): 0UL,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -2385,8 +2556,11 @@ noexcept try
|
|||
set(*this, *opts.sopts);
|
||||
|
||||
// The user can opt out of performing the handshake here.
|
||||
if(!opts.handshake)
|
||||
if(!ssl || !opts.handshake)
|
||||
{
|
||||
blocking(*this, false);
|
||||
return call_user(callback, ec);
|
||||
}
|
||||
|
||||
assert(!fini);
|
||||
handshake(opts, std::move(callback));
|
||||
|
@ -2809,18 +2983,20 @@ ircd::net::socket::set_timeout(const milliseconds &t,
|
|||
ircd::net::socket::operator
|
||||
SSL &()
|
||||
{
|
||||
assert(ssl.native_handle());
|
||||
return *ssl.native_handle();
|
||||
assert(ssl);
|
||||
assert(ssl->native_handle());
|
||||
return *ssl->native_handle();
|
||||
}
|
||||
|
||||
ircd::net::socket::operator
|
||||
const SSL &()
|
||||
const
|
||||
{
|
||||
using type = typename std::remove_const<decltype(socket::ssl)>::type;
|
||||
auto &ssl(const_cast<type &>(this->ssl));
|
||||
assert(ssl.native_handle());
|
||||
return *ssl.native_handle();
|
||||
auto &ssl(mutable_cast(this)->ssl);
|
||||
|
||||
assert(ssl);
|
||||
assert(ssl->native_handle());
|
||||
return *ssl->native_handle();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -326,15 +326,11 @@ try
|
|||
{
|
||||
ios::get()
|
||||
}
|
||||
,secure
|
||||
{
|
||||
configure(opts)
|
||||
}
|
||||
{
|
||||
configure(opts);
|
||||
|
||||
log::debug
|
||||
{
|
||||
log, "%s configured listener SSL",
|
||||
loghead(*this)
|
||||
};
|
||||
|
||||
open();
|
||||
}
|
||||
catch(const boost::system::system_error &e)
|
||||
|
@ -493,7 +489,9 @@ try
|
|||
{
|
||||
const auto &sock
|
||||
{
|
||||
std::make_shared<ircd::socket>(ssl)
|
||||
secure?
|
||||
std::make_shared<ircd::socket>(ssl):
|
||||
std::make_shared<ircd::socket>()
|
||||
};
|
||||
|
||||
auto handler
|
||||
|
@ -503,7 +501,7 @@ try
|
|||
|
||||
sock->local = ep;
|
||||
ip::tcp::socket &sd(*sock);
|
||||
a.async_accept(sd, ios::handle(accept_desc, std::move(handler)));
|
||||
a.async_accept(sd, sock->remote, ios::handle(accept_desc, std::move(handler)));
|
||||
++accepting;
|
||||
return true;
|
||||
}
|
||||
|
@ -529,14 +527,6 @@ noexcept try
|
|||
assert(accepting > 0);
|
||||
assert(accepting == 1); // for now
|
||||
|
||||
if(likely(sock->sd.is_open()))
|
||||
sock->remote = sock->sd.remote_endpoint();
|
||||
|
||||
const auto remote
|
||||
{
|
||||
remote_ipport(*sock)
|
||||
};
|
||||
|
||||
char ecbuf[64];
|
||||
log::debug
|
||||
{
|
||||
|
@ -555,7 +545,12 @@ noexcept try
|
|||
return;
|
||||
}
|
||||
|
||||
if(unlikely(!check_handshake_limit(*sock, remote)))
|
||||
const auto remote
|
||||
{
|
||||
remote_ipport(*sock)
|
||||
};
|
||||
|
||||
if(unlikely(secure && !check_handshake_limit(*sock, remote)))
|
||||
{
|
||||
allow(*this);
|
||||
net::close(*sock, dc::RST, close_ignore);
|
||||
|
@ -571,6 +566,12 @@ noexcept try
|
|||
return;
|
||||
}
|
||||
|
||||
if(!secure)
|
||||
{
|
||||
accepted(sock);
|
||||
return;
|
||||
}
|
||||
|
||||
static const socket::handshake_type handshake_type
|
||||
{
|
||||
socket::handshake_type::server
|
||||
|
@ -587,7 +588,7 @@ noexcept try
|
|||
};
|
||||
|
||||
sock->set_timeout(milliseconds(timeout));
|
||||
sock->ssl.async_handshake(handshake_type, ios::handle(handshake_desc, std::move(handshake)));
|
||||
sock->ssl->async_handshake(handshake_type, ios::handle(handshake_desc, std::move(handshake)));
|
||||
assert(!openssl::get_app_data(*sock));
|
||||
openssl::set_app_data(*sock, sock.get());
|
||||
}
|
||||
|
@ -750,11 +751,7 @@ noexcept try
|
|||
openssl::set_app_data(*sock, nullptr);
|
||||
check_handshake_error(ec, *sock);
|
||||
sock->cancel_timeout();
|
||||
assert(bool(cb));
|
||||
|
||||
// Toggles the behavior of non-async functions; see func comment
|
||||
blocking(*sock, false);
|
||||
cb(*this, sock);
|
||||
accepted(sock);
|
||||
}
|
||||
catch(const ctx::interrupted &e)
|
||||
{
|
||||
|
@ -1068,6 +1065,22 @@ catch(...)
|
|||
}
|
||||
|
||||
void
|
||||
ircd::net::acceptor::accepted(const std::shared_ptr<socket> &sock)
|
||||
{
|
||||
assert(bool(cb));
|
||||
assert(bool(sock));
|
||||
|
||||
#if !defined(BSD_BASED_OS)
|
||||
// Toggles the behavior of non-async functions; see func comment
|
||||
// This is not needed on BSD because the socket inherits the listener's
|
||||
// non-blocking disposition.
|
||||
blocking(*sock, false);
|
||||
#endif
|
||||
|
||||
cb(*this, sock);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::acceptor::configure(const json::object &opts)
|
||||
{
|
||||
log::debug
|
||||
|
@ -1076,12 +1089,26 @@ ircd::net::acceptor::configure(const json::object &opts)
|
|||
loghead(*this)
|
||||
};
|
||||
|
||||
configure_password(opts);
|
||||
configure_flags(opts);
|
||||
if(!configure_certs(opts))
|
||||
return false;
|
||||
|
||||
configure_password(opts);
|
||||
configure_ciphers(opts);
|
||||
configure_curves(opts);
|
||||
configure_certs(opts);
|
||||
configure_sni(opts);
|
||||
log::debug
|
||||
{
|
||||
log, "%s configured listener SSL",
|
||||
loghead(*this)
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ircd::net::acceptor::configure_sni(const json::object &opts)
|
||||
{
|
||||
SSL_CTX_set_alpn_select_cb(ssl.native_handle(), ircd_net_acceptor_handle_alpn, this);
|
||||
SSL_CTX_set_tlsext_servername_callback(ssl.native_handle(), ircd_net_acceptor_handle_sni);
|
||||
SSL_CTX_set_tlsext_servername_arg(ssl.native_handle(), this);
|
||||
|
@ -1113,7 +1140,8 @@ ircd::net::acceptor::configure_flags(const json::object &opts)
|
|||
if(opts.get<bool>("ssl_no_tlsv1_2", false))
|
||||
flags |= ssl.no_tlsv1_2;
|
||||
|
||||
ssl.set_options(flags);
|
||||
if(flags)
|
||||
ssl.set_options(flags);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1195,9 +1223,10 @@ ircd::net::acceptor::configure_curves(const json::object &opts)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
ircd::net::acceptor::configure_certs(const json::object &opts)
|
||||
{
|
||||
uint ret(0);
|
||||
if(!empty(unquote(opts["certificate_chain_path"])))
|
||||
{
|
||||
const json::string filename
|
||||
|
@ -1214,6 +1243,7 @@ ircd::net::acceptor::configure_certs(const json::object &opts)
|
|||
};
|
||||
|
||||
ssl.use_certificate_chain_file(filename);
|
||||
ret += 1;
|
||||
log::info
|
||||
{
|
||||
log, "%s using certificate chain file '%s'",
|
||||
|
@ -1238,7 +1268,6 @@ ircd::net::acceptor::configure_certs(const json::object &opts)
|
|||
};
|
||||
|
||||
ssl.use_certificate_file(filename, asio::ssl::context::pem);
|
||||
|
||||
const auto *const x509
|
||||
{
|
||||
SSL_CTX_get0_certificate(ssl.native_handle())
|
||||
|
@ -1252,6 +1281,7 @@ ircd::net::acceptor::configure_certs(const json::object &opts)
|
|||
string_view{};
|
||||
});
|
||||
|
||||
ret += 1;
|
||||
log::info
|
||||
{
|
||||
log, "%s using file '%s' with certificate for '%s'",
|
||||
|
@ -1277,6 +1307,8 @@ ircd::net::acceptor::configure_certs(const json::object &opts)
|
|||
};
|
||||
|
||||
ssl.use_private_key_file(filename, asio::ssl::context::pem);
|
||||
|
||||
ret += 1;
|
||||
log::info
|
||||
{
|
||||
log, "%s using private key file '%s'",
|
||||
|
@ -1284,6 +1316,16 @@ ircd::net::acceptor::configure_certs(const json::object &opts)
|
|||
filename
|
||||
};
|
||||
}
|
||||
|
||||
if(ret != 0 && ret != 3)
|
||||
log::warning
|
||||
{
|
||||
"%s missing some paths to PEM files in its options."
|
||||
" SSL is probably misconfigured.",
|
||||
loghead(*this),
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
140
ircd/resource.cc
140
ircd/resource.cc
|
@ -1101,28 +1101,48 @@ ircd::resource::response::HEAD_BUF_SZ
|
|||
|
||||
ircd::resource::response::response(client &client,
|
||||
const http::code &code)
|
||||
:response{client, json::object{json::empty_object}, code}
|
||||
:response
|
||||
{
|
||||
client,
|
||||
json::object{json::empty_object},
|
||||
code
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
ircd::resource::response::response(client &client,
|
||||
const http::code &code,
|
||||
const json::iov &members)
|
||||
:response{client, members, code}
|
||||
:response
|
||||
{
|
||||
client,
|
||||
members,
|
||||
code
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
ircd::resource::response::response(client &client,
|
||||
const json::members &members,
|
||||
const http::code &code)
|
||||
:response{client, code, members}
|
||||
:response
|
||||
{
|
||||
client,
|
||||
code,
|
||||
members
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
ircd::resource::response::response(client &client,
|
||||
const json::value &value,
|
||||
const http::code &code)
|
||||
:response{client, code, value}
|
||||
:response
|
||||
{
|
||||
client,
|
||||
code,
|
||||
value
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1141,27 +1161,45 @@ try
|
|||
size
|
||||
};
|
||||
|
||||
const string_view str
|
||||
{
|
||||
stringify(mutable_buffer{buffer}, value)
|
||||
};
|
||||
|
||||
switch(type(value))
|
||||
{
|
||||
case json::ARRAY:
|
||||
{
|
||||
response(client, json::array{stringify(mutable_buffer{buffer}, value)}, code);
|
||||
response
|
||||
{
|
||||
client,
|
||||
json::array{str},
|
||||
code,
|
||||
};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
case json::OBJECT:
|
||||
{
|
||||
response(client, json::object{stringify(mutable_buffer{buffer}, value)}, code);
|
||||
response
|
||||
{
|
||||
client,
|
||||
json::object{str},
|
||||
code,
|
||||
};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
[[unlikely]]
|
||||
default: throw http::error
|
||||
{
|
||||
"Cannot send json::%s as response content",
|
||||
http::INTERNAL_SERVER_ERROR,
|
||||
type(value),
|
||||
};
|
||||
default:
|
||||
throw http::error
|
||||
{
|
||||
"Cannot send json::%s as response content",
|
||||
http::INTERNAL_SERVER_ERROR,
|
||||
type(value),
|
||||
};
|
||||
}
|
||||
}
|
||||
catch(const json::error &e)
|
||||
|
@ -1194,7 +1232,12 @@ try
|
|||
stringify(mutable_buffer{buffer}, members)
|
||||
};
|
||||
|
||||
response(client, object, code);
|
||||
response
|
||||
{
|
||||
client,
|
||||
object,
|
||||
code,
|
||||
};
|
||||
}
|
||||
catch(const json::error &e)
|
||||
{
|
||||
|
@ -1226,7 +1269,12 @@ try
|
|||
stringify(mutable_buffer{buffer}, members)
|
||||
};
|
||||
|
||||
response(client, object, code);
|
||||
response
|
||||
{
|
||||
client,
|
||||
object,
|
||||
code,
|
||||
};
|
||||
}
|
||||
catch(const json::error &e)
|
||||
{
|
||||
|
@ -1248,7 +1296,13 @@ ircd::resource::response::response(client &client,
|
|||
};
|
||||
|
||||
assert(json::valid(object, std::nothrow));
|
||||
response(client, object, content_type, code);
|
||||
response
|
||||
{
|
||||
client,
|
||||
string_view{object},
|
||||
content_type,
|
||||
code,
|
||||
};
|
||||
}
|
||||
|
||||
ircd::resource::response::response(client &client,
|
||||
|
@ -1261,7 +1315,13 @@ ircd::resource::response::response(client &client,
|
|||
};
|
||||
|
||||
assert(json::valid(array, std::nothrow));
|
||||
response(client, array, content_type, code);
|
||||
response
|
||||
{
|
||||
client,
|
||||
string_view{array},
|
||||
content_type,
|
||||
code,
|
||||
};
|
||||
}
|
||||
|
||||
ircd::resource::response::response(client &client,
|
||||
|
@ -1283,7 +1343,11 @@ ircd::resource::response::response(client &client,
|
|||
|
||||
response
|
||||
{
|
||||
client, content, content_type, code, string_view{sb.completed()}
|
||||
client,
|
||||
content,
|
||||
content_type,
|
||||
code,
|
||||
string_view{sb.completed()},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1298,18 +1362,13 @@ ircd::resource::response::response(client &client,
|
|||
// Head gets sent
|
||||
response
|
||||
{
|
||||
client, code, content_type, size(content), headers
|
||||
client,
|
||||
code,
|
||||
content_type,
|
||||
size(content),
|
||||
headers,
|
||||
content,
|
||||
};
|
||||
|
||||
// All content gets sent
|
||||
const size_t written
|
||||
{
|
||||
size(content)?
|
||||
client.write_all(content):
|
||||
0
|
||||
};
|
||||
|
||||
assert(written == size(content));
|
||||
}
|
||||
|
||||
decltype(ircd::resource::response::access_control_allow_origin)
|
||||
|
@ -1324,8 +1383,12 @@ ircd::resource::response::response(client &client,
|
|||
const http::code &code,
|
||||
const string_view &content_type,
|
||||
const size_t &content_length,
|
||||
const string_view &headers)
|
||||
const string_view &headers,
|
||||
const string_view &content)
|
||||
{
|
||||
// content may be empty if the caller wants to send it themselves, but
|
||||
// either way the type and length must still be passed by caller.
|
||||
assert(!content || content_length);
|
||||
assert(!content_length || !empty(content_type));
|
||||
|
||||
const auto request_time
|
||||
|
@ -1362,13 +1425,20 @@ ircd::resource::response::response(client &client,
|
|||
if(unlikely(!head.remaining()))
|
||||
throw panic
|
||||
{
|
||||
"HTTP headers too large for buffer of %zu", sizeof(head_buf)
|
||||
"HTTP headers too large for buffer of %zu",
|
||||
sizeof(head_buf),
|
||||
};
|
||||
|
||||
size_t wrote_head {0};
|
||||
const const_buffer iov[]
|
||||
{
|
||||
head.completed(),
|
||||
content,
|
||||
};
|
||||
|
||||
size_t wrote {0};
|
||||
std::exception_ptr eptr; try
|
||||
{
|
||||
wrote_head += client.write_all(head.completed());
|
||||
wrote += client.write_all(iov);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
@ -1385,17 +1455,17 @@ ircd::resource::response::response(client &client,
|
|||
log::logf
|
||||
{
|
||||
log, level,
|
||||
"%s HTTP %u `%s' %s in %s; %s content-length:%s head-length:%zu %s%s",
|
||||
"%s HTTP %u `%s' %s in %s; %s head:%zu content:%s %s%s",
|
||||
loghead(client),
|
||||
uint(code),
|
||||
client.request.head.path,
|
||||
http::status(code),
|
||||
rtime,
|
||||
content_type,
|
||||
size(iov[0]),
|
||||
ssize_t(content_length) >= 0?
|
||||
lex_cast(content_length):
|
||||
"chunked"_sv,
|
||||
wrote_head,
|
||||
eptr?
|
||||
"error:"_sv:
|
||||
string_view{},
|
||||
|
@ -1406,7 +1476,7 @@ ircd::resource::response::response(client &client,
|
|||
if(unlikely(eptr))
|
||||
std::rethrow_exception(eptr);
|
||||
|
||||
assert(wrote_head == size(head.completed()));
|
||||
assert(wrote == buffers::size(vector_view(iov)));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -14,6 +14,8 @@ namespace ircd::server
|
|||
extern log::log log;
|
||||
extern ctx::dock dock;
|
||||
extern conf::item<seconds> close_all_timeout;
|
||||
extern conf::item<seconds> wait_all_timeout;
|
||||
extern conf::item<size_t> wait_all_max;
|
||||
extern peers_allocator_state peers_alloc;
|
||||
|
||||
// Internal util
|
||||
|
@ -59,10 +61,24 @@ ircd::server::enable
|
|||
decltype(ircd::server::close_all_timeout)
|
||||
ircd::server::close_all_timeout
|
||||
{
|
||||
{ "name", "ircd.server.close_all_timeout" },
|
||||
{ "name", "ircd.server.close_all.timeout" },
|
||||
{ "default", 2L },
|
||||
};
|
||||
|
||||
decltype(ircd::server::wait_all_timeout)
|
||||
ircd::server::wait_all_timeout
|
||||
{
|
||||
{ "name", "ircd.server.wait_all.timeout" },
|
||||
{ "default", 5L },
|
||||
};
|
||||
|
||||
decltype(ircd::server::wait_all_max)
|
||||
ircd::server::wait_all_max
|
||||
{
|
||||
{ "name", "ircd.server.wait_all.max" },
|
||||
{ "default", 9L },
|
||||
};
|
||||
|
||||
decltype(ircd::server::peers_alloc)
|
||||
ircd::server::peers_alloc;
|
||||
|
||||
|
@ -115,12 +131,15 @@ ircd::server::wait()
|
|||
[] { return !peer_unfinished(); }
|
||||
};
|
||||
|
||||
while(!dock.wait_for(seconds(5), finished))
|
||||
const size_t max(wait_all_max);
|
||||
const seconds timeout(wait_all_timeout);
|
||||
for(size_t i(0); i < max && !dock.wait_for(timeout, finished); ++i)
|
||||
{
|
||||
for(const auto &[name, peer] : peers)
|
||||
log::dwarning
|
||||
log::logf
|
||||
{
|
||||
log, "Waiting for peer %s tags:%zu links:%zu err:%b op[r:%b f:%b]",
|
||||
log, log::level::DWARNING,
|
||||
"Waiting for peer %s tags:%zu links:%zu err:%b op[r:%b f:%b]",
|
||||
name,
|
||||
peer->tag_count(),
|
||||
peer->link_count(),
|
||||
|
@ -2424,6 +2443,15 @@ ircd::server::link::handle_open(std::exception_ptr eptr)
|
|||
peer->handle_open(*this, std::move(eptr));
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::server::link::close(const net::dc type)
|
||||
{
|
||||
return close(net::close_opts
|
||||
{
|
||||
.type = type,
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::server::link::close(const net::close_opts &close_opts)
|
||||
{
|
||||
|
@ -2902,41 +2930,25 @@ void
|
|||
ircd::server::link::discard_read()
|
||||
{
|
||||
assert(socket);
|
||||
const size_t available
|
||||
const size_t pending
|
||||
{
|
||||
net::available(*socket)
|
||||
};
|
||||
|
||||
const ssize_t has_pending
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
|
||||
SSL_has_pending(socket->ssl.native_handle())
|
||||
#else
|
||||
-2L
|
||||
#endif
|
||||
};
|
||||
|
||||
const ssize_t pending
|
||||
{
|
||||
SSL_pending(socket->ssl.native_handle())
|
||||
net::pending(*socket)
|
||||
};
|
||||
|
||||
const size_t discarded
|
||||
{
|
||||
discard_any(*socket, size_t(pending))
|
||||
discard_any(*socket, pending)
|
||||
};
|
||||
|
||||
if(discarded)
|
||||
{
|
||||
log::dwarning
|
||||
{
|
||||
log, "%s q:%zu discarded:%zu pending:%zd has_pending:%zd available:%zd",
|
||||
log, "%s q:%zu pending:%zu discarded:%zu",
|
||||
loghead(*this),
|
||||
queue.size(),
|
||||
discarded,
|
||||
pending,
|
||||
has_pending,
|
||||
available,
|
||||
discarded,
|
||||
};
|
||||
|
||||
assert(peer);
|
||||
|
|
|
@ -354,7 +354,7 @@ ircd::m::app::handle_stdout()
|
|||
|
||||
const auto message_id
|
||||
{
|
||||
!ircd::write_avoid?
|
||||
!ircd::read_only && !ircd::maintenance?
|
||||
m::msghtml(room_id, user_id, content, string_view{alt}, "m.notice"):
|
||||
m::event::id::buf{}
|
||||
};
|
||||
|
|
|
@ -213,6 +213,55 @@ noexcept
|
|||
delete homeserver;
|
||||
}
|
||||
|
||||
bool
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::homeserver::rehash(homeserver *const homeserver)
|
||||
{
|
||||
if(!homeserver)
|
||||
return false;
|
||||
|
||||
if(!homeserver->conf)
|
||||
return false;
|
||||
|
||||
homeserver->conf->load();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IRCD_MODULE_EXPORT
|
||||
ircd::m::homeserver::refresh(homeserver *const homeserver)
|
||||
try
|
||||
{
|
||||
if(!homeserver)
|
||||
return false;
|
||||
|
||||
const ctx::uninterruptible::nothrow ui;
|
||||
const vm::sequence::refresh refresh;
|
||||
if(ircd::debugmode)
|
||||
log::logf
|
||||
{
|
||||
log, log::level::DEBUG,
|
||||
"refreshed events[%12lu -> %-12lu] vm[%10lu -> %-10lu] %s",
|
||||
refresh.database[0],
|
||||
refresh.database[1],
|
||||
refresh.retired[0],
|
||||
refresh.retired[1],
|
||||
string_view{refresh.event_id},
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
catch(const std::exception &e)
|
||||
{
|
||||
log::error
|
||||
{
|
||||
log, "refresh :%s",
|
||||
e.what(),
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// homeserver::homeserver::homeserver
|
||||
//
|
||||
|
@ -283,17 +332,17 @@ try
|
|||
if(ircd::mods::autoload)
|
||||
mods::imports.emplace("net_dns_cache"s, "net_dns_cache");
|
||||
|
||||
if(!ircd::write_avoid)
|
||||
if(!ircd::read_only && !ircd::maintenance)
|
||||
if(key && !key->verify_keys.empty())
|
||||
m::keys::cache::set(key->verify_keys);
|
||||
|
||||
if(opts->autoapps)
|
||||
m::app::init();
|
||||
|
||||
if(!ircd::maintenance)
|
||||
if(!ircd::read_only && !ircd::maintenance)
|
||||
signon(*this);
|
||||
|
||||
if(!ircd::maintenance && opts->backfill)
|
||||
if(!ircd::read_only && !ircd::maintenance && opts->backfill)
|
||||
m::init::backfill::init();
|
||||
}
|
||||
catch(const std::exception &e)
|
||||
|
@ -321,7 +370,7 @@ noexcept try
|
|||
server::wait();
|
||||
m::sync::pool.join();
|
||||
|
||||
if(!ircd::maintenance && _vm)
|
||||
if(!ircd::read_only && !ircd::maintenance && _vm)
|
||||
signoff(*this);
|
||||
|
||||
///TODO: XXX primary
|
||||
|
@ -394,7 +443,7 @@ ircd::m::homeserver::key::key(const struct opts &opts)
|
|||
})
|
||||
};
|
||||
|
||||
if(!fs::exists(sk_file) && !ircd::write_avoid)
|
||||
if(!fs::exists(sk_file) && !ircd::read_only && !ircd::maintenance)
|
||||
log::notice
|
||||
{
|
||||
m::log, "Creating ed25519 secret key @ `%s'", sk_file
|
||||
|
@ -404,7 +453,7 @@ ircd::m::homeserver::key::key(const struct opts &opts)
|
|||
}()}
|
||||
,secret_key
|
||||
{
|
||||
secret_key_path, &public_key, !ircd::write_avoid
|
||||
secret_key_path, &public_key, !ircd::read_only && !ircd::maintenance
|
||||
}
|
||||
,public_key_b64
|
||||
{
|
||||
|
|
|
@ -186,6 +186,8 @@ ircd::m::expired(const m::keys &keys)
|
|||
namespace ircd::m
|
||||
{
|
||||
extern conf::item<milliseconds> keys_query_timeout;
|
||||
extern conf::item<size_t> keys_query_buffer_size;
|
||||
extern conf::item<bool> keys_query_buffer_dynamic;
|
||||
}
|
||||
|
||||
decltype(ircd::m::keys_query_timeout)
|
||||
|
@ -195,22 +197,51 @@ ircd::m::keys_query_timeout
|
|||
{ "default", 20000L }
|
||||
};
|
||||
|
||||
decltype(ircd::m::keys_query_buffer_size)
|
||||
ircd::m::keys_query_buffer_size
|
||||
{
|
||||
{ "name", "ircd.keys.query.buffer.size" },
|
||||
{ "default", long(32_KiB) },
|
||||
};
|
||||
|
||||
decltype(ircd::m::keys_query_buffer_dynamic)
|
||||
ircd::m::keys_query_buffer_dynamic
|
||||
{
|
||||
{ "name", "ircd.keys.query.buffer.dynamic" },
|
||||
{ "default", false },
|
||||
};
|
||||
|
||||
bool
|
||||
ircd::m::keys::query(const string_view &query_server,
|
||||
const queries &queries,
|
||||
const closure_bool &closure)
|
||||
{
|
||||
const unique_mutable_buffer buf
|
||||
{
|
||||
keys_query_buffer_size
|
||||
};
|
||||
|
||||
const bool dynamic
|
||||
{
|
||||
keys_query_buffer_dynamic
|
||||
};
|
||||
|
||||
return query(query_server, queries, closure, buf, dynamic);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::keys::query(const string_view &query_server,
|
||||
const queries &queries,
|
||||
const closure_bool &closure,
|
||||
const mutable_buffer &buf,
|
||||
const bool dynamic)
|
||||
try
|
||||
{
|
||||
assert(!query_server.empty());
|
||||
|
||||
m::fed::key::opts opts;
|
||||
opts.remote = query_server;
|
||||
opts.dynamic = false;
|
||||
const unique_buffer<mutable_buffer> buf
|
||||
{
|
||||
32_KiB
|
||||
};
|
||||
|
||||
opts.dynamic = dynamic;
|
||||
m::fed::key::query request
|
||||
{
|
||||
queries, buf, std::move(opts)
|
||||
|
|
19
matrix/vm.cc
19
matrix/vm.cc
|
@ -109,6 +109,25 @@ noexcept
|
|||
assert(retired == sequence::retired || ircd::read_only);
|
||||
}
|
||||
|
||||
ircd::m::vm::phase
|
||||
ircd::m::vm::phase_reflect(const string_view &str)
|
||||
noexcept
|
||||
{
|
||||
phase ret{phase::NONE};
|
||||
util::for_each<phase>([&ret, &str]
|
||||
(const auto &phase)
|
||||
{
|
||||
if(reflect(phase) == str)
|
||||
{
|
||||
ret = phase;
|
||||
return false;
|
||||
}
|
||||
else return true;
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ircd::string_view
|
||||
ircd::m::vm::reflect(const enum phase &code)
|
||||
{
|
||||
|
|
|
@ -20,6 +20,34 @@ ircd::m::vm::sequence::committed;
|
|||
decltype(ircd::m::vm::sequence::uncommitted)
|
||||
ircd::m::vm::sequence::uncommitted;
|
||||
|
||||
//
|
||||
// refresh::refresh
|
||||
//
|
||||
|
||||
ircd::m::vm::sequence::refresh::refresh()
|
||||
{
|
||||
auto &database
|
||||
{
|
||||
db::database::get("events")
|
||||
};
|
||||
|
||||
if(!database.slave)
|
||||
return;
|
||||
|
||||
this->database[0] = db::sequence(database);
|
||||
this->retired[0] = sequence::retired;
|
||||
|
||||
db::refresh(database);
|
||||
sequence::retired = sequence::get(this->event_id);
|
||||
|
||||
this->database[1] = db::sequence(database);
|
||||
this->retired[1] = sequence::retired;
|
||||
}
|
||||
|
||||
//
|
||||
// tools
|
||||
//
|
||||
|
||||
uint64_t
|
||||
ircd::m::vm::sequence::min()
|
||||
{
|
||||
|
|
|
@ -4596,7 +4596,8 @@ static void
|
|||
_print_sst_info_header(opt &out)
|
||||
{
|
||||
out << std::left << std::setfill(' ')
|
||||
<< std::setw(12) << "name"
|
||||
<< std::setw(3) << "chkp"
|
||||
<< " " << std::setw(12) << "name"
|
||||
<< " " << std::setw(32) << "creation"
|
||||
<< " " << std::setw(3) << "flt"
|
||||
<< std::right
|
||||
|
@ -4637,7 +4638,9 @@ _print_sst_info(opt &out,
|
|||
|
||||
char tmbuf[64], pbuf[48];
|
||||
out << std::left << std::setfill(' ')
|
||||
<< std::setw(12) << f.name
|
||||
<< std::setw(3) << std::left << rsplit(f.path, '/').second
|
||||
<< " "
|
||||
<< std::setw(12) << std::left << f.name
|
||||
<< " " << std::setw(32) << std::left << (f.created? timef(tmbuf, f.created, ircd::localtime) : string_view{})
|
||||
<< " " << std::setw(1) << std::left << (!f.filter.empty()? 'F' : '-')
|
||||
<< std::setw(1) << std::left << (f.delta_encoding? 'D' : '-')
|
||||
|
@ -5004,30 +5007,32 @@ try
|
|||
db::database::get(dbname)
|
||||
};
|
||||
|
||||
const auto _print_totals{[&out]
|
||||
(const auto &vector)
|
||||
size_t totals(0);
|
||||
db::database::sst::info total;
|
||||
total.name = "total"s;
|
||||
const auto _add_totals{[&total, &totals]
|
||||
(const auto &info)
|
||||
{
|
||||
db::database::sst::info total;
|
||||
total.name = "total"s;
|
||||
for(const auto &info : vector)
|
||||
{
|
||||
total.size += info.size;
|
||||
total.data_size += info.data_size;
|
||||
total.index_data_size += info.index_data_size;
|
||||
total.index_root_size += info.index_root_size;
|
||||
total.filter_size += info.filter_size;
|
||||
total.keys_size += info.keys_size;
|
||||
total.values_size += info.values_size;
|
||||
total.index_parts += info.index_parts;
|
||||
total.data_blocks += info.data_blocks;
|
||||
total.entries += info.entries;
|
||||
total.range_deletes += info.range_deletes;
|
||||
total.num_reads += info.num_reads;
|
||||
}
|
||||
total.size += info.size;
|
||||
total.data_size += info.data_size;
|
||||
total.index_data_size += info.index_data_size;
|
||||
total.index_root_size += info.index_root_size;
|
||||
total.filter_size += info.filter_size;
|
||||
total.keys_size += info.keys_size;
|
||||
total.values_size += info.values_size;
|
||||
total.index_parts += info.index_parts;
|
||||
total.data_blocks += info.data_blocks;
|
||||
total.entries += info.entries;
|
||||
total.range_deletes += info.range_deletes;
|
||||
total.num_reads += info.num_reads;
|
||||
totals++;
|
||||
}};
|
||||
|
||||
const auto _print_totals{[&out, &total, &totals]
|
||||
{
|
||||
_print_sst_info_header(out);
|
||||
_print_sst_info(out, total);
|
||||
out << "--- " << vector.size() << " files." << std::endl;
|
||||
out << "--- " << totals << " files." << std::endl;
|
||||
}};
|
||||
|
||||
if(colname == "*")
|
||||
|
@ -5050,10 +5055,11 @@ try
|
|||
continue;
|
||||
|
||||
_print_sst_info(out, fileinfo);
|
||||
_add_totals(fileinfo);
|
||||
}
|
||||
|
||||
out << std::endl;
|
||||
_print_totals(vector);
|
||||
_print_totals();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -5061,6 +5067,7 @@ try
|
|||
{
|
||||
const db::database::sst::info info{database, colname};
|
||||
_print_sst_info_full(out, info);
|
||||
_add_totals(info);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -5087,10 +5094,11 @@ try
|
|||
continue;
|
||||
|
||||
_print_sst_info(out, info);
|
||||
_add_totals(info);
|
||||
}
|
||||
|
||||
out << std::endl;
|
||||
_print_totals(vector);
|
||||
_print_totals();
|
||||
return true;
|
||||
}
|
||||
catch(const std::out_of_range &e)
|
||||
|
@ -5915,7 +5923,7 @@ try
|
|||
const auto print_head{[&out]
|
||||
{
|
||||
out
|
||||
<< std::setw(4) << std::left << "ID" << ' '
|
||||
<< std::setw(6) << std::left << "ID" << ' '
|
||||
<< std::setw(40) << std::right << "ADDRESS" << ' '
|
||||
<< std::setw(7) << std::right << "TTL" << ' '
|
||||
<< std::setw(50) << std::left << "NAME" << ' '
|
||||
|
@ -5954,7 +5962,7 @@ try
|
|||
|
||||
char pbuf[32];
|
||||
out
|
||||
<< std::setw(4) << std::left << peer.id << ' '
|
||||
<< std::setw(6) << std::left << peer.id << ' '
|
||||
<< std::setw(40) << std::right << net::ipport{peer.remote} << ' '
|
||||
<< std::setw(7) << std::right << std::max(expires, -1L) << ' '
|
||||
<< std::setw(50) << std::left << trunc(host, 50) << ' '
|
||||
|
@ -6125,6 +6133,21 @@ console_cmd__peer__error__clear(opt &out, const string_view &line)
|
|||
bool
|
||||
console_cmd__peer__version(opt &out, const string_view &line)
|
||||
{
|
||||
const params param{line, " ",
|
||||
{
|
||||
"[expression]"
|
||||
}};
|
||||
|
||||
const bool expr
|
||||
{
|
||||
param["[expression]"] && param["[expression]"] != "*"
|
||||
};
|
||||
|
||||
const globular_imatch match
|
||||
{
|
||||
param["[expression]"]
|
||||
};
|
||||
|
||||
for(const auto &p : server::peers)
|
||||
{
|
||||
using std::setw;
|
||||
|
@ -6132,9 +6155,15 @@ console_cmd__peer__version(opt &out, const string_view &line)
|
|||
using std::right;
|
||||
|
||||
const auto &host{p.first};
|
||||
if(expr)
|
||||
{
|
||||
const auto &[name, proto] (rsplit(host, ':'));
|
||||
if(!match(host) && !match(name))
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto &peer{*p.second};
|
||||
const net::ipport &ipp{peer.remote};
|
||||
|
||||
out << setw(40) << right << host;
|
||||
|
||||
if(ipp)
|
||||
|
@ -6145,9 +6174,10 @@ console_cmd__peer__version(opt &out, const string_view &line)
|
|||
if(!empty(peer.server_version))
|
||||
out << " :" << peer.server_version;
|
||||
|
||||
out << std::endl;
|
||||
out << '\n';
|
||||
}
|
||||
|
||||
out << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6724,8 +6754,8 @@ console_cmd__net__listen(opt &out, const string_view &line)
|
|||
{
|
||||
{ "host", token.at("host", "0.0.0.0"_sv) },
|
||||
{ "port", token.at("port", 8448L) },
|
||||
{ "private_key_pem_path", token.at("private_key_pem_path") },
|
||||
{ "certificate_pem_path", token.at("certificate_pem_path") },
|
||||
{ "private_key_pem_path", token.at("private_key_pem_path", ""_sv) },
|
||||
{ "certificate_pem_path", token.at("certificate_pem_path", ""_sv) },
|
||||
{ "certificate_chain_path", token.at("certificate_chain_path", ""_sv) },
|
||||
};
|
||||
|
||||
|
@ -7181,15 +7211,62 @@ console_cmd__key__get(opt &out, const string_view &line)
|
|||
|
||||
const auto server_name
|
||||
{
|
||||
param.at(0)
|
||||
param.at("server_name")
|
||||
};
|
||||
|
||||
const auto query_server
|
||||
{
|
||||
param[1]
|
||||
param["[query_server]"]
|
||||
};
|
||||
|
||||
if(!query_server)
|
||||
if(m::valid(m::id::ROOM, server_name) || m::valid(m::id::ROOM_ALIAS, server_name))
|
||||
{
|
||||
const auto query_server
|
||||
{
|
||||
param.at("[query_server]")
|
||||
};
|
||||
|
||||
const auto room_id
|
||||
{
|
||||
m::room_id(server_name)
|
||||
};
|
||||
|
||||
const m::room::origins origins
|
||||
{
|
||||
room_id
|
||||
};
|
||||
|
||||
std::vector<std::string> servers;
|
||||
servers.reserve(origins.count());
|
||||
origins.for_each([&servers]
|
||||
(const auto &server)
|
||||
{
|
||||
servers.emplace_back(server);
|
||||
});
|
||||
|
||||
std::vector<m::fed::key::server_key> queries(servers.size());
|
||||
std::transform(begin(servers), end(servers), begin(queries), []
|
||||
(const auto &server) -> m::fed::key::server_key
|
||||
{
|
||||
return { server, {} };
|
||||
});
|
||||
|
||||
const auto closure{[&out]
|
||||
(const m::keys &keys)
|
||||
{
|
||||
pretty_oneline(out, keys) << std::endl;
|
||||
return true;
|
||||
}};
|
||||
|
||||
const bool dynamic_response {true};
|
||||
const unique_mutable_buffer buf
|
||||
{
|
||||
64_KiB
|
||||
};
|
||||
|
||||
m::keys::query(query_server, queries, closure, buf, dynamic_response);
|
||||
}
|
||||
else if(!query_server)
|
||||
{
|
||||
m::keys::get(server_name, [&out]
|
||||
(const m::keys &keys)
|
||||
|
@ -9503,9 +9580,9 @@ console_cmd__room(opt &out, const string_view &line)
|
|||
out << "top index: " << std::get<m::event::idx>(top) << std::endl;
|
||||
out << std::endl;
|
||||
|
||||
out << "m.room state: " << std::endl;
|
||||
out << "m. state: " << std::endl;
|
||||
|
||||
state.for_each(m::room::state::type_prefix{"m.room."}, [&out, &state]
|
||||
state.for_each(m::room::state::type_prefix{"m."}, [&out, &state]
|
||||
(const string_view &type, const string_view &state_key, const m::event::idx &event_idx)
|
||||
{
|
||||
assert(startswith(type, "m.room."));
|
||||
|
@ -11668,21 +11745,21 @@ bool
|
|||
console_cmd__room__acquire__list(opt &out, const string_view &line)
|
||||
{
|
||||
out
|
||||
<< std::right << std::setw(4) << "id"
|
||||
<< std::right << std::setw(5) << "id"
|
||||
<< " "
|
||||
<< std::right << std::setw(4) << "fid"
|
||||
<< std::right << std::setw(6) << "fid"
|
||||
<< " "
|
||||
<< std::left << std::setw(50) << "room"
|
||||
<< " "
|
||||
<< std::right << std::setw(4) << "view"
|
||||
<< std::right << std::setw(5) << "view"
|
||||
<< " ["
|
||||
<< std::right << std::setw(7) << "depth"
|
||||
<< std::right << std::setw(8) << "depth"
|
||||
<< " "
|
||||
<< std::right << std::setw(7) << "depth"
|
||||
<< std::right << std::setw(8) << "depth"
|
||||
<< " | "
|
||||
<< std::right << std::setw(8) << "ref"
|
||||
<< std::right << std::setw(9) << "ref"
|
||||
<< " "
|
||||
<< std::right << std::setw(8) << "ref"
|
||||
<< std::right << std::setw(9) << "ref"
|
||||
<< "] "
|
||||
<< std::left << std::setw(50) << "event"
|
||||
<< " "
|
||||
|
@ -11693,21 +11770,21 @@ console_cmd__room__acquire__list(opt &out, const string_view &line)
|
|||
size_t j(0);
|
||||
for(const auto &result : a->fetching)
|
||||
out
|
||||
<< std::right << std::setw(4) << a->id
|
||||
<< std::right << std::setw(5) << a->id
|
||||
<< " "
|
||||
<< std::right << std::setw(4) << (a->fetches - j++)
|
||||
<< std::right << std::setw(6) << (a->fetches - j++)
|
||||
<< " "
|
||||
<< std::left << std::setw(50) << trunc(a->opts.room.room_id, 40)
|
||||
<< " "
|
||||
<< std::right << std::setw(4) << a->opts.viewport_size
|
||||
<< std::right << std::setw(5) << a->opts.viewport_size
|
||||
<< " ["
|
||||
<< std::right << std::setw(7) << a->opts.depth.first
|
||||
<< std::right << std::setw(8) << a->opts.depth.first
|
||||
<< " "
|
||||
<< std::right << std::setw(7) << a->opts.depth.second
|
||||
<< std::right << std::setw(8) << a->opts.depth.second
|
||||
<< " | "
|
||||
<< std::right << std::setw(8) << a->opts.ref.first
|
||||
<< std::right << std::setw(9) << a->opts.ref.first
|
||||
<< " "
|
||||
<< std::right << std::setw(8) << long(a->opts.ref.second)
|
||||
<< std::right << std::setw(9) << long(a->opts.ref.second)
|
||||
<< "] "
|
||||
<< std::left << std::setw(50) << trunc(result.event_id, 60)
|
||||
<< " "
|
||||
|
|
|
@ -52,8 +52,8 @@ IRCD_MODULE
|
|||
decltype(ircd::m::bridge::enable)
|
||||
ircd::m::bridge::enable
|
||||
{
|
||||
{ "name", "ircd.m.bridge.enable" },
|
||||
{ "default", true },
|
||||
{ "name", "ircd.m.bridge.enable" },
|
||||
{ "default", true && !ircd::maintenance },
|
||||
};
|
||||
|
||||
decltype(ircd::m::bridge::backoff)
|
||||
|
@ -139,7 +139,7 @@ ircd::m::bridge::init()
|
|||
string_view{event.event_id},
|
||||
};
|
||||
|
||||
if(!enable)
|
||||
if(!enable || ircd::read_only)
|
||||
return true;
|
||||
|
||||
start(event, config);
|
||||
|
@ -169,7 +169,7 @@ ircd::m::bridge::handle_config(const m::event &event,
|
|||
vm::eval &eval)
|
||||
try
|
||||
{
|
||||
if(!enable)
|
||||
if(!enable || ircd::read_only)
|
||||
return;
|
||||
|
||||
const config config
|
||||
|
|
|
@ -63,6 +63,11 @@ on_load()
|
|||
|
||||
init_conf_listeners();
|
||||
init_room_listeners();
|
||||
if(listeners.empty())
|
||||
log::warning
|
||||
{
|
||||
"No listening sockets configured; can't hear anyone."
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -145,7 +150,7 @@ init_conf_listeners()
|
|||
{
|
||||
"Listener '%s' configured for %s:%s by environment",
|
||||
p.first,
|
||||
p.second["host"],
|
||||
unquote(p.second["host"]),
|
||||
p.second["port"],
|
||||
};
|
||||
}
|
||||
|
@ -167,12 +172,6 @@ init_room_listeners()
|
|||
{
|
||||
load_listener(event);
|
||||
});
|
||||
|
||||
if(listeners.empty())
|
||||
log::warning
|
||||
{
|
||||
"No listening sockets configured; can't hear anyone."
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -265,19 +264,35 @@ load_listener(const m::event &event)
|
|||
json::get<"content"_>(event)
|
||||
};
|
||||
|
||||
if(!load_listener(name, opts))
|
||||
return false;
|
||||
|
||||
log::notice
|
||||
if(ircd::slave)
|
||||
{
|
||||
"Listener '%s' configured for %s:%s by %s",
|
||||
name,
|
||||
opts["host"],
|
||||
opts["port"],
|
||||
string_view{event.event_id},
|
||||
};
|
||||
log::warning
|
||||
{
|
||||
"Listener '%s' configured for %s:%s by %s ignored in slave mode.",
|
||||
name,
|
||||
unquote(opts["host"]),
|
||||
opts["port"],
|
||||
string_view{event.event_id},
|
||||
};
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(load_listener(name, opts))
|
||||
{
|
||||
log::notice
|
||||
{
|
||||
"Listener '%s' configured for %s:%s by %s",
|
||||
name,
|
||||
unquote(opts["host"]),
|
||||
opts["port"],
|
||||
string_view{event.event_id},
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ctx::context
|
||||
|
|
Loading…
Reference in New Issue