Skip to content
Permalink
Browse files
GEODE-9291 Benchmarks for sorted sets (#158)
Basic ZADD and ZRANGE benchmarks for redis sorted sets.
  • Loading branch information
ezoerner committed Oct 27, 2021
1 parent db2a063 commit 6f9b9c859f1ed39f414b589f418ce48254c9d697
Showing 12 changed files with 323 additions and 14 deletions.
@@ -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 @@ 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 = redisClient.hget(key, field);
if (validate) {
assertThat(value).isEqualTo(field);
@@ -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 void setUp(final BenchmarkConfiguration cfg) throws Exception {
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;
@@ -57,6 +57,16 @@ public boolean hset(final String key, final String field, final String value) {
return 1 == jedisCluster.hset(key, field, value);
}

@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<>();
@@ -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;
@@ -67,6 +69,16 @@ public boolean hset(final String key, final String field, final String value) {
return redisAdvancedClusterCommands.get().hset(key, field, value);
}

@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();
@@ -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 @@ public PrePopulateRedisHash(

@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);
}
}
@@ -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);
}
}
@@ -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 @@ public interface RedisClient {
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);
}
@@ -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;
}
}
@@ -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;
}

}
@@ -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;
}

}
@@ -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;
}
}

0 comments on commit 6f9b9c8

Please sign in to comment.