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;
分类
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可以帮助跟踪某数据是否被更新。
