Skip to content

Commit 7c77dae

Browse files
committed
update: bump descriptor versions during repair
Previously, the post deserialization repair incorrectly wrote the descriptors at the exact same version. While the leasing manager will tolerate this for non-historical descriptors, any historical queries can end up failing after the first upgrade. This patch adds a version bump when running post deserialization changes to avoid these issues. Fixes: #153358 Release note: None
1 parent 4fe5b55 commit 7c77dae

File tree

2 files changed

+43
-15
lines changed

2 files changed

+43
-15
lines changed

pkg/upgrade/upgrades/first_upgrade.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,11 @@ func upgradeDescriptors(
127127
}
128128
b := txn.KV().NewBatch()
129129
for _, mut := range muts {
130-
if !mut.GetPostDeserializationChanges().HasChanges() {
130+
// Both newly created and altered descriptors never write the modification time
131+
// to storage. This post-deserialization change is always expected now.
132+
changes := mut.GetPostDeserializationChanges()
133+
hasChanges := changes.Len() > 1 || !changes.Contains(catalog.SetModTimeToMVCCTimestamp)
134+
if !hasChanges {
131135
// In the upgrade to 25.4, we do a one-time rewrite of all
132136
// descriptors in order to upgrade them to use the new type
133137
// serialization format.
@@ -137,6 +141,7 @@ func upgradeDescriptors(
137141
}
138142
}
139143
key := catalogkeys.MakeDescMetadataKey(d.Codec, mut.GetID())
144+
mut.MaybeIncrementVersion()
140145
b.CPut(key, mut.DescriptorProto(), mut.GetRawBytesInStorage())
141146
}
142147
return txn.KV().Run(ctx, b)

pkg/upgrade/upgrades/first_upgrade_test.go

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,16 @@ func TestFirstUpgrade(t *testing.T) {
7979
"USE test",
8080
"CREATE TABLE foo (i INT PRIMARY KEY, j INT, INDEX idx(j))",
8181
)
82-
82+
// Select a timestamp for when the tables were created.
83+
startTime := testServer.Clock().Now()
8384
// Corrupt the table descriptor in an unrecoverable manner. We are not able to automatically repair this
8485
// descriptor.
8586
tbl := desctestutils.TestingGetPublicTableDescriptor(kvDB, keys.SystemSQLCodec, "test", "foo")
8687
descKey := catalogkeys.MakeDescMetadataKey(keys.SystemSQLCodec, tbl.GetID())
8788
require.NoError(t, kvDB.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error {
8889
mut := tabledesc.NewBuilder(tbl.TableDesc()).BuildExistingMutableTable()
8990
mut.NextIndexID = 1
91+
mut.MaybeIncrementVersion()
9092
return txn.Put(ctx, descKey, mut.DescriptorProto())
9193
}))
9294

@@ -106,6 +108,8 @@ func TestFirstUpgrade(t *testing.T) {
106108
require.NoError(t, kvDB.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error {
107109
mut := tabledesc.NewBuilder(tbl.TableDesc()).BuildExistingMutableTable()
108110
mut.ModificationTime = hlc.Timestamp{}
111+
mut.Indexes[0].NotVisible = true
112+
mut.Version += 2 // Increment by 2 because we wrote a version above.
109113
return txn.Put(ctx, descKey, mut.DescriptorProto())
110114
}))
111115

@@ -127,8 +131,9 @@ func TestFirstUpgrade(t *testing.T) {
127131
// the MVCC timestamp.
128132
require.False(t, readDescFromStorage().GetModificationTime().IsEmpty())
129133
changes := readDescFromStorage().GetPostDeserializationChanges()
130-
require.Equal(t, changes.Len(), 1)
134+
require.Equal(t, 2, changes.Len())
131135
require.True(t, changes.Contains(catalog.SetModTimeToMVCCTimestamp))
136+
require.True(t, changes.Contains(catalog.SetIndexInvisibility))
132137

133138
// Wait long enough for precondition check to see the unbroken table descriptor.
134139
execStmts(t, "CREATE DATABASE test3")
@@ -137,18 +142,18 @@ func TestFirstUpgrade(t *testing.T) {
137142
// Upgrade the cluster version.
138143
tdb.Exec(t, qUpgrade)
139144

140-
// The table descriptor protobuf should still have the modification time set;
141-
// the only post-deserialization change should be SetModTimeToMVCCTimestamp.
145+
// Run a schema change on the bar table.
146+
tdb.Exec(t, "ALTER TABLE foo ADD COLUMN z INT")
147+
148+
// The only post-deserialization change should be SetModTimeToMVCCTimestamp,
149+
// because the MVCC timestamp gets on each write.
142150
require.False(t, readDescFromStorage().GetModificationTime().IsEmpty())
143151
changes = readDescFromStorage().GetPostDeserializationChanges()
144-
if v1.Equal(clusterversion.V25_4.Version()) {
145-
// In 25.4, we do a one-time rewrite of all descriptors, so there should be
146-
// no changes here. In later versions, there should be one change.
147-
require.Equal(t, 0, changes.Len())
148-
} else {
149-
require.Equal(t, 1, changes.Len())
150-
require.True(t, changes.Contains(catalog.SetModTimeToMVCCTimestamp))
151-
}
152+
require.Equal(t, 1, changes.Len())
153+
require.True(t, changes.Contains(catalog.SetModTimeToMVCCTimestamp))
154+
// Validate we can read bar before this upgrade. The lease manager should see
155+
// distinct version numbers in the history. Otherwise, it can panic.
156+
tdb.Exec(t, fmt.Sprintf("SELECT * FROM foo AS OF SYSTEM TIME '%s'", startTime.AsOfSystemTime()))
152157
}
153158

154159
// TestFirstUpgradeRepair tests the correct repair behavior of upgrade
@@ -241,12 +246,14 @@ func TestFirstUpgradeRepair(t *testing.T) {
241246
ConstraintID: tbl.NextConstraintID,
242247
}}
243248
tbl.NextConstraintID++
249+
tbl.MaybeIncrementVersion()
244250
b.Put(catalogkeys.MakeDescMetadataKey(codec, tbl.GetID()), tbl.DescriptorProto())
245251
fn := funcdesc.NewBuilder(fooFn.FuncDesc()).BuildExistingMutableFunction()
246252
fn.DependedOnBy = []descpb.FunctionDescriptor_Reference{{
247253
ID: 123456789,
248254
ColumnIDs: []descpb.ColumnID{1},
249255
}}
256+
fn.MaybeIncrementVersion()
250257
b.Put(catalogkeys.MakeDescMetadataKey(codec, fn.GetID()), fn.DescriptorProto())
251258
return txn.Run(ctx, b)
252259
}))
@@ -340,18 +347,34 @@ func TestFirstUpgradeRepair(t *testing.T) {
340347
tdb.CheckQueryResults(t, qDetectRepairableCorruption, [][]string{{"0"}})
341348
close(upgradeCompleted)
342349
require.NoError(t, grp.Wait())
350+
expectedVersionBump := 1
351+
// Upgrades from before 25.4 will round-trip all descriptors once, so we
352+
// expect two version bumps. Once for the repair and the next for the
353+
// round trip.
354+
if v0.Less(clusterversion.V25_4.Version()) {
355+
expectedVersionBump += 1
356+
}
343357
// Assert that a version upgrade is reflected for repaired descriptors (stricly one version upgrade).
344358
for _, d := range corruptDescs {
345359
descId := d.GetID()
346360
desc := readDescFromStorage(descId)
347-
require.Equalf(t, descOldVersionMap[descId]+1, desc.GetVersion(), desc.GetName())
361+
require.Equalf(t, descOldVersionMap[descId]+descpb.DescriptorVersion(expectedVersionBump), desc.GetVersion(), desc.GetName())
348362
}
349363

350364
// Assert that no version upgrade is reflected for non-repaired descriptors.
365+
expectedVersionBump = 0
366+
// Upgrading from before 25.4 all non-database descriptors will be round tripped.
367+
if v0.Less(clusterversion.V25_4.Version()) {
368+
expectedVersionBump += 1
369+
}
351370
for _, d := range nonCorruptDescs {
352371
descId := d.GetID()
353372
desc := readDescFromStorage(descId)
354-
require.Equalf(t, descOldVersionMap[descId], desc.GetVersion(), desc.GetName())
373+
if desc.DescriptorType() != catalog.Database {
374+
require.Equalf(t, descOldVersionMap[descId]+descpb.DescriptorVersion(expectedVersionBump), desc.GetVersion(), desc.GetName())
375+
} else {
376+
require.Equalf(t, descOldVersionMap[descId], desc.GetVersion(), desc.GetName())
377+
}
355378
}
356379

357380
// Check that the repaired table and function are OK.

0 commit comments

Comments
 (0)