From 4be8c25711606a3388cd26b301aafd784f4ab649 Mon Sep 17 00:00:00 2001 From: Roman Gershman Date: Thu, 12 May 2022 09:13:49 +0300 Subject: [PATCH] Configure keep-alive for server sockets. Minor fixes to docker build. Provide a workaround for #35 that should suffice for the initial release. --- helio | 2 +- src/core/expire_period.h | 10 +++---- src/facade/dragonfly_listener.cc | 44 +++++++++++++++++++++++++++++ src/facade/dragonfly_listener.h | 6 ++-- src/server/db_slice.cc | 3 +- tools/docker/Dockerfile.ubuntu-prod | 9 ++++-- 6 files changed, 63 insertions(+), 11 deletions(-) diff --git a/helio b/helio index 3b83acc..0420a22 160000 --- a/helio +++ b/helio @@ -1 +1 @@ -Subproject commit 3b83acc66bf7bc2308435039b0aba565626d933a +Subproject commit 0420a22a085f09b01ff9a0849f70779492988039 diff --git a/src/core/expire_period.h b/src/core/expire_period.h index 61f3f6f..023b568 100644 --- a/src/core/expire_period.h +++ b/src/core/expire_period.h @@ -13,7 +13,7 @@ class ExpirePeriod { static constexpr size_t kMaxGenId = 15; ExpirePeriod() : val_(0), gen_(0), precision_(0) { - static_assert(sizeof(ExpirePeriod) == 4); + static_assert(sizeof(ExpirePeriod) == 8); // TODO } explicit ExpirePeriod(uint64_t ms, unsigned gen = 0) : ExpirePeriod() { @@ -38,13 +38,13 @@ class ExpirePeriod { bool is_second_precision() { return precision_ == 1;} private: - uint32_t val_ : 27; - uint32_t gen_ : 4; - uint32_t precision_ : 1; // 0 - ms, 1 - sec. + uint64_t val_ : 59; + uint64_t gen_ : 4; + uint64_t precision_ : 1; // 0 - ms, 1 - sec. }; inline void ExpirePeriod::Set(uint64_t ms) { - constexpr uint64_t kBarrier = (1ULL << 27); + constexpr uint64_t kBarrier = (1ULL << 48); if (ms < kBarrier) { val_ = ms; diff --git a/src/facade/dragonfly_listener.cc b/src/facade/dragonfly_listener.cc index 887a362..f93d1ad 100644 --- a/src/facade/dragonfly_listener.cc +++ b/src/facade/dragonfly_listener.cc @@ -42,6 +42,7 @@ namespace facade { using namespace util; using namespace std; +namespace { // To connect: openssl s_client -cipher "ADH:@SECLEVEL=0" -state -crlf -connect 127.0.0.1:6380 static SSL_CTX* CreateSslCntx() { SSL_CTX* ctx = SSL_CTX_new(TLS_server_method()); @@ -86,6 +87,35 @@ static SSL_CTX* CreateSslCntx() { return ctx; } +bool ConfigureKeepAlive(int fd, unsigned interval_sec) { + DCHECK_GT(interval_sec, 3u); + + int val = 1; + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) < 0) + return false; + + val = interval_sec; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) + return false; + + /* Send next probes after the specified interval. Note that we set the + * delay as interval / 3, as we send three probes before detecting + * an error (see the next setsockopt call). */ + val = interval_sec / 3; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) + return false; + + /* Consider the socket in error state after three we send three ACK + * probes without getting a reply. */ + val = 3; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) + return false; + + return true; +} + +} // namespace + Listener::Listener(Protocol protocol, ServiceInterface* e) : service_(e), protocol_(protocol) { if (FLAGS_tls) { OPENSSL_init_ssl(OPENSSL_INIT_SSL_DEFAULT, NULL); @@ -104,6 +134,20 @@ util::Connection* Listener::NewConnection(ProactorBase* proactor) { return new Connection{protocol_, http_base_.get(), ctx_, service_}; } +error_code Listener::ConfigureServerSocket(int fd) { + int val = 1; + constexpr int kInterval = 300; // 300 seconds is ok to start checking for liveness. + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { + LOG(WARNING) << "Could not set reuse addr on socket " << detail::SafeErrorMessage(errno); + } + bool success = ConfigureKeepAlive(fd, kInterval); + + LOG_IF(WARNING, !success) << "Could not configure keep alive " << detail::SafeErrorMessage(errno); + + return error_code{}; +} + void Listener::PreShutdown() { } diff --git a/src/facade/dragonfly_listener.h b/src/facade/dragonfly_listener.h index 0622549..2b652d2 100644 --- a/src/facade/dragonfly_listener.h +++ b/src/facade/dragonfly_listener.h @@ -19,13 +19,15 @@ class Listener : public util::ListenerInterface { Listener(Protocol protocol, ServiceInterface*); ~Listener(); + std::error_code ConfigureServerSocket(int fd) final; + private: util::Connection* NewConnection(util::ProactorBase* proactor) final; util::ProactorBase* PickConnectionProactor(util::LinuxSocketBase* sock) final; - void PreShutdown(); + void PreShutdown() final; - void PostShutdown(); + void PostShutdown() final; std::unique_ptr http_base_; diff --git a/src/server/db_slice.cc b/src/server/db_slice.cc index f2ae7e3..48b03ba 100644 --- a/src/server/db_slice.cc +++ b/src/server/db_slice.cc @@ -32,7 +32,8 @@ constexpr auto kExpireSegmentSize = ExpireTable::kSegBytes; static_assert(kPrimeSegmentSize == 32720); // 20480 is the next goodsize so we are loosing ~300 bytes or 1.5%. -static_assert(kExpireSegmentSize == 20168); +// 24576 +static_assert(kExpireSegmentSize == 23528); class PrimeEvictionPolicy { public: diff --git a/tools/docker/Dockerfile.ubuntu-prod b/tools/docker/Dockerfile.ubuntu-prod index 7d3425f..ec7c85b 100644 --- a/tools/docker/Dockerfile.ubuntu-prod +++ b/tools/docker/Dockerfile.ubuntu-prod @@ -20,12 +20,15 @@ RUN curl -O https://raw.githubusercontent.com/ncopa/su-exec/master/su-exec.c && # Now prod image FROM ubuntu:20.04 +# ARG in fact change the env vars during the build process +# ENV persist the env vars for the built image as well. ARG QEMU_CPU ARG ORG_NAME=dragonflydb +ARG DEBIAN_FRONTEND=noninteractive LABEL org.opencontainers.image.title Dragonfly LABEL org.opencontainers.image.source https://github.com/${ORG_NAME}/dragonfly -ENV DEBIAN_FRONTEND=noninteractive + RUN groupadd -r -g 999 dfly && useradd -r -g dfly -u 999 dfly RUN apt update && apt install -y libunwind8 libssl1.1 && \ @@ -40,5 +43,7 @@ COPY --from=builder /build/build-opt/su-exec /usr/local/bin/ ENTRYPOINT ["entrypoint.sh"] -EXPOSE 6380 +# For inter-container communication. +EXPOSE 6379 + CMD ["dragonfly", "--logtostderr"] \ No newline at end of file