From 5d38ef36a0ba75ac2ec88aa285f86cb132b889ef Mon Sep 17 00:00:00 2001 From: Nikita Date: Thu, 2 Jan 2014 19:20:10 +0400 Subject: [PATCH] RedissonList added --- src/main/java/org/redisson/Redisson.java | 40 ++- src/main/java/org/redisson/RedissonList.java | 262 ++++++++++++++++++ .../java/org/redisson/RedissonListTest.java | 36 +++ 3 files changed, 331 insertions(+), 7 deletions(-) create mode 100644 src/main/java/org/redisson/RedissonList.java create mode 100644 src/test/java/org/redisson/RedissonListTest.java diff --git a/src/main/java/org/redisson/Redisson.java b/src/main/java/org/redisson/Redisson.java index 1e466f23d..c284ffb63 100644 --- a/src/main/java/org/redisson/Redisson.java +++ b/src/main/java/org/redisson/Redisson.java @@ -1,5 +1,6 @@ package org.redisson; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.Lock; @@ -12,6 +13,7 @@ import com.lambdaworks.redis.pubsub.RedisPubSubConnection; public class Redisson { // TODO drain after some time + private final ConcurrentMap listsMap = new ConcurrentHashMap(); private final ConcurrentMap mapsMap = new ConcurrentHashMap(); private final ConcurrentMap locksMap = new ConcurrentHashMap(); @@ -19,12 +21,36 @@ public class Redisson { RedisClient redisClient; - Redisson() { - redisClient = new RedisClient("localhost"); + Redisson(String host, int port) { + redisClient = new RedisClient(host, port); } public static Redisson create() { - return new Redisson(); + return create("localhost"); + } + + public static Redisson create(String host) { + return create(host, 6379); + } + + public static Redisson create(String host, int port) { + return new Redisson(host, port); + } + + public List getList(String name) { + RedissonList list = listsMap.get(name); + if (list == null) { + RedisConnection connection = connect(); + list = new RedissonList(connection, name); + RedissonList oldList = listsMap.putIfAbsent(name, list); + if (oldList != null) { + connection.close(); + + list = oldList; + } + } + + return list; } public ConcurrentMap getMap(String name) { @@ -43,10 +69,6 @@ public class Redisson { return map; } - RedisConnection connect() { - return redisClient.connect(codec); - } - public Lock getLock(String name) { RedissonLock lock = locksMap.get(name); if (lock == null) { @@ -67,4 +89,8 @@ public class Redisson { return lock; } + RedisConnection connect() { + return redisClient.connect(codec); + } } + diff --git a/src/main/java/org/redisson/RedissonList.java b/src/main/java/org/redisson/RedissonList.java new file mode 100644 index 000000000..d02e89b73 --- /dev/null +++ b/src/main/java/org/redisson/RedissonList.java @@ -0,0 +1,262 @@ +package org.redisson; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +import com.lambdaworks.redis.RedisConnection; + +public class RedissonList implements List { + + private RedisConnection connection; + private String name; + + RedissonList(RedisConnection connection, String name) { + this.connection = connection; + this.name = name; + } + + @Override + public int size() { + return connection.llen(name).intValue(); + } + + @Override + public boolean isEmpty() { + return size() == 0; + } + + @Override + public boolean contains(Object o) { + return indexOf(o) != -1; + } + + @Override + public Iterator iterator() { + return listIterator(); + } + + @Override + public Object[] toArray() { + List list = subList(0, size()); + return list.toArray(); + } + + @Override + public T[] toArray(T[] a) { + List list = subList(0, size()); + return list.toArray(a); + } + + @Override + public boolean add(V e) { + return connection.rpush(name, e) > 1; + } + + @Override + public boolean remove(Object o) { + return connection.lrem(name, 1, o) > 0; + } + + @Override + public boolean containsAll(Collection c) { + for (Object object : c) { + // TODO optimize - search bulk values at once in range + if (!contains(object)) { + return false; + } + } + return true; + } + + @Override + public boolean addAll(Collection c) { + for (V v : c) { + add(v); + } + return true; + } + + @Override + public boolean addAll(int index, Collection c) { + for (V v : c) { + add(index++, v); + } + return true; + } + + @Override + public boolean removeAll(Collection c) { + boolean result = false; + for (Object object : c) { + boolean res = connection.lrem(name, 0, object) > 0; + if (!result) { + result = res; + } + } + return result; + } + + @Override + public boolean retainAll(Collection c) { + boolean changed = false; + for (Iterator iterator = iterator(); iterator.hasNext();) { + V object = iterator.next(); + if (!c.contains(object)) { + iterator.remove(); + changed = true; + } + } + return changed; + } + + @Override + public void clear() { + connection.del(name); + } + + @Override + public V get(int index) { + return (V) connection.lindex(name, index); + } + + @Override + public V set(int index, V element) { + V prev = get(index); + connection.lset(name, index, element); + return prev; + } + + @Override + public void add(int index, V element) { + V value = get(index); + connection.linsert(name, true, value, element); + } + + @Override + public V remove(int index) { + V value = get(index); + connection.lrem(name, 1, value); + return value; + } + + @Override + public int indexOf(Object o) { + if (isEmpty()) { + return -1; + } + + int to = Math.max(size()/100, 1); + for (int i = 0; i < to; i++) { + List range = connection.lrange(name, i*100, i*100 + 100); + int index = range.indexOf(o); + if (index != -1) { + return index + i*100; + } + } + + return -1; + } + + @Override + public int lastIndexOf(Object o) { + if (isEmpty()) { + return -1; + } + + int to = Math.max(size()/100, 1); + for (int i = 1; i <= to; i++) { + List range = connection.lrange(name, -i*100, 100); + int index = range.indexOf(o); + if (index != -1) { + return index + i*100; + } + } + + return -1; + } + + @Override + public ListIterator listIterator() { + return listIterator(0); + } + + @Override + public ListIterator listIterator(final int ind) { + return new ListIterator() { + + private int currentIndex = ind - 1; + private boolean removeExecuted; + + @Override + public boolean hasNext() { + int size = size(); + return currentIndex+1 < size && size > 0; + } + + @Override + public V next() { + if (!hasNext()) { + throw new NoSuchElementException("No such element at index " + currentIndex); + } + currentIndex++; + removeExecuted = false; + return RedissonList.this.get(currentIndex); + } + + @Override + public void remove() { + if (removeExecuted) { + throw new IllegalStateException("Element been already deleted"); + } + RedissonList.this.remove(currentIndex); + removeExecuted = true; + } + + @Override + public boolean hasPrevious() { + int size = size(); + return currentIndex-1 < size && size > 0; + } + + @Override + public V previous() { + if (!hasPrevious()) { + throw new NoSuchElementException("No such element at index " + currentIndex); + } + currentIndex--; + removeExecuted = false; + return RedissonList.this.get(currentIndex); + } + + @Override + public int nextIndex() { + return currentIndex + 1; + } + + @Override + public int previousIndex() { + return currentIndex - 1; + } + + @Override + public void set(V e) { + RedissonList.this.set(currentIndex, e); + } + + @Override + public void add(V e) { + RedissonList.this.add(currentIndex, e); + } + }; + } + + @Override + public List subList(int fromIndex, int toIndex) { + return (List) connection.lrange(name, fromIndex, toIndex); + } + + +} diff --git a/src/test/java/org/redisson/RedissonListTest.java b/src/test/java/org/redisson/RedissonListTest.java new file mode 100644 index 000000000..96df0c0f9 --- /dev/null +++ b/src/test/java/org/redisson/RedissonListTest.java @@ -0,0 +1,36 @@ +package org.redisson; + +import java.util.List; + +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.Test; + +public class RedissonListTest { + + @Test + public void testSize() { + Redisson redisson = Redisson.create(); + List list = redisson.getList("list"); + + list.add("1"); + list.add("2"); + list.add("3"); + list.add("4"); + list.add("5"); + list.add("6"); + Assert.assertThat(list, Matchers.contains("1", "2", "3", "4", "5", "6")); + + list.remove("2"); + Assert.assertThat(list, Matchers.contains("1", "3", "4", "5", "6")); + + clear(list); + } + + private void clear(List list) { + list.clear(); + Assert.assertEquals(0, list.size()); + } + + +}