aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2025-03-06 16:18:32 +0100
committerGitHub Enterprise <[email protected]>2025-03-06 16:18:32 +0100
commit920120bbcec9f91df3336f62970b3e010a4fa6c2 (patch)
tree363460fbb90da8d1f8f0172483a7f5ffe22ea9f9 /src/zenserver
parent5.6.0 (diff)
downloadzen-920120bbcec9f91df3336f62970b3e010a4fa6c2.tar.xz
zen-920120bbcec9f91df3336f62970b3e010a4fa6c2.zip
reduced memory churn using fixed_xxx containers (#236)
* Added EASTL to help with eliminating memory allocations * Applied EASTL to eliminate memory allocations, primarily by using `fixed_vector` et al to use stack allocations / inline struct allocations Reduces memory events in traces by close to a factor of 10 in test scenario (starting editor for project F)
Diffstat (limited to 'src/zenserver')
-rw-r--r--src/zenserver/objectstore/objectstore.cpp27
-rw-r--r--src/zenserver/objectstore/objectstore.h4
-rw-r--r--src/zenserver/projectstore/httpprojectstore.cpp32
-rw-r--r--src/zenserver/projectstore/projectstore.cpp45
-rw-r--r--src/zenserver/workspaces/httpworkspaces.cpp12
5 files changed, 70 insertions, 50 deletions
diff --git a/src/zenserver/objectstore/objectstore.cpp b/src/zenserver/objectstore/objectstore.cpp
index 5d96de225..e757ef84e 100644
--- a/src/zenserver/objectstore/objectstore.cpp
+++ b/src/zenserver/objectstore/objectstore.cpp
@@ -269,9 +269,9 @@ HttpObjectStoreService::Inititalize()
m_Router.RegisterRoute(
"bucket/{path}",
[this](zen::HttpRouterRequest& Request) {
- const std::string Path = Request.GetCapture(1);
- const auto Sep = Path.find_last_of('.');
- const bool IsObject = Sep != std::string::npos && Path.size() - Sep > 0;
+ const std::string_view Path = Request.GetCapture(1);
+ const auto Sep = Path.find_last_of('.');
+ const bool IsObject = Sep != std::string::npos && Path.size() - Sep > 0;
if (IsObject)
{
@@ -337,18 +337,18 @@ HttpObjectStoreService::CreateBucket(zen::HttpRouterRequest& Request)
}
void
-HttpObjectStoreService::ListBucket(zen::HttpRouterRequest& Request, const std::string& Path)
+HttpObjectStoreService::ListBucket(zen::HttpRouterRequest& Request, const std::string_view Path)
{
namespace fs = std::filesystem;
- const auto Sep = Path.find_first_of('/');
- const std::string BucketName = Sep == std::string::npos ? Path : Path.substr(0, Sep);
+ const auto Sep = Path.find_first_of('/');
+ const std::string BucketName{Sep == std::string::npos ? Path : Path.substr(0, Sep)};
if (BucketName.empty())
{
return Request.ServerRequest().WriteResponse(HttpResponseCode::BadRequest);
}
- std::string BucketPrefix = Sep == std::string::npos || Sep == Path.size() - 1 ? std::string() : Path.substr(BucketName.size() + 1);
+ std::string BucketPrefix{Sep == std::string::npos || Sep == Path.size() - 1 ? std::string() : Path.substr(BucketName.size() + 1)};
if (BucketPrefix.empty())
{
const auto QueryParms = Request.ServerRequest().GetQueryParams();
@@ -450,14 +450,13 @@ HttpObjectStoreService::DeleteBucket(zen::HttpRouterRequest& Request)
}
void
-HttpObjectStoreService::GetObject(zen::HttpRouterRequest& Request, const std::string& Path)
+HttpObjectStoreService::GetObject(zen::HttpRouterRequest& Request, const std::string_view Path)
{
namespace fs = std::filesystem;
- const auto Sep = Path.find_first_of('/');
- const std::string BucketName = Sep == std::string::npos ? Path : Path.substr(0, Sep);
- const std::string BucketPrefix =
- Sep == std::string::npos || Sep == Path.size() - 1 ? std::string() : Path.substr(BucketName.size() + 1);
+ const auto Sep = Path.find_first_of('/');
+ const std::string BucketName{Sep == std::string::npos ? Path : Path.substr(0, Sep)};
+ const std::string BucketPrefix{Sep == std::string::npos || Sep == Path.size() - 1 ? std::string() : Path.substr(BucketName.size() + 1)};
const fs::path BucketDir = GetBucketDirectory(BucketName);
@@ -554,8 +553,8 @@ HttpObjectStoreService::PutObject(zen::HttpRouterRequest& Request)
{
namespace fs = std::filesystem;
- const std::string& BucketName = Request.GetCapture(1);
- const fs::path BucketDir = GetBucketDirectory(BucketName);
+ const std::string_view BucketName = Request.GetCapture(1);
+ const fs::path BucketDir = GetBucketDirectory(BucketName);
if (BucketDir.empty())
{
diff --git a/src/zenserver/objectstore/objectstore.h b/src/zenserver/objectstore/objectstore.h
index c905ceab3..dae979c4c 100644
--- a/src/zenserver/objectstore/objectstore.h
+++ b/src/zenserver/objectstore/objectstore.h
@@ -36,9 +36,9 @@ private:
void Inititalize();
std::filesystem::path GetBucketDirectory(std::string_view BucketName);
void CreateBucket(zen::HttpRouterRequest& Request);
- void ListBucket(zen::HttpRouterRequest& Request, const std::string& Path);
+ void ListBucket(zen::HttpRouterRequest& Request, const std::string_view Path);
void DeleteBucket(zen::HttpRouterRequest& Request);
- void GetObject(zen::HttpRouterRequest& Request, const std::string& Path);
+ void GetObject(zen::HttpRouterRequest& Request, const std::string_view Path);
void PutObject(zen::HttpRouterRequest& Request);
ObjectStoreConfig m_Cfg;
diff --git a/src/zenserver/projectstore/httpprojectstore.cpp b/src/zenserver/projectstore/httpprojectstore.cpp
index 0b8e5f13b..47748dd90 100644
--- a/src/zenserver/projectstore/httpprojectstore.cpp
+++ b/src/zenserver/projectstore/httpprojectstore.cpp
@@ -983,15 +983,19 @@ HttpProjectService::HandleOplogOpPrepRequest(HttpRouterRequest& Req)
IoBuffer Payload = HttpReq.ReadPayload();
CbObject RequestObject = LoadCompactBinaryObject(Payload);
- std::vector<IoHash> ChunkList;
- CbArrayView HaveList = RequestObject["have"sv].AsArrayView();
- ChunkList.reserve(HaveList.Num());
- for (auto& Entry : HaveList)
+ std::vector<IoHash> NeedList;
+
{
- ChunkList.push_back(Entry.AsHash());
- }
+ eastl::fixed_vector<IoHash, 16> ChunkList;
+ CbArrayView HaveList = RequestObject["have"sv].AsArrayView();
+ ChunkList.reserve(HaveList.Num());
+ for (auto& Entry : HaveList)
+ {
+ ChunkList.push_back(Entry.AsHash());
+ }
- std::vector<IoHash> NeedList = FoundLog->CheckPendingChunkReferences(ChunkList, std::chrono::minutes(2));
+ NeedList = FoundLog->CheckPendingChunkReferences(std::span(begin(ChunkList), end(ChunkList)), std::chrono::minutes(2));
+ }
CbObjectWriter Cbo(1 + 1 + 5 + NeedList.size() * (1 + sizeof(IoHash::Hash)) + 1);
Cbo.BeginArray("need");
@@ -1151,7 +1155,7 @@ HttpProjectService::HandleOplogOpNewRequest(HttpRouterRequest& Req)
return HttpReq.WriteResponse(HttpResponseCode::BadRequest, HttpContentType::kText, "No oplog entry key specified");
}
- std::vector<IoHash> ReferencedChunks;
+ eastl::fixed_vector<IoHash, 16> ReferencedChunks;
Core.IterateAttachments([&ReferencedChunks](CbFieldView View) { ReferencedChunks.push_back(View.AsAttachment()); });
// Write core to oplog
@@ -1169,7 +1173,7 @@ HttpProjectService::HandleOplogOpNewRequest(HttpRouterRequest& Req)
// Once we stored the op, we no longer need to retain any chunks this op references
if (!ReferencedChunks.empty())
{
- FoundLog->RemovePendingChunkReferences(ReferencedChunks);
+ FoundLog->RemovePendingChunkReferences(std::span(begin(ReferencedChunks), end(ReferencedChunks)));
}
m_ProjectStats.OpWriteCount++;
@@ -1301,9 +1305,9 @@ HttpProjectService::HandleOpLogOpRequest(HttpRouterRequest& Req)
HttpServerRequest& HttpReq = Req.ServerRequest();
- const std::string& ProjectId = Req.GetCapture(1);
- const std::string& OplogId = Req.GetCapture(2);
- const std::string& OpIdString = Req.GetCapture(3);
+ const std::string_view ProjectId = Req.GetCapture(1);
+ const std::string_view OplogId = Req.GetCapture(2);
+ const std::string_view OpIdString = Req.GetCapture(3);
Ref<ProjectStore::Project> Project = m_ProjectStore->OpenProject(ProjectId);
if (!Project)
@@ -1690,8 +1694,8 @@ HttpProjectService::HandleProjectRequest(HttpRouterRequest& Req)
using namespace std::literals;
- HttpServerRequest& HttpReq = Req.ServerRequest();
- const std::string ProjectId = Req.GetCapture(1);
+ HttpServerRequest& HttpReq = Req.ServerRequest();
+ const std::string_view ProjectId = Req.GetCapture(1);
switch (HttpReq.RequestVerb())
{
diff --git a/src/zenserver/projectstore/projectstore.cpp b/src/zenserver/projectstore/projectstore.cpp
index 53df12b14..86791e29a 100644
--- a/src/zenserver/projectstore/projectstore.cpp
+++ b/src/zenserver/projectstore/projectstore.cpp
@@ -423,9 +423,13 @@ ComputeOpKey(const CbObjectView& Op)
{
using namespace std::literals;
- BinaryWriter KeyStream;
+ eastl::fixed_vector<uint8_t, 256> KeyData;
- Op["key"sv].WriteToStream([&](const void* Data, size_t Size) { KeyStream.Write(Data, Size); });
+ Op["key"sv].WriteToStream([&](const void* Data, size_t Size) {
+ auto Begin = reinterpret_cast<const uint8_t*>(Data);
+ auto End = Begin + Size;
+ KeyData.insert(KeyData.end(), Begin, End);
+ });
XXH3_128 KeyHash128;
@@ -434,15 +438,15 @@ ComputeOpKey(const CbObjectView& Op)
// path but longer paths are evaluated properly. In the future all key lengths
// should be evaluated using the proper path, this is a temporary workaround to
// maintain compatibility with existing disk state.
- if (KeyStream.GetSize() < 240)
+ if (KeyData.size() < 240)
{
XXH3_128Stream_deprecated KeyHasher;
- KeyHasher.Append(KeyStream.Data(), KeyStream.Size());
+ KeyHasher.Append(KeyData.data(), KeyData.size());
KeyHash128 = KeyHasher.GetHash();
}
else
{
- KeyHash128 = XXH3_128::HashMemory(KeyStream.GetView());
+ KeyHash128 = XXH3_128::HashMemory(KeyData.data(), KeyData.size());
}
Oid KeyHash;
@@ -2735,7 +2739,7 @@ ProjectStore::Oplog::CheckPendingChunkReferences(std::span<const IoHash> ChunkHa
MissingChunks.reserve(ChunkHashes.size());
for (const IoHash& FileHash : ChunkHashes)
{
- if (IoBuffer Payload = m_CidStore.FindChunkByCid(FileHash); !Payload)
+ if (!m_CidStore.ContainsChunk(FileHash))
{
MissingChunks.push_back(FileHash);
}
@@ -3359,7 +3363,6 @@ ProjectStore::Project::OpenOplog(std::string_view OplogId, bool AllowCompact, bo
ZEN_MEMSCOPE(GetProjectstoreTag());
ZEN_TRACE_CPU("Store::OpenOplog");
- std::filesystem::path OplogBasePath = BasePathForOplog(OplogId);
{
RwLock::SharedLockScope ProjectLock(m_ProjectLock);
@@ -3367,21 +3370,35 @@ ProjectStore::Project::OpenOplog(std::string_view OplogId, bool AllowCompact, bo
if (OplogIt != m_Oplogs.end())
{
- if (!VerifyPathOnDisk || Oplog::ExistsAt(OplogBasePath))
+ bool ReOpen = false;
+
+ if (VerifyPathOnDisk)
{
- return OplogIt->second.get();
+ std::filesystem::path OplogBasePath = BasePathForOplog(OplogId);
+
+ if (!Oplog::ExistsAt(OplogBasePath))
+ {
+ // Somebody deleted the oplog on disk behind our back
+ ProjectLock.ReleaseNow();
+ std::filesystem::path DeletePath;
+ if (!RemoveOplog(OplogId, DeletePath))
+ {
+ ZEN_WARN("Failed to clean up deleted oplog {}/{}", Identifier, OplogId, OplogBasePath);
+ }
+
+ ReOpen = true;
+ }
}
- // Somebody deleted the oplog on disk behind our back
- ProjectLock.ReleaseNow();
- std::filesystem::path DeletePath;
- if (!RemoveOplog(OplogId, DeletePath))
+ if (!ReOpen)
{
- ZEN_WARN("Failed to clean up deleted oplog {}/{}", Identifier, OplogId, OplogBasePath);
+ return OplogIt->second.get();
}
}
}
+ std::filesystem::path OplogBasePath = BasePathForOplog(OplogId);
+
RwLock::ExclusiveLockScope Lock(m_ProjectLock);
if (auto It = m_Oplogs.find(std::string{OplogId}); It != m_Oplogs.end())
{
diff --git a/src/zenserver/workspaces/httpworkspaces.cpp b/src/zenserver/workspaces/httpworkspaces.cpp
index 905ba5ab2..8a4b977ad 100644
--- a/src/zenserver/workspaces/httpworkspaces.cpp
+++ b/src/zenserver/workspaces/httpworkspaces.cpp
@@ -589,7 +589,7 @@ void
HttpWorkspacesService::ShareAliasFilesRequest(HttpRouterRequest& Req)
{
HttpServerRequest& ServerRequest = Req.ServerRequest();
- std::string Alias = Req.GetCapture(1);
+ std::string_view Alias = Req.GetCapture(1);
if (Alias.empty())
{
return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
@@ -608,7 +608,7 @@ void
HttpWorkspacesService::ShareAliasChunkInfoRequest(HttpRouterRequest& Req)
{
HttpServerRequest& ServerRequest = Req.ServerRequest();
- std::string Alias = Req.GetCapture(1);
+ std::string_view Alias = Req.GetCapture(1);
if (Alias.empty())
{
return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
@@ -635,7 +635,7 @@ void
HttpWorkspacesService::ShareAliasBatchRequest(HttpRouterRequest& Req)
{
HttpServerRequest& ServerRequest = Req.ServerRequest();
- std::string Alias = Req.GetCapture(1);
+ std::string_view Alias = Req.GetCapture(1);
if (Alias.empty())
{
return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
@@ -654,7 +654,7 @@ void
HttpWorkspacesService::ShareAliasEntriesRequest(HttpRouterRequest& Req)
{
HttpServerRequest& ServerRequest = Req.ServerRequest();
- std::string Alias = Req.GetCapture(1);
+ std::string_view Alias = Req.GetCapture(1);
if (Alias.empty())
{
return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
@@ -673,7 +673,7 @@ void
HttpWorkspacesService::ShareAliasChunkRequest(HttpRouterRequest& Req)
{
HttpServerRequest& ServerRequest = Req.ServerRequest();
- std::string Alias = Req.GetCapture(1);
+ std::string_view Alias = Req.GetCapture(1);
if (Alias.empty())
{
return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,
@@ -700,7 +700,7 @@ void
HttpWorkspacesService::ShareAliasRequest(HttpRouterRequest& Req)
{
HttpServerRequest& ServerRequest = Req.ServerRequest();
- std::string Alias = Req.GetCapture(1);
+ std::string_view Alias = Req.GetCapture(1);
if (Alias.empty())
{
return ServerRequest.WriteResponse(HttpResponseCode::BadRequest,