github.com/matrixorigin/matrixone@v0.7.0/pkg/container/types/txnts.go (about) 1 // Copyright 2021 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package types 16 17 import ( 18 "bytes" 19 "fmt" 20 "math" 21 "strconv" 22 "strings" 23 24 "sync/atomic" 25 "time" 26 27 "github.com/cespare/xxhash/v2" 28 "github.com/matrixorigin/matrixone/pkg/pb/timestamp" 29 "github.com/matrixorigin/matrixone/pkg/txn/clock" 30 ) 31 32 // Transaction ts contains a physical ts in higher 8 bytes 33 // and a logical in lower 4 bytes. higher lower in little 34 // ending sense. 35 func (ts TS) Physical() int64 { 36 return DecodeInt64(ts[4:12]) 37 } 38 func (ts TS) Logical() uint32 { 39 return DecodeUint32(ts[:4]) 40 } 41 42 func (ts TS) IsEmpty() bool { 43 return ts.Physical() == 0 && ts.Logical() == 0 44 } 45 func (ts TS) Equal(rhs TS) bool { 46 return ts == rhs 47 } 48 49 // Compare physical first then logical. 50 func (ts TS) Compare(rhs TS) int { 51 p1, p2 := ts.Physical(), rhs.Physical() 52 if p1 < p2 { 53 return -1 54 } 55 if p1 > p2 { 56 return 1 57 } 58 l1, l2 := ts.Logical(), rhs.Logical() 59 if l1 < l2 { 60 return -1 61 } 62 if l1 == l2 { 63 return 0 64 } 65 return 1 66 } 67 68 func (ts TS) Less(rhs TS) bool { 69 return ts.Compare(rhs) < 0 70 } 71 func (ts TS) LessEq(rhs TS) bool { 72 return ts.Compare(rhs) <= 0 73 } 74 func (ts TS) Greater(rhs TS) bool { 75 return ts.Compare(rhs) > 0 76 } 77 func (ts TS) GreaterEq(rhs TS) bool { 78 return ts.Compare(rhs) >= 0 79 } 80 81 // TODO::need to take "NodeID" account into 82 func TimestampToTS(ts timestamp.Timestamp) TS { 83 return BuildTS(ts.PhysicalTime, ts.LogicalTime) 84 } 85 86 func (ts TS) ToTimestamp() timestamp.Timestamp { 87 return timestamp.Timestamp{ 88 PhysicalTime: DecodeInt64(ts[4:12]), 89 LogicalTime: DecodeUint32(ts[:4])} 90 } 91 92 func BuildTS(p int64, l uint32) (ret TS) { 93 copy(ret[4:12], EncodeInt64(&p)) 94 copy(ret[:4], EncodeUint32(&l)) 95 return 96 } 97 98 func MaxTs() TS { 99 return BuildTS(math.MaxInt64, math.MaxUint32) 100 } 101 102 // Who use this function? 103 func (ts TS) Prev() TS { 104 p, l := ts.Physical(), ts.Logical() 105 if l == 0 { 106 return BuildTS(p-1, math.MaxUint32) 107 } 108 return BuildTS(p, l-1) 109 } 110 func (ts TS) Next() TS { 111 p, l := ts.Physical(), ts.Logical() 112 if l == math.MaxUint32 { 113 return BuildTS(p+1, 0) 114 } 115 return BuildTS(p, l+1) 116 } 117 118 func (ts TS) ToString() string { 119 return fmt.Sprintf("%d-%d", ts.Physical(), ts.Logical()) 120 } 121 122 func StringToTS(s string) (ts TS) { 123 tmp := strings.Split(s, "-") 124 if len(tmp) != 2 { 125 panic("format of ts must be physical-logical") 126 } 127 128 pTime, err := strconv.ParseInt(tmp[0], 10, 64) 129 if err != nil { 130 panic("format of ts must be physical-logical, physical is not an integer") 131 } 132 133 lTime, err := strconv.ParseUint(tmp[1], 10, 32) 134 if err != nil { 135 panic("format of ts must be physical-logical, logical is not an uint32") 136 } 137 return BuildTS(pTime, uint32(lTime)) 138 } 139 140 // XXX 141 // XXX The following code does not belong to types. TAE folks please fix. 142 143 // CompoundKeyType -- this is simply deadly wrong thing. 144 var CompoundKeyType Type 145 146 // Why this was in package types? 147 var SystemDBTS TS 148 149 func init() { 150 CompoundKeyType = T_varchar.ToType() 151 CompoundKeyType.Width = 100 152 153 SystemDBTS = BuildTS(1, 0) 154 } 155 156 // Very opinioned code, almost surely a bug, but there you go. 157 type Null struct{} 158 159 func IsNull(v any) bool { 160 _, ok := v.(Null) 161 return ok 162 } 163 164 // TAE's own hash ... Sigh. 165 func Hash(v any, typ Type) (uint64, error) { 166 data := EncodeValue(v, typ) 167 xx := xxhash.Sum64(data) 168 return xx, nil 169 } 170 171 // Why don't we just do 172 // var v T 173 func DefaultVal[T any]() T { 174 var v T 175 return v 176 } 177 178 // TAE test infra, should move out 179 var ( 180 //just for test 181 GlobalTsAlloctor *TsAlloctor 182 ) 183 184 func init() { 185 GlobalTsAlloctor = NewTsAlloctor(NewMockHLCClock(1)) 186 } 187 188 type TsAlloctor struct { 189 clock clock.Clock 190 } 191 192 func NewTsAlloctor(clock clock.Clock) *TsAlloctor { 193 return &TsAlloctor{clock: clock} 194 } 195 196 func (alloc *TsAlloctor) Alloc() TS { 197 now, _ := alloc.clock.Now() 198 var ts TS 199 copy(ts[4:12], EncodeInt64(&now.PhysicalTime)) 200 copy(ts[:4], EncodeUint32(&now.LogicalTime)) 201 return ts 202 } 203 204 // TODO::will be removed 205 func (alloc *TsAlloctor) Get() TS { 206 if mockClock, ok := alloc.clock.(*MockHLCClock); ok { 207 var ts TS 208 i64 := mockClock.Get().PhysicalTime 209 copy(ts[4:12], EncodeInt64(&i64)) 210 //copy(ts[:4], EncodeUint32(mockClock.Get().LogicalTime)) 211 return ts 212 } 213 panic("HLCClock does not support Get()") 214 } 215 216 func (alloc *TsAlloctor) SetStart(start TS) { 217 //if start.Greater(alloc.Get()) { 218 alloc.clock.Update(timestamp.Timestamp{PhysicalTime: DecodeInt64(start[4:12]), 219 LogicalTime: DecodeUint32(start[:4])}) 220 //} 221 } 222 223 func NextGlobalTsForTest() TS { 224 return GlobalTsAlloctor.Alloc() 225 } 226 227 type MockHLCClock struct { 228 pTime int64 229 //always be 0 230 //lTime uint32 231 maxOffset time.Duration 232 } 233 234 // Just for test , start >= 1 235 func NewMockHLCClock(start int64) *MockHLCClock { 236 return &MockHLCClock{pTime: start} 237 } 238 239 func (c *MockHLCClock) Now() (timestamp.Timestamp, timestamp.Timestamp) { 240 now := timestamp.Timestamp{ 241 PhysicalTime: atomic.AddInt64(&c.pTime, 1), 242 //LogicalTime: c.lTime, 243 } 244 return now, timestamp.Timestamp{PhysicalTime: now.PhysicalTime + int64(c.maxOffset)} 245 } 246 247 // TODO::will be removed 248 func (c *MockHLCClock) Get() timestamp.Timestamp { 249 return timestamp.Timestamp{ 250 PhysicalTime: atomic.LoadInt64(&c.pTime), 251 //LogicalTime: c.lTime, 252 } 253 } 254 255 func (c *MockHLCClock) Update(m timestamp.Timestamp) { 256 atomic.StoreInt64(&c.pTime, m.PhysicalTime) 257 //atomic.StoreUint32(&c.lTime, m.LogicalTime) 258 } 259 260 func (c *MockHLCClock) HasNetworkLatency() bool { 261 return false 262 } 263 264 func (c *MockHLCClock) MaxOffset() time.Duration { 265 return c.maxOffset 266 } 267 268 func (c *MockHLCClock) SetNodeID(id uint16) { 269 // nothing to do. 270 } 271 272 func MockColTypes(colCnt int) (ct []Type) { 273 for i := 0; i < colCnt; i++ { 274 var typ Type 275 switch i { 276 case 0: 277 typ = Type{ 278 Oid: T_int8, 279 Size: 1, 280 Width: 8, 281 } 282 case 1: 283 typ = Type{ 284 Oid: T_int16, 285 Size: 2, 286 Width: 16, 287 } 288 case 2: 289 typ = Type{ 290 Oid: T_int32, 291 Size: 4, 292 Width: 32, 293 } 294 case 3: 295 typ = Type{ 296 Oid: T_int64, 297 Size: 8, 298 Width: 64, 299 } 300 case 4: 301 typ = Type{ 302 Oid: T_uint8, 303 Size: 1, 304 Width: 8, 305 } 306 case 5: 307 typ = Type{ 308 Oid: T_uint16, 309 Size: 2, 310 Width: 16, 311 } 312 case 6: 313 typ = Type{ 314 Oid: T_uint32, 315 Size: 4, 316 Width: 32, 317 } 318 case 7: 319 typ = Type{ 320 Oid: T_uint64, 321 Size: 8, 322 Width: 64, 323 } 324 case 8: 325 typ = Type{ 326 Oid: T_float32, 327 Size: 4, 328 Width: 32, 329 } 330 case 9: 331 typ = Type{ 332 Oid: T_float64, 333 Size: 8, 334 Width: 64, 335 } 336 case 10: 337 typ = Type{ 338 Oid: T_date, 339 Size: 4, 340 Width: 32, 341 } 342 case 11: 343 typ = Type{ 344 Oid: T_datetime, 345 Size: 8, 346 Width: 64, 347 } 348 case 12: 349 typ = Type{ 350 Oid: T_varchar, 351 Size: 24, 352 Width: 100, 353 } 354 case 13: 355 typ = Type{ 356 Oid: T_char, 357 Size: 24, 358 Width: 100, 359 } 360 case 14: 361 typ = T_bool.ToType() 362 typ.Width = 8 363 case 15: 364 typ = T_timestamp.ToType() 365 typ.Width = 64 366 case 16: 367 typ = T_decimal64.ToType() 368 typ.Width = 64 369 case 17: 370 typ = T_decimal128.ToType() 371 typ.Width = 128 372 } 373 ct = append(ct, typ) 374 } 375 return 376 } 377 378 func BuildRowid(a, b int64) (ret Rowid) { 379 copy(ret[0:8], EncodeInt64(&a)) 380 copy(ret[0:8], EncodeInt64(&b)) 381 return 382 } 383 384 func CompareTSTSAligned(a, b TS) int64 { 385 return int64(bytes.Compare(a[:], b[:])) 386 } 387 388 func CompareRowidRowidAligned(a, b Rowid) int64 { 389 return int64(bytes.Compare(a[:], b[:])) 390 }