1/* 2Copyright 2017 Google LLC 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package spanner 18 19import ( 20 "fmt" 21 "time" 22 23 pbd "github.com/golang/protobuf/ptypes/duration" 24 pbt "github.com/golang/protobuf/ptypes/timestamp" 25 sppb "google.golang.org/genproto/googleapis/spanner/v1" 26) 27 28// timestampBoundType specifies the timestamp bound mode. 29type timestampBoundType int 30 31const ( 32 strong timestampBoundType = iota // strong reads 33 exactStaleness // read with exact staleness 34 maxStaleness // read with max staleness 35 minReadTimestamp // read with min freshness 36 readTimestamp // read data at exact timestamp 37) 38 39// TimestampBound defines how Cloud Spanner will choose a timestamp for a single 40// read/query or read-only transaction. 41// 42// There are three types of timestamp bound: strong, bounded staleness and exact 43// staleness. Strong is the default. 44// 45// If the Cloud Spanner database to be read is geographically distributed, stale 46// read-only transactions can execute more quickly than strong or read-write 47// transactions, because they are able to execute far from the leader replica. 48// 49// Each type of timestamp bound is discussed in detail below. A TimestampBound 50// can be specified when creating transactions, see the documentation of 51// spanner.Client for an example. 52// 53// Strong reads 54// 55// Strong reads are guaranteed to see the effects of all transactions that have 56// committed before the start of the read. Furthermore, all rows yielded by a 57// single read are consistent with each other: if any part of the read 58// observes a transaction, all parts of the read see the transaction. 59// 60// Strong reads are not repeatable: two consecutive strong read-only 61// transactions might return inconsistent results if there are concurrent 62// writes. If consistency across reads is required, the reads should be 63// executed within a transaction or at an exact read timestamp. 64// 65// Use StrongRead to create a bound of this type. 66// 67// Exact staleness 68// 69// An exact staleness timestamp bound executes reads at a user-specified 70// timestamp. Reads at a timestamp are guaranteed to see a consistent prefix of 71// the global transaction history: they observe modifications done by all 72// transactions with a commit timestamp less than or equal to the read 73// timestamp, and observe none of the modifications done by transactions with a 74// larger commit timestamp. They will block until all conflicting transactions 75// that may be assigned commit timestamps less than or equal to the read 76// timestamp have finished. 77// 78// The timestamp can either be expressed as an absolute Cloud Spanner commit 79// timestamp or a staleness relative to the current time. 80// 81// These modes do not require a "negotiation phase" to pick a timestamp. As a 82// result, they execute slightly faster than the equivalent boundedly stale 83// concurrency modes. On the other hand, boundedly stale reads usually return 84// fresher results. 85// 86// Use ReadTimestamp and ExactStaleness to create a bound of this type. 87// 88// Bounded staleness 89// 90// Bounded staleness modes allow Cloud Spanner to pick the read timestamp, 91// subject to a user-provided staleness bound. Cloud Spanner chooses the newest 92// timestamp within the staleness bound that allows execution of the reads at 93// the closest available replica without blocking. 94// 95// All rows yielded are consistent with each other: if any part of the read 96// observes a transaction, all parts of the read see the transaction. Boundedly 97// stale reads are not repeatable: two stale reads, even if they use the same 98// staleness bound, can execute at different timestamps and thus return 99// inconsistent results. 100// 101// Boundedly stale reads execute in two phases. The first phase negotiates a 102// timestamp among all replicas needed to serve the read. In the second phase, 103// reads are executed at the negotiated timestamp. 104// 105// As a result of this two-phase execution, bounded staleness reads are usually 106// a little slower than comparable exact staleness reads. However, they are 107// typically able to return fresher results, and are more likely to execute at 108// the closest replica. 109// 110// Because the timestamp negotiation requires up-front knowledge of which rows 111// will be read, it can only be used with single-use reads and single-use 112// read-only transactions. 113// 114// Use MinReadTimestamp and MaxStaleness to create a bound of this type. 115// 116// Old read timestamps and garbage collection 117// 118// Cloud Spanner continuously garbage collects deleted and overwritten data in 119// the background to reclaim storage space. This process is known as "version 120// GC". By default, version GC reclaims versions after they are one hour old. 121// Because of this, Cloud Spanner cannot perform reads at read timestamps more 122// than one hour in the past. This restriction also applies to in-progress reads 123// and/or SQL queries whose timestamps become too old while executing. Reads and 124// SQL queries with too-old read timestamps fail with the error 125// ErrorCode.FAILED_PRECONDITION. 126type TimestampBound struct { 127 mode timestampBoundType 128 d time.Duration 129 t time.Time 130} 131 132// StrongRead returns a TimestampBound that will perform reads and queries at a 133// timestamp where all previously committed transactions are visible. 134func StrongRead() TimestampBound { 135 return TimestampBound{mode: strong} 136} 137 138// ExactStaleness returns a TimestampBound that will perform reads and queries 139// at an exact staleness. 140func ExactStaleness(d time.Duration) TimestampBound { 141 return TimestampBound{ 142 mode: exactStaleness, 143 d: d, 144 } 145} 146 147// MaxStaleness returns a TimestampBound that will perform reads and queries at 148// a time chosen to be at most "d" stale. 149func MaxStaleness(d time.Duration) TimestampBound { 150 return TimestampBound{ 151 mode: maxStaleness, 152 d: d, 153 } 154} 155 156// MinReadTimestamp returns a TimestampBound that bound that will perform reads 157// and queries at a time chosen to be at least "t". 158func MinReadTimestamp(t time.Time) TimestampBound { 159 return TimestampBound{ 160 mode: minReadTimestamp, 161 t: t, 162 } 163} 164 165// ReadTimestamp returns a TimestampBound that will peform reads and queries at 166// the given time. 167func ReadTimestamp(t time.Time) TimestampBound { 168 return TimestampBound{ 169 mode: readTimestamp, 170 t: t, 171 } 172} 173 174func (tb TimestampBound) String() string { 175 switch tb.mode { 176 case strong: 177 return fmt.Sprintf("(strong)") 178 case exactStaleness: 179 return fmt.Sprintf("(exactStaleness: %s)", tb.d) 180 case maxStaleness: 181 return fmt.Sprintf("(maxStaleness: %s)", tb.d) 182 case minReadTimestamp: 183 return fmt.Sprintf("(minReadTimestamp: %s)", tb.t) 184 case readTimestamp: 185 return fmt.Sprintf("(readTimestamp: %s)", tb.t) 186 default: 187 return fmt.Sprintf("{mode=%v, d=%v, t=%v}", tb.mode, tb.d, tb.t) 188 } 189} 190 191// durationProto takes a time.Duration and converts it into pdb.Duration for 192// calling gRPC APIs. 193func durationProto(d time.Duration) *pbd.Duration { 194 n := d.Nanoseconds() 195 return &pbd.Duration{ 196 Seconds: n / int64(time.Second), 197 Nanos: int32(n % int64(time.Second)), 198 } 199} 200 201// timestampProto takes a time.Time and converts it into pbt.Timestamp for 202// calling gRPC APIs. 203func timestampProto(t time.Time) *pbt.Timestamp { 204 return &pbt.Timestamp{ 205 Seconds: t.Unix(), 206 Nanos: int32(t.Nanosecond()), 207 } 208} 209 210// buildTransactionOptionsReadOnly converts a spanner.TimestampBound into a 211// sppb.TransactionOptions_ReadOnly transaction option, which is then used in 212// transactional reads. 213func buildTransactionOptionsReadOnly(tb TimestampBound, returnReadTimestamp bool) *sppb.TransactionOptions_ReadOnly { 214 pb := &sppb.TransactionOptions_ReadOnly{ 215 ReturnReadTimestamp: returnReadTimestamp, 216 } 217 switch tb.mode { 218 case strong: 219 pb.TimestampBound = &sppb.TransactionOptions_ReadOnly_Strong{ 220 Strong: true, 221 } 222 case exactStaleness: 223 pb.TimestampBound = &sppb.TransactionOptions_ReadOnly_ExactStaleness{ 224 ExactStaleness: durationProto(tb.d), 225 } 226 case maxStaleness: 227 pb.TimestampBound = &sppb.TransactionOptions_ReadOnly_MaxStaleness{ 228 MaxStaleness: durationProto(tb.d), 229 } 230 case minReadTimestamp: 231 pb.TimestampBound = &sppb.TransactionOptions_ReadOnly_MinReadTimestamp{ 232 MinReadTimestamp: timestampProto(tb.t), 233 } 234 case readTimestamp: 235 pb.TimestampBound = &sppb.TransactionOptions_ReadOnly_ReadTimestamp{ 236 ReadTimestamp: timestampProto(tb.t), 237 } 238 default: 239 panic(fmt.Sprintf("buildTransactionOptionsReadOnly(%v,%v)", tb, returnReadTimestamp)) 240 } 241 return pb 242} 243