aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver/hub/hub.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zenserver/hub/hub.cpp')
-rw-r--r--src/zenserver/hub/hub.cpp56
1 files changed, 47 insertions, 9 deletions
diff --git a/src/zenserver/hub/hub.cpp b/src/zenserver/hub/hub.cpp
index c9720b32d..3c9f40eaa 100644
--- a/src/zenserver/hub/hub.cpp
+++ b/src/zenserver/hub/hub.cpp
@@ -22,6 +22,8 @@ ZEN_THIRD_PARTY_INCLUDES_END
# include <zencore/workthreadpool.h>
#endif
+#include <numeric>
+
namespace zen {
///////////////////////////////////////////////////////////////////////////
@@ -137,10 +139,10 @@ Hub::Hub(const Configuration& Config,
m_HydrationTempPath = m_RunEnvironment.CreateChildDir("hydration_temp");
ZEN_INFO("using hydration temp path: '{}'", m_HydrationTempPath);
- // This is necessary to ensure the hub assigns a distinct port range.
- // We need to do this primarily because otherwise automated tests will
- // fail as the test runner will create processes in the default range.
- m_RunEnvironment.SetNextPortNumber(m_Config.BasePortNumber);
+ ZEN_ASSERT(uint64_t(Config.BasePortNumber) + Config.InstanceLimit <= std::numeric_limits<uint16_t>::max());
+
+ m_FreePorts.resize(Config.InstanceLimit);
+ std::iota(m_FreePorts.begin(), m_FreePorts.end(), Config.BasePortNumber);
#if ZEN_PLATFORM_WINDOWS
if (m_Config.UseJobObject)
@@ -199,6 +201,15 @@ Hub::Provision(std::string_view ModuleId, HubProvisionedInstanceInfo& OutInfo, s
bool IsNewInstance = false;
{
RwLock::ExclusiveLockScope _(m_Lock);
+ uint16_t AllocatedPort = 0;
+ auto RestoreAllocatedPort = MakeGuard([this, &AllocatedPort]() {
+ if (AllocatedPort != 0)
+ {
+ m_FreePorts.push_back(AllocatedPort);
+ AllocatedPort = 0;
+ }
+ });
+
if (auto It = m_Instances.find(std::string(ModuleId)); It == m_Instances.end())
{
std::string Reason;
@@ -211,9 +222,18 @@ Hub::Provision(std::string_view ModuleId, HubProvisionedInstanceInfo& OutInfo, s
return false;
}
- IsNewInstance = true;
- auto NewInstance =
- std::make_unique<StorageServerInstance>(m_RunEnvironment, ModuleId, m_FileHydrationPath, m_HydrationTempPath);
+ AllocatedPort = m_FreePorts.front();
+ m_FreePorts.pop_front();
+
+ IsNewInstance = true;
+ auto NewInstance = std::make_unique<StorageServerInstance>(
+ m_RunEnvironment,
+ StorageServerInstance::Configuration{.BasePort = AllocatedPort,
+ .HydrationTempPath = m_HydrationTempPath,
+ .FileHydrationPath = m_FileHydrationPath,
+ .HttpThreadCount = m_Config.InstanceHttpThreadCount,
+ .CoreLimit = m_Config.InstanceCoreLimit},
+ ModuleId);
#if ZEN_PLATFORM_WINDOWS
if (m_JobObject.IsValid())
{
@@ -222,6 +242,7 @@ Hub::Provision(std::string_view ModuleId, HubProvisionedInstanceInfo& OutInfo, s
#endif
Instance = NewInstance.get();
m_Instances.emplace(std::string(ModuleId), std::move(NewInstance));
+ AllocatedPort = 0;
ZEN_INFO("Created new storage server instance for module '{}'", ModuleId);
}
@@ -258,7 +279,13 @@ Hub::Provision(std::string_view ModuleId, HubProvisionedInstanceInfo& OutInfo, s
{
// Clean up
RwLock::ExclusiveLockScope _(m_Lock);
- m_Instances.erase(std::string(ModuleId));
+ if (auto It = m_Instances.find(std::string(ModuleId)); It != m_Instances.end())
+ {
+ ZEN_ASSERT(It->second != nullptr);
+ uint16_t BasePort = It->second->GetBasePort();
+ m_FreePorts.push_back(BasePort);
+ m_Instances.erase(It);
+ }
}
return false;
}
@@ -337,6 +364,7 @@ Hub::Deprovision(const std::string& ModuleId, std::string& OutReason)
auto _ = MakeGuard([&] {
RwLock::ExclusiveLockScope _(m_Lock);
m_DeprovisioningModules.erase(ModuleId);
+ m_FreePorts.push_back(BasePort);
});
Instance->Deprovision();
@@ -413,7 +441,17 @@ Hub::CanProvisionInstance(std::string_view ModuleId, std::string& OutReason)
if (gsl::narrow_cast<int>(m_Instances.size()) >= m_Config.InstanceLimit)
{
- OutReason = fmt::format("instance limit exceeded ({})", m_Config.InstanceLimit);
+ OutReason = fmt::format("instance limit ({}) exceeded", m_Config.InstanceLimit);
+
+ return false;
+ }
+
+ // Since deprovisioning happens outside the lock and we don't add the port back until the instance is full shut down we might be under
+ // the instance limit but all ports may be in use
+ if (m_FreePorts.empty())
+ {
+ OutReason = fmt::format("no free ports available, deprovisioning of instances might be in flight ({})",
+ m_Config.InstanceLimit - m_Instances.size());
return false;
}