aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorserg-belyakov <serg-belyakov@yandex-team.com>2023-01-17 13:14:06 +0300
committerserg-belyakov <serg-belyakov@yandex-team.com>2023-01-17 13:14:06 +0300
commit51674dac4bb91435ef6009fa104dfb835e158780 (patch)
tree1d13c55219b3929517fb24f297958c8dd1b46d8e
parent4dd5d15a4ccd02507d72968f7d585ed79c442c51 (diff)
downloadydb-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.cpp257
-rw-r--r--ydb/core/driver_lib/run/version.h18
-rw-r--r--ydb/core/driver_lib/run/version_ut.cpp621
-rw-r--r--ydb/core/protos/config.proto45
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() ? &current->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(&currentPB, &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;
+}