diff options
| author | Stefan Boberg <[email protected]> | 2021-10-28 13:15:59 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2021-10-28 13:15:59 +0200 |
| commit | 2d0e0052f37c7dfaab82f58bf8546d48d38bfc0f (patch) | |
| tree | a628eec1e624291d607f95f64f2f8bc2ab23616c | |
| parent | cas: minor improvement to CasLogFile::Open error handling (diff) | |
| parent | Lockfile implementation (#24) (diff) | |
| download | zen-2d0e0052f37c7dfaab82f58bf8546d48d38bfc0f.tar.xz zen-2d0e0052f37c7dfaab82f58bf8546d48d38bfc0f.zip | |
Merge remote-tracking branch 'origin/main' into gc
| -rw-r--r-- | zenserver/zenserver.cpp | 72 | ||||
| -rw-r--r-- | zenstore/basicfile.cpp | 48 | ||||
| -rw-r--r-- | zenstore/include/zenstore/basicfile.h | 18 | ||||
| -rw-r--r-- | zenutil/include/zenutil/zenserverprocess.h | 13 | ||||
| -rw-r--r-- | zenutil/zenserverprocess.cpp | 6 |
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) { |