package edu.uw.zookeeper.client.random; import java.util.Random; import com.google.common.collect.ImmutableList; import edu.uw.zookeeper.data.ZNodeCache; import edu.uw.zookeeper.common.Generator; import edu.uw.zookeeper.data.AbsoluteZNodePath; import edu.uw.zookeeper.data.CreateMode; import edu.uw.zookeeper.data.LockableZNodeCache; import edu.uw.zookeeper.data.Operations; import edu.uw.zookeeper.data.StampedValue; import edu.uw.zookeeper.data.ZNodePath; import edu.uw.zookeeper.data.ZNodeLabel; import edu.uw.zookeeper.protocol.proto.OpCode; import edu.uw.zookeeper.protocol.proto.Records; import edu.uw.zookeeper.protocol.proto.Stats; public class RandomRequestGenerator implements Generator<Records.Request> { public static RandomRequestGenerator fromCache( LockableZNodeCache<?,?,?> cache) { Random random = new Random(); RandomLabel labels = RandomLabel.create(random, 1, 9); RandomData datum = RandomData.create(random, 0, 1024); CachedPaths paths = CachedPaths.fromCache(cache, random); RandomFromList<OpCode> opcodes = RandomFromList.create(random, BASIC_OPCODES); return new RandomRequestGenerator( random, opcodes, paths, labels, datum, cache); } protected static final ImmutableList<OpCode> BASIC_OPCODES = ImmutableList.of( OpCode.CREATE, OpCode.GET_CHILDREN, OpCode.DELETE, OpCode.EXISTS, OpCode.GET_DATA, OpCode.SET_DATA, OpCode.SYNC); protected final Random random; protected final ZNodeCache<?,?,?> cache; protected final Generator<OpCode> opcodes; protected final Generator<ZNodePath> paths; protected final Generator<ZNodeLabel> labels; protected final Generator<byte[]> datum; protected RandomRequestGenerator( Random random, Generator<OpCode> opcodes, Generator<ZNodePath> paths, Generator<ZNodeLabel> labels, Generator<byte[]> datum, ZNodeCache<?,?,?> client) { this.random = random; this.opcodes = opcodes; this.labels = labels; this.datum = datum; this.cache = client; this.paths = paths; } @Override public synchronized Records.Request next() { Operations.Builder<? extends Records.Request> builder; synchronized (cache.cache()) { ZNodePath path; ZNodeCache.CacheNode<?,?> node = null; do { path = nextPath(); node = cache.cache().get(path); } while (node == null); StampedValue<Records.ZNodeStatGetter> statView = node.stat(); Records.ZNodeStatGetter stat = (statView == null) ? null : statView.get(); int version = (stat == null) ? Stats.VERSION_ANY : stat.getVersion(); OpCode opcode; while (true) { opcode = opcodes.next(); if (opcode == OpCode.DELETE) { if (path.isRoot() || !node.isEmpty()) { continue; } } else if ((opcode == OpCode.CREATE) || (opcode == OpCode.CREATE2)) { if ((stat == null) || (stat.getEphemeralOwner() != Stats.CreateStat.ephemeralOwnerNone())) { continue; } } break; } builder = Operations.Requests.fromOpCode(opcode); if (builder instanceof Operations.Requests.Create) { CreateMode mode = CreateMode.values()[random.nextInt(CreateMode.values().length)]; ZNodeLabel child = labels.next(); while (node.containsKey(child)) { child = labels.next(); } ((Operations.Requests.Create) builder).setPath(path.join(child)).setMode(mode).setData(datum.next()); } else { ((Operations.PathBuilder<?,?>) builder).setPath(path); if (builder instanceof Operations.Requests.VersionBuilder<?,?>) { ((Operations.Requests.VersionBuilder<?,?>) builder).setVersion(version); } if (builder instanceof Operations.Requests.WatchBuilder<?,?>) { ((Operations.Requests.WatchBuilder<?,?>) builder).setWatch(random.nextBoolean()); } if (builder instanceof Operations.DataBuilder<?,?>) { ((Operations.DataBuilder<?,?>) builder).setData(datum.next()); } } } return builder.build(); } protected ZNodePath nextPath() { ZNodePath path; do { path = paths.next(); } while (path.startsWith(AbsoluteZNodePath.zookeeper())); return path; } }