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  }