From b62af061371fd8dd2128e7e7b928efee8463c6ef Mon Sep 17 00:00:00 2001 From: Matt Peters Date: Fri, 11 Oct 2024 06:07:06 -0600 Subject: =?UTF-8?q?Add=20ability=20to=20read=20the=20oplog's=20ReferencedS?= =?UTF-8?q?et,=20as=20written=20by=20the=20cook=E2=80=A6=20(#190)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add ability to read the oplog's ReferencedSet, as written by the cooker, from the ReferencedSet op. Filter oplog entries requests by the ReferencedSet, if trim_by_referencedset parameter is present.. Add -trim=true/false parameter to oplog-mirror command, default to true, to request the trimmed/not trimmed oplog. Helper functions: Add paging to IterateOpLogWithKey. Add unit tests for IterateOpLog functions. Move OpKeyStringAsOid from httpprojectstore into projectstore. --- src/zenserver/projectstore/oplogreferencedset.cpp | 110 ++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 src/zenserver/projectstore/oplogreferencedset.cpp (limited to 'src/zenserver/projectstore/oplogreferencedset.cpp') diff --git a/src/zenserver/projectstore/oplogreferencedset.cpp b/src/zenserver/projectstore/oplogreferencedset.cpp new file mode 100644 index 000000000..c6bfa0b98 --- /dev/null +++ b/src/zenserver/projectstore/oplogreferencedset.cpp @@ -0,0 +1,110 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "oplogreferencedset.h" + +#include "projectstore.h" + +#include +#include +#include + +namespace zen { + +std::optional +OplogReferencedSet::LoadFromChunk(const IoBuffer& ChunkData) +{ + using namespace std::literals; + + if (!ChunkData || ChunkData.Size() == 0) + { + return std::optional(); + } + std::string_view ChunkText(reinterpret_cast(ChunkData.Data()), ChunkData.Size()); + + AsciiSet TrimWhitespace(" \t\r\n"); + const char* FirstNonComment = nullptr; + uint64_t Version = 0; + + // Parse the initial comment block: the leading block of empty or comment lines. + ForEachStrTok(ChunkText, '\n', [&Version, &FirstNonComment, &TrimWhitespace](std::string_view Line) { + Line = AsciiSet::TrimSuffixWith(AsciiSet::TrimPrefixWith(Line, TrimWhitespace), TrimWhitespace); + if (Line.empty()) + { + return true; // empty line, keep reading + } + if (!Line.starts_with('#')) + { + FirstNonComment = Line.data(); + return false; // non-comment line, stop + } + + // Comment line in the header block of comments in the file. Interpret it if it is a version line. + // Skip past the '#' and whitespace. + Line.remove_prefix(1); + Line = AsciiSet::TrimPrefixWith(Line, TrimWhitespace); + + // Parse "# Version ". + constexpr std::string_view VersionStr("Version "sv); + if (Line.starts_with(VersionStr)) + { + std::string_view VersionToken = Line; + VersionToken.remove_prefix(VersionStr.length()); + VersionToken.remove_suffix(AsciiSet::TrimPrefixWithout(VersionToken, TrimWhitespace).length()); + std::optional ParsedVersion = ParseInt(VersionToken); + if (ParsedVersion) + { + Version = *ParsedVersion; + } + } + return true; + }); + + // Report no referencedset if the version is below our minimum version. + constexpr uint64_t MinSupportedVersion = 1; + if (Version < MinSupportedVersion) + { + ZEN_INFO("ReferencedSet is below the minimum supported version, ignoring it. Version: {}, minimum version: {}.", + Version, + MinSupportedVersion); + return std::optional(); + } + + // Parse the remaining lines after the leading comment block. + ChunkText.remove_prefix(FirstNonComment ? FirstNonComment - ChunkText.data() : ChunkText.length()); + + OplogReferencedSet Result; + ForEachStrTok(ChunkText, '\n', [&Result, &TrimWhitespace](std::string_view Line) { + Line = AsciiSet::TrimSuffixWith(AsciiSet::TrimPrefixWith(Line, TrimWhitespace), TrimWhitespace); + if (!Line.empty() && !Line.starts_with('#')) + { + Result.Emplace(OpKeyStringAsOid(Line)); + } + return true; + }); + return std::optional(std::move(Result)); +} + +void +OplogReferencedSet::Emplace(Oid OplogId) +{ + Set.emplace(OplogId); +} + +void +OplogReferencedSet::Clear() +{ + Set.clear(); +} + +bool +OplogReferencedSet::Contains(Oid OplogId, std::string_view OplogKey) +{ + // A referencedset always includes all non-package keys + if (OplogKey.empty() || !OplogKey.starts_with("/")) + { + return true; + } + return Set.contains(OplogId); +} + +} // namespace zen -- cgit v1.2.3