Skip to content

Commit

Permalink
generalize new fields introduced in higher versions.
Browse files Browse the repository at this point in the history
Signed-off-by: Siyuan Zhang <sizhang@google.com>
  • Loading branch information
siyuanfoundation committed Apr 30, 2024
1 parent ca3d48c commit 892abc2
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 17 deletions.
19 changes: 12 additions & 7 deletions server/storage/schema/changes.go
Expand Up @@ -21,17 +21,22 @@ type schemaChange interface {
downgradeAction() action
}

// addNewField represents adding new field when upgrading. Downgrade will remove the field.
func addNewField(bucket backend.Bucket, fieldName []byte, fieldValue []byte) schemaChange {
type NewField struct {
Bucket backend.Bucket
FieldName []byte
FieldValue []byte
}

func (f *NewField) schemaChange() schemaChange {
return simpleSchemaChange{
upgrade: setKeyAction{
Bucket: bucket,
FieldName: fieldName,
FieldValue: fieldValue,
Bucket: f.Bucket,
FieldName: f.FieldName,
FieldValue: f.FieldValue,
},
downgrade: deleteKeyAction{
Bucket: bucket,
FieldName: fieldName,
Bucket: f.Bucket,
FieldName: f.FieldName,
},
}
}
Expand Down
2 changes: 1 addition & 1 deletion server/storage/schema/changes_test.go
Expand Up @@ -30,7 +30,7 @@ func TestUpgradeDowngrade(t *testing.T) {
}{
{
name: "addNewField empty",
change: addNewField(Meta, []byte("/test"), []byte("1")),
change: (&NewField{Meta, []byte("/test"), []byte("1")}).schemaChange(),
expectStateAfterUpgrade: map[string]string{"/test": "1"},
},
}
Expand Down
29 changes: 26 additions & 3 deletions server/storage/schema/schema.go
Expand Up @@ -123,14 +123,37 @@ func schemaChangesForVersion(v semver.Version, isUpgrade bool) ([]schemaChange,
return actions, nil
}

func NewFieldsForVersion(v semver.Version) []NewField {
if newFields, found := newFieldsMapping[v]; found {
return newFields
}
return nil
}

func newFieldMappingsToSchemaChanges(newFieldMap map[semver.Version][]NewField) map[semver.Version][]schemaChange {
schemaChangeMap := map[semver.Version][]schemaChange{}
for ver, newFields := range newFieldMap {
changes := []schemaChange{}
for _, f := range newFields {
changes = append(changes, f.schemaChange())
}
schemaChangeMap[ver] = changes
}
return schemaChangeMap
}

var (
// schemaChanges list changes that were introduced in a particular version.
// newFieldsMapping list new fields that were introduced in a particular version.
// schema was introduced in v3.6 as so its changes were not tracked before.
schemaChanges = map[semver.Version][]schemaChange{
newFieldsMapping = map[semver.Version][]NewField{
version.V3_6: {
addNewField(Meta, MetaStorageVersionName, emptyStorageVersion),
{Meta, MetaStorageVersionName, emptyStorageVersion},
},
}
// schemaChanges list changes that were introduced in a particular version.
// schema was introduced in v3.6 as so its changes were not tracked before.
schemaChanges = newFieldMappingsToSchemaChanges(newFieldsMapping)

// emptyStorageVersion is used for v3.6 Step for the first time, in all other version StoragetVersion should be set by migrator.
// Adding a addNewField for StorageVersion we can reuse logic to remove it when downgrading to v3.5
emptyStorageVersion = []byte("")
Expand Down
16 changes: 10 additions & 6 deletions tests/framework/e2e/etcd_process.go
Expand Up @@ -31,7 +31,6 @@ import (
"github.com/coreos/go-semver/semver"
"go.uber.org/zap"

"go.etcd.io/etcd/api/v3/version"
"go.etcd.io/etcd/client/pkg/v3/fileutil"
"go.etcd.io/etcd/pkg/v3/expect"
"go.etcd.io/etcd/pkg/v3/proxy"
Expand Down Expand Up @@ -279,12 +278,17 @@ func (ep *EtcdServerProcess) VerifySchemaVersion(lg *zap.Logger) error {
if currentEtcdVer.LessThan(ver) || ver.LessThan(prevEtcdVer) {
return fmt.Errorf("expect backend schema version to be between [%s, %s], but got %s", prevEtcdVer.String(), currentEtcdVer.String(), ver.String())
}
// check new fields introduced in V3_6 do not exist in V3_5 data file.
// V3_6 contains all the fields in V3_5, so no need to check for V3_6 servers.
if *currentEtcdVer == version.V3_5 {
_, vs := be.BatchTx().UnsafeRange(schema.Meta, schema.MetaStorageVersionName, nil, 1)
// storage schema is generally backward compatible. No need to check the buckets for higher version.
if ep.cfg.ExecPath == BinPath.Etcd {
return nil
}
lg.Info("verify no new storage schema field is present in the db file of last release process")
nextEtcdVer := semver.Version{Major: currentEtcdVer.Major, Minor: currentEtcdVer.Minor + 1}
newFields := schema.NewFieldsForVersion(nextEtcdVer)
for _, f := range newFields {
_, vs := be.BatchTx().UnsafeRange(f.Bucket, f.FieldName, nil, 1)
if len(vs) != 0 {
return fmt.Errorf("expect storageVersion not exist in the meta bucket, but got %s", string(vs[0]))
return fmt.Errorf("expect %s not exist in the %s bucket, but got %s", f.Bucket.Name(), f.FieldName, vs[0])
}
}
return nil
Expand Down

0 comments on commit 892abc2

Please sign in to comment.