- CAS(Compare-and-Swap)でカウンタを実現する
- CASとは?
import java.nio.ByteBuffer
import org.apache.zookeeper.ZooKeeper
import org.apache.zookeeper.ZooDefs.Ids
import org.apache.zookeeper.CreateMode
import org.apache.zookeeper.KeeperException
class PrimitiveCounter {
private ZooKeeper zk
private String path
PrimitiveCounter(ZooKeeper zk, path) {
this.zk = zk
this.path = path
if (zk.exists(path, false) == null) {
zk.create(path, toBytes(0), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT)
} else {
get() //既にPathが存在している場合、カウンタ用のznodeであるか確認する
}
}
def long incrementAndGet() {
def counter
while (true) {
try {
def stat = zk.exists(path, false)
if (stat == null) throw new RuntimeException()
byte[] data = zk.getData(path, false, stat)
counter = toLong(data) + 1
zk.setData(path, toBytes(counter), stat.getVersion())
break;
} catch (KeeperException e) {
}
}
return counter
}
def long get() {
def stat = zk.exists(path, false)
if (stat == null) throw new RuntimeException()
byte[] data = zk.getData(path, false, stat)
return toLong(data)
}
private def byte[] toBytes(long value) {
return ByteBuffer.allocate(8).putLong(value).array()
}
private def long toLong(byte[] value) {
return ByteBuffer.wrap(value).getLong()
}
}