GEODE-9291 Benchmarks for sorted sets (#158)
Basic ZADD and ZRANGE benchmarks for redis sorted sets.
diff --git a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/HgetRedisTask.java b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/HgetRedisTask.java
index 6b1a3a5..84e434e 100644
--- a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/HgetRedisTask.java
+++ b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/HgetRedisTask.java
@@ -17,8 +17,8 @@
package org.apache.geode.benchmark.redis.tasks;
-import static org.apache.geode.benchmark.redis.tasks.RedisHash.toField;
-import static org.apache.geode.benchmark.redis.tasks.RedisHash.toKey;
+import static org.apache.geode.benchmark.redis.tasks.RedisSplitKey.toPart;
+import static org.apache.geode.benchmark.redis.tasks.RedisSplitKey.toKey;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.Serializable;
@@ -62,7 +62,7 @@
final long k = keyRange.random();
final String key = keyCache.valueOf(toKey(k));
- final String field = keyCache.valueOf(toField(k));
+ final String field = keyCache.valueOf(toPart(k));
final String value = redisClient.hget(key, field);
if (validate) {
assertThat(value).isEqualTo(field);
diff --git a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/HsetRedisTask.java b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/HsetRedisTask.java
index 6c902e8..96b3a21 100644
--- a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/HsetRedisTask.java
+++ b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/HsetRedisTask.java
@@ -18,8 +18,8 @@
package org.apache.geode.benchmark.redis.tasks;
-import static org.apache.geode.benchmark.redis.tasks.RedisHash.toField;
-import static org.apache.geode.benchmark.redis.tasks.RedisHash.toKey;
+import static org.apache.geode.benchmark.redis.tasks.RedisSplitKey.toPart;
+import static org.apache.geode.benchmark.redis.tasks.RedisSplitKey.toKey;
import java.io.Serializable;
import java.util.Map;
@@ -58,7 +58,7 @@
public boolean test(final Map<Object, Object> ctx) throws Exception {
final long k = keyRange.random();
final String key = keyCache.valueOf(toKey(k));
- final String field = keyCache.valueOf(toField(k));
+ final String field = keyCache.valueOf(toPart(k));
final String value = keyCache.valueOf(k);
redisClient.hset(key, field, value);
return true;
diff --git a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/JedisClientManager.java b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/JedisClientManager.java
index ffaae83..bb6af11 100644
--- a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/JedisClientManager.java
+++ b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/JedisClientManager.java
@@ -58,6 +58,16 @@
}
@Override
+ public long zadd(String key, double score, String value) {
+ return jedisCluster.zadd(key, score, value);
+ }
+
+ @Override
+ public Set<String> zrange(String key, long start, long stop) {
+ return jedisCluster.zrange(key, start, stop);
+ }
+
+ @Override
public void flushdb() {
Set<String> seen = new HashSet<>();
for (int i = 0; i < HASHSLOTS; ++i) {
diff --git a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/LettuceClientManager.java b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/LettuceClientManager.java
index bd38216..028b430 100644
--- a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/LettuceClientManager.java
+++ b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/LettuceClientManager.java
@@ -19,7 +19,9 @@
import java.net.InetSocketAddress;
import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.stream.Collectors;
import io.lettuce.core.ReadFrom;
@@ -68,6 +70,16 @@
}
@Override
+ public long zadd(String key, double score, String value) {
+ return redisAdvancedClusterCommands.get().zadd(key, score, value);
+ }
+
+ @Override
+ public Set<String> zrange(String key, long start, long stop) {
+ return new HashSet<>(redisAdvancedClusterCommands.get().zrange(key, start, stop));
+ }
+
+ @Override
public void flushdb() {
redisAdvancedClusterCommands.get().flushdb();
}
diff --git a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/PrePopulateRedisHash.java b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/PrePopulateRedisHash.java
index c36371d..14299e4 100644
--- a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/PrePopulateRedisHash.java
+++ b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/PrePopulateRedisHash.java
@@ -18,8 +18,8 @@
package org.apache.geode.benchmark.redis.tasks;
import static java.lang.String.valueOf;
-import static org.apache.geode.benchmark.redis.tasks.RedisHash.toField;
-import static org.apache.geode.benchmark.redis.tasks.RedisHash.toKey;
+import static org.apache.geode.benchmark.redis.tasks.RedisSplitKey.toPart;
+import static org.apache.geode.benchmark.redis.tasks.RedisSplitKey.toKey;
import org.apache.geode.benchmark.LongRange;
@@ -33,7 +33,7 @@
@Override
protected void prepopulate(final RedisClient redisClient, final long key) {
- final String value = valueOf(toField(key));
+ final String value = valueOf(toPart(key));
redisClient.hset(valueOf(toKey(key)), value, value);
}
}
diff --git a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/PrePopulateRedisSortedSet.java b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/PrePopulateRedisSortedSet.java
new file mode 100644
index 0000000..9de9ff6
--- /dev/null
+++ b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/PrePopulateRedisSortedSet.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.geode.benchmark.redis.tasks;
+
+import static java.lang.String.valueOf;
+import static org.apache.geode.benchmark.redis.tasks.RedisSplitKey.toPart;
+import static org.apache.geode.benchmark.redis.tasks.RedisSplitKey.toKey;
+
+import org.apache.geode.benchmark.LongRange;
+
+public class PrePopulateRedisSortedSet extends AbstractPrePopulate {
+
+ public PrePopulateRedisSortedSet(
+ final RedisClientManager redisClientManager,
+ final LongRange keyRangeToPrepopulate) {
+ super(redisClientManager, keyRangeToPrepopulate);
+ }
+
+ @Override
+ protected void prepopulate(final RedisClient redisClient, final long key) {
+ final long score = toPart(key);
+ final String value = valueOf(score);
+ redisClient.zadd(valueOf(toKey(key)), score, value);
+ }
+}
diff --git a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/RedisClient.java b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/RedisClient.java
index 6155536..732a332 100644
--- a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/RedisClient.java
+++ b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/RedisClient.java
@@ -15,6 +15,8 @@
package org.apache.geode.benchmark.redis.tasks;
+import java.util.Set;
+
public interface RedisClient {
String get(String key);
@@ -25,4 +27,8 @@
boolean hset(String key, String field, String value);
void flushdb();
+
+ long zadd(String key, double score, String value);
+
+ Set<String> zrange(String key, long start, long stop);
}
diff --git a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/RedisHash.java b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/RedisSplitKey.java
similarity index 79%
rename from geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/RedisHash.java
rename to geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/RedisSplitKey.java
index 3aecb0b..b32525d 100644
--- a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/RedisHash.java
+++ b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/RedisSplitKey.java
@@ -16,15 +16,17 @@
package org.apache.geode.benchmark.redis.tasks;
/**
- * Split keyspace into Redis hash key and field parts.
+ * Split keyspace into a sublevel of keys.
*/
-public class RedisHash {
+public class RedisSplitKey {
+
+ public static long NUM_PARTS_PER_KEY = 1000;
public static long toKey(final long key) {
- return key / 1000;
+ return key / NUM_PARTS_PER_KEY;
}
- public static long toField(final long key) {
- return key % 1000;
+ public static long toPart(final long key) {
+ return key % NUM_PARTS_PER_KEY;
}
}
diff --git a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/ZaddRedisTask.java b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/ZaddRedisTask.java
new file mode 100644
index 0000000..5016c66
--- /dev/null
+++ b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/ZaddRedisTask.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.geode.benchmark.redis.tasks;
+
+
+import static org.apache.geode.benchmark.redis.tasks.RedisSplitKey.toPart;
+import static org.apache.geode.benchmark.redis.tasks.RedisSplitKey.toKey;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.yardstickframework.BenchmarkConfiguration;
+import org.yardstickframework.BenchmarkDriverAdapter;
+
+import org.apache.geode.benchmark.LongRange;
+
+public class ZaddRedisTask extends BenchmarkDriverAdapter implements Serializable {
+ private static final Logger logger = LoggerFactory.getLogger(ZaddRedisTask.class);
+
+ private final RedisClientManager redisClientManager;
+ private final LongRange keyRange;
+
+ private transient LongStringCache keyCache;
+ private transient RedisClient redisClient;
+
+ public ZaddRedisTask(final RedisClientManager redisClientManager, final LongRange keyRange) {
+ logger.info("Initialized: keyRange={}", keyRange);
+ this.redisClientManager = redisClientManager;
+ this.keyRange = keyRange;
+ }
+
+ @Override
+ public void setUp(final BenchmarkConfiguration cfg) throws Exception {
+ super.setUp(cfg);
+
+ keyCache = new LongStringCache(keyRange);
+ redisClient = redisClientManager.get();
+ }
+
+ @Override
+ public boolean test(final Map<Object, Object> ctx) throws Exception {
+ final long k = keyRange.random();
+
+ final String key = keyCache.valueOf(toKey(k));
+ final long score = toPart(k);
+ final String value = keyCache.valueOf(score);
+ redisClient.zadd(key, score, value);
+ return true;
+ }
+
+}
diff --git a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/ZrangeRedisTask.java b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/ZrangeRedisTask.java
new file mode 100644
index 0000000..641388b
--- /dev/null
+++ b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tasks/ZrangeRedisTask.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.geode.benchmark.redis.tasks;
+
+import static org.apache.geode.benchmark.redis.tasks.RedisSplitKey.toKey;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.Collectors;
+import java.util.stream.LongStream;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.yardstickframework.BenchmarkConfiguration;
+import org.yardstickframework.BenchmarkDriverAdapter;
+
+import org.apache.geode.benchmark.LongRange;
+
+public class ZrangeRedisTask extends BenchmarkDriverAdapter implements Serializable {
+ private static final Logger logger = LoggerFactory.getLogger(ZrangeRedisTask.class);
+
+ private final RedisClientManager redisClientManager;
+ private final LongRange keyRange;
+ private final boolean validate;
+
+ private transient LongStringCache keyCache;
+ private transient RedisClient redisClient;
+
+ public ZrangeRedisTask(final RedisClientManager redisClientManager, final LongRange keyRange,
+ final boolean validate) {
+ logger.info("Initialized: keyRange={}, validate={}", keyRange, validate);
+ this.redisClientManager = redisClientManager;
+ this.keyRange = keyRange;
+ this.validate = validate;
+ }
+
+ @Override
+ public void setUp(final BenchmarkConfiguration cfg) throws Exception {
+ super.setUp(cfg);
+
+ keyCache = new LongStringCache(keyRange);
+ redisClient = redisClientManager.get();
+ }
+
+ @Override
+ public boolean test(final Map<Object, Object> ctx) throws Exception {
+ final long k = keyRange.random();
+
+ final String key = keyCache.valueOf(toKey(k));
+
+ final long start = ThreadLocalRandom.current()
+ .nextLong(0, RedisSplitKey.NUM_PARTS_PER_KEY);
+ final long len = ThreadLocalRandom.current()
+ .nextLong(0, RedisSplitKey.NUM_PARTS_PER_KEY - start);
+ final long stop = start + len;
+
+ final Set<String> values = redisClient.zrange(key, start, stop);
+ if (validate) {
+ final LongRange range =
+ new LongRange(start, stop);
+
+ final Set<String> expectedValues =
+ LongStream.range(range.getMin(), range.getMax())
+ .boxed()
+ .map(keyCache::valueOf)
+ .collect(Collectors.toSet());
+
+ assertThat(values).isEqualTo(expectedValues);
+ }
+ return true;
+ }
+
+}
diff --git a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tests/RedisZaddBenchmark.java b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tests/RedisZaddBenchmark.java
new file mode 100644
index 0000000..a4ea713
--- /dev/null
+++ b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tests/RedisZaddBenchmark.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.geode.benchmark.redis.tests;
+
+import static org.apache.geode.benchmark.Config.before;
+import static org.apache.geode.benchmark.Config.workload;
+import static org.apache.geode.benchmark.topology.Roles.CLIENT;
+
+import org.apache.geode.benchmark.redis.tasks.HsetRedisTask;
+import org.apache.geode.benchmark.redis.tasks.PrePopulateRedisHash;
+import org.apache.geode.benchmark.redis.tasks.PrePopulateRedisSortedSet;
+import org.apache.geode.benchmark.redis.tasks.ZaddRedisTask;
+import org.apache.geode.perftest.TestConfig;
+
+public class RedisZaddBenchmark extends RedisBenchmark {
+
+ @Override
+ public TestConfig configure() {
+ final TestConfig config = super.configure();
+
+ before(config, new PrePopulateRedisSortedSet(redisClientManager, keyRange), CLIENT);
+ workload(config, new ZaddRedisTask(redisClientManager, keyRange),
+ CLIENT);
+ return config;
+ }
+}
diff --git a/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tests/RedisZrangeBenchmark.java b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tests/RedisZrangeBenchmark.java
new file mode 100644
index 0000000..c2474af
--- /dev/null
+++ b/geode-benchmarks/src/main/java/org/apache/geode/benchmark/redis/tests/RedisZrangeBenchmark.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.geode.benchmark.redis.tests;
+
+import static org.apache.geode.benchmark.Config.before;
+import static org.apache.geode.benchmark.Config.workload;
+import static org.apache.geode.benchmark.topology.Roles.CLIENT;
+
+import org.apache.geode.benchmark.redis.tasks.PrePopulateRedisSortedSet;
+import org.apache.geode.benchmark.redis.tasks.ZrangeRedisTask;
+import org.apache.geode.perftest.TestConfig;
+
+public class RedisZrangeBenchmark extends RedisBenchmark {
+
+ @Override
+ public TestConfig configure() {
+ final TestConfig config = super.configure();
+
+ before(config, new PrePopulateRedisSortedSet(redisClientManager, keyRange), CLIENT);
+ workload(config, new ZrangeRedisTask(redisClientManager, keyRange, isValidationEnabled()),
+ CLIENT);
+ return config;
+ }
+}