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 timestamp. 70// Reads at a timestamp are guaranteed to see a consistent prefix of the global 71// transaction history: they observe modifications done by all transactions with a 72// commit timestamp less than or equal to the read timestamp, and observe none of the 73// modifications done by transactions with a larger commit timestamp. They will block 74// until all conflicting transactions that may be assigned commit timestamps less 75// than or equal to the read timestamp have finished. 76// 77// The timestamp can either be expressed as an absolute Cloud Spanner commit 78// timestamp or a staleness relative to the current time. 79// 80// These modes do not require a "negotiation phase" to pick a timestamp. As a 81// result, they execute slightly faster than the equivalent boundedly stale 82// concurrency modes. On the other hand, boundedly stale reads usually return 83// fresher results. 84// 85// Use ReadTimestamp and ExactStaleness to create a bound of this type. 86// 87// Bounded staleness 88// 89// Bounded staleness modes allow Cloud Spanner to pick the read timestamp, subject to 90// a user-provided staleness bound. Cloud Spanner chooses the newest timestamp within 91// the staleness bound that allows execution of the reads at the closest 92// available replica without blocking. 93// 94// All rows yielded are consistent with each other: if any part of the read 95// observes a transaction, all parts of the read see the transaction. Boundedly 96// stale reads are not repeatable: two stale reads, even if they use the same 97// staleness bound, can execute at different timestamps and thus return 98// inconsistent results. 99// 100// Boundedly stale reads execute in two phases. The first phase negotiates a 101// timestamp among all replicas needed to serve the read. In the second phase, 102// reads are executed at the negotiated timestamp. 103// 104// As a result of this two-phase execution, bounded staleness reads are usually 105// a little slower than comparable exact staleness reads. However, they are 106// typically able to return fresher results, and are more likely to execute at 107// the closest replica. 108// 109// Because the timestamp negotiation requires up-front knowledge of which rows 110// will be read, it can only be used with single-use reads and single-use 111// read-only transactions. 112// 113// Use MinReadTimestamp and MaxStaleness to create a bound of this type. 114// 115// Old read timestamps and garbage collection 116// 117// Cloud Spanner continuously garbage collects deleted and overwritten data in the 118// background to reclaim storage space. This process is known as "version 119// GC". By default, version GC reclaims versions after they are four hours 120// old. Because of this, Cloud Spanner cannot perform reads at read timestamps more 121// than four hours in the past. This restriction also applies to in-progress 122// reads and/or SQL queries whose timestamps become too old while 123// executing. Reads and SQL queries with too-old read timestamps fail with the 124// error ErrorCode.FAILED_PRECONDITION. 125type TimestampBound struct { 126 mode timestampBoundType 127 d time.Duration 128 t time.Time 129} 130 131// StrongRead returns a TimestampBound that will perform reads and queries at a 132// timestamp where all previously committed transactions are visible. 133func StrongRead() TimestampBound { 134 return TimestampBound{mode: strong} 135} 136 137// ExactStaleness returns a TimestampBound that will perform reads and queries 138// at an exact staleness. 139func ExactStaleness(d time.Duration) TimestampBound { 140 return TimestampBound{ 141 mode: exactStaleness, 142 d: d, 143 } 144} 145 146// MaxStaleness returns a TimestampBound that will perform reads and queries at 147// a time chosen to be at most "d" stale. 148func MaxStaleness(d time.Duration) TimestampBound { 149 return TimestampBound{ 150 mode: maxStaleness, 151 d: d, 152 } 153} 154 155// MinReadTimestamp returns a TimestampBound that bound that will perform reads 156// and queries at a time chosen to be at least "t". 157func MinReadTimestamp(t time.Time) TimestampBound { 158 return TimestampBound{ 159 mode: minReadTimestamp, 160 t: t, 161 } 162} 163 164// ReadTimestamp returns a TimestampBound that will peform reads and queries at 165// the given time. 166func ReadTimestamp(t time.Time) TimestampBound { 167 return TimestampBound{ 168 mode: readTimestamp, 169 t: t, 170 } 171} 172 173func (tb TimestampBound) String() string { 174 switch tb.mode { 175 case strong: 176 return fmt.Sprintf("(strong)") 177 case exactStaleness: 178 return fmt.Sprintf("(exactStaleness: %s)", tb.d) 179 case maxStaleness: 180 return fmt.Sprintf("(maxStaleness: %s)", tb.d) 181 case minReadTimestamp: 182 return fmt.Sprintf("(minReadTimestamp: %s)", tb.t) 183 case readTimestamp: 184 return fmt.Sprintf("(readTimestamp: %s)", tb.t) 185 default: 186 return fmt.Sprintf("{mode=%v, d=%v, t=%v}", tb.mode, tb.d, tb.t) 187 } 188} 189 190// durationProto takes a time.Duration and converts it into pdb.Duration for 191// calling gRPC APIs. 192func durationProto(d time.Duration) *pbd.Duration { 193 n := d.Nanoseconds() 194 return &pbd.Duration{ 195 Seconds: n / int64(time.Second), 196 Nanos: int32(n % int64(time.Second)), 197 } 198} 199 200// timestampProto takes a time.Time and converts it into pbt.Timestamp for calling 201// gRPC APIs. 202func timestampProto(t time.Time) *pbt.Timestamp { 203 return &pbt.Timestamp{ 204 Seconds: t.Unix(), 205 Nanos: int32(t.Nanosecond()), 206 } 207} 208 209// buildTransactionOptionsReadOnly converts a spanner.TimestampBound into a sppb.TransactionOptions_ReadOnly 210// transaction option, which is then used in transactional reads. 211func buildTransactionOptionsReadOnly(tb TimestampBound, returnReadTimestamp bool) *sppb.TransactionOptions_ReadOnly { 212 pb := &sppb.TransactionOptions_ReadOnly{ 213 ReturnReadTimestamp: returnReadTimestamp, 214 } 215 switch tb.mode { 216 case strong: 217 pb.TimestampBound = &sppb.TransactionOptions_ReadOnly_Strong{ 218 Strong: true, 219 } 220 case exactStaleness: 221 pb.TimestampBound = &sppb.TransactionOptions_ReadOnly_ExactStaleness{ 222 ExactStaleness: durationProto(tb.d), 223 } 224 case maxStaleness: 225 pb.TimestampBound = &sppb.TransactionOptions_ReadOnly_MaxStaleness{ 226 MaxStaleness: durationProto(tb.d), 227 } 228 case minReadTimestamp: 229 pb.TimestampBound = &sppb.TransactionOptions_ReadOnly_MinReadTimestamp{ 230 MinReadTimestamp: timestampProto(tb.t), 231 } 232 case readTimestamp: 233 pb.TimestampBound = &sppb.TransactionOptions_ReadOnly_ReadTimestamp{ 234 ReadTimestamp: timestampProto(tb.t), 235 } 236 default: 237 panic(fmt.Sprintf("buildTransactionOptionsReadOnly(%v,%v)", tb, returnReadTimestamp)) 238 } 239 return pb 240} 241