+ generified implementation for RedisSortedSet

+ added BoundedZSet/ZSetOperations
This commit is contained in:
Costin Leau
2010-11-15 13:35:14 +01:00
parent d5365c146e
commit c909de1fb8
7 changed files with 441 additions and 58 deletions

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2010 the original author or authors.
*
* Licensed 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.springframework.datastore.redis.core;
import java.util.Set;
/**
* ZSet (or SortedSet) operations bound to a certain key.
*
* @author Costin Leau
*/
public interface BoundZSetOperations<K, V> extends KeyBound<K> {
RedisOperations<K, V> getOperations();
void intersectAndStore(K destKey, K... keys);
Set<V> range(int start, int end);
Set<V> rangeByScore(double min, double max);
void removeRange(int start, int end);
void removeRangeByScore(double min, double max);
void unionAndStore(K destKey, K... keys);
boolean add(V value, double score);
Integer rank(Object o);
boolean remove(Object o);
int size();
Set<V> reverseRange(int start, int end);
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright 2010 the original author or authors.
*
* Licensed 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.springframework.datastore.redis.core;
import java.util.Set;
/**
* Default implementation for {@link BoundZSetOperations}.
*
* @author Costin Leau
*/
class DefaultBoundZSetOperations<K, V> extends DefaultKeyBound<K> implements BoundZSetOperations<K, V> {
private final ZSetOperations<K, V> ops;
public DefaultBoundZSetOperations(K key, RedisTemplate<K, V> template) {
super(key);
this.ops = template.zSetOps();
}
@Override
public boolean add(V value, double score) {
return ops.add(getKey(), value, score);
}
@Override
public RedisOperations<K, V> getOperations() {
return ops.getOperations();
}
@Override
public void intersectAndStore(K destKey, K... keys) {
ops.intersectAndStore(getKey(), destKey, keys);
}
@Override
public Set<V> range(int start, int end) {
return ops.range(getKey(), start, end);
}
@Override
public Set<V> rangeByScore(double min, double max) {
return ops.rangeByScore(getKey(), min, max);
}
@Override
public Integer rank(Object o) {
return ops.rank(getKey(), o);
}
@Override
public boolean remove(Object o) {
return ops.remove(getKey(), o);
}
@Override
public void removeRange(int start, int end) {
ops.removeRange(getKey(), start, end);
}
@Override
public void removeRangeByScore(double min, double max) {
ops.removeRangeByScore(getKey(), min, max);
}
@Override
public Set<V> reverseRange(int start, int end) {
return ops.reverseRange(getKey(), start, end);
}
@Override
public int size() {
return ops.size(getKey());
}
@Override
public void unionAndStore(K destKey, K... keys) {
ops.unionAndStore(getKey(), destKey, keys);
}
}

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.datastore.redis.core;
/**
* Basic set of Redis operations, implemented by {@link RedisTemplate}.
*
@@ -45,4 +46,8 @@ public interface RedisOperations<K, V> {
SetOperations<K, V> setOps();
BoundSetOperations<K, V> forSet(K key);
ZSetOperations<K, V> zSetOps();
BoundZSetOperations<K, V> forZSet(K key);
}

View File

@@ -492,6 +492,16 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
// Set operations
//
private K[] aggregateKeys(K key, K... keys) {
Object[] aggregate = new Object[keys.length + 1];
aggregate[0] = key;
for (int i = 0; i < keys.length; i++) {
aggregate[i + 1] = keys[i];
}
return (K[]) aggregate;
}
@Override
public BoundSetOperations<K, V> forSet(K key) {
return new DefaultBoundSetOperations<K, V>(key, this);
@@ -516,16 +526,6 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
}, false);
}
private K[] aggregateKeys(K key, K... keys) {
Object[] aggregate = new Object[keys.length + 1];
aggregate[0] = key;
for (int i = 0; i < keys.length; i++) {
aggregate[i + 1] = keys[i];
}
return (K[]) aggregate;
}
@Override
public Set<V> diff(final K key, final K... keys) {
final byte[][] rawKeys = rawKeys(aggregateKeys(key, keys));
@@ -554,7 +554,7 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
@Override
public RedisOperations<K, V> getOperations() {
throw new UnsupportedOperationException();
return RedisTemplate.this;
}
@Override
@@ -648,7 +648,7 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
public void unionAndStore(K key, K destKey, K... keys) {
final byte[][] rawKeys = rawKeys(aggregateKeys(key, keys));
final byte[] rawDestKey = rawKey(destKey);
Object rawValues = execute(new RedisCallback<Object>() {
execute(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection connection) throws Exception {
connection.sUnionStore(rawDestKey, rawKeys);
@@ -657,4 +657,169 @@ public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperation
}, false);
}
}
//
// ZSet operations
//
@Override
public BoundZSetOperations<K, V> forZSet(K key) {
return new DefaultBoundZSetOperations<K, V>(key, this);
}
@Override
public ZSetOperations<K, V> zSetOps() {
return new DefaultZSetOperations();
}
private class DefaultZSetOperations implements ZSetOperations<K, V> {
@Override
public boolean add(final K key, final V value, final double score) {
final byte[] rawKey = rawKey(key);
final byte[] rawValue = rawValue(value);
return execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws Exception {
return connection.zAdd(rawKey, score, rawValue);
}
}, false);
}
@Override
public RedisOperations<K, V> getOperations() {
return RedisTemplate.this;
}
@Override
public void intersectAndStore(K key, K destKey, K... keys) {
final byte[][] rawKeys = rawKeys(aggregateKeys(key, keys));
final byte[] rawDestKey = rawKey(destKey);
execute(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection connection) throws Exception {
connection.zInterStore(rawDestKey, rawKeys);
return null;
}
}, false);
}
@Override
public Set<V> range(K key, final int start, final int end) {
final byte[] rawKey = rawKey(key);
Set<byte[]> rawValues = execute(new RedisCallback<Set<byte[]>>() {
@Override
public Set<byte[]> doInRedis(RedisConnection connection) throws Exception {
return connection.zRange(rawKey, start, end);
}
}, false);
return values(rawValues, Set.class);
}
@Override
public Set<V> rangeByScore(K key, final double min, final double max) {
final byte[] rawKey = rawKey(key);
Set<byte[]> rawValues = execute(new RedisCallback<Set<byte[]>>() {
@Override
public Set<byte[]> doInRedis(RedisConnection connection) throws Exception {
return connection.zRangeByScore(rawKey, min, max);
}
}, false);
return values(rawValues, Set.class);
}
@Override
public Integer rank(K key, Object o) {
final byte[] rawKey = rawKey(key);
final byte[] rawValue = rawValue(o);
return execute(new RedisCallback<Integer>() {
@Override
public Integer doInRedis(RedisConnection connection) throws Exception {
return connection.zRank(rawKey, rawValue);
}
}, false);
}
@Override
public boolean remove(K key, Object o) {
final byte[] rawKey = rawKey(key);
final byte[] rawValue = rawValue(o);
return execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws Exception {
return connection.zRem(rawKey, rawValue);
}
}, false);
}
@Override
public void removeRange(K key, final int start, final int end) {
final byte[] rawKey = rawKey(key);
execute(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection connection) throws Exception {
connection.zRemRange(rawKey, start, end);
return null;
}
}, false);
}
@Override
public void removeRangeByScore(K key, final double min, final double max) {
final byte[] rawKey = rawKey(key);
execute(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection connection) throws Exception {
connection.zRemRangeByScore(rawKey, min, max);
return null;
}
}, false);
}
@Override
public Set<V> reverseRange(K key, final int start, final int end) {
final byte[] rawKey = rawKey(key);
Set<byte[]> rawValues = execute(new RedisCallback<Set<byte[]>>() {
@Override
public Set<byte[]> doInRedis(RedisConnection connection) throws Exception {
return connection.zRevRange(rawKey, start, end);
}
}, false);
return values(rawValues, Set.class);
}
@Override
public int size(K key) {
final byte[] rawKey = rawKey(key);
return execute(new RedisCallback<Integer>() {
@Override
public Integer doInRedis(RedisConnection connection) throws Exception {
return connection.zCard(rawKey);
}
}, false);
}
@Override
public void unionAndStore(K key, K destKey, K... keys) {
final byte[][] rawKeys = rawKeys(aggregateKeys(key, keys));
final byte[] rawDestKey = rawKey(destKey);
execute(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection connection) throws Exception {
connection.zUnionStore(rawDestKey, rawKeys);
return null;
}
}, false);
}
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2010 the original author or authors.
*
* Licensed 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.springframework.datastore.redis.core;
import java.util.Set;
/**
* Redis ZSet/sorted set specific operations.
*
* @author Costin Leau
*/
public interface ZSetOperations<K, V> {
void intersectAndStore(K key, K destKey, K... keys);
Set<V> range(K key, int start, int end);
Set<V> rangeByScore(K key, double min, double max);
void removeRange(K key, int start, int end);
void removeRangeByScore(K key, double min, double max);
void unionAndStore(K key, K destKey, K... keys);
boolean add(K key, V value, double score);
Integer rank(K key, Object o);
boolean remove(K key, Object o);
int size(K key);
Set<V> reverseRange(K key, int start, int end);
RedisOperations<K, V> getOperations();
}

View File

@@ -20,126 +20,142 @@ import java.util.Iterator;
import java.util.Set;
import java.util.SortedSet;
import org.springframework.datastore.redis.connection.RedisCommands;
import org.springframework.datastore.redis.core.BoundZSetOperations;
import org.springframework.datastore.redis.core.RedisOperations;
/**
* Default implementation for {@link RedisSortedSet}.
*
* @author Costin Leau
*/
class DefaultRedisSortedSet extends AbstractRedisCollection<String> implements RedisSortedSet {
class DefaultRedisSortedSet<E> extends AbstractRedisCollection<E> implements RedisSortedSet<E> {
private class DefaultRedisSortedSetIterator extends RedisIterator<String> {
private final BoundZSetOperations<String, E> boundZSetOps;
private class DefaultRedisSortedSetIterator extends RedisIterator<E> {
public DefaultRedisSortedSetIterator(Iterator<String> delegate) {
public DefaultRedisSortedSetIterator(Iterator<E> delegate) {
super(delegate);
}
@Override
protected void removeFromRedisStorage(String item) {
protected void removeFromRedisStorage(E item) {
DefaultRedisSortedSet.this.remove(item);
}
}
public DefaultRedisSortedSet(String key, RedisCommands commands) {
super(key, commands);
/**
* Constructs a new <code>DefaultRedisSortedSet</code> instance.
*
* @param key
* @param operations
*/
public DefaultRedisSortedSet(String key, RedisOperations<String, E> operations) {
super(key, operations);
boundZSetOps = operations.forZSet(key);
}
public DefaultRedisSortedSet(BoundZSetOperations<String, E> boundOps) {
super(boundOps.getKey(), boundOps.getOperations());
this.boundZSetOps = boundOps;
}
@Override
public RedisSortedSet intersectAndStore(String destKey, RedisSortedSet... sets) {
commands.zInterStore(destKey, extractKeys(sets));
return new DefaultRedisSortedSet(destKey, commands);
public RedisSortedSet<E> intersectAndStore(String destKey, RedisSortedSet<E>... sets) {
boundZSetOps.intersectAndStore(destKey, extractKeys(sets));
return new DefaultRedisSortedSet<E>(boundZSetOps.getOperations().forZSet(destKey));
}
@Override
public Set<String> range(int start, int end) {
return commands.zRange(key, start, end);
public Set<E> range(int start, int end) {
return boundZSetOps.range(start, end);
}
@Override
public Set<String> rangeByScore(double min, double max) {
return commands.zRangeByScore(key, min, max);
public Set<E> rangeByScore(double min, double max) {
return boundZSetOps.rangeByScore(min, max);
}
@Override
public RedisSortedSet remove(int start, int end) {
commands.zRemRange(key, start, end);
public RedisSortedSet<E> remove(int start, int end) {
boundZSetOps.removeRange(start, end);
return this;
}
@Override
public RedisSortedSet removeByScore(double min, double max) {
commands.zRemRangeByScore(key, min, max);
public RedisSortedSet<E> removeByScore(double min, double max) {
boundZSetOps.removeRangeByScore(min, max);
return this;
}
@Override
public RedisSortedSet unionAndStore(String destKey, RedisSortedSet... sets) {
commands.zUnionStore(destKey, extractKeys(sets));
return new DefaultRedisSortedSet(destKey, commands);
public RedisSortedSet<E> unionAndStore(String destKey, RedisSortedSet<E>... sets) {
boundZSetOps.unionAndStore(destKey, extractKeys(sets));
return new DefaultRedisSortedSet<E>(boundZSetOps.getOperations().forZSet(destKey));
}
@Override
public boolean add(String e) {
return commands.zAdd(key, 0, e);
public boolean add(E e) {
return boundZSetOps.add(e, 0);
}
@Override
public void clear() {
commands.zRemRange(key, 0, -1);
boundZSetOps.removeRange(0, -1);
}
@Override
public boolean contains(Object o) {
return (commands.zRank(key, o.toString()) != null);
return (boundZSetOps.rank(o) != null);
}
@Override
public Iterator<String> iterator() {
return new DefaultRedisSortedSetIterator(commands.zRange(key, 0, -1).iterator());
public Iterator<E> iterator() {
return new DefaultRedisSortedSetIterator(boundZSetOps.range(0, -1).iterator());
}
@Override
public boolean remove(Object o) {
return commands.zRem(key, o.toString());
return boundZSetOps.remove(o);
}
@Override
public int size() {
return commands.zCard(key);
return boundZSetOps.size();
}
@Override
public Comparator<? super String> comparator() {
public Comparator<? super E> comparator() {
return null;
}
@Override
public String first() {
return commands.zRange(key, 0, 0).iterator().next();
public E first() {
return boundZSetOps.range(0, 0).iterator().next();
}
@Override
public SortedSet<String> headSet(String toElement) {
public SortedSet<E> headSet(E toElement) {
throw new UnsupportedOperationException();
}
@Override
public String last() {
return commands.zRevRange(key, 0, 0).iterator().next();
public E last() {
return boundZSetOps.reverseRange(0, 0).iterator().next();
}
@Override
public SortedSet<String> subSet(String fromElement, String toElement) {
public SortedSet<E> subSet(E fromElement, E toElement) {
throw new UnsupportedOperationException();
}
@Override
public SortedSet<String> tailSet(String fromElement) {
public SortedSet<E> tailSet(E fromElement) {
throw new UnsupportedOperationException();
}
private String[] extractKeys(RedisSortedSet... sets) {
private String[] extractKeys(RedisSortedSet<E>... sets) {
String[] keys = new String[sets.length + 1];
keys[0] = key;
for (int i = 0; i < keys.length; i++) {

View File

@@ -20,21 +20,21 @@ import java.util.SortedSet;
/**
* Redis extension for the {@link SortedSet} contract. Supports {@link SortedSet} specific
* operations backed by Redis commands.
* operations backed by Redis operations.
*
* @author Costin Leau
*/
public interface RedisSortedSet extends RedisStore, SortedSet<String> {
public interface RedisSortedSet<E> extends RedisStore<String>, SortedSet<E> {
RedisSortedSet intersectAndStore(String destKey, RedisSortedSet... sets);
RedisSortedSet<E> intersectAndStore(String destKey, RedisSortedSet<E>... sets);
RedisSortedSet unionAndStore(String destKey, RedisSortedSet... sets);
RedisSortedSet<E> unionAndStore(String destKey, RedisSortedSet<E>... sets);
Set<String> range(int start, int end);
Set<E> range(int start, int end);
Set<String> rangeByScore(double min, double max);
Set<E> rangeByScore(double min, double max);
RedisSortedSet remove(int start, int end);
RedisSortedSet<E> remove(int start, int end);
RedisSortedSet removeByScore(double min, double max);
RedisSortedSet<E> removeByScore(double min, double max);
}