aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2022-02-07 14:13:48 +0100
committerGitHub <[email protected]>2022-02-07 14:13:48 +0100
commit2a322aba6876ab30cdaa4db829e5ad5031cc7967 (patch)
tree9afd1054e18c6d48dcda4e623da7a72cc095c0f7
parentMissing override suffix compile fix (diff)
parentAdded log output to make it clearer which lock file is in use (diff)
downloadzen-2a322aba6876ab30cdaa4db829e5ad5031cc7967.tar.xz
zen-2a322aba6876ab30cdaa4db829e5ad5031cc7967.zip
Merging minor fixes to main
-rw-r--r--zenserver-test/zenserver-test.cpp416
-rw-r--r--zenserver/zenserver.cpp2
-rw-r--r--zenutil/cache/cachepolicy.cpp32
-rw-r--r--zenutil/include/zenutil/cache/cachepolicy.h1
4 files changed, 26 insertions, 425 deletions
diff --git a/zenserver-test/zenserver-test.cpp b/zenserver-test/zenserver-test.cpp
index 425f43946..b46106287 100644
--- a/zenserver-test/zenserver-test.cpp
+++ b/zenserver-test/zenserver-test.cpp
@@ -92,398 +92,6 @@ struct Concurrency
};
#endif
-/*
-
-___ ___ _________ _________ ________ ________ ___ ___ _______ ________ _________
-|\ \|\ \|\___ ___\\___ ___\\ __ \ |\ ____\|\ \ |\ \|\ ___ \ |\ ___ \|\___ ___\
-\ \ \\\ \|___ \ \_\|___ \ \_\ \ \|\ \ \ \ \___|\ \ \ \ \ \ \ __/|\ \ \\ \ \|___ \ \_|
- \ \ __ \ \ \ \ \ \ \ \ \ ____\ \ \ \ \ \ \ \ \ \ \ \_|/_\ \ \\ \ \ \ \ \
- \ \ \ \ \ \ \ \ \ \ \ \ \ \___| \ \ \____\ \ \____\ \ \ \ \_|\ \ \ \\ \ \ \ \ \
- \ \__\ \__\ \ \__\ \ \__\ \ \__\ \ \_______\ \_______\ \__\ \_______\ \__\\ \__\ \ \__\
- \|__|\|__| \|__| \|__| \|__| \|_______|\|_______|\|__|\|_______|\|__| \|__| \|__|
-
-*/
-
-class HttpConnectionPool;
-
-/**
- * Http client connection
- *
- * Represents an established socket connection to a certain endpoint
- */
-
-class HttpClientConnection
-{
- static HttpClientConnection* This(http_parser* Parser) { return (HttpClientConnection*)Parser->data; };
-
-public:
- HttpClientConnection(asio::io_context& IoContext, zen::Ref<HttpConnectionPool> Pool, asio::ip::tcp::socket&& InSocket)
- : m_IoContext(IoContext)
- , m_Pool(Pool)
- , m_Resolver(IoContext)
- , m_Socket(std::move(InSocket))
- {
- }
- ~HttpClientConnection() {}
-
- zen::Ref<HttpConnectionPool> ConnectionPool() { return m_Pool; }
- void SetKeepAlive(bool NewState) { m_KeepAlive = NewState; }
-
- void Get(const std::string_view Server, int Port, const std::string_view Path)
- {
- ZEN_UNUSED(Port);
-
- http_parser_init(&m_HttpParser, HTTP_RESPONSE);
- m_HttpParser.data = this;
-
- m_HttpParserSettings = http_parser_settings{
- .on_message_begin = [](http_parser* p) -> int { return This(p)->OnMessageBegin(); },
- .on_url = nullptr,
- .on_status = nullptr,
- .on_header_field = [](http_parser* p, const char* data, size_t size) { return This(p)->OnHeader(data, size); },
- .on_header_value = [](http_parser* p, const char* data, size_t size) { return This(p)->OnHeaderValue(data, size); },
- .on_headers_complete = [](http_parser* p) -> int { return This(p)->OnHeadersComplete(); },
- .on_body = [](http_parser* p, const char* data, size_t size) { return This(p)->OnBody(data, size); },
- .on_message_complete = [](http_parser* p) -> int { return This(p)->OnMessageComplete(); },
- .on_chunk_header = nullptr,
- .on_chunk_complete = nullptr};
-
- m_Headers.reserve(16);
-
- zen::ExtendableStringBuilder<256> RequestBody;
- RequestBody << "GET "sv << Path << " HTTP/1.1\r\n"sv;
- RequestBody << "Host: "sv << Server << "\r\n"sv;
- RequestBody << "Accept: */*\r\n"sv;
- RequestBody << "Connection: "sv << (m_KeepAlive ? "keep-alive"sv : "close"sv) << "\r\n\r\n"sv; // TODO: support keep-alive
-
- m_RequestBody = RequestBody;
-
- OnConnected();
- }
-
-private:
- void Reset() {}
-
- void OnError(const asio::error_code& Error)
- {
- // Let EOF errors proceed. They're raised when sockets close.
- if (Error == asio::error::eof)
- {
- return;
- }
-
- zen::ThrowLastError(fmt::format("HTTP client error! '{}'", Error.message()));
- }
-
- int OnHeader(const char* Data, size_t Bytes)
- {
- m_CurrentHeaderName = std::string_view(Data, Bytes);
- return 0;
- }
- int OnHeaderValue(const char* Data, size_t Bytes)
- {
- m_Headers.emplace_back(HeaderEntry{m_CurrentHeaderName, {Data, Bytes}});
- return 0;
- }
- int OnHeadersComplete()
- {
- ZEN_DEBUG("Headers complete");
- return 0;
- }
- int OnMessageComplete()
- {
- if (http_should_keep_alive(&m_HttpParser))
- {
- Reset();
- }
- else
- {
- m_Socket.close();
- m_RequestState = RequestState::Done;
- }
- return 0;
- }
- int OnMessageBegin() { return 0; }
- int OnBody(const char* Data, size_t Bytes)
- {
- ZEN_UNUSED(Data, Bytes);
- return 0;
- }
-
- void OnConnected()
- {
- // Send initial request payload
- asio::async_write(m_Socket,
- asio::const_buffer(m_RequestBody.data(), m_RequestBody.size()),
- [this](const asio::error_code& Error, size_t Bytes) {
- ZEN_UNUSED(Bytes);
- if (Error)
- {
- return OnError(Error);
- }
-
- OnRequestWritten();
- });
- }
-
- void OnRequestWritten()
- {
- asio::async_read(m_Socket, m_ResponseBuffer, asio::transfer_at_least(1), [this](const asio::error_code& Error, size_t Bytes) {
- if (Error)
- {
- return OnError(Error);
- }
-
- OnStatusLineRead(Bytes);
- });
- }
-
- void OnStatusLineRead(size_t Bytes)
- {
- // Parse
-
- size_t rv = http_parser_execute(&m_HttpParser, &m_HttpParserSettings, (const char*)m_ResponseBuffer.data(), Bytes);
-
- ZEN_UNUSED(rv);
-
- if (m_HttpParser.http_errno != 0)
- {
- // Something bad!
-
- ZEN_ERROR("parse error {}", (uint32_t)m_HttpParser.http_errno);
- }
-
- switch (m_RequestState)
- {
- case RequestState::Init:
- asio::async_read(m_Socket,
- m_ResponseBuffer,
- asio::transfer_at_least(1),
- [this](const asio::error_code& Error, size_t Bytes) {
- if (Error)
- {
- return OnError(Error);
- }
- OnStatusLineRead(Bytes);
- });
- return;
- case RequestState::Done:
- break;
- }
- }
-
-private:
- asio::io_context& m_IoContext;
- zen::Ref<HttpConnectionPool> m_Pool;
- asio::ip::tcp::resolver m_Resolver;
- asio::ip::tcp::socket m_Socket;
- std::string m_Uri;
- std::string m_RequestBody; // Initial request data
- http_parser m_HttpParser{};
- http_parser_settings m_HttpParserSettings{};
- uint8_t m_ResponseIoBuffer[4096];
- asio::mutable_buffer m_ResponseBuffer{m_ResponseIoBuffer, sizeof m_ResponseIoBuffer};
-
- enum class RequestState
- {
- Init,
- Done
- };
-
- RequestState m_RequestState = RequestState::Init;
-
- struct HeaderEntry
- {
- std::string_view Name;
- std::string_view Value;
- };
-
- std::string_view m_CurrentHeaderName; // Used while parsing headers
- std::vector<HeaderEntry> m_Headers;
- bool m_KeepAlive = false;
-};
-
-//////////////////////////////////////////////////////////////////////////
-
-class HttpConnectionPool : public zen::RefCounted
-{
-public:
- HttpConnectionPool(asio::io_context& Context, std::string_view HostName, uint16_t Port);
- ~HttpConnectionPool();
-
- std::unique_ptr<HttpClientConnection> GetConnection();
- void ReturnConnection(std::unique_ptr<HttpClientConnection>&& Connection);
-
-private:
- zen::RwLock m_Lock;
- asio::io_context& m_Context;
- std::vector<HttpClientConnection*> m_AvailableConnections;
- std::string m_HostName;
- uint16_t m_Port;
-};
-
-HttpConnectionPool::HttpConnectionPool(asio::io_context& Context, std::string_view HostName, uint16_t Port)
-: m_Context(Context)
-, m_HostName(HostName)
-, m_Port(Port)
-{
-}
-
-HttpConnectionPool::~HttpConnectionPool()
-{
- zen::RwLock::ExclusiveLockScope ScopedLock(m_Lock);
-
- for (auto $ : m_AvailableConnections)
- {
- delete $;
- }
-}
-
-std::unique_ptr<HttpClientConnection>
-HttpConnectionPool::GetConnection()
-{
- zen::RwLock::ExclusiveLockScope ScopedLock(m_Lock);
-
- if (m_AvailableConnections.empty())
- {
- zen::StringBuilder<16> Service;
- Service << int64_t(m_Port);
-
- asio::ip::tcp::resolver Resolver{m_Context};
-
- asio::error_code ErrCode;
- auto it = Resolver.resolve(m_HostName, Service, ErrCode);
- auto itEnd = asio::ip::tcp::resolver::iterator();
-
- if (ErrCode)
- {
- zen::ThrowLastError(fmt::format("Unabled to resolve '{}'", m_HostName));
- }
-
- asio::ip::tcp::socket Socket{m_Context};
- asio::connect(Socket, it, ErrCode);
-
- if (ErrCode)
- {
- zen::ThrowLastError(fmt::format("Failed connecting '{}:{}'", m_HostName, m_Port));
- }
-
- return std::make_unique<HttpClientConnection>(m_Context, this, std::move(Socket));
- }
-
- std::unique_ptr<HttpClientConnection> Connection{m_AvailableConnections.back()};
- m_AvailableConnections.pop_back();
- return Connection;
-}
-
-void
-HttpConnectionPool::ReturnConnection(std::unique_ptr<HttpClientConnection>&& Connection)
-{
- zen::RwLock::ExclusiveLockScope ScopedLock(m_Lock);
- m_AvailableConnections.emplace_back(Connection.release());
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-class HttpContext
-{
-public:
- HttpContext(asio::io_context& Context) : m_Context(Context) {}
- ~HttpContext() = default;
-
- std::unique_ptr<HttpClientConnection> GetConnection(std::string_view HostName, uint16_t Port)
- {
- return ConnectionPool(HostName, Port)->GetConnection();
- }
-
- void ReturnConnection(std::unique_ptr<HttpClientConnection> Connection)
- {
- Connection->ConnectionPool()->ReturnConnection(std::move(Connection));
- }
-
- zen::Ref<HttpConnectionPool> ConnectionPool(std::string_view HostName, uint16_t Port)
- {
- zen::RwLock::ExclusiveLockScope _(m_Lock);
- ConnectionId ConnId{std::string(HostName), Port};
-
- if (auto It = m_ConnectionPools.find(ConnId); It == end(m_ConnectionPools))
- {
- // Not found - create new entry
-
- auto In = m_ConnectionPools.emplace(ConnId, new HttpConnectionPool(m_Context, HostName, Port));
-
- return In.first->second;
- }
- else
- {
- return It->second;
- }
- }
-
-private:
- asio::io_context& m_Context;
-
- struct ConnectionId
- {
- inline bool operator<(const ConnectionId& Rhs) const
- {
- if (HostName != Rhs.HostName)
- {
- return HostName < Rhs.HostName;
- }
-
- return Port < Rhs.Port;
- }
-
- std::string HostName;
- uint16_t Port;
- };
-
- zen::RwLock m_Lock;
- std::map<ConnectionId, zen::Ref<HttpConnectionPool>> m_ConnectionPools;
-};
-
-//////////////////////////////////////////////////////////////////////////
-
-class HttpClientRequest
-{
-public:
- HttpClientRequest(HttpContext& Context) : m_HttpContext(Context) {}
- ~HttpClientRequest()
- {
- if (m_Connection)
- {
- m_HttpContext.ReturnConnection(std::move(m_Connection));
- }
- }
-
- void Get(const std::string_view Url)
- {
- http_parser_url ParsedUrl;
- int ErrCode = http_parser_parse_url(Url.data(), Url.size(), 0, &ParsedUrl);
-
- if (ErrCode)
- {
- ZEN_NOT_IMPLEMENTED();
- }
-
- if ((ParsedUrl.field_set & (UF_HOST | UF_PORT | UF_PATH)) != (UF_HOST | UF_PORT | UF_PATH))
- {
- // Bad URL
- }
-
- std::string_view HostName(Url.data() + ParsedUrl.field_data[UF_HOST].off, ParsedUrl.field_data[UF_HOST].len);
- std::string_view Path(Url.data() + ParsedUrl.field_data[UF_PATH].off);
-
- m_Connection = m_HttpContext.GetConnection(HostName, ParsedUrl.port);
- m_Connection->Get(HostName, ParsedUrl.port, Path);
- }
-
-private:
- HttpContext& m_HttpContext;
- std::unique_ptr<HttpClientConnection> m_Connection;
-};
-
//////////////////////////////////////////////////////////////////////////
//
// Custom logging -- test code, this should be tweaked
@@ -729,30 +337,6 @@ main(int argc, char** argv)
namespace zen::tests {
-# if 1
-TEST_CASE("asio.http")
-{
- std::filesystem::path TestDir = TestEnv.CreateNewTestDir();
-
- ZenServerInstance Instance(TestEnv);
- Instance.SetTestDir(TestDir);
- Instance.SpawnServer(13337);
-
- ZEN_INFO("Waiting...");
-
- Instance.WaitUntilReady();
-
- // asio test
-
- asio::io_context IoContext;
- HttpContext HttpCtx(IoContext);
- HttpClientRequest Request(HttpCtx);
- Request.Get("http://localhost:13337/test/hello");
-
- IoContext.run();
-}
-# endif
-
TEST_CASE("default.single")
{
std::filesystem::path TestDir = TestEnv.CreateNewTestDir();
diff --git a/zenserver/zenserver.cpp b/zenserver/zenserver.cpp
index c1a5fe507..f745f321a 100644
--- a/zenserver/zenserver.cpp
+++ b/zenserver/zenserver.cpp
@@ -847,6 +847,8 @@ ZenEntryPoint::Run()
InitializeLogging(ServerOptions);
+ ZEN_INFO(ZEN_APP_NAME " - using lock file at '{}'", LockFilePath);
+
ZEN_INFO(ZEN_APP_NAME " - starting on port {}, version '{}'", ServerOptions.BasePort, ZEN_CFG_VERSION_BUILD_STRING_FULL);
ZenServerState ServerState;
diff --git a/zenutil/cache/cachepolicy.cpp b/zenutil/cache/cachepolicy.cpp
index 7e6477cd4..8c10ea674 100644
--- a/zenutil/cache/cachepolicy.cpp
+++ b/zenutil/cache/cachepolicy.cpp
@@ -20,7 +20,7 @@ using namespace std::literals;
namespace DerivedData::Private {
- constexpr char CachePolicyDelimiter = ',';
+ constinit char CachePolicyDelimiter = ',';
struct CachePolicyToTextData
{
@@ -28,7 +28,7 @@ namespace DerivedData::Private {
std::string_view Text;
};
- const CachePolicyToTextData CachePolicyToText[]{
+ constinit CachePolicyToTextData CachePolicyToText[]{
// Flags with multiple bits are ordered by bit count to minimize token count in the text format.
{CachePolicy::Default, "Default"sv},
{CachePolicy::Remote, "Remote"sv},
@@ -48,7 +48,7 @@ namespace DerivedData::Private {
{CachePolicy::None, "None"sv},
};
- constexpr CachePolicy CachePolicyKnownFlags =
+ constinit CachePolicy CachePolicyKnownFlags =
CachePolicy::Default | CachePolicy::SkipMeta | CachePolicy::SkipData | CachePolicy::PartialRecord | CachePolicy::KeepAlive;
StringBuilderBase& CachePolicyToString(StringBuilderBase& Builder, CachePolicy Policy)
@@ -120,11 +120,27 @@ ConvertToUpstream(CachePolicy Policy)
// Set Local flags equal to downstream's Remote flags.
// Delete Skip flags if StoreLocal is true, otherwise use the downstream value.
// Use the downstream value for all other flags.
- return (EnumHasAllFlags(Policy, CachePolicy::QueryRemote) ? CachePolicy::QueryLocal : CachePolicy::None) |
- (EnumHasAllFlags(Policy, CachePolicy::StoreRemote) ? CachePolicy::StoreLocal : CachePolicy::None) |
- (!EnumHasAllFlags(Policy, CachePolicy::StoreLocal) ? (Policy & (CachePolicy::SkipData | CachePolicy::SkipMeta))
- : CachePolicy::None) |
- (Policy & ~(CachePolicy::Local | CachePolicy::SkipData | CachePolicy::SkipMeta));
+
+ CachePolicy UpstreamPolicy = CachePolicy::None;
+
+ if (EnumHasAllFlags(Policy, CachePolicy::QueryRemote))
+ {
+ UpstreamPolicy |= CachePolicy::QueryLocal;
+ }
+
+ if (EnumHasAllFlags(Policy, CachePolicy::StoreRemote))
+ {
+ UpstreamPolicy |= CachePolicy::StoreLocal;
+ }
+
+ if (!EnumHasAllFlags(Policy, CachePolicy::StoreLocal))
+ {
+ UpstreamPolicy |= (Policy & (CachePolicy::SkipData | CachePolicy::SkipMeta));
+ }
+
+ UpstreamPolicy |= Policy & ~(CachePolicy::Local | CachePolicy::SkipData | CachePolicy::SkipMeta);
+
+ return UpstreamPolicy;
}
class Private::CacheRecordPolicyShared final : public Private::ICacheRecordPolicyShared
diff --git a/zenutil/include/zenutil/cache/cachepolicy.h b/zenutil/include/zenutil/cache/cachepolicy.h
index 3eb0fda66..efcc4fb49 100644
--- a/zenutil/include/zenutil/cache/cachepolicy.h
+++ b/zenutil/include/zenutil/cache/cachepolicy.h
@@ -10,7 +10,6 @@
#include <gsl/gsl-lite.hpp>
#include <span>
-#include <unordered_map>
#define BACKWARDS_COMPATABILITY_JAN2022 1
#if BACKWARDS_COMPATABILITY_JAN2022