Google format

This commit is contained in:
Ian Gulliver
2019-05-18 12:18:26 -07:00
parent 07c5e5661d
commit 83dfa81138
11 changed files with 397 additions and 250 deletions

151
.clang-format Normal file
View File

@@ -0,0 +1,151 @@
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: true
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
CanonicalDelimiter: ''
BasedOnStyle: google
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseTab: Never
...

View File

@@ -1,57 +1,57 @@
#include <atomic>
#include <gflags/gflags.h> #include <gflags/gflags.h>
#include <glog/logging.h> #include <glog/logging.h>
#include <sys/time.h> #include <sys/time.h>
#include <atomic>
#include <thread> #include <thread>
#include "server.h" #include "server.h"
DEFINE_int32(port, 9000, "TCP port to bind"); DEFINE_int32(port, 9000, "TCP port to bind");
int main(int argc, char *argv[]) { int main(int argc, char* argv[]) {
google::InitGoogleLogging(argv[0]); google::InitGoogleLogging(argv[0]);
gflags::ParseCommandLineFlags(&argc, &argv, true); gflags::ParseCommandLineFlags(&argc, &argv, true);
std::mutex mu; std::mutex mu;
std::unordered_set<firesse::Stream*> streams; std::unordered_set<firesse::Stream*> streams;
std::atomic<bool> running = true; std::atomic<bool> running = true;
std::thread clock([&streams, &mu, &running]() { std::thread clock([&streams, &mu, &running]() {
while (running) { while (running) {
sleep(1); sleep(1);
timeval tv; timeval tv;
PCHECK(gettimeofday(&tv, nullptr) == 0); PCHECK(gettimeofday(&tv, nullptr) == 0);
const uint64_t time_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000; const uint64_t time_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
const auto time_str = std::to_string(time_ms); const auto time_str = std::to_string(time_ms);
{ {
std::lock_guard l(mu); std::lock_guard l(mu);
for (auto* stream : streams) { for (auto* stream : streams) {
stream->WriteEvent(time_str, 0, "time"); stream->WriteEvent(time_str, 0, "time");
} }
} }
} }
}); });
firesse::Server server(FLAGS_port, [&streams, &mu](firesse::Stream* stream) { firesse::Server server(FLAGS_port, [&streams, &mu](firesse::Stream* stream) {
LOG(INFO) << "new stream: " << stream; LOG(INFO) << "new stream: " << stream;
std::lock_guard l(mu); std::lock_guard l(mu);
streams.insert(stream); streams.insert(stream);
stream->OnClose([stream, &streams, &mu]() { stream->OnClose([stream, &streams, &mu]() {
LOG(INFO) << "stream closed: " << stream; LOG(INFO) << "stream closed: " << stream;
std::lock_guard l(mu); std::lock_guard l(mu);
streams.erase(stream); streams.erase(stream);
}); });
}); });
server.RegisterSignalHandlers(); server.RegisterSignalHandlers();
server.Serve(); server.Serve();
running = false; running = false;
clock.join(); clock.join();
gflags::ShutDownCommandLineFlags(); gflags::ShutDownCommandLineFlags();
google::ShutdownGoogleLogging(); google::ShutdownGoogleLogging();
} }

Submodule firecgi updated: a39ef8e25d...f9988beb88

142
index.cc
View File

@@ -3,92 +3,94 @@
namespace firesse { namespace firesse {
void Index::Add(Stream* stream) { void Index::Add(Stream* stream) {
std::lock_guard l(mu_); std::lock_guard l(mu_);
stream->last_message_time_ = std::chrono::steady_clock::now(); stream->last_message_time_ = std::chrono::steady_clock::now();
stream->fresher_ = nullptr; stream->fresher_ = nullptr;
stream->staler_ = freshest_; stream->staler_ = freshest_;
if (stream->staler_) { if (stream->staler_) {
stream->staler_->fresher_ = stream; stream->staler_->fresher_ = stream;
} }
freshest_ = stream; freshest_ = stream;
if (!stalest_) { if (!stalest_) {
stalest_ = stream; stalest_ = stream;
} }
} }
void Index::Remove(Stream* stream) { void Index::Remove(Stream* stream) {
std::lock_guard l(mu_); std::lock_guard l(mu_);
if (freshest_ == stream) { if (freshest_ == stream) {
freshest_ = stream->staler_; freshest_ = stream->staler_;
} }
if (stalest_ == stream) { if (stalest_ == stream) {
stalest_ = stream->fresher_; stalest_ = stream->fresher_;
} }
if (stream->fresher_) { if (stream->fresher_) {
stream->fresher_->staler_ = stream->staler_; stream->fresher_->staler_ = stream->staler_;
stream->fresher_ = nullptr; stream->fresher_ = nullptr;
} }
if (stream->staler_) { if (stream->staler_) {
stream->staler_->fresher_ = stream->fresher_; stream->staler_->fresher_ = stream->fresher_;
stream->staler_ = nullptr; stream->staler_ = nullptr;
} }
} }
void Index::Freshen(Stream* stream) { void Index::Freshen(Stream* stream) {
std::lock_guard l(mu_); std::lock_guard l(mu_);
if (freshest_ == stream) { if (freshest_ == stream) {
// Shortcut // Shortcut
stream->last_message_time_ = std::chrono::steady_clock::now(); stream->last_message_time_ = std::chrono::steady_clock::now();
return; return;
} }
Remove(stream); Remove(stream);
Add(stream); Add(stream);
} }
std::chrono::nanoseconds Index::WithStalest(std::function<void(Stream*)> callback, const std::chrono::nanoseconds& min_stale) { std::chrono::nanoseconds Index::WithStalest(
Stream* stalest = nullptr; std::function<void(Stream*)> callback,
std::chrono::nanoseconds ret; const std::chrono::nanoseconds& min_stale) {
const auto now = std::chrono::steady_clock::now(); Stream* stalest = nullptr;
const auto latest = now - min_stale; std::chrono::nanoseconds ret;
const auto now = std::chrono::steady_clock::now();
const auto latest = now - min_stale;
{ {
std::lock_guard l(mu_); std::lock_guard l(mu_);
if (!stalest_) { if (!stalest_) {
return min_stale; return min_stale;
} }
if (stalest_->last_message_time_ > latest) { if (stalest_->last_message_time_ > latest) {
return stalest_->last_message_time_ - latest; return stalest_->last_message_time_ - latest;
} }
// stalest_ is valid for callback // stalest_ is valid for callback
stalest = stalest_; stalest = stalest_;
if (stalest->fresher_) { if (stalest->fresher_) {
if (stalest->fresher_->last_message_time_ > latest) { if (stalest->fresher_->last_message_time_ > latest) {
ret = stalest_->fresher_->last_message_time_ - latest; ret = stalest_->fresher_->last_message_time_ - latest;
} }
// Otherwise ret is 0 for immediate cycle // Otherwise ret is 0 for immediate cycle
} else { } else {
ret = min_stale; ret = min_stale;
} }
if (!stalest->mu_.try_lock()) { if (!stalest->mu_.try_lock()) {
// We're acquiring mutexes in the wrong order here; normally it's // We're acquiring mutexes in the wrong order here; normally it's
// (Stream, Index), but we're doing (Index, Stream). That means we // (Stream, Index), but we're doing (Index, Stream). That means we
// may deadlock. We take the lower-priority path and fail in case // may deadlock. We take the lower-priority path and fail in case
// of deadlock. // of deadlock.
return {}; return {};
} }
Freshen(stalest); Freshen(stalest);
} }
callback(stalest); callback(stalest);
stalest->mu_.unlock(); stalest->mu_.unlock();
return ret; return ret;
} }
} // namespace firesse } // namespace firesse

28
index.h
View File

@@ -11,20 +11,22 @@ namespace firesse {
// Avoids allocation and folds in iterators by using an intrusive list // Avoids allocation and folds in iterators by using an intrusive list
// inside Stream. // inside Stream.
class Index { class Index {
public: public:
void Add(Stream* stream); void Add(Stream* stream);
void Remove(Stream* stream); void Remove(Stream* stream);
void Freshen(Stream* stream); void Freshen(Stream* stream);
// Returns time to sleep until next stalest, or min_stale if none // Returns time to sleep until next stalest, or min_stale if none
// Only calls callback if stalest is at least min_stale // Only calls callback if stalest is at least min_stale
// Handles all locking and marks Stream as fresh after callback // Handles all locking and marks Stream as fresh after callback
std::chrono::nanoseconds WithStalest(std::function<void(Stream*)> callback, const std::chrono::nanoseconds& min_stale); std::chrono::nanoseconds WithStalest(
std::function<void(Stream*)> callback,
const std::chrono::nanoseconds& min_stale);
private: private:
std::recursive_mutex mu_; std::recursive_mutex mu_;
Stream* freshest_ = nullptr; Stream* freshest_ = nullptr;
Stream* stalest_ = nullptr; Stream* stalest_ = nullptr;
}; };
} // namespace firesse } // namespace firesse

View File

@@ -6,42 +6,38 @@
namespace firesse { namespace firesse {
KeepAlive::KeepAlive(const std::chrono::nanoseconds& max_stale, Index* index) KeepAlive::KeepAlive(const std::chrono::nanoseconds& max_stale, Index* index)
: max_stale_(max_stale), : max_stale_(max_stale), index_(index), shutdown_fd_(eventfd(0, 0)) {
index_(index), PCHECK(shutdown_fd_ >= 0) << "eventfd()";
shutdown_fd_(eventfd(0, 0)) {
PCHECK(shutdown_fd_ >= 0) << "eventfd()";
} }
KeepAlive::~KeepAlive() { KeepAlive::~KeepAlive() { PCHECK(close(shutdown_fd_) == 0); }
PCHECK(close(shutdown_fd_) == 0);
}
void KeepAlive::Start() { void KeepAlive::Start() {
thread_ = std::thread([this]() { thread_ = std::thread([this]() {
int timeout = 0; int timeout = 0;
constexpr auto num_fds = 1; constexpr auto num_fds = 1;
pollfd fds[num_fds] = { pollfd fds[num_fds] = {
{ {
.fd = shutdown_fd_, .fd = shutdown_fd_,
.events = POLLIN, .events = POLLIN,
}, },
}; };
while (running_ && (timeout == 0 || poll(fds, num_fds, timeout) <= 0)) { while (running_ && (timeout == 0 || poll(fds, num_fds, timeout) <= 0)) {
auto sleep = index_->WithStalest([](Stream* stream) { auto sleep = index_->WithStalest(
stream->WriteRaw(":\n"); [](Stream* stream) { stream->WriteRaw(":\n"); }, max_stale_);
}, max_stale_); timeout =
timeout = std::chrono::duration_cast<std::chrono::milliseconds>(sleep).count(); std::chrono::duration_cast<std::chrono::milliseconds>(sleep).count();
} }
}); });
} }
void KeepAlive::Stop() { void KeepAlive::Stop() {
CHECK(thread_.joinable()); CHECK(thread_.joinable());
running_ = false; running_ = false;
uint64_t shutdown = 1; uint64_t shutdown = 1;
PCHECK(write(shutdown_fd_, &shutdown, sizeof(shutdown)) == sizeof(shutdown)); PCHECK(write(shutdown_fd_, &shutdown, sizeof(shutdown)) == sizeof(shutdown));
thread_.join(); thread_.join();
} }
} // namespace firesse } // namespace firesse

View File

@@ -8,23 +8,23 @@
namespace firesse { namespace firesse {
class KeepAlive { class KeepAlive {
public: public:
KeepAlive(const std::chrono::nanoseconds& max_stale, Index* index); KeepAlive(const std::chrono::nanoseconds& max_stale, Index* index);
~KeepAlive(); ~KeepAlive();
void Start(); void Start();
void Stop(); void Stop();
private: private:
const std::chrono::nanoseconds max_stale_; const std::chrono::nanoseconds max_stale_;
Index* index_; Index* index_;
// Two shutdown mechanisms, one for if we're in a tight no-syscall loop, // Two shutdown mechanisms, one for if we're in a tight no-syscall loop,
// and one for if we're sleeping in poll() // and one for if we're sleeping in poll()
int shutdown_fd_; int shutdown_fd_;
std::atomic<bool> running_ = true; std::atomic<bool> running_ = true;
std::thread thread_; std::thread thread_;
}; };
} // namespace firesse } // namespace firesse

View File

@@ -3,41 +3,38 @@
namespace firesse { namespace firesse {
Server::Server(int port, const std::function<void(Stream*)>& callback) Server::Server(int port, const std::function<void(Stream*)>& callback)
: callback_(callback), : callback_(callback),
keep_alive_(std::chrono::seconds(15), &index_), keep_alive_(std::chrono::seconds(15), &index_),
firecgi_server_(port, firecgi_server_(
[this](firecgi::Request* request) { OnRequest(request); }, port, [this](firecgi::Request* request) { OnRequest(request); }, 1) {}
1) {}
void Server::Serve() { void Server::Serve() {
keep_alive_.Start(); keep_alive_.Start();
firecgi_server_.Serve(); firecgi_server_.Serve();
keep_alive_.Stop(); keep_alive_.Stop();
} }
void Server::Shutdown() { void Server::Shutdown() { firecgi_server_.Shutdown(); }
firecgi_server_.Shutdown();
}
void Server::RegisterSignalHandlers() { void Server::RegisterSignalHandlers() {
firecgi_server_.RegisterSignalHandlers(); firecgi_server_.RegisterSignalHandlers();
} }
void Server::OnRequest(firecgi::Request* request) { void Server::OnRequest(firecgi::Request* request) {
request->WriteHeader("Content-Type", "text/event-stream; charset=utf-8"); request->WriteHeader("Content-Type", "text/event-stream; charset=utf-8");
request->WriteHeader("Cache-Control", "no-cache"); request->WriteHeader("Cache-Control", "no-cache");
request->WriteHeader("X-Accel-Buffering", "no"); request->WriteHeader("X-Accel-Buffering", "no");
request->WriteBody(""); request->WriteBody("");
auto stream = new Stream(request, &index_); auto stream = new Stream(request, &index_);
{ {
request->OnClose([stream]() { request->OnClose([stream]() {
stream->Close(); stream->Close();
delete stream; delete stream;
}); });
} }
callback_(stream); callback_(stream);
} }
} // namespace firesse } // namespace firesse

View File

@@ -11,19 +11,19 @@
namespace firesse { namespace firesse {
class Server { class Server {
public: public:
Server(int port, const std::function<void(Stream*)>& callback); Server(int port, const std::function<void(Stream*)>& callback);
void Serve(); void Serve();
void Shutdown(); void Shutdown();
void RegisterSignalHandlers(); void RegisterSignalHandlers();
private: private:
void OnRequest(firecgi::Request* request); void OnRequest(firecgi::Request* request);
std::function<void(Stream*)> callback_; std::function<void(Stream*)> callback_;
Index index_; Index index_;
KeepAlive keep_alive_; KeepAlive keep_alive_;
firecgi::Server firecgi_server_; firecgi::Server firecgi_server_;
}; };
} // namespace firesse } // namespace firesse

View File

@@ -5,52 +5,50 @@
namespace firesse { namespace firesse {
Stream::Stream(firecgi::Request* request, Index* index) Stream::Stream(firecgi::Request* request, Index* index)
: request_(request), : request_(request), index_(index) {
index_(index) { index_->Add(this);
index_->Add(this);
} }
Stream::~Stream() { Stream::~Stream() {
std::lock_guard l(mu_); std::lock_guard l(mu_);
index_->Remove(this); index_->Remove(this);
} }
void Stream::OnClose(const std::function<void()>& callback) { void Stream::OnClose(const std::function<void()>& callback) {
on_close_ = callback; on_close_ = callback;
} }
bool Stream::WriteEvent(const std::string_view& data, uint64_t id, const std::string& type) { bool Stream::WriteEvent(const std::string_view& data, uint64_t id,
std::lock_guard l(mu_); const std::string& type) {
std::lock_guard l(mu_);
index_->Freshen(this); index_->Freshen(this);
return request_->InTransaction<bool>([=]() { return request_->InTransaction<bool>([=]() {
if (id) { if (id) {
request_->WriteBody("id: ", std::to_string(id), "\n"); request_->WriteBody("id: ", std::to_string(id), "\n");
} }
if (!type.empty()) { if (!type.empty()) {
request_->WriteBody("event: ", type, "\n"); request_->WriteBody("event: ", type, "\n");
} }
request_->WriteBody("data: ", data, "\n\n"); request_->WriteBody("data: ", data, "\n\n");
return request_->Flush(); return request_->Flush();
}); });
} }
bool Stream::WriteRaw(const std::string_view& data) { bool Stream::WriteRaw(const std::string_view& data) {
std::lock_guard l(mu_); std::lock_guard l(mu_);
request_->WriteBody(data); request_->WriteBody(data);
return request_->Flush(); return request_->Flush();
} }
bool Stream::End() { bool Stream::End() { return request_->End(); }
return request_->End();
}
void Stream::Close() { void Stream::Close() {
if (on_close_) { if (on_close_) {
on_close_(); on_close_();
} }
} }
} // namespace firesse } // namespace firesse

View File

@@ -9,30 +9,31 @@ namespace firesse {
class Index; class Index;
class Stream { class Stream {
public: public:
Stream(firecgi::Request* request, Index* index); Stream(firecgi::Request* request, Index* index);
~Stream(); ~Stream();
void OnClose(const std::function<void()>& callback); void OnClose(const std::function<void()>& callback);
bool WriteEvent(const std::string_view& data, uint64_t id=0, const std::string& type=""); bool WriteEvent(const std::string_view& data, uint64_t id = 0,
bool WriteRaw(const std::string_view& data); const std::string& type = "");
bool End(); bool WriteRaw(const std::string_view& data);
void Close(); bool End();
void Close();
private: private:
firecgi::Request* request_; firecgi::Request* request_;
Index* index_; Index* index_;
std::function<void()> on_close_; std::function<void()> on_close_;
// TODO: What exactly is this protecting? // TODO: What exactly is this protecting?
std::recursive_mutex mu_; std::recursive_mutex mu_;
std::chrono::steady_clock::time_point last_message_time_; std::chrono::steady_clock::time_point last_message_time_;
Stream* fresher_; Stream* fresher_;
Stream* staler_; Stream* staler_;
friend class Index; friend class Index;
}; };
} // namespace firesse } // namespace firesse