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  }