Skip to content

Commit

Permalink
roachpb: add lock durability info to Get/Scan/ReverseScan requests
Browse files Browse the repository at this point in the history
This patch adds lock durability information to Get, Scan, and
ReverseScan requests. This field is only ever meaningful in conjunction
with a locking strength that's not lock.None.

By default, all locking requests ask for best-effort locks. This
preserves the mixed version story between 23.1 <-> 23.2 nodes. However,
transactions that need them for correctness (read: read committed), will
now have the option to ask for guranteed durability locks. These will
then correspond to replicated locks. Note that the field here is named
in terms of durability guarantees, and not the specific implementation
detail we'll use to provide this -- this is intentional. It allows us to
offer a different kind of durable locks in the future, for example
schemes that selectively replicate locks because they have buy-in from
the both the kvserver and kvclient, in conjunction with some scheme to
verify locks at commit time.

Informs #109672

Release note: None
  • Loading branch information
arulajmani committed Sep 8, 2023
1 parent b7840ea commit 943e2f5
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 10 deletions.
6 changes: 4 additions & 2 deletions pkg/kv/kvclient/kvstreamer/size.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
package kvstreamer

import (
"fmt"
"unsafe"

"github.com/cockroachdb/cockroach/pkg/kv/kvpb"
Expand All @@ -36,8 +37,9 @@ var zeroInt32Slice []int32
func init() {
scanRequestOverhead := int64(unsafe.Sizeof(kvpb.RequestUnion_Scan{}) +
unsafe.Sizeof(kvpb.ScanRequest{}))
if requestOverhead != scanRequestOverhead {
panic("GetRequest and ScanRequest have different overheads")
// TODO(XXX): understand this.
if requestOverhead+8 != scanRequestOverhead {
panic(fmt.Sprintf("GetRequest and ScanRequest have different overheads %d and scan req %d", requestOverhead, scanRequestOverhead))
}
scanResponseUnionOverhead := int64(unsafe.Sizeof(kvpb.ResponseUnion_Scan{}))
if responseUnionOverhead != scanResponseUnionOverhead {
Expand Down
70 changes: 62 additions & 8 deletions pkg/kv/kvpb/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,33 @@ enum ResumeReason {
RESUME_ELASTIC_CPU_LIMIT = 5;
}

enum DurabilityType {
option (gogoproto.goproto_enum_prefix) = false;
// LockDurabilityBestEffort represents the default: make a best-effort attempt
// to hold any locks acquired until commit time. Typically, the lock is not
// replicated; instead, it's kept in-memory on the leaseholder of the locked
// key. As such, bes-effort locks are susceptible to things like lease
// transfers and node crashes. However, they're faster to acquire than
// guaranteed-durable locks, which makes them appealing for transactions that
// do not require locks for correctness (read: serializable isolation
// transactions).
LockDurabilityBestEffort = 0;

// LockDurabilityGuaranteed represents locks that must be held until a
// transaction commits. Unlike best-effort locks, they aren't susceptible to
// things like lease transfers, range {splits, merges}, memory limits, node
// crashes etc. Typically, these locks are replicated[1], which adds a
// performance penalty to asking for these. As such, they should only be asked
// for by transactions that use locks for correctness (read: read-committed or
// snapshot isolation transactions).
//
// [1] In the future, we may decide to (selectively) not replicate locks
// even if they need durability guarantees. Such a scheme would need buy-in
// from the KV client, KV server, and some mechanism to verify whether a lock
// is held or not before a transaction can commit.
LockDurabilityGuaranteed = 1;
}

// RequestHeaderPure is not to be used directly. It's generated only for use of
// its marshaling methods by RequestHeader. See the comment there.
message RequestHeaderPure {
Expand Down Expand Up @@ -236,9 +263,18 @@ message GetRequest {
// The desired key-level locking mode used during this get. When set to None
// (the default), no key-level locking mode is used - meaning that the get
// does not acquire a lock. When set to any other strength, a lock of that
// strength is acquired with the Unreplicated durability (i.e. best-effort)
// the key, if it exists.
// strength is acquired with the associated durability guarantees on the key,
// if it exists.
kv.kvserver.concurrency.lock.Strength key_locking = 2;

// DurabilityType is only ever meaningful when KeyLocking is set to something
// other than None. It dictates the effort we want to go through in keeping
// our lock once its been acquired -- do we want a best-effort unreplicated
// lock, or do we want a guaranteed to exist until commit time (replicated)
// lock? The latter is more expensive, so transaction's that can do with
// best-effort locks (read: serializable isolation transactions) should use
// the former.
DurabilityType durability_type = 6;
}

// A GetResponse is the return value from the Get() method.
Expand Down Expand Up @@ -609,14 +645,23 @@ message ScanRequest {
// The desired key-level locking mode used during this scan. When set to None
// (the default), no key-level locking mode is used - meaning that the scan
// does not acquire any locks. When set to any other strength, a lock of that
// strength is acquired with the Unreplicated durability (i.e. best-effort) on
// each of the keys scanned by the request, subject to any key limit applied
// to the batch which limits the number of keys returned.
// strength is acquired with the associated durability guarantees on each of
// the keys scanned by the request, subject to any key limit applied to the
// batch which limits the number of keys returned.
//
// NOTE: the locks acquire with this strength are point locks on each of the
// keys returned by the request, not a single range lock over the entire span
// scanned by the request.
kv.kvserver.concurrency.lock.Strength key_locking = 5;

// DurabilityType is only ever meaningful when KeyLocking is set to something
// other than None. It dictates the effort we want to go through in keeping
// our lock once its been acquired -- do we want a best-effort unreplicated
// lock, or do we want a guaranteed to exist until commit time (replicated)
// lock? The latter is more expensive, so transaction's that can do with
// best-effort locks (read: serializable isolation transactions) should use
// the former.
DurabilityType durability_type = 6;
}

// A ScanResponse is the return value from the Scan() method.
Expand Down Expand Up @@ -674,14 +719,23 @@ message ReverseScanRequest {
// The desired key-level locking mode used during this scan. When set to None
// (the default), no key-level locking mode is used - meaning that the scan
// does not acquire any locks. When set to any other strength, a lock of that
// strength is acquired with the Unreplicated durability (i.e. best-effort) on
// each of the keys scanned by the request, subject to any key limit applied
// to the batch which limits the number of keys returned.
// strength is acquired with the associated durability guarantees on each of
// the keys scanned by the request, subject to any key limit applied to the
// batch which limits the number of keys returned.
//
// NOTE: the locks acquire with this strength are point locks on each of the
// keys returned by the request, not a single range lock over the entire span
// scanned by the request.
kv.kvserver.concurrency.lock.Strength key_locking = 5;

// DurabilityType is only ever meaningful when KeyLocking is set to something
// other than None. It dictates the effort we want to go through in keeping
// our lock once its been acquired -- do we want a best-effort unreplicated
// lock, or do we want a guaranteed to exist until commit time (replicated)
// lock? The latter is more expensive, so transaction's that can do with
// best-effort locks (read: serializable isolation transactions) should use
// the former.
DurabilityType durability_type = 6;
}

// A ReverseScanResponse is the return value from the ReverseScan() method.
Expand Down

0 comments on commit 943e2f5

Please sign in to comment.