aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2021-10-28 13:15:59 +0200
committerStefan Boberg <[email protected]>2021-10-28 13:15:59 +0200
commit2d0e0052f37c7dfaab82f58bf8546d48d38bfc0f (patch)
treea628eec1e624291d607f95f64f2f8bc2ab23616c
parentcas: minor improvement to CasLogFile::Open error handling (diff)
parentLockfile implementation (#24) (diff)
downloadzen-2d0e0052f37c7dfaab82f58bf8546d48d38bfc0f.tar.xz
zen-2d0e0052f37c7dfaab82f58bf8546d48d38bfc0f.zip
Merge remote-tracking branch 'origin/main' into gc
-rw-r--r--zenserver/zenserver.cpp72
-rw-r--r--zenstore/basicfile.cpp48
-rw-r--r--zenstore/include/zenstore/basicfile.h18
-rw-r--r--zenutil/include/zenutil/zenserverprocess.h13
-rw-r--r--zenutil/zenserverprocess.cpp6
5 files changed, 143 insertions, 14 deletions
diff --git a/zenserver/zenserver.cpp b/zenserver/zenserver.cpp
index 542ad6dd2..040d73581 100644
--- a/zenserver/zenserver.cpp
+++ b/zenserver/zenserver.cpp
@@ -8,11 +8,13 @@
#include <zencore/logging.h>
#include <zencore/refcount.h>
#include <zencore/scopeguard.h>
+#include <zencore/session.h>
#include <zencore/string.h>
#include <zencore/thread.h>
#include <zencore/timer.h>
#include <zencore/windows.h>
#include <zenhttp/httpserver.h>
+#include <zenstore/basicfile.h>
#include <zenstore/cas.h>
#include <zenstore/cidstore.h>
#include <zenutil/zenserverprocess.h>
@@ -305,11 +307,13 @@ public:
const bool IsInteractiveMode = zen::IsInteractiveSession() && !m_TestMode;
- m_CurrentState = kRunning;
+ SetNewState(kRunning);
+
+ OnReady();
m_Http->Run(IsInteractiveMode);
- m_CurrentState = kShuttingDown;
+ SetNewState(kShuttingDown);
ZEN_INFO(ZEN_APP_NAME " exiting");
@@ -331,6 +335,10 @@ public:
void SetDataRoot(std::filesystem::path Root) { m_DataRoot = Root; }
void SetContentRoot(std::filesystem::path Root) { m_ContentRoot = Root; }
+ std::function<void()> m_IsReadyFunc;
+ void SetIsReadyFunc(std::function<void()>&& IsReadyFunc) { m_IsReadyFunc = std::move(IsReadyFunc); }
+ void OnReady();
+
void EnsureIoRunner()
{
if (!m_IoRunner.joinable())
@@ -454,6 +462,8 @@ private:
kShuttingDown
} m_CurrentState = kInitializing;
+ inline void SetNewState(ServerState NewState) { m_CurrentState = NewState; }
+
std::string_view ToString(ServerState Value)
{
switch (Value)
@@ -501,6 +511,17 @@ private:
};
void
+ZenServer::OnReady()
+{
+ m_ServerEntry->SignalReady();
+
+ if (m_IsReadyFunc)
+ {
+ m_IsReadyFunc();
+ }
+}
+
+void
ZenServer::InitializeState(ZenServiceConfig& ServiceConfig)
{
// Check root manifest to deal with schema versioning
@@ -703,6 +724,7 @@ public:
private:
ZenServerOptions& m_GlobalOptions;
ZenServiceConfig& m_ServiceConfig;
+ zen::LockFile m_LockFile;
};
int
@@ -725,6 +747,32 @@ ZenWindowsService::Run()
try
{
+ // Mutual exclusion and synchronization
+
+ std::error_code Ec;
+
+ std::filesystem::path LockFilePath = GlobalOptions.DataDir / ".lock";
+
+ bool IsReady = false;
+
+ auto MakeLockData = [&] {
+ CbObjectWriter Cbo;
+ Cbo << "pid" << _getpid() << "data" << ToUtf8(GlobalOptions.DataDir) << "port" << GlobalOptions.BasePort << "session_id"
+ << GetSessionId() << "ready" << IsReady;
+ return Cbo.Save();
+ };
+
+ m_LockFile.Create(LockFilePath, MakeLockData(), Ec);
+
+ if (Ec)
+ {
+ ConsoleLog().error("ERROR: Unable to grab lock at '{}' (error: '{}')", LockFilePath, Ec.message());
+
+ std::exit(99);
+ }
+
+ InitializeLogging(GlobalOptions);
+
// Prototype config system, we'll see how this pans out
//
// TODO: we need to report any parse errors here
@@ -786,13 +834,19 @@ ZenWindowsService::Run()
}});
// If we have a parent process, establish the mechanisms we need
- // to be able to communicate with the parent
+ // to be able to communicate readiness with the parent
- if (!GlobalOptions.ChildId.empty())
- {
- zen::NamedEvent ParentEvent{GlobalOptions.ChildId};
- ParentEvent.Set();
- }
+ Server.SetIsReadyFunc([&] {
+ IsReady = true;
+
+ m_LockFile.Update(MakeLockData(), Ec);
+
+ if (!GlobalOptions.ChildId.empty())
+ {
+ zen::NamedEvent ParentEvent{GlobalOptions.ChildId};
+ ParentEvent.Set();
+ }
+ });
Server.Run();
Server.Cleanup();
@@ -831,8 +885,6 @@ main(int argc, char* argv[])
std::filesystem::create_directories(GlobalOptions.DataDir);
}
- InitializeLogging(GlobalOptions);
-
#if ZEN_PLATFORM_WINDOWS
if (GlobalOptions.InstallService)
{
diff --git a/zenstore/basicfile.cpp b/zenstore/basicfile.cpp
index bbb9e1036..9ed70a5ec 100644
--- a/zenstore/basicfile.cpp
+++ b/zenstore/basicfile.cpp
@@ -2,6 +2,7 @@
#include "zenstore/basicfile.h"
+#include <zencore/compactbinary.h>
#include <zencore/except.h>
#include <zencore/filesystem.h>
#include <zencore/fmtutils.h>
@@ -266,6 +267,53 @@ TemporaryFile::MoveTemporaryIntoPlace(std::filesystem::path FinalFileName, std::
std::filesystem::rename(m_TempPath, FinalFileName, Ec);
}
+//////////////////////////////////////////////////////////////////////////
+
+LockFile::LockFile()
+{
+}
+
+LockFile::~LockFile()
+{
+}
+
+void
+LockFile::Create(std::filesystem::path FileName, CbObject Payload, std::error_code& Ec)
+{
+ Ec.clear();
+
+ const DWORD dwCreationDisposition = CREATE_ALWAYS;
+ DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE | DELETE;
+ const DWORD dwShareMode = FILE_SHARE_READ;
+ const DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE;
+ HANDLE hTemplateFile = nullptr;
+
+ HANDLE FileHandle = CreateFile(FileName.c_str(),
+ dwDesiredAccess,
+ dwShareMode,
+ /* lpSecurityAttributes */ nullptr,
+ dwCreationDisposition,
+ dwFlagsAndAttributes,
+ hTemplateFile);
+
+ if (FileHandle == INVALID_HANDLE_VALUE)
+ {
+ Ec = zen::MakeErrorCodeFromLastError();
+
+ return;
+ }
+
+ m_FileHandle = FileHandle;
+
+ BasicFile::Write(Payload.GetBuffer(), 0, Ec);
+}
+
+void
+LockFile::Update(CbObject Payload, std::error_code& Ec)
+{
+ BasicFile::Write(Payload.GetBuffer(), 0, Ec);
+}
+
/*
___________ __
\__ ___/___ _______/ |_ ______
diff --git a/zenstore/include/zenstore/basicfile.h b/zenstore/include/zenstore/basicfile.h
index 7ae35dea6..e4414787c 100644
--- a/zenstore/include/zenstore/basicfile.h
+++ b/zenstore/include/zenstore/basicfile.h
@@ -12,6 +12,8 @@
namespace zen {
+class CbObject;
+
/**
* Probably the most basic file abstraction in the universe
*
@@ -80,6 +82,22 @@ private:
using BasicFile::Open;
};
+/** Lock file abstraction
+
+ */
+
+class LockFile : protected BasicFile
+{
+public:
+ LockFile();
+ ~LockFile();
+
+ void Create(std::filesystem::path FileName, CbObject Payload, std::error_code& Ec);
+ void Update(CbObject Payload, std::error_code& Ec);
+
+private:
+};
+
ZENCORE_API void basicfile_forcelink();
} // namespace zen
diff --git a/zenutil/include/zenutil/zenserverprocess.h b/zenutil/include/zenutil/zenserverprocess.h
index bc4b135f0..8a4f9604d 100644
--- a/zenutil/include/zenutil/zenserverprocess.h
+++ b/zenutil/include/zenutil/zenserverprocess.h
@@ -94,13 +94,17 @@ public:
struct ZenServerEntry
{
+ // NOTE: any changes to this should consider backwards compatibility
+ // which means you should not rearrange members only potentially
+ // add something to the end or use a different mechanism for
+ // additional state. For example, you can use the session ID
+ // to introduce additional named objects
std::atomic<uint32_t> Pid;
std::atomic<uint16_t> ListenPort;
std::atomic<uint16_t> Flags;
uint8_t SessionId[12];
- std::atomic<uint32_t> SponsorPids[32];
+ std::atomic<uint32_t> SponsorPids[8];
uint8_t Padding[12];
- uint8_t Padding2[96];
enum class FlagsEnum : uint16_t
{
@@ -113,10 +117,11 @@ public:
Oid GetSessionId() const { return Oid::FromMemory(SessionId); }
void Reset();
void SignalShutdownRequest();
+ void SignalReady();
bool AddSponsorProcess(uint32_t Pid);
};
- static_assert(sizeof(ZenServerEntry) == 256);
+ static_assert(sizeof(ZenServerEntry) == 64);
void Initialize();
[[nodiscard]] bool InitializeReadOnly();
@@ -129,7 +134,7 @@ public:
private:
void* m_hMapFile = nullptr;
ZenServerEntry* m_Data = nullptr;
- int m_MaxEntryCount = 131072 / sizeof(ZenServerEntry);
+ int m_MaxEntryCount = 65536 / sizeof(ZenServerEntry);
ZenServerEntry* m_OurEntry = nullptr;
bool m_IsReadOnly = true;
};
diff --git a/zenutil/zenserverprocess.cpp b/zenutil/zenserverprocess.cpp
index 55b592ab1..4098954a8 100644
--- a/zenutil/zenserverprocess.cpp
+++ b/zenutil/zenserverprocess.cpp
@@ -269,6 +269,12 @@ ZenServerState::ZenServerEntry::SignalShutdownRequest()
Flags |= uint16_t(FlagsEnum::kShutdownPlease);
}
+void
+ZenServerState::ZenServerEntry::SignalReady()
+{
+ Flags |= uint16_t(FlagsEnum::kIsReady);
+}
+
bool
ZenServerState::ZenServerEntry::AddSponsorProcess(uint32_t PidToAdd)
{