func (t *timestampOracle) differentiateLogical(rawLogical int64, suffixBits int) int64 {
	return rawLogical<<suffixBits + int64(t.suffix)
}
Because the Local TSO in each Local TSO Allocator is independent, so they are possible
to be the same at sometimes, to avoid this case, we need to use the logical part of the
Local TSO to do some differentiating work.
For example, we have three DCs: dc-1, dc-2 and dc-3. The bits of suffix is defined by
the const suffixBits. Then, for dc-2, the suffix may be 1 because it's persisted
in etcd with the value of 1.
Once we get a noramal TSO like this (18 bits): xxxxxxxxxxxxxxxxxx. We will make the TSO's
low bits of logical part from each DC looks like:
global: xxxxxxxxxx00000000
dc-1: xxxxxxxxxx00000001
dc-2: xxxxxxxxxx00000010
dc-3: xxxxxxxxxx00000011
package tso
import (
	"fmt"
	"path"
	"strings"
	"sync"
	"sync/atomic"
	"time"
	"github.com/pingcap/failpoint"
	"github.com/pingcap/kvproto/pkg/pdpb"
	"github.com/pingcap/log"
	"github.com/tikv/pd/pkg/errs"
	"github.com/tikv/pd/pkg/etcdutil"
	"github.com/tikv/pd/pkg/tsoutil"
	"github.com/tikv/pd/pkg/typeutil"
	"github.com/tikv/pd/server/election"
	"go.etcd.io/etcd/clientv3"
	"go.uber.org/zap"
)
const (
	timestampKey = "timestamp"
	UpdateTimestampGuard = time.Millisecond
	maxLogical = int64(1 << 18)
	MaxSuffixBits = 4
)
type tsoObject struct {
	sync.RWMutex
	physical   time.Time
	logical    int64
	updateTime time.Time
}
type timestampOracle struct {
	client   *clientv3.Client
	rootPath string
	saveInterval           time.Duration
	updatePhysicalInterval time.Duration
	maxResetTSGap          func() time.Duration
	tsoMux *tsoObject
	lastSavedTime atomic.Value  
	suffix        int
	dcLocation    string
}
func (t *timestampOracle) setTSOPhysical(next time.Time) {
	t.tsoMux.Lock()
	defer t.tsoMux.Unlock()
	if typeutil.SubTSOPhysicalByWallClock(next, t.tsoMux.physical) > 0 {
		t.tsoMux.physical = next
		t.tsoMux.logical = 0
		t.setTSOUpdateTimeLocked(time.Now())
	}
}
func (t *timestampOracle) setTSOUpdateTimeLocked(updateTime time.Time) {
	t.tsoMux.updateTime = updateTime
	tsoGauge.WithLabelValues("tso_update_time", t.dcLocation).Set(float64(updateTime.UnixNano() / int64(time.Millisecond)))
}
func (t *timestampOracle) getTSO() (time.Time, int64) {
	t.tsoMux.RLock()
	defer t.tsoMux.RUnlock()
	if t.tsoMux.physical == typeutil.ZeroTime {
		return typeutil.ZeroTime, 0
	}
	return t.tsoMux.physical, t.tsoMux.logical
}
func (t *timestampOracle) generateTSO(count int64, suffixBits int) (physical int64, logical int64, lastUpdateTime time.Time) {
	t.tsoMux.Lock()
	defer t.tsoMux.Unlock()
	if t.tsoMux.physical == typeutil.ZeroTime {
		return 0, 0, typeutil.ZeroTime
	}
	physical = t.tsoMux.physical.UnixNano() / int64(time.Millisecond)
	t.tsoMux.logical += count
	logical = t.tsoMux.logical
	if suffixBits > 0 && t.suffix >= 0 {
		logical = t.differentiateLogical(logical, suffixBits)
	}
	lastUpdateTime = t.tsoMux.updateTime
	t.setTSOUpdateTimeLocked(time.Now())
	return physical, logical, lastUpdateTime
}