Add dragonfly skeleton: listener, connection and main
This commit is contained in:
parent
90516b53dd
commit
2bce379341
|
@ -24,3 +24,4 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
|||
include_directories(async)
|
||||
|
||||
add_subdirectory(async)
|
||||
add_subdirectory(server)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
add_executable(dragonfly dfly_main.cc)
|
||||
cxx_link(dragonfly base dragonfly_lib)
|
||||
|
||||
add_library(dragonfly_lib dragonfly_listener.cc dragonfly_connection.cc main_service.cc)
|
||||
|
||||
cxx_link(dragonfly_lib uring_fiber_lib
|
||||
fibers_ext strings_lib http_server_lib)
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright 2021, Beeri 15. All rights reserved.
|
||||
// Author: Roman Gershman (romange@gmail.com)
|
||||
//
|
||||
|
||||
#include "base/init.h"
|
||||
#include "server/main_service.h"
|
||||
#include "server/dragonfly_listener.h"
|
||||
#include "util/accept_server.h"
|
||||
#include "util/uring/uring_pool.h"
|
||||
#include "util/varz.h"
|
||||
|
||||
DEFINE_int32(http_port, 8080, "Http port.");
|
||||
DECLARE_uint32(port);
|
||||
|
||||
using namespace util;
|
||||
|
||||
namespace dfly {
|
||||
|
||||
void RunEngine(ProactorPool* pool, AcceptServer* acceptor, HttpListener<>* http) {
|
||||
Service service(pool);
|
||||
service.Init(acceptor);
|
||||
|
||||
if (http) {
|
||||
service.RegisterHttp(http);
|
||||
}
|
||||
|
||||
acceptor->AddListener(FLAGS_port, new Listener{&service});
|
||||
acceptor->Run();
|
||||
acceptor->Wait();
|
||||
|
||||
service.Shutdown();
|
||||
}
|
||||
|
||||
} // namespace dfly
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
MainInitGuard guard(&argc, &argv);
|
||||
|
||||
CHECK_GT(FLAGS_port, 0u);
|
||||
|
||||
uring::UringPool pp{1024};
|
||||
pp.Run();
|
||||
|
||||
AcceptServer acceptor(&pp);
|
||||
HttpListener<>* http_listener = nullptr;
|
||||
|
||||
if (FLAGS_http_port >= 0) {
|
||||
http_listener = new HttpListener<>;
|
||||
|
||||
// Ownership over http_listener is moved to the acceptor.
|
||||
uint16_t port = acceptor.AddListener(FLAGS_http_port, http_listener);
|
||||
|
||||
LOG(INFO) << "Started http service on port " << port;
|
||||
}
|
||||
|
||||
dfly::RunEngine(&pp, &acceptor, http_listener);
|
||||
|
||||
pp.Stop();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
// Copyright 2021, Beeri 15. All rights reserved.
|
||||
// Author: Roman Gershman (romange@gmail.com)
|
||||
//
|
||||
|
||||
#include "server/dragonfly_connection.h"
|
||||
|
||||
#include <boost/fiber/operations.hpp>
|
||||
|
||||
#include "base/io_buf.h"
|
||||
#include "base/logging.h"
|
||||
#include "server/main_service.h"
|
||||
#include "util/fiber_sched_algo.h"
|
||||
|
||||
using namespace util;
|
||||
using namespace std;
|
||||
namespace this_fiber = boost::this_fiber;
|
||||
namespace fibers = boost::fibers;
|
||||
|
||||
namespace dfly {
|
||||
namespace {
|
||||
|
||||
|
||||
|
||||
constexpr size_t kMinReadSize = 256;
|
||||
|
||||
} // namespace
|
||||
|
||||
struct Connection::Shutdown {
|
||||
absl::flat_hash_map<ShutdownHandle, ShutdownCb> map;
|
||||
ShutdownHandle next_handle = 1;
|
||||
|
||||
ShutdownHandle Add(ShutdownCb cb) {
|
||||
map[next_handle] = move(cb);
|
||||
return next_handle++;
|
||||
}
|
||||
|
||||
void Remove(ShutdownHandle sh) {
|
||||
map.erase(sh);
|
||||
}
|
||||
};
|
||||
|
||||
Connection::Connection(Service* service)
|
||||
: service_(service) {
|
||||
}
|
||||
|
||||
Connection::~Connection() {
|
||||
}
|
||||
|
||||
void Connection::OnShutdown() {
|
||||
VLOG(1) << "Connection::OnShutdown";
|
||||
if (shutdown_) {
|
||||
for (const auto& k_v : shutdown_->map) {
|
||||
k_v.second();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Connection::RegisterShutdownHook(ShutdownCb cb) -> ShutdownHandle {
|
||||
if (!shutdown_) {
|
||||
shutdown_ = make_unique<Shutdown>();
|
||||
}
|
||||
return shutdown_->Add(std::move(cb));
|
||||
}
|
||||
|
||||
void Connection::UnregisterShutdownHook(ShutdownHandle id) {
|
||||
if (shutdown_) {
|
||||
shutdown_->Remove(id);
|
||||
if (shutdown_->map.empty())
|
||||
shutdown_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void Connection::HandleRequests() {
|
||||
this_fiber::properties<FiberProps>().set_name("DflyConnection");
|
||||
|
||||
int val = 1;
|
||||
CHECK_EQ(0, setsockopt(socket_->native_handle(), SOL_TCP, TCP_NODELAY, &val, sizeof(val)));
|
||||
|
||||
FiberSocketBase* peer = socket_.get();
|
||||
InputLoop(peer);
|
||||
|
||||
VLOG(1) << "Closed connection for peer " << socket_->RemoteEndpoint();
|
||||
}
|
||||
|
||||
void Connection::InputLoop(FiberSocketBase* peer) {
|
||||
base::IoBuf io_buf{kMinReadSize};
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
do {
|
||||
auto buf = io_buf.AppendBuffer();
|
||||
::io::Result<size_t> recv_sz = peer->Recv(buf);
|
||||
|
||||
if (!recv_sz) {
|
||||
ec = recv_sz.error();
|
||||
break;
|
||||
}
|
||||
|
||||
io_buf.CommitWrite(*recv_sz);
|
||||
ec = peer->Write(io_buf.InputBuffer());
|
||||
if (ec)
|
||||
break;
|
||||
} while (peer->IsOpen());
|
||||
|
||||
if (ec && !FiberSocketBase::IsConnClosed(ec)) {
|
||||
LOG(WARNING) << "Socket error " << ec;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dfly
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2021, Beeri 15. All rights reserved.
|
||||
// Author: Roman Gershman (romange@gmail.com)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/connection.h"
|
||||
|
||||
namespace dfly {
|
||||
|
||||
class Service;
|
||||
|
||||
class Connection : public util::Connection {
|
||||
public:
|
||||
Connection(Service* service);
|
||||
~Connection();
|
||||
|
||||
using error_code = std::error_code;
|
||||
using ShutdownCb = std::function<void()>;
|
||||
using ShutdownHandle = unsigned;
|
||||
|
||||
ShutdownHandle RegisterShutdownHook(ShutdownCb cb);
|
||||
void UnregisterShutdownHook(ShutdownHandle id);
|
||||
|
||||
protected:
|
||||
void OnShutdown() override;
|
||||
|
||||
private:
|
||||
void HandleRequests() final;
|
||||
|
||||
void InputLoop(util::FiberSocketBase* peer);
|
||||
void DispatchFiber(util::FiberSocketBase* peer);
|
||||
|
||||
Service* service_;
|
||||
|
||||
struct Shutdown;
|
||||
std::unique_ptr<Shutdown> shutdown_;
|
||||
};
|
||||
|
||||
} // namespace dfly
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2021, Beeri 15. All rights reserved.
|
||||
// Author: Roman Gershman (romange@gmail.com)
|
||||
//
|
||||
|
||||
#include "server/dragonfly_listener.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "server/dragonfly_connection.h"
|
||||
#include "util/proactor_pool.h"
|
||||
|
||||
using namespace util;
|
||||
|
||||
DEFINE_uint32(conn_threads, 0, "Number of threads used for handing server connections");
|
||||
|
||||
|
||||
namespace dfly {
|
||||
|
||||
Listener::Listener(Service* e) : engine_(e) {
|
||||
}
|
||||
|
||||
Listener::~Listener() {
|
||||
}
|
||||
|
||||
util::Connection* Listener::NewConnection(ProactorBase* proactor) {
|
||||
return new Connection{engine_};
|
||||
}
|
||||
|
||||
void Listener::PreShutdown() {
|
||||
}
|
||||
|
||||
void Listener::PostShutdown() {
|
||||
}
|
||||
|
||||
// We can limit number of threads handling dragonfly connections.
|
||||
ProactorBase* Listener::PickConnectionProactor(LinuxSocketBase* sock) {
|
||||
uint32_t id = next_id_.fetch_add(1, std::memory_order_relaxed);
|
||||
uint32_t total = FLAGS_conn_threads;
|
||||
util::ProactorPool* pp = pool();
|
||||
|
||||
if (total == 0 || total > pp->size()) {
|
||||
total = pp->size();
|
||||
}
|
||||
|
||||
return pp->at(id % total);
|
||||
}
|
||||
|
||||
} // namespace dfly
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2021, Beeri 15. All rights reserved.
|
||||
// Author: Roman Gershman (romange@gmail.com)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/listener_interface.h"
|
||||
|
||||
namespace dfly {
|
||||
|
||||
class Service;
|
||||
|
||||
class Listener : public util::ListenerInterface {
|
||||
public:
|
||||
Listener(Service*);
|
||||
~Listener();
|
||||
|
||||
private:
|
||||
util::Connection* NewConnection(util::ProactorBase* proactor) final;
|
||||
util::ProactorBase* PickConnectionProactor(util::LinuxSocketBase* sock) final;
|
||||
|
||||
void PreShutdown();
|
||||
|
||||
void PostShutdown();
|
||||
|
||||
Service* engine_;
|
||||
|
||||
std::atomic_uint32_t next_id_{0};
|
||||
};
|
||||
|
||||
} // namespace dfly
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright 2021, Beeri 15. All rights reserved.
|
||||
// Author: Roman Gershman (romange@gmail.com)
|
||||
//
|
||||
|
||||
#include "server/main_service.h"
|
||||
|
||||
#include <boost/fiber/operations.hpp>
|
||||
#include <filesystem>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "util/uring/uring_fiber_algo.h"
|
||||
#include "util/varz.h"
|
||||
|
||||
DEFINE_uint32(port, 6380, "Redis port");
|
||||
|
||||
|
||||
namespace dfly {
|
||||
|
||||
using namespace std;
|
||||
using namespace util;
|
||||
using base::VarzValue;
|
||||
|
||||
namespace fibers = ::boost::fibers;
|
||||
namespace this_fiber = ::boost::this_fiber;
|
||||
|
||||
namespace {
|
||||
|
||||
DEFINE_VARZ(VarzMapAverage, request_latency_usec);
|
||||
|
||||
std::optional<VarzFunction> engine_varz;
|
||||
|
||||
} // namespace
|
||||
|
||||
Service::Service(ProactorPool* pp)
|
||||
: pp_(*pp) {
|
||||
CHECK(pp);
|
||||
engine_varz.emplace("engine", [this] { return GetVarzStats(); });
|
||||
}
|
||||
|
||||
Service::~Service() {
|
||||
engine_varz.reset();
|
||||
}
|
||||
|
||||
void Service::Init(util::AcceptServer* acceptor) {
|
||||
request_latency_usec.Init(&pp_);
|
||||
}
|
||||
|
||||
void Service::Shutdown() {
|
||||
request_latency_usec.Shutdown();
|
||||
}
|
||||
|
||||
void Service::RegisterHttp(HttpListenerBase* listener) {
|
||||
CHECK_NOTNULL(listener);
|
||||
}
|
||||
|
||||
VarzValue::Map Service::GetVarzStats() {
|
||||
VarzValue::Map res;
|
||||
|
||||
res.emplace_back("keys", VarzValue::FromInt(0));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace dfly
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2021, Beeri 15. All rights reserved.
|
||||
// Author: Roman Gershman (romange@gmail.com)
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/varz_value.h"
|
||||
#include "util/http/http_handler.h"
|
||||
|
||||
namespace util {
|
||||
class AcceptServer;
|
||||
} // namespace util
|
||||
|
||||
namespace dfly {
|
||||
|
||||
class Service {
|
||||
public:
|
||||
using error_code = std::error_code;
|
||||
|
||||
explicit Service(util::ProactorPool* pp);
|
||||
~Service();
|
||||
|
||||
void RegisterHttp(util::HttpListenerBase* listener);
|
||||
|
||||
void Init(util::AcceptServer* acceptor);
|
||||
|
||||
void Shutdown();
|
||||
|
||||
util::ProactorPool& proactor_pool() {
|
||||
return pp_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
base::VarzValue::Map GetVarzStats();
|
||||
|
||||
util::ProactorPool& pp_;
|
||||
};
|
||||
|
||||
} // namespace dfly
|
Loading…
Reference in New Issue