Datastax Cassandra Driver Analyst (4)-Configuration-TimestampGenerator

TimestampGenerator主要是标示请求的先后顺序,分本地和远程产生两种方式。

功能

功能是为了resolve conflicts,也为了识别数据新旧等。API DOC如下:

* Generates client-side, microsecond-precision query timestamps.
* Given that Cassandra uses those timestamps to resolve conflicts, implementations should generate
* incrementing timestamps for successive implementations.

 

查询timestamp可以使用下列CQL语法:writetime()

select id,writetime(id),ttl(id) FROM table;

分类

timestamp

 

Monotonic的意思可以参考网上找的一篇文章:

clock-realtime

代表机器上可以理解为当前的我们所常看的时间,其当time-of-day 被修改的时候而改变,这包括NTP对它的修改。

clock-monotonic

代表从过去某个固定的时间点开始的绝对的逝去时间,它不受任何系统time-of-day时钟修改的影响。
一共分为3种:
ServerSideTimestampGenerator:  客户端不产生,让服务器端自己产生维护;
AtomicMonotonicTimestampGenerator:客户端产生:使用的是CAS乐观锁;
private AtomicLong lastRef = new AtomicLong(0);

@Override
public long next() {
while (true) {
long last = lastRef.get();
long next = computeNext(last);
if (lastRef.compareAndSet(last, next))
return next;
}
}
ThreadLocalMonotonicTimestampGenerator:客户端产生:使用的是thread local产生.
  private final ThreadLocal<Long> lastRef = new ThreadLocal<Long>();

 @Override
 public long next() {
 Long last = this.lastRef.get();
 if (last == null)
 last = 0L;

 long next = computeNext(last);

 this.lastRef.set(next);
 return next;
 }
其中后两者复用如下代码:即在1ms之内能区分1000个请求,如果超过1000就区分不了。

protected long computeNext(long last) {
long millis = last / 1000;
long counter = last % 1000;

long now = clock.currentTime();

// System.currentTimeMillis can go backwards on an NTP resync, hence the ">" below
if (millis >= now) {
if (counter == 999)
logger.warn("Sub-millisecond counter overflowed, some query timestamps will not be distinct");
else
counter += 1;
} else {
millis = now;
counter = 0;
}

return millis * 1000 + counter;
}
使用
(1)组装请求:
 使用TimeStamp的代码:
long defaultTimestamp = Long.MIN_VALUE;
if (cluster.manager.protocolVersion().compareTo(ProtocolVersion.V3) >= 0) {
defaultTimestamp = statement.getDefaultTimestamp();
if (defaultTimestamp == Long.MIN_VALUE)
defaultTimestamp = cluster.getConfiguration().getPolicies().getTimestampGenerator().next();
}
可见:
 1)使用的协议版本要>=V3;
 2)   假设没有为statement设置timestamp,那么默认为 private volatile long defaultTimestamp = Long.MIN_VALUE; 然后会使用默认TimeStampGenerator去产生timestamp.即让server端自己产生。
public static TimestampGenerator defaultTimestampGenerator() {
return ServerSideTimestampGenerator.INSTANCE;
}

(2)编码请求:

 

第一步:初始化请求


 if (defaultTimestamp != Long.MIN_VALUE)
 flags.add(QueryFlag.DEFAULT_TIMESTAMP);

第二步:编码PDU

case V3:
 if (version == ProtocolVersion.V3 && flags.contains(QueryFlag.DEFAULT_TIMESTAMP))
 dest.writeLong(defaultTimestamp);

总结:
1 V3版本协议是可以为单独的Statement设置timestamp的;
com.datastax.driver.core.Statement.setDefaultTimestamp(long)
2 V3和V3之后的版本,如果不单独设置,默认采用的是让server自己产生的方式。
3 V3之前的版本client不做任何处理,让Server自己产生。
4 timestamp可以帮助跟踪某数据是否被更新。

 

发布者

傅, 健

程序员,Java、C++、开源爱好者. About me

发表评论