diff options
author | serg-belyakov <serg-belyakov@yandex-team.com> | 2023-01-17 13:14:06 +0300 |
---|---|---|
committer | serg-belyakov <serg-belyakov@yandex-team.com> | 2023-01-17 13:14:06 +0300 |
commit | 51674dac4bb91435ef6009fa104dfb835e158780 (patch) | |
tree | 1d13c55219b3929517fb24f297958c8dd1b46d8e | |
parent | 4dd5d15a4ccd02507d72968f7d585ed79c442c51 (diff) | |
download | ydb-51674dac4bb91435ef6009fa104dfb835e158780.tar.gz |
BlobStorage version control system and UT,
Some more tests
Mechanism implemented, require some more tests
-rw-r--r-- | ydb/core/driver_lib/run/version.cpp | 257 | ||||
-rw-r--r-- | ydb/core/driver_lib/run/version.h | 18 | ||||
-rw-r--r-- | ydb/core/driver_lib/run/version_ut.cpp | 621 | ||||
-rw-r--r-- | ydb/core/protos/config.proto | 45 |
4 files changed, 941 insertions, 0 deletions
diff --git a/ydb/core/driver_lib/run/version.cpp b/ydb/core/driver_lib/run/version.cpp index a8dc6f825b..65be9c262c 100644 --- a/ydb/core/driver_lib/run/version.cpp +++ b/ydb/core/driver_lib/run/version.cpp @@ -1,6 +1,263 @@ #include <library/cpp/svnversion/svnversion.h> #include "version.h" + +NKikimrConfig::TCurrentCompatibilityInformation* CompatibilityInformation = nullptr; + +const NKikimrConfig::TCurrentCompatibilityInformation* GetCurrentCompatibilityInformation() { + static TSpinLock lock; + TGuard<TSpinLock> g(lock); + + if (!CompatibilityInformation) { + CompatibilityInformation = new NKikimrConfig::TCurrentCompatibilityInformation(); + // Look for protobuf message format in ydb/core/protos/config.proto + // To be changed in new release: + CompatibilityInformation->SetBuild("trunk"); + } + + return CompatibilityInformation; +} + + + +// Last stable YDB release, which doesn't include version control change +// When the compatibility information is not present in component's data, +// we assume component's version to be this version +NKikimrConfig::TStoredCompatibilityInformation* UnknownYdbRelease = nullptr; +const NKikimrConfig::TStoredCompatibilityInformation* GetUnknownYdbRelease() { + static TSpinLock lock; + TGuard<TSpinLock> g(lock); + + if (!UnknownYdbRelease) { + UnknownYdbRelease = new NKikimrConfig::TStoredCompatibilityInformation(); + UnknownYdbRelease->SetBuild("ydb"); + + auto* version = UnknownYdbRelease->MutableYdbVersion(); + version->SetYear(22); + version->SetMajor(5); + version->SetMinor(7); + version->SetHotfix(0); + } + + return UnknownYdbRelease; +} + +NKikimrConfig::TStoredCompatibilityInformation MakeStoredCompatibiltyInformation( + ui32 componentId, const NKikimrConfig::TCurrentCompatibilityInformation* current) { + Y_VERIFY(current); + + NKikimrConfig::TStoredCompatibilityInformation stored; + stored.SetBuild(current->GetBuild()); + if (current->HasYdbVersion()) { + stored.MutableYdbVersion()->CopyFrom(current->GetYdbVersion()); + } + + for (ui32 i = 0; i < current->StoresReadableBySize(); i++) { + auto rule = current->GetStoresReadableBy(i); + if (!rule.HasComponentId() || rule.GetComponentId() == componentId || + rule.GetComponentId() == (ui32)NKikimrConfig::TCompatibilityRule::Any) { + auto *newRule = stored.AddReadableBy(); + if (rule.HasBuild()) { + newRule->SetBuild(rule.GetBuild()); + } + newRule->MutableUpperLimit()->CopyFrom(rule.GetUpperLimit()); + newRule->MutableBottomLimit()->CopyFrom(rule.GetBottomLimit()); + newRule->SetForbidden(rule.GetForbidden()); + } + } + + return stored; +} + +NKikimrConfig::TStoredCompatibilityInformation MakeStoredCompatibiltyInformation(ui32 componentId) { + return MakeStoredCompatibiltyInformation(componentId, GetCurrentCompatibilityInformation()); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// YDB versions are compared alphabetically, much like strings, +// but instead of chars there are 4 componets: Year, Major, Minor and Hotfix +// Each of the version's components can be absent +// If one is, than all the following components are also considered to be 'absent' +// Absent component is equal to any other, including other absent +// +// Some examples: +// 22.1.1.1 < 22.1.2.0 +// 22.2.1.0 > 22.1._._ +// 23.1._._ == 23.1.1.0 +// +// Function returns -1 if left < right, 0 if left == right, 1 if left > right +i32 CompareVersions(const NKikimrConfig::TYdbVersion& left, const NKikimrConfig::TYdbVersion& right) { + if (!left.HasYear() || !right.HasYear()) { + return 0; + } + if (left.GetYear() < right.GetYear()) { + return -1; + } else if (left.GetYear() > right.GetYear()) { + return 1; + } + + if (!left.HasMajor() || !right.HasMajor()) { + return 0; + } + if (left.GetMajor() < right.GetMajor()) { + return -1; + } else if (left.GetMajor() > right.GetMajor()) { + return 1; + } + + if (!left.HasMinor() || !right.HasMinor()) { + return 0; + } + if (left.GetMinor() < right.GetMinor()) { + return -1; + } else if (left.GetMinor() > right.GetMinor()) { + return 1; + } + + if (!left.HasHotfix() || !right.HasHotfix()) { + return 0; + } + if (left.GetHotfix() < right.GetHotfix()) { + return -1; + } else if (left.GetHotfix() > right.GetHotfix()) { + return 1; + } + + return 0; +} + +// If StoredCompatibilityInformation is not present, we: +// compare current to UnknownYdbRelease, if current version is stable, otherwise +// we consider versions compatible +bool CheckNonPresent(const NKikimrConfig::TCurrentCompatibilityInformation* current, + ui32 componentId, TString& errorReason) { + if (!current->HasYdbVersion()) { + return true; + } + const auto* lastUnsupported = GetUnknownYdbRelease(); + Y_VERIFY(lastUnsupported); + TString errorReason1; + if (!CheckVersionCompatibility(current, lastUnsupported, componentId, errorReason1)) { + errorReason = "No stored YDB version found, last unsupported release is incompatible: " + errorReason1; + return false; + } else { + return true; + } +} + +// By default two stable versions are considered compatible, if their Year is the same +// and Major differ for no more, than 1, regardless of their Build +// Two unstable versions are compatible only if they have the same Build +// Stable and non-stable versions are not compatible by default +bool CheckDefaultRules(TString currentBuild, const NKikimrConfig::TYdbVersion* currentYdbVersion, + TString storedBuild, const NKikimrConfig::TYdbVersion* storedYdbVersion) { + if (!currentYdbVersion && !storedYdbVersion) { + return currentBuild == storedBuild; + } + if (currentYdbVersion && storedYdbVersion) { + if (!currentYdbVersion->HasYear() || !storedYdbVersion->HasYear()) { + return true; + } + if (!currentYdbVersion->HasMajor() || !storedYdbVersion->HasMajor()) { + return true; + } + return currentYdbVersion->GetYear() == storedYdbVersion->GetYear() && + std::abs((i32)currentYdbVersion->GetMajor() - (i32)storedYdbVersion->GetMajor()) <= 1; + } + + return false; +} + +bool CheckRule(TString build, const NKikimrConfig::TYdbVersion* version, + const NKikimrConfig::TCompatibilityRule& rule) { + if (rule.HasBuild()) { + if (rule.GetBuild() != build) { + return false; + } + if (version == nullptr) { + return true; + } + } else { + if (version == nullptr) { + return false; + } + } + + return (!rule.HasBottomLimit() || CompareVersions(*version, rule.GetBottomLimit()) > -1) && + (!rule.HasUpperLimit() || CompareVersions(*version, rule.GetUpperLimit()) < 1); +} + +bool CheckVersionCompatibility(const NKikimrConfig::TCurrentCompatibilityInformation* current, + const NKikimrConfig::TStoredCompatibilityInformation* stored, ui32 componentId, TString& errorReason) { + if (stored == nullptr) { + // version record is not found + return CheckNonPresent(current, componentId, errorReason); + } + + const auto currentBuild = current->GetBuild(); + const auto storedBuild = stored->GetBuild(); + const auto* currentYdbVersion = current->HasYdbVersion() ? ¤t->GetYdbVersion() : nullptr; + const auto* storedYdbVersion = stored->HasYdbVersion() ? &stored->GetYdbVersion() : nullptr; + + bool permitted = false; + bool useDefault = true; + + for (ui32 i = 0; i < current->CanLoadFromSize(); ++i) { + const auto rule = current->GetCanLoadFrom(i); + if (!rule.HasComponentId() || rule.GetComponentId() == componentId || + rule.GetComponentId() == (ui32)NKikimrConfig::TCompatibilityRule::Any) { + useDefault = false; + if (CheckRule(storedBuild, storedYdbVersion, rule)) { + if (rule.HasForbidden() && rule.GetForbidden()) { + errorReason = "Stored version is explicitly prohibited"; + return false; + } else { + permitted = true; + } + } + } + } + + for (ui32 i = 0; i < stored->ReadableBySize(); ++i) { + const auto rule = stored->GetReadableBy(i); + if (!rule.HasComponentId() || rule.GetComponentId() == componentId || + rule.GetComponentId() == (ui32)NKikimrConfig::TCompatibilityRule::Any) { + if (CheckRule(currentBuild, currentYdbVersion, rule)) { + useDefault = false; + if (rule.HasForbidden() && rule.GetForbidden()) { + errorReason = "Current version is explicitly prohibited"; + return false; + } else { + permitted = true; + } + } + } + } + + + if (permitted) { + return true; + } else { + if (useDefault) { + if (CheckDefaultRules(currentBuild, currentYdbVersion, storedBuild, storedYdbVersion)) { + return true; + } else { + errorReason = "Versions are not compatible by default rules"; + return false; + } + } + errorReason = "Versions are not compatible by given rule sets"; + return false; + } +} + +bool CheckVersionCompatibility(const NKikimrConfig::TStoredCompatibilityInformation* stored, + ui32 componentId, TString& errorReason) { + return CheckVersionCompatibility(GetCurrentCompatibilityInformation(), + stored, componentId, errorReason); +} + +// obsolete version control TMaybe<NActors::TInterconnectProxyCommon::TVersionInfo> VERSION = NActors::TInterconnectProxyCommon::TVersionInfo{ // version of this binary "trunk", diff --git a/ydb/core/driver_lib/run/version.h b/ydb/core/driver_lib/run/version.h index 27230577aa..644c518c37 100644 --- a/ydb/core/driver_lib/run/version.h +++ b/ydb/core/driver_lib/run/version.h @@ -1,7 +1,25 @@ #pragma once #include <library/cpp/actors/interconnect/interconnect_common.h> +#include <ydb/core/protos/config.pb.h> +const NKikimrConfig::TCurrentCompatibilityInformation* GetCurrentCompatibilityInformation(); +const NKikimrConfig::TStoredCompatibilityInformation* GetUnknownYdbRelease(); + +NKikimrConfig::TStoredCompatibilityInformation MakeStoredCompatibiltyInformation(ui32 componentId, + const NKikimrConfig::TCurrentCompatibilityInformation* current); + +NKikimrConfig::TStoredCompatibilityInformation MakeStoredCompatibiltyInformation(ui32 componentId); + +bool CheckVersionCompatibility(const NKikimrConfig::TCurrentCompatibilityInformation* current, + const NKikimrConfig::TStoredCompatibilityInformation* stored, + ui32 componentId, TString& errorReason); + +bool CheckVersionCompatibility(const NKikimrConfig::TStoredCompatibilityInformation* stored, + ui32 componentId, TString& errorReason); + +// obsolete version control +// TODO: remove in the next major release extern TMaybe<NActors::TInterconnectProxyCommon::TVersionInfo> VERSION; void CheckVersionTag(); diff --git a/ydb/core/driver_lib/run/version_ut.cpp b/ydb/core/driver_lib/run/version_ut.cpp index 319f7e5266..3eaf55ed8a 100644 --- a/ydb/core/driver_lib/run/version_ut.cpp +++ b/ydb/core/driver_lib/run/version_ut.cpp @@ -9,3 +9,624 @@ Y_UNIT_TEST_SUITE(VersionParser) { UNIT_ASSERT_VALUES_EQUAL(GetBranchName("svn://arcadia/arc/branches/kikimr/arcadia"), "branches/kikimr"); } } + +Y_UNIT_TEST_SUITE(YdbVersion) { + struct TYdbVersion { + std::optional<ui32> Year; + std::optional<ui32> Major; + std::optional<ui32> Minor; + std::optional<ui32> Hotfix; + + NKikimrConfig::TYdbVersion ToPB() { + NKikimrConfig::TYdbVersion res; + if (Year) { + res.SetYear(*Year); + } + if (Major) { + res.SetMajor(*Major); + } + if (Minor) { + res.SetMinor(*Minor); + } + if (Hotfix) { + res.SetHotfix(*Hotfix); + } + + return res; + } + }; + + struct TCompatibilityRule { + std::optional<std::string> Build; + std::optional<TYdbVersion> BottomLimit; + std::optional<TYdbVersion> UpperLimit; + std::optional<ui32> ComponentId; + std::optional<bool> Forbidden; + + NKikimrConfig::TCompatibilityRule ToPB() { + NKikimrConfig::TCompatibilityRule res; + if (Build) { + res.SetBuild(Build->data()); + } + if (BottomLimit) { + res.MutableBottomLimit()->CopyFrom(BottomLimit->ToPB()); + } + if (UpperLimit) { + res.MutableUpperLimit()->CopyFrom(UpperLimit->ToPB()); + } + if (ComponentId) { + res.SetComponentId(*ComponentId); + } + if (Forbidden) { + res.SetForbidden(*Forbidden); + } + + return res; + } + }; + + struct TCurrentCompatibilityInformation { + std::string Build = "ydb"; + std::optional<TYdbVersion> YdbVersion; + std::vector<TCompatibilityRule> CanLoadFrom; + std::vector<TCompatibilityRule> StoresReadableBy; + + NKikimrConfig::TCurrentCompatibilityInformation ToPB() { + NKikimrConfig::TCurrentCompatibilityInformation res; + res.SetBuild(Build.data()); + if (YdbVersion) { + res.MutableYdbVersion()->CopyFrom(YdbVersion->ToPB()); + } + + for (auto canLoadFrom : CanLoadFrom) { + res.AddCanLoadFrom()->CopyFrom(canLoadFrom.ToPB()); + } + for (auto storesReadableBy : StoresReadableBy) { + res.AddStoresReadableBy()->CopyFrom(storesReadableBy.ToPB()); + } + + return res; + } + }; + + struct TStoredCompatibilityInformation { + std::string Build = "ydb"; + std::optional<TYdbVersion> YdbVersion; + std::vector<TCompatibilityRule> ReadableBy; + + NKikimrConfig::TStoredCompatibilityInformation ToPB() { + NKikimrConfig::TStoredCompatibilityInformation res; + res.SetBuild(Build.data()); + if (YdbVersion) { + res.MutableYdbVersion()->CopyFrom(YdbVersion->ToPB()); + } + + for (auto readableBy : ReadableBy) { + res.AddReadableBy()->CopyFrom(readableBy.ToPB()); + } + + return res; + } + }; + + void Test(TCurrentCompatibilityInformation current, TCurrentCompatibilityInformation store, bool expected) { + TString errorReason; + auto currentPB = current.ToPB(); + auto storePB = store.ToPB(); + auto storedPB = MakeStoredCompatibiltyInformation((ui32)NKikimrConfig::TCompatibilityRule::Test1, &storePB); + UNIT_ASSERT_EQUAL_C(CheckVersionCompatibility(¤tPB, &storedPB, + (ui32)NKikimrConfig::TCompatibilityRule::Test1, errorReason), expected, errorReason); + } + + Y_UNIT_TEST(DefaultSameVersion) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 1, .Hotfix = 0 } + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 1, .Hotfix = 0 } + }, + true + ); + } + Y_UNIT_TEST(DefaultPrevMajor) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 2, .Minor = 1, .Hotfix = 0 } + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 1, .Hotfix = 10 } + }, + true + ); + } + Y_UNIT_TEST(DefaultNextMajor) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 8, .Hotfix = 0 } + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 2, .Minor = 1, .Hotfix = 0 } + }, + true + ); + } + Y_UNIT_TEST(DefaultHotfix) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 1, .Hotfix = 10 } + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 1, .Hotfix = 0 } + }, + true + ); + } + Y_UNIT_TEST(DefaultCompatible) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 2, .Minor = 1, .Hotfix = 10 } + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 10, .Hotfix = 0 } + }, + true + ); + } + Y_UNIT_TEST(DefaultNextYear) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 2, .Major = 1, .Minor = 1, .Hotfix = 0 } + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 1, .Hotfix = 0 } + }, + false + ); + } + Y_UNIT_TEST(DefaultPrevYear) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 1, .Hotfix = 0 } + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 2, .Major = 1, .Minor = 1, .Hotfix = 0 } + }, + false + ); + } + Y_UNIT_TEST(DefaultNewMajor) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 1, .Hotfix = 0 } + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 3, .Hotfix = 0 } + }, + false + ); + } + Y_UNIT_TEST(DefaultOldMajor) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 1, .Hotfix = 0 } + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 1, .Hotfix = 0 } + }, + false + ); + } + Y_UNIT_TEST(DefaultDifferentBuild) { + Test( + TCurrentCompatibilityInformation{ + .Build = "ydb", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 1, .Hotfix = 0 } + }, + TCurrentCompatibilityInformation{ + .Build = "nbs", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 2, .Minor = 1, .Hotfix = 0 } + }, + true + ); + } + Y_UNIT_TEST(DefaultDifferentBuildIncompatible) { + Test( + TCurrentCompatibilityInformation{ + .Build = "ydb", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 1, .Hotfix = 0 }, + }, + TCurrentCompatibilityInformation{ + .Build = "nbs", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 1, .Hotfix = 0 }, + }, + false + ); + } + Y_UNIT_TEST(LimitOld) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 2, .Minor = 1, .Hotfix = 0 }, + .CanLoadFrom = { + TCompatibilityRule{ + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 1 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 3 }, + .Forbidden = true + } + } + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 2, .Hotfix = 1 } + }, + false + ); + } + Y_UNIT_TEST(LimitNew) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 1, .Hotfix = 3 }, + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 2, .Minor = 2, .Hotfix = 0 }, + .StoresReadableBy = { + TCompatibilityRule{ + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 1 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 2, .Minor = 1 }, + .Forbidden = true + } + } + }, + false + ); + } + Y_UNIT_TEST(CurrentCanLoadFrom) { + Test( + TCurrentCompatibilityInformation{ + .Build = "ydb", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 1, .Hotfix = 0 }, + .CanLoadFrom = { + TCompatibilityRule{ + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 1 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 1, .Hotfix = 0 } + } + } + }, + TCurrentCompatibilityInformation{ + .Build = "nbs", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 3, .Hotfix = 1 } + }, + true + ); + } + Y_UNIT_TEST(CurrentCanLoadFromAllOlder) { + Test( + TCurrentCompatibilityInformation{ + .Build = "ydb", + .YdbVersion = TYdbVersion{ .Year = 2, .Major = 4, .Minor = 1, .Hotfix = 0 }, + .CanLoadFrom = { + TCompatibilityRule{ + .UpperLimit = TYdbVersion{ .Year = 2, .Major = 4, .Minor = 1, .Hotfix = 0 } + } + } + }, + TCurrentCompatibilityInformation{ + .Build = "nbs", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 3, .Hotfix = 1 } + }, + true + ); + } + Y_UNIT_TEST(CurrentCanLoadFromIncompatible) { + Test( + TCurrentCompatibilityInformation{ + .Build = "ydb", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 1, .Hotfix = 0 }, + .CanLoadFrom = { + TCompatibilityRule{ + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 2 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 1, .Hotfix = 0 } + } + } + }, + TCurrentCompatibilityInformation{ + .Build = "nbs", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 3, .Hotfix = 1 } + }, + false + ); + } + Y_UNIT_TEST(CurrentStoresReadableBy) { + Test( + TCurrentCompatibilityInformation{ + .Build = "ydb", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 1, .Hotfix = 0 }, + .StoresReadableBy = { + TCompatibilityRule{ + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 1 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 1, .Hotfix = 0 } + } + } + }, + TCurrentCompatibilityInformation{ + .Build = "nbs", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 3, .Hotfix = 1 } + }, + false + ); + } + Y_UNIT_TEST(StoredReadableBy) { + Test( + TCurrentCompatibilityInformation{ + .Build = "ydb", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 2, .Hotfix = 0 } + }, + TCurrentCompatibilityInformation{ + .Build = "nbs", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 3, .Hotfix = 1 }, + .StoresReadableBy = { + TCompatibilityRule{ + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 1 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 3, .Hotfix = 1 } + } + } + }, + true + ); + } + Y_UNIT_TEST(StoredReadableByIncompatible) { + Test( + TCurrentCompatibilityInformation{ + .Build = "ydb", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 2, .Hotfix = 0 } + }, + TCurrentCompatibilityInformation{ + .Build = "nbs", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 3, .Hotfix = 1 }, + .StoresReadableBy = { + TCompatibilityRule{ + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 3, .Hotfix = 1 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 3, .Hotfix = 1 } + } + } + }, + false + ); + } + Y_UNIT_TEST(StoredWithRules) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 4, .Minor = 1, .Hotfix = 0 } + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 3, .Hotfix = 1 }, + .StoresReadableBy = { + TCompatibilityRule{ + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 3 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 3, .Hotfix = 1 } + } + } + }, + true + ); + } + Y_UNIT_TEST(StoredWithRulesIncompatible) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 5, .Minor = 1, .Hotfix = 0 } + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 3, .Hotfix = 1 }, + .StoresReadableBy = { + TCompatibilityRule{ + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 3 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 3, .Hotfix = 1 } + } + } + }, + false + ); + } + Y_UNIT_TEST(OldNbsStored) { + Test( + TCurrentCompatibilityInformation{ + .Build = "nbs", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 2, .Hotfix = 0 } + }, + TCurrentCompatibilityInformation{ + .Build = "ydb", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 3, .Hotfix = 1 }, + .StoresReadableBy = { + TCompatibilityRule{ + .Build = "nbs", + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 1 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 3, .Hotfix = 1 } + } + } + }, + true + ); + } + Y_UNIT_TEST(OldNbsIncompatibleStored) { + Test( + TCurrentCompatibilityInformation{ + .Build = "ydb", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 2, .Hotfix = 0 } + }, + TCurrentCompatibilityInformation{ + .Build = "ydb", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 3, .Hotfix = 1 }, + .StoresReadableBy = { + TCompatibilityRule{ + .Build = "nbs", + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 1 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 3, .Hotfix = 1 } + } + } + }, + false + ); + } + Y_UNIT_TEST(NewNbsCurrent) { + Test( + TCurrentCompatibilityInformation{ + .Build = "nbs", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 2, .Hotfix = 0 }, + .CanLoadFrom = { + TCompatibilityRule{ + .Build = "ydb", + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 1 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 2, .Hotfix = 0 } + } + } + }, + TCurrentCompatibilityInformation{ + .Build = "ydb", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 3, .Hotfix = 2 }, + }, + true + ); + } + Y_UNIT_TEST(NewNbsIncompatibleCurrent) { + Test( + TCurrentCompatibilityInformation{ + .Build = "nbs", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 2, .Hotfix = 0 }, + .CanLoadFrom = { + TCompatibilityRule{ + .Build = "ydb", + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 1 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 2, .Hotfix = 0 } + } + } + }, + TCurrentCompatibilityInformation{ + .Build = "nbs", + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 3, .Hotfix = 2 }, + }, + false + ); + } + Y_UNIT_TEST(OneAcceptedVersion) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 3, .Minor = 2, .Hotfix = 0 }, + .CanLoadFrom = { + TCompatibilityRule{ + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 3, .Hotfix = 2 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 3, .Hotfix = 2 } + } + } + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 3, .Hotfix = 2 }, + }, + true + ); + } + Y_UNIT_TEST(ForbiddenMinor) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 2, .Minor = 2, .Hotfix = 0 }, + .CanLoadFrom = { + TCompatibilityRule{ + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 3 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 3 }, + .Forbidden = true + } + } + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 1, .Minor = 3, .Hotfix = 1 }, + }, + false + ); + } + Y_UNIT_TEST(ExtraAndForbidden) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 4, .Minor = 2, .Hotfix = 0 }, + .CanLoadFrom = { + TCompatibilityRule{ + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 1 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 4, .Minor = 2, .Hotfix = 0 }, + }, + TCompatibilityRule{ + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 2, .Minor = 3 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 2, .Minor = 3 }, + .Forbidden = true + } + } + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 2, .Minor = 3, .Hotfix = 0 }, + }, + false + ); + } + Y_UNIT_TEST(SomeRulesAndOtherForbidden) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 4, .Minor = 2, .Hotfix = 0 }, + .CanLoadFrom = { + TCompatibilityRule{ + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 1 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 4, .Minor = 2, .Hotfix = 0 }, + }, + TCompatibilityRule{ + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 2, .Minor = 4 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 2, .Minor = 4 }, + .Forbidden = true + } + } + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 2, .Minor = 3, .Hotfix = 0 }, + }, + true + ); + } + Y_UNIT_TEST(Component) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 4, .Minor = 2, .Hotfix = 0 }, + .CanLoadFrom = { + TCompatibilityRule{ + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 1 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 4, .Minor = 2, .Hotfix = 0 }, + .ComponentId = (ui32)NKikimrConfig::TCompatibilityRule::Test1, + }, + } + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 2, .Minor = 3, .Hotfix = 0 }, + }, + true + ); + } + Y_UNIT_TEST(OtherComponent) { + Test( + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 4, .Minor = 2, .Hotfix = 0 }, + .CanLoadFrom = { + TCompatibilityRule{ + .BottomLimit = TYdbVersion{ .Year = 1, .Major = 1 }, + .UpperLimit = TYdbVersion{ .Year = 1, .Major = 4, .Minor = 2, .Hotfix = 0 }, + .ComponentId = (ui32)NKikimrConfig::TCompatibilityRule::Test2, + }, + } + }, + TCurrentCompatibilityInformation{ + .YdbVersion = TYdbVersion{ .Year = 1, .Major = 2, .Minor = 3, .Hotfix = 0 }, + }, + false + ); + } + + Y_UNIT_TEST(CompatibleWithSelf) { + auto* current = GetCurrentCompatibilityInformation(); + auto stored = MakeStoredCompatibiltyInformation((ui32)NKikimrConfig::TCompatibilityRule::Test1); + TString errorReason; + UNIT_ASSERT_C(CheckVersionCompatibility(current, &stored, + (ui32)NKikimrConfig::TCompatibilityRule::Test1, errorReason), errorReason); + } +} diff --git a/ydb/core/protos/config.proto b/ydb/core/protos/config.proto index a8d488a77d..bcfc2eedbf 100644 --- a/ydb/core/protos/config.proto +++ b/ydb/core/protos/config.proto @@ -1725,3 +1725,48 @@ message TAppConfig { optional TConfigVersion Version = 102; } + +message TYdbVersion { + optional uint32 Year = 1; + optional uint32 Major = 2; + optional uint32 Minor = 3; + optional uint32 Hotfix = 4; +} + +message TCompatibilityRule { + enum EComponentId { + Any = 0; + Test1 = 1; + Test2 = 2; + } + + optional string Build = 1; + optional TYdbVersion BottomLimit = 2; + optional TYdbVersion UpperLimit = 3; + + // don't use enum, because stored data can have values from newer YDB versions, + // which are not included in current version + optional uint32 ComponentId = 4; + + // don't use Forbidden until it's absolutely necessary + optional bool Forbidden = 5 [default = false]; +} + +message TCurrentCompatibilityInformation { + required string Build = 1; + + // if YdbVersion is empty, build is assumed to be non-stable + optional TYdbVersion YdbVersion = 2; + + repeated TCompatibilityRule CanLoadFrom = 3; + repeated TCompatibilityRule StoresReadableBy = 4; +} + +message TStoredCompatibilityInformation { + required string Build = 1; + + // if YdbVersion is empty, build is assumed to be non-stable + optional TYdbVersion YdbVersion = 2; + + repeated TCompatibilityRule ReadableBy = 3; +} |