Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

migration: introduce fence versions #57186

Merged
merged 2 commits into from
Nov 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/generated/settings/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,6 @@
<tr><td><code>trace.debug.enable</code></td><td>boolean</td><td><code>false</code></td><td>if set, traces for recent requests can be seen in the /debug page</td></tr>
<tr><td><code>trace.lightstep.token</code></td><td>string</td><td><code></code></td><td>if set, traces go to Lightstep using this token</td></tr>
<tr><td><code>trace.zipkin.collector</code></td><td>string</td><td><code></code></td><td>if set, traces go to the given Zipkin instance (example: '127.0.0.1:9411'); ignored if trace.lightstep.token is set</td></tr>
<tr><td><code>version</code></td><td>version</td><td><code>20.2-2</code></td><td>set the active cluster version in the format '<major>.<minor>'</td></tr>
<tr><td><code>version</code></td><td>version</td><td><code>20.2-4</code></td><td>set the active cluster version in the format '<major>.<minor>'</td></tr>
</tbody>
</table>
1 change: 1 addition & 0 deletions pkg/clusterversion/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ go_test(
"//pkg/roachpb",
"//pkg/util/leaktest",
"//vendor/github.com/cockroachdb/redact",
"//vendor/github.com/dustin/go-humanize",
"//vendor/github.com/stretchr/testify/require",
],
)
17 changes: 16 additions & 1 deletion pkg/clusterversion/clusterversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,13 +233,28 @@ func (cv ClusterVersion) IsActive(versionKey VersionKey) bool {
return cv.IsActiveVersion(v)
}

func (cv ClusterVersion) String() string { return redact.StringWithoutMarkers(cv) }
func (cv ClusterVersion) String() string {
return redact.StringWithoutMarkers(cv)
}

// SafeFormat implements the redact.SafeFormatter interface.
func (cv ClusterVersion) SafeFormat(p redact.SafePrinter, _ rune) {
p.Print(cv.Version)
}

// PrettyPrint returns the value in a format that makes it apparent whether or
// not it is a fence version.
func (cv ClusterVersion) PrettyPrint() string {
// If we're a version greater than v20.2 and have an odd internal version,
// we're a fence version. See fenceVersionFor in pkg/migration to understand
// what these are.
fenceVersion := !cv.Version.LessEq(roachpb.Version{Major: 20, Minor: 2}) && (cv.Internal%2) == 1
if !fenceVersion {
return cv.String()
}
return redact.Sprintf("%s%s", cv.String(), "(fence)").StripMarkers()
}

// ClusterVersionImpl implements the settings.ClusterVersionImpl interface.
func (cv ClusterVersion) ClusterVersionImpl() {}

Expand Down
27 changes: 23 additions & 4 deletions pkg/clusterversion/cockroach_versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ type VersionKey int
// frequent release schedule.
//
// When introducing a version constant, you'll want to:
// (1) Add it at the end of this block
// (1) Add it at the end of this block. For versions introduced during and
// after the 21.1 release, Internal versions must be even-numbered. The
// odd versions are used for internal book-keeping.
// (2) Add it at the end of the `versionsSingleton` block below.
//
// ---
Expand Down Expand Up @@ -364,14 +366,14 @@ var versionsSingleton = keyedVersions([]keyedVersion{
Version: roachpb.Version{Major: 20, Minor: 2},
},

// v21.1 versions.
// v21.1 versions. Internal versions defined here-on-forth must be even.
{
Key: VersionStart21_1,
Version: roachpb.Version{Major: 20, Minor: 2, Internal: 1},
Version: roachpb.Version{Major: 20, Minor: 2, Internal: 2},
},
{
Key: VersionEmptyArraysInInvertedIndexes,
Version: roachpb.Version{Major: 20, Minor: 2, Internal: 2},
Version: roachpb.Version{Major: 20, Minor: 2, Internal: 4},
},

// Step (2): Add new versions here.
Expand All @@ -398,3 +400,20 @@ var (
func VersionByKey(key VersionKey) roachpb.Version {
return versionsSingleton.MustByKey(key)
}

// GetVersionsBetween returns the list of cluster versions in the range
// (from, to].
func GetVersionsBetween(from, to ClusterVersion) []ClusterVersion {
return getVersionBetweenInternal(from, to, versionsSingleton)
}

func getVersionBetweenInternal(from, to ClusterVersion, vs keyedVersions) []ClusterVersion {
var cvs []ClusterVersion
for _, keyedV := range vs {
// Read: "from < keyedV <= to".
if from.Less(keyedV.Version) && keyedV.Version.LessEq(to.Version) {
cvs = append(cvs, ClusterVersion{Version: keyedV.Version})
}
}
return cvs
}
81 changes: 81 additions & 0 deletions pkg/clusterversion/cockroach_versions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/roachpb"
"github.com/cockroachdb/cockroach/pkg/util/leaktest"
"github.com/cockroachdb/redact"
"github.com/dustin/go-humanize"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -48,3 +49,83 @@ func TestVersionFormat(t *testing.T) {
t.Errorf("expected %q, got %q", expected, actual)
}
}

func TestClusterVersionPrettyPrint(t *testing.T) {
defer leaktest.AfterTest(t)()

cv := func(major, minor, patch, internal int32) ClusterVersion {
return ClusterVersion{
Version: roachpb.Version{
Major: major,
Minor: minor,
Patch: patch,
Internal: internal,
},
}
}

var tests = []struct {
cv ClusterVersion
exp string
}{
{cv(19, 2, 1, 5), "19.2-5"},
{cv(20, 1, 0, 4), "20.1-4"},
{cv(20, 2, 0, 7), "20.2-7(fence)"},
{cv(20, 2, 0, 4), "20.2-4"},
{cv(20, 2, 1, 5), "20.2-5(fence)"},
{cv(20, 2, 1, 4), "20.2-4"},
}
for _, test := range tests {
if actual := test.cv.PrettyPrint(); actual != test.exp {
t.Errorf("expected %s, got %q", test.exp, actual)
}
}
}

func TestGetVersionsBetween(t *testing.T) {
defer leaktest.AfterTest(t)()

// Define a list of versions v3..v9
var vs keyedVersions
for i := 3; i < 10; i++ {
vs = append(vs, keyedVersion{
Key: VersionKey(42),
Version: roachpb.Version{Major: int32(i)},
})
}
cv := func(major int32) ClusterVersion {
return ClusterVersion{Version: roachpb.Version{Major: major}}
}
list := func(first, last int32) []ClusterVersion {
var cvs []ClusterVersion
for i := first; i <= last; i++ {
cvs = append(cvs, cv(i))
}
return cvs
}

var tests = []struct {
from, to ClusterVersion
exp []ClusterVersion
}{
{cv(5), cv(8), list(6, 8)},
{cv(1), cv(1), []ClusterVersion{}},
{cv(7), cv(7), []ClusterVersion{}},
{cv(1), cv(5), list(3, 5)},
{cv(6), cv(12), list(7, 9)},
{cv(4), cv(5), list(5, 5)},
}

for _, test := range tests {
actual := getVersionBetweenInternal(test.from, test.to, vs)
if len(actual) != len(test.exp) {
t.Errorf("expected %d versions, got %d", len(test.exp), len(actual))
}

for i := range test.exp {
if actual[i] != test.exp[i] {
t.Errorf("%s version incorrect: expected %s, got %s", humanize.Ordinal(i), test.exp[i], actual[i])
}
}
}
}
39 changes: 32 additions & 7 deletions pkg/clusterversion/keyed_versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,17 @@ func (kv keyedVersions) MustByKey(k VersionKey) roachpb.Version {
// Validate makes sure that the keyedVersions are sorted chronologically, that
// their keys correspond to their position in the list, and that no obsolete
// versions (i.e. known to always be active) are present.
//
// For versions introduced in v21.1 and beyond, the internal versions must be
// even.
func (kv keyedVersions) Validate() error {
type majorMinor struct {
major, minor int32
vs []keyedVersion
}
// byRelease maps major.minor to a slice of versions that were first
// released right after major.minor. For example, a version 2.1-12 would
// first be released in 19.1, and would be slotted under 2.1. We'll need
// released right after major.minor. For example, a version 20.1-12 would
// first be released in 20.2, and would be slotted under 20.1. We'll need
// this to determine which versions are always active with a binary built
// from the current SHA.
var byRelease []majorMinor
Expand Down Expand Up @@ -78,13 +81,13 @@ func (kv keyedVersions) Validate() error {

// Iterate through all versions known to be active. For example, if
//
// byRelease = ["2.0", "2.1", "19.1"]
// byRelease = ["19.1", "19.2", "20.1", "20.2"]
//
// then we know that the current release cycle is 19.2, so mixed version
// clusters are running at least 19.1, so anything slotted under 2.1 (like
// 2.1-12) and 2.0 is always-on. To avoid interfering with backports, we're
// then we know that the current release cycle is 21.1, so mixed version
// clusters are running at least 20.2, so anything slotted under 20.1 (like
// 20.1-12) and 19.2 is always-on. To avoid interfering with backports, we're
// a bit more lenient and allow one more release cycle until validation fails.
// In the above example, we would tolerate 2.1-x but not 2.0-x.
// In the above example, we would tolerate 20.1-x but not 19.2-x.
// Currently we're actually a few versions behind in enforcing a ban on old
// versions/migrations. See #47447.
if n := len(byRelease) - 5; n >= 0 {
Expand All @@ -107,5 +110,27 @@ func (kv keyedVersions) Validate() error {
buf.String(),
)
}

// Check to see that for versions introduced in v21.1 and beyond, the
// internal versions are always even. The odd versions are used for internal
// book-keeping.
for _, release := range byRelease {
// v21.1 versions (20.2-x) will be slotted under 20.2. Ignore all other
// releases.
if release.major < 20 {
continue
}
if release.major == 20 && release.minor == 1 {
continue
}

for _, v := range release.vs {
if (v.Internal % 2) != 0 {
return errors.Errorf("found version %s with odd-numbered internal version (%s);"+
" versions introduced in 21.1+ must have even-numbered internal versions", v.Key, v.Version)
}
}
}

return nil
}
Loading