github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/concurrency/lock/locking.proto (about) 1 // Copyright 2020 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 syntax = "proto3"; 12 package cockroach.kv.kvserver.concurrency.lock; 13 option go_package = "lock"; 14 15 import "gogoproto/gogo.proto"; 16 17 // Strength represents the different locking modes that determine how key-values 18 // can be accessed by concurrent transactions. 19 // 20 // Locking modes apply to locks that are held with a per-key granularity. It is 21 // up to users of the key-value layer to decide on which keys to acquire locks 22 // for when imposing structure that can span multiple keys, such as SQL rows 23 // (see column families and secondary indexes). 24 // 25 // Locking modes have differing levels of strength, growing from "weakest" to 26 // "strongest" in the order that the variants are presented in the enumeration. 27 // The "stronger" a locking mode, the more protection it provides for the lock 28 // holder but the more restrictive it is to concurrent transactions attempting 29 // to access the same keys. 30 // 31 // Compatibility Matrix 32 // 33 // The following matrix presents the compatibility of locking strengths with one 34 // another. A cell with an X means that the two strengths are incompatible with 35 // each other and that they can not both be held on a given key by different 36 // transactions, concurrently. A cell without an X means that the two strengths 37 // are compatible with each other and that they can be held on a given key by 38 // different transactions, concurrently. 39 // 40 // +-----------+-----------+-----------+-----------+-----------+ 41 // | | None | Shared | Upgrade | Exclusive | 42 // +-----------+-----------+-----------+-----------+-----------+ 43 // | None | | | | X^† | 44 // +-----------+-----------+-----------+-----------+-----------+ 45 // | Shared | | | X | X | 46 // +-----------+-----------+-----------+-----------+-----------+ 47 // | Upgrade | | X | X | X | 48 // +-----------+-----------+-----------+-----------+-----------+ 49 // | Exclusive | X^† | X | X | X | 50 // +-----------+-----------+-----------+-----------+-----------+ 51 // 52 // [†] reads under optimistic concurrency control in CockroachDB only conflict 53 // with Exclusive locks if the read's timestamp is equal to or greater than the 54 // lock's timestamp. If the read's timestamp is below the Exclusive lock's 55 // timestamp then the two are compatible. 56 enum Strength { 57 option (gogoproto.goproto_enum_prefix) = false; 58 59 // None represents the absence of a lock or the intention to acquire locks. 60 // It corresponds to the behavior of transactions performing key-value reads 61 // under optimistic concurrency control. No locks are acquired on the keys 62 // read by these requests when they evaluate. However, the reads do respect 63 // Exclusive locks already held by other transactions at timestamps equal to 64 // or less than their read timestamp. 65 // 66 // Optimistic concurrency control (OCC) can improve performance under some 67 // workloads because it avoids the need to perform any locking during reads. 68 // This can increase the amount of concurrency that the system can permit 69 // between ongoing transactions. However, OCC does mandate a read validation 70 // phase if/when transactions need to commit at a different timestamp than 71 // they performed all reads at. CockroachDB calls this a "read refresh", 72 // which is implemented by the txnSpanRefresher. If a read refresh fails due 73 // to new key-value writes that invalidate what was previously read, 74 // transactions are forced to restart. See the comment on txnSpanRefresher 75 // for more. 76 None = 0; 77 78 // Shared (S) locks are used by read-only operations and allow concurrent 79 // transactions to read under pessimistic concurrency control. Shared locks 80 // are compatible with each other but are not compatible with Upgrade or 81 // Exclusive locks. This means that multiple transactions can hold a Shared 82 // lock on the same key at the same time, but no other transaction can 83 // modify the key at the same time. A holder of a Shared lock on a key is 84 // only permitted to read the key's value while the lock is held. 85 // 86 // Share locks are currently unused, as all KV reads are currently performed 87 // optimistically (see None). 88 Shared = 1; 89 90 // Upgrade (U) locks are a hybrid of Shared and Exclusive locks which are 91 // used to prevent a common form of deadlock. When a transaction intends to 92 // modify existing KVs, it is often the case that it reads the KVs first and 93 // then attempts to modify them. Under pessimistic concurrency control, this 94 // would correspond to first acquiring a Shared lock on the keys and then 95 // converting the lock to an Exclusive lock when modifying the keys. If two 96 // transactions were to acquire the Shared lock initially and then attempt 97 // to update the keys concurrently, both transactions would get stuck 98 // waiting for the other to release its Shared lock and a deadlock would 99 // occur. To resolve the deadlock, one of the two transactions would need to 100 // be aborted. 101 // 102 // To avoid this potential deadlock problem, an Upgrade lock can be used in 103 // place of a Shared lock. Upgrade locks are not compatible with any other 104 // form of locking. As with Shared locks, the lock holder of a Shared lock 105 // on a key is only allowed to read from the key while the lock is held. 106 // This resolves the deadlock scenario presented above because only one of 107 // the transactions would have been able to acquire an Upgrade lock at a 108 // time while reading the initial state of the KVs. This means that the 109 // Shared-to-Exclusive lock upgrade would never need to wait on another 110 // transaction to release its locks. 111 // 112 // Under pure pessimistic concurrency control, an Upgrade lock is equivalent 113 // to an Exclusive lock. However, unlike with Exclusive locks, reads under 114 // optimistic concurrency control do not conflict with Upgrade locks. This 115 // is because a transaction can only hold an Upgrade lock on keys that it 116 // has not yet modified. This improves concurrency between read and write 117 // transactions compared to if the writing transaction had immediately 118 // acquired an Exclusive lock. 119 // 120 // The trade-off here is twofold. First, if the Upgrade lock holder does 121 // convert its lock on a key to an Exclusive lock after an optimistic read 122 // has observed the state of the key, the transaction that performed the 123 // optimistic read may be unable to perform a successful read refresh if it 124 // attempts to refresh to a timestamp at or past the timestamp of the lock 125 // conversion. Second, the optimistic reads permitted while the Upgrade lock 126 // is held will bump the timestamp cache. This may result in the Upgrade 127 // lock holder being forced to increase its write timestamp when converting 128 // to an Exclusive lock, which in turn may force it to restart if its read 129 // refresh fails. 130 Upgrade = 2; 131 132 // Exclusive (X) locks are used by read-write and read-only operations and 133 // provide a transaction with exclusive access to a key. When an Exclusive 134 // lock is held by a transaction on a given key, no other transaction can 135 // read from or write to that key. The lock holder is free to read from and 136 // write to the key as frequently as it would like. 137 Exclusive = 3; 138 } 139 140 // Durability represents the different durability properties of a lock acquired 141 // by a transaction. Durability levels provide varying degrees of survivability, 142 // often in exchange for the cost of lock acquisition. 143 enum Durability { 144 option (gogoproto.goproto_enum_prefix) = false; 145 146 // Replicated locks are held on at least a quorum of Replicas in a Range. 147 // They are slower to acquire and release than Unreplicated locks because 148 // updating them requires both cross-node coordination and interaction with 149 // durable storage. In exchange, Replicated locks provide a guarantee of 150 // survivability across lease transfers, leaseholder crashes, and other 151 // forms of failure events. They will remain available as long as their 152 // Range remains available and they will never be lost. 153 Replicated = 0; 154 155 // Unreplicated locks are held only on a single Replica in a Range, which is 156 // typically the leaseholder. Unreplicated locks are very fast to acquire 157 // and release because they are held in memory or on fast local storage and 158 // require no cross-node coordination to update. In exchange, Unreplicated 159 // locks provide no guarantee of survivability across lease transfers or 160 // leaseholder crashes. They should therefore be thought of as best-effort 161 // and should not be relied upon for correctness. 162 Unreplicated = 1; 163 }