mirror of
https://github.com/XTXMarkets/ternfs.git
synced 2026-05-05 11:51:08 -05:00
8075e99bb6
See <https://mazzo.li/posts/stopping-linux-threads.html> for tradeoffs regarding how to terminate threads gracefully. The goal of this work was for valgrind to work correctly, which in turn was to investigate #141. It looks like I have succeeded: ==2715080== Warning: unimplemented fcntl command: 1036 ==2715080== 20,052 bytes in 5,013 blocks are definitely lost in loss record 133 of 135 ==2715080== at 0x483F013: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==2715080== by 0x3B708E: allocate (new_allocator.h:121) ==2715080== by 0x3B708E: allocate (allocator.h:173) ==2715080== by 0x3B708E: allocate (alloc_traits.h:460) ==2715080== by 0x3B708E: _M_allocate (stl_vector.h:346) ==2715080== by 0x3B708E: std::vector<Crc, std::allocator<Crc> >::_M_default_append(unsigned long) (vector.tcc:635) ==2715080== by 0x42BF1C: resize (stl_vector.h:940) ==2715080== by 0x42BF1C: ShardDBImpl::_fileSpans(rocksdb::ReadOptions&, FileSpansReq const&, FileSpansResp&) (shard/ShardDB.cpp:921) ==2715080== by 0x420867: ShardDBImpl::read(ShardReqContainer const&, ShardRespContainer&) (shard/ShardDB.cpp:1034) ==2715080== by 0x3CB3EE: ShardServer::_handleRequest(int, sockaddr_in*, char*, unsigned long) (shard/Shard.cpp:347) ==2715080== by 0x3C8A39: ShardServer::step() (shard/Shard.cpp:405) ==2715080== by 0x40B1E8: run (core/Loop.cpp:67) ==2715080== by 0x40B1E8: startLoop(void*) (core/Loop.cpp:37) ==2715080== by 0x4BEA258: start_thread (in /usr/lib/libpthread-2.33.so) ==2715080== by 0x4D005E2: clone (in /usr/lib/libc-2.33.so) ==2715080== ==2715080== ==2715080== Exit program on first error (--exit-on-first-error=yes)
152 lines
4.1 KiB
C++
152 lines
4.1 KiB
C++
#pragma once
|
|
|
|
#include <atomic>
|
|
#include <queue>
|
|
#include <mutex>
|
|
#include <unordered_map>
|
|
#include <semaphore>
|
|
#include <memory>
|
|
#include <unordered_set>
|
|
#include <poll.h>
|
|
|
|
#include "Common.hpp"
|
|
#include "Env.hpp"
|
|
#include "XmonAgent.hpp"
|
|
#include "Loop.hpp"
|
|
#include "Stopper.hpp"
|
|
|
|
struct XmonConfig {
|
|
bool prod = false;
|
|
std::string appInstance = "";
|
|
std::string appType = "restech_eggsfs.never";
|
|
};
|
|
|
|
struct XmonBuf {
|
|
size_t cur = 0;
|
|
size_t len = 0;
|
|
char buf[4096];
|
|
|
|
void reset() {
|
|
cur = 0;
|
|
len = 0;
|
|
}
|
|
|
|
void ensurePackSizeOrPanic(size_t sz) const {
|
|
ALWAYS_ASSERT((sizeof(buf) - len) >= sz);
|
|
}
|
|
|
|
template<typename A>
|
|
void packScalar(A x) {
|
|
static_assert(std::is_integral_v<A> || std::is_enum_v<A>);
|
|
static_assert(std::endian::native == std::endian::little);
|
|
ensurePackSizeOrPanic(sizeof(A));
|
|
if constexpr (sizeof(A) == 8) {
|
|
x = (A)__builtin_bswap64((uint64_t)x);
|
|
} else if constexpr (sizeof(A) == 4) {
|
|
x = (A)__builtin_bswap32((uint32_t)x);
|
|
} else if constexpr (sizeof(A) == 2) {
|
|
x = (A)__builtin_bswap16((uint16_t)x);
|
|
} else {
|
|
static_assert(sizeof(A) == 1);
|
|
}
|
|
memcpy(buf+len, &x, sizeof(x));
|
|
len += sizeof(A);
|
|
}
|
|
|
|
void packString(const std::string& str) {
|
|
ALWAYS_ASSERT(str.size() < (1ull<<16)-1);
|
|
packScalar<uint16_t>(str.size());
|
|
ensurePackSizeOrPanic(str.size());
|
|
memcpy(buf+len, str.data(), str.size());
|
|
len += str.size();
|
|
}
|
|
|
|
void ensureUnpackSizeOrPanic(size_t sz) const {
|
|
ALWAYS_ASSERT((sizeof(buf) - cur) >= sz);
|
|
}
|
|
|
|
template<typename A>
|
|
A unpackScalar() {
|
|
static_assert(std::is_integral_v<A> || std::is_enum_v<A>);
|
|
static_assert(std::endian::native == std::endian::little);
|
|
ensureUnpackSizeOrPanic(sizeof(A));
|
|
A x;
|
|
memcpy(&x, buf+cur, sizeof(x));
|
|
if constexpr (sizeof(A) == 8) {
|
|
x = (A)__builtin_bswap64((uint64_t)x);
|
|
} else if constexpr (sizeof(A) == 4) {
|
|
x = (A)__builtin_bswap32((uint32_t)x);
|
|
} else if constexpr (sizeof(A) == 2) {
|
|
x = (A)__builtin_bswap16((uint16_t)x);
|
|
} else {
|
|
static_assert(sizeof(A) == 1);
|
|
}
|
|
cur += sizeof(x);
|
|
return x;
|
|
}
|
|
|
|
std::string unpackString() {
|
|
int16_t sz = unpackScalar<int16_t>();
|
|
ensurePackSizeOrPanic(sz);
|
|
std::string s(sz, '\0');
|
|
memcpy(s.data(), buf+cur, sz);
|
|
cur += sz;
|
|
return s;
|
|
}
|
|
|
|
// returns an error string if it failed
|
|
std::string writeOut(int fd);
|
|
// if false with empty error string, we got EAGAIN immediately.
|
|
bool readIn(int fd, size_t sz, std::string& errString);
|
|
};
|
|
|
|
struct Xmon : Loop {
|
|
private:
|
|
Stopper _stopper;
|
|
std::shared_ptr<XmonAgent> _agent;
|
|
std::string _hostname;
|
|
std::string _appType;
|
|
std::string _appInstance;
|
|
std::string _xmonHost;
|
|
uint16_t _xmonPort;
|
|
|
|
// xmon socket, xmon agent pipe read end, timer fd
|
|
static constexpr int SOCK_FD = 0;
|
|
static constexpr int PIPE_FD = 1;
|
|
static constexpr int TIMER_FD = 2;
|
|
static constexpr int NUM_FDS = 3;
|
|
struct pollfd _fds[NUM_FDS];
|
|
// requests we got from the pipe
|
|
std::deque<XmonRequest> _queuedRequests;
|
|
// active binnable alerts
|
|
std::unordered_set<int64_t> _binnableAlerts;
|
|
// quiet alerts we're waiting to send out
|
|
struct QuietAlert {
|
|
EggsTime quietUntil;
|
|
std::string message;
|
|
};
|
|
std::unordered_map<int64_t, QuietAlert> _quietAlerts;
|
|
// last heartbeat from xmon
|
|
EggsTime _gotHeartbeatAt;
|
|
// what the timer fd expiration is currently set to
|
|
EggsTime _timerExpiresAt;
|
|
|
|
XmonBuf _buf;
|
|
|
|
void _packLogon(XmonBuf& buf);
|
|
void _packUpdate(XmonBuf& buf);
|
|
void _packRequest(XmonBuf& buf, const XmonRequest& req);
|
|
void _ensureTimer(EggsTime now, EggsTime t);
|
|
|
|
EggsTime _stepNextWakeup();
|
|
public:
|
|
Xmon(
|
|
Logger& logger,
|
|
std::shared_ptr<XmonAgent>& agent,
|
|
const XmonConfig& config
|
|
);
|
|
virtual ~Xmon();
|
|
|
|
virtual void step() override;
|
|
};
|