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