Skip to content

Commit 901677f

Browse files
craig[bot]fqaziarulajmani
committed
155422: catalog/lease: retain descriptor versions for old timestamps r=fqazi a=fqazi Previously, when we added support locked timestamps leasing we would not hold descriptors that previous versions that older timestamps may need. This could lead to use needing to reading old versions from KV more frequently as well as limiting when transactions could commit in this mode. To address this, this patch allows the lease manager to hold older versions while the timestamps is in use. Fixes: #153618 Release note: None 156126: asim: bump timeout r=arulajmani a=arulajmani Closes #156109 Epic: none Release note: None Co-authored-by: Faizan Qazi <[email protected]> Co-authored-by: Arul Ajmani <[email protected]>
3 parents 4a2ec70 + bd5d95d + 0c9fe78 commit 901677f

File tree

14 files changed

+439
-97
lines changed

14 files changed

+439
-97
lines changed

pkg/kv/kvserver/asim/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ go_library(
2525

2626
go_test(
2727
name = "asim_test",
28+
size = "large",
2829
srcs = ["asim_test.go"],
2930
deps = [
3031
":asim",

pkg/sql/catalog/descs/collection.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1482,7 +1482,8 @@ func (tc *Collection) GetIndexComment(
14821482
// MaybeSetReplicationSafeTS modifies a txn to apply the replication safe timestamp,
14831483
// if we are executing against a PCR reader catalog.
14841484
func (tc *Collection) MaybeSetReplicationSafeTS(ctx context.Context, txn *kv.Txn) error {
1485-
now := tc.leased.lm.GetReadTimestamp(txn.DB().Clock().Now())
1485+
now := tc.leased.lm.GetReadTimestamp(ctx, txn.DB().Clock().Now())
1486+
defer now.Release(ctx)
14861487
desc, err := tc.leased.lm.Acquire(ctx, now, keys.SystemDatabaseID)
14871488
if err != nil {
14881489
return err

pkg/sql/catalog/descs/leased_descriptors.go

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ type LeaseManager interface {
4141

4242
GetLeaseGeneration() int64
4343

44-
GetReadTimestamp(timestamp hlc.Timestamp) lease.ReadTimestamp
44+
GetReadTimestamp(ctx context.Context, timestamp hlc.Timestamp) lease.ReadTimestamp
4545
}
4646

4747
type deadlineHolder interface {
@@ -180,24 +180,27 @@ func (ld *leasedDescriptors) maybeAssertExternalRowDataTS(desc catalog.Descripto
180180
}
181181

182182
// maybeInitReadTimestamp selects a read timestamp for the lease manager.
183-
func (ld *leasedDescriptors) maybeInitReadTimestamp(txn deadlineHolder) {
183+
func (ld *leasedDescriptors) maybeInitReadTimestamp(ctx context.Context, txn deadlineHolder) {
184184
// Refresh the leased timestamp if the read timestamp has changed on us
185185
// or if it hasn't been populated yet.
186-
// TODO (fqazi): For locked read timestamps inside leasing,
187-
// we will need to have extra logic to ensure this is safe.
188186
if ld.leaseTimestampSet &&
189187
ld.leaseTimestamp.GetBaseTimestamp() == txn.ReadTimestamp() {
190188
return
189+
} else if ld.leaseTimestampSet {
190+
// Timestamp is already set so release it before picking a new one.
191+
// TODO (fqazi): Add handling for moving timestamps forward.
192+
ld.leaseTimestamp.Release(ctx)
193+
ld.leaseTimestampSet = false
191194
}
192195
readTimestamp := txn.ReadTimestamp()
193196
ld.leaseTimestampSet = true
194-
// Fixed timestamp queries will use descriptors at the user select timestamp.
197+
// Fixed timestamp queries will use descriptors at the user-selected timestamp.
195198
if txn.ReadTimestampFixed() {
196199
ld.leaseTimestamp = lease.TimestampToReadTimestamp(readTimestamp)
197200
return
198201
}
199202
// Otherwise, get a safe read timestamp from the lease manager.
200-
ld.leaseTimestamp = ld.lm.GetReadTimestamp(readTimestamp)
203+
ld.leaseTimestamp = ld.lm.GetReadTimestamp(ctx, readTimestamp)
201204
}
202205

203206
// getLeasedDescriptorByName return a leased descriptor valid for the
@@ -223,7 +226,7 @@ func (ld *leasedDescriptors) getByName(
223226
desc = cached.(lease.LeasedDescriptor).Underlying()
224227
return desc, false, nil
225228
}
226-
ld.maybeInitReadTimestamp(txn)
229+
ld.maybeInitReadTimestamp(ctx, txn)
227230
ldesc, err := ld.lm.AcquireByName(ctx, ld.leaseTimestamp, parentID, parentSchemaID, name)
228231
const setTxnDeadline = true
229232
return ld.getResult(ctx, txn, setTxnDeadline, ldesc, err)
@@ -238,7 +241,7 @@ func (ld *leasedDescriptors) getByID(
238241
if cached := ld.getCachedByID(ctx, id); cached != nil {
239242
return cached, false, nil
240243
}
241-
ld.maybeInitReadTimestamp(txn)
244+
ld.maybeInitReadTimestamp(ctx, txn)
242245
desc, err := ld.lm.Acquire(ctx, ld.leaseTimestamp, id)
243246
const setTxnDeadline = false
244247
return ld.getResult(ctx, txn, setTxnDeadline, desc, err)
@@ -286,7 +289,7 @@ func (ld *leasedDescriptors) getResult(
286289
expiration := ldesc.Expiration(ctx)
287290
readTimestamp := txn.ReadTimestamp()
288291
if expiration.LessEq(txn.ReadTimestamp()) {
289-
return nil, false, errors.AssertionFailedf("bad descriptor for id=%d readTimestamp=%s, expiration=%s", ldesc.GetID(), readTimestamp, expiration)
292+
return nil, false, errors.AssertionFailedf("bad descriptor for id=%d readTimestamp=%s, expiration=%s (leaseTimestamp: %s)", ldesc.GetID(), readTimestamp, expiration, ld.leaseTimestamp.GetTimestamp())
290293
}
291294

292295
ld.cache.Upsert(ldesc, ldesc.Underlying().SkipNamespace())
@@ -391,6 +394,9 @@ func (ld *leasedDescriptors) releaseAll(ctx context.Context) {
391394
return nil
392395
})
393396
ld.cache.Clear()
397+
if ld.leaseTimestampSet {
398+
ld.leaseTimestamp.Release(ctx)
399+
}
394400
ld.leaseTimestampSet = false
395401
}
396402

@@ -401,6 +407,9 @@ func (ld *leasedDescriptors) release(ctx context.Context, descs []lease.IDVersio
401407
}
402408
}
403409
if ld.cache.Len() == 0 {
410+
if ld.leaseTimestampSet {
411+
ld.leaseTimestamp.Release(ctx)
412+
}
404413
ld.leaseTimestampSet = false
405414
}
406415
}

pkg/sql/catalog/lease/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ go_test(
124124
"//pkg/sql/schemachanger/scexec",
125125
"//pkg/sql/schemachanger/scop",
126126
"//pkg/sql/schemachanger/scplan",
127+
"//pkg/sql/sem/eval",
127128
"//pkg/sql/sem/tree",
128129
"//pkg/sql/sessiondata",
129130
"//pkg/sql/sqlinstance/instancestorage",

pkg/sql/catalog/lease/descriptor_set.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ func (l *descriptorSet) findNewest() *descriptorVersionState {
9191
return l.data[len(l.data)-1]
9292
}
9393

94+
func (l *descriptorSet) findPrevious() *descriptorVersionState {
95+
if len(l.data) < 2 {
96+
return nil
97+
}
98+
return l.data[len(l.data)-2]
99+
}
100+
94101
func (l *descriptorSet) findPreviousToExpire(dropped bool) *descriptorVersionState {
95102
// If there are no versions, then no previous version exists.
96103
if len(l.data) == 0 {

pkg/sql/catalog/lease/descriptor_state.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,36 @@ func (t *descriptorState) findForTimestamp(
9292
if len(t.mu.active.data) == 0 {
9393
return nil, false, errRenewLease
9494
}
95+
return t.findForTimestampImpl(ctx, timestamp.GetTimestamp(), timestamp.GetBaseTimestamp(), expensiveLogEnabled)
96+
}
9597

98+
// findForTimestampImpl searches for a descriptor that is valid for both the lease
99+
// timestamp and read timestamp. If no such descriptor exists, then this function
100+
// will return a descriptor satisfying the read timestamp (when using locked leases
101+
// this means we will allow mixing versions on first reads).
102+
func (t *descriptorState) findForTimestampImpl(
103+
ctx context.Context,
104+
leaseTimestamp hlc.Timestamp,
105+
readTimestamp hlc.Timestamp,
106+
expensiveLogEnabled bool,
107+
) (*descriptorVersionState, bool, error) {
96108
// Walk back the versions to find one that is valid for the timestamp.
97109
for i := len(t.mu.active.data) - 1; i >= 0; i-- {
98110
// Check to see if the ModificationTime is valid. If only the initial version
99111
// of the descriptor is known, then read it at the base timestamp.
100-
if desc := t.mu.active.data[i]; desc.GetModificationTime().LessEq(timestamp.GetTimestamp()) ||
101-
(len(t.mu.active.data) == 1 && desc.GetModificationTime().LessEq(timestamp.GetBaseTimestamp())) {
112+
if desc := t.mu.active.data[i]; desc.GetModificationTime().LessEq(leaseTimestamp) {
102113
latest := i+1 == len(t.mu.active.data)
103-
if !desc.hasExpired(ctx, timestamp.GetBaseTimestamp()) {
114+
if !desc.hasExpired(ctx, readTimestamp) {
104115
// Existing valid descriptor version.
105116
desc.incRefCount(ctx, expensiveLogEnabled)
106117
return desc, latest, nil
118+
} else if !latest && readTimestamp != leaseTimestamp {
119+
// The lease timestamp is not compatible with the read timestamp, since
120+
// the descriptor returned will be expired. This means we are seeing the
121+
// first read of this descriptor, since the prior version was not locked.
122+
// In this scenario, we will allow this transaction to mix versions as a
123+
// last resort.
124+
return t.findForTimestampImpl(ctx, readTimestamp, readTimestamp, expensiveLogEnabled)
107125
}
108126

109127
if latest {

0 commit comments

Comments
 (0)