From c19c44d06cb28a33436d74fd44e3a0159fa7074f Mon Sep 17 00:00:00 2001 From: Faizan Qazi Date: Fri, 22 Sep 2023 10:22:52 -0400 Subject: [PATCH] catalog/lease: add new cluster setting for session based leasing To help support session-based leasing, we will add a new internal cluster setting for tracking the leasing mode. As well as interfaces to query this setting to help add support for future session-based leasing. This setting will be used in future PRs. Epic: CC-24173 Release note: None --- pkg/gen/stringer.bzl | 1 + pkg/sql/catalog/lease/BUILD.bazel | 7 +++ pkg/sql/catalog/lease/lease.go | 47 ++++++++++++++++++- pkg/sql/catalog/lease/lease_internal_test.go | 31 ++++++++++++ .../lease/sessionbasedleasingmode_string.go | 30 ++++++++++++ pkg/sql/catalog/lease/storage.go | 20 +++++--- 6 files changed, 128 insertions(+), 8 deletions(-) create mode 100644 pkg/sql/catalog/lease/sessionbasedleasingmode_string.go diff --git a/pkg/gen/stringer.bzl b/pkg/gen/stringer.bzl index 9bb9b945259c..6d40a458e1cd 100644 --- a/pkg/gen/stringer.bzl +++ b/pkg/gen/stringer.bzl @@ -16,6 +16,7 @@ STRINGER_SRCS = [ "//pkg/sql/catalog/catalogkeys:commenttype_string.go", "//pkg/sql/catalog/catpb:privilegedescversion_string.go", "//pkg/sql/catalog/descpb:formatversion_string.go", + "//pkg/sql/catalog/lease:sessionbasedleasingmode_string.go", "//pkg/sql/colfetcher:fetcherstate_string.go", "//pkg/sql/execinfra:consumerstatus_string.go", "//pkg/sql/execinfra:procstate_string.go", diff --git a/pkg/sql/catalog/lease/BUILD.bazel b/pkg/sql/catalog/lease/BUILD.bazel index 93b27f0bb8fb..674d61286ebd 100644 --- a/pkg/sql/catalog/lease/BUILD.bazel +++ b/pkg/sql/catalog/lease/BUILD.bazel @@ -1,4 +1,5 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("//build:STRINGER.bzl", "stringer") go_library( name = "lease", @@ -62,6 +63,12 @@ go_library( ], ) +stringer( + name = "gen-lease-mode-stringer", + src = "lease.go", + typ = "SessionBasedLeasingMode", +) + go_test( name = "lease_test", size = "large", diff --git a/pkg/sql/catalog/lease/lease.go b/pkg/sql/catalog/lease/lease.go index 3f251e954128..b866c0b3e9b3 100644 --- a/pkg/sql/catalog/lease/lease.go +++ b/pkg/sql/catalog/lease/lease.go @@ -73,6 +73,51 @@ var LeaseJitterFraction = settings.RegisterFloatSetting( base.DefaultDescriptorLeaseJitterFraction, settings.Fraction) +//go:generate stringer -type=SessionBasedLeasingMode + +type SessionBasedLeasingMode int64 + +const ( + // SessionBasedLeasingOff expiry based leasing is being used. + SessionBasedLeasingOff SessionBasedLeasingMode = iota + // SessionBasedDualWrite expiry based and session based leasing are + // active concurrently, and both tables must be consulted schema changes. + SessionBasedDualWrite + // SessionBasedDrain expiry based leases will not be granted or renewed. + // Valid pre-existing leases that are expiry based will still be respected. + SessionBasedDrain + // SessionBasedOnly session based leases are only active, and schema + // changes only need to consult this table. + SessionBasedOnly +) + +// LeaseEnableSessionBasedLeasing used to enable / disable support for +// session based leasing. +var LeaseEnableSessionBasedLeasing = settings.RegisterEnumSetting( + settings.ApplicationLevel, + "sql.catalog.experimental_use_session_based_leasing", + "enables session based leasing for internal testing.", + "off", + map[int64]string{ + int64(SessionBasedLeasingOff): "off", + int64(SessionBasedDualWrite): "dual_write", + int64(SessionBasedDrain): "drain", + int64(SessionBasedOnly): "session", + }, + settings.WithReportable(false), +) + +// sessionBasedLeasingModeActive determines if the current mode at least meets +// the required minimum. +func (m *Manager) isSessionBasedLeasingModeActive(minimumMode SessionBasedLeasingMode) bool { + return m.getSessionBasedLeasingMode() >= minimumMode +} + +// getSessionBasedLeasingMode returns the current session based leasing mode. +func (m *Manager) getSessionBasedLeasingMode() SessionBasedLeasingMode { + return SessionBasedLeasingMode(LeaseEnableSessionBasedLeasing.Get(&m.settings.SV)) +} + // WaitForNoVersion returns once there are no unexpired leases left // for any version of the descriptor. func (m *Manager) WaitForNoVersion( @@ -756,10 +801,10 @@ func NewLeaseManager( } lm.storage.regionPrefix = &atomic.Value{} lm.storage.regionPrefix.Store(enum.One) + lm.storage.sessionBasedLeasingMode = lm lm.stopper.AddCloser(lm.sem.Closer("stopper")) lm.mu.descriptors = make(map[descpb.ID]*descriptorState) lm.mu.updatesResolvedTimestamp = clock.Now() - lm.draining.Store(false) return lm } diff --git a/pkg/sql/catalog/lease/lease_internal_test.go b/pkg/sql/catalog/lease/lease_internal_test.go index 1cec3295de58..478b0d397ef1 100644 --- a/pkg/sql/catalog/lease/lease_internal_test.go +++ b/pkg/sql/catalog/lease/lease_internal_test.go @@ -1568,3 +1568,34 @@ func TestGetDescriptorsFromStoreForIntervalCPULimiterPagination(t *testing.T) { require.Len(t, descs, 3) require.Equal(t, numRequests, 1) } + +// TestSessionLeasingClusterSetting sanity testing for the new +// experimental_use_session_based_leasing cluster setting and interfaces used +// to consume it. +func TestSessionLeasingClusterSetting(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + + ctx := context.Background() + srv, sqlDB, _ := serverutils.StartServer(t, base.TestServerArgs{}) + defer srv.Stopper().Stop(ctx) + + // Validate all settings can be set and the provider works correctly. + for idx, setting := range []string{"off", "dual_write", "drain", "session"} { + _, err := sqlDB.Exec("SET CLUSTER SETTING sql.catalog.experimental_use_session_based_leasing=$1::STRING", setting) + require.NoError(t, err) + lm := srv.LeaseManager().(*Manager) + + // Validate that the mode we just set is active and the provider handles + // it properly. + require.True(t, lm.isSessionBasedLeasingModeActive(SessionBasedLeasingMode(idx))) + require.Equal(t, lm.getSessionBasedLeasingMode(), SessionBasedLeasingMode(idx)) + // Validate that the previous minimums are active and forwards ones are not. + for mode := SessionBasedLeasingOff; mode <= SessionBasedLeasingMode(idx); mode++ { + require.True(t, lm.isSessionBasedLeasingModeActive(mode)) + } + for mode := SessionBasedLeasingMode(idx) + 1; mode <= SessionBasedOnly; mode++ { + require.False(t, lm.isSessionBasedLeasingModeActive(mode)) + } + } +} diff --git a/pkg/sql/catalog/lease/sessionbasedleasingmode_string.go b/pkg/sql/catalog/lease/sessionbasedleasingmode_string.go new file mode 100644 index 000000000000..6cd2bf2a80c6 --- /dev/null +++ b/pkg/sql/catalog/lease/sessionbasedleasingmode_string.go @@ -0,0 +1,30 @@ +// Code generated by "stringer"; DO NOT EDIT. + +package lease + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[SessionBasedLeasingOff-0] + _ = x[SessionBasedDualWrite-1] + _ = x[SessionBasedDrain-2] + _ = x[SessionBasedOnly-3] +} + +func (i SessionBasedLeasingMode) String() string { + switch i { + case SessionBasedLeasingOff: + return "SessionBasedLeasingOff" + case SessionBasedDualWrite: + return "SessionBasedDualWrite" + case SessionBasedDrain: + return "SessionBasedDrain" + case SessionBasedOnly: + return "SessionBasedOnly" + default: + return "SessionBasedLeasingMode(" + strconv.FormatInt(int64(i), 10) + ")" + } +} diff --git a/pkg/sql/catalog/lease/storage.go b/pkg/sql/catalog/lease/storage.go index db6c337628e4..0a329dd12ada 100644 --- a/pkg/sql/catalog/lease/storage.go +++ b/pkg/sql/catalog/lease/storage.go @@ -48,13 +48,14 @@ import ( // the manager. Some of these fields belong on the manager, in any case, since // they're only used by the manager and not by the store itself. type storage struct { - nodeIDContainer *base.SQLIDContainer - db isql.DB - clock *hlc.Clock - settings *cluster.Settings - codec keys.SQLCodec - regionPrefix *atomic.Value - sysDBCache *catkv.SystemDatabaseCache + nodeIDContainer *base.SQLIDContainer + db isql.DB + clock *hlc.Clock + settings *cluster.Settings + codec keys.SQLCodec + regionPrefix *atomic.Value + sessionBasedLeasingMode sessionBasedLeasingModeReader + sysDBCache *catkv.SystemDatabaseCache // group is used for all calls made to acquireNodeLease to prevent // concurrent lease acquisitions from the store. @@ -78,6 +79,11 @@ type writer interface { insertLease(context.Context, *kv.Txn, leaseFields) error } +type sessionBasedLeasingModeReader interface { + isSessionBasedLeasingModeActive(minimumMode SessionBasedLeasingMode) bool + getSessionBasedLeasingMode() SessionBasedLeasingMode +} + // LeaseRenewalDuration controls the default time before a lease expires when // acquisition to renew the lease begins. var LeaseRenewalDuration = settings.RegisterDurationSetting(