github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/store/localstore/local_version_provider.go (about) 1 package localstore 2 3 import ( 4 "errors" 5 "sync" 6 "time" 7 8 "github.com/insionng/yougam/libraries/ngaut/log" 9 "github.com/insionng/yougam/libraries/pingcap/tidb/kv" 10 ) 11 12 // ErrOverflow is the error returned by CurrentVersion, it describes if 13 // there're too many versions allocations in a very short period of time, ID 14 // may conflict. 15 var ErrOverflow = errors.New("overflow when allocating new version") 16 17 // LocalVersionProvider uses local timestamp for version. 18 type LocalVersionProvider struct { 19 mu sync.Mutex 20 lastTimestamp uint64 21 // logical guaranteed version's monotonic increasing for calls when lastTimestamp 22 // are equal. 23 logical uint64 24 } 25 26 const ( 27 timePrecisionOffset = 18 28 ) 29 30 func time2TsPhysical(t time.Time) uint64 { 31 return uint64((t.UnixNano() / int64(time.Millisecond)) << timePrecisionOffset) 32 } 33 34 func version2Second(v kv.Version) int64 { 35 return int64(v.Ver>>timePrecisionOffset) / 1000 36 } 37 38 // CurrentVersion implements the VersionProvider's GetCurrentVer interface. 39 func (l *LocalVersionProvider) CurrentVersion() (kv.Version, error) { 40 l.mu.Lock() 41 defer l.mu.Unlock() 42 43 for { 44 var ts uint64 45 ts = time2TsPhysical(time.Now()) 46 47 if l.lastTimestamp > ts { 48 log.Error("[kv] invalid physical time stamp") 49 continue 50 } 51 52 if l.lastTimestamp == uint64(ts) { 53 l.logical++ 54 if l.logical >= 1<<timePrecisionOffset { 55 return kv.Version{}, ErrOverflow 56 } 57 return kv.Version{Ver: ts + l.logical}, nil 58 } 59 l.lastTimestamp = ts 60 l.logical = 0 61 return kv.Version{Ver: ts}, nil 62 } 63 } 64 65 func localVersionToTimestamp(ver kv.Version) uint64 { 66 return ver.Ver >> timePrecisionOffset 67 }