package com.alibaba.doris.dataserver.store;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.alibaba.doris.common.data.Key;
import com.alibaba.doris.common.data.Pair;
import com.alibaba.doris.common.data.Value;
import com.alibaba.doris.common.data.impl.KeyImpl;
import com.alibaba.doris.common.data.impl.ValueImpl;
import com.alibaba.doris.common.data.util.ByteUtils;
import com.alibaba.doris.dataserver.store.exception.VersionConflictException;
/**
* 存储层通用单元测试
*
* @author ajun Email:jack.yuj@alibaba-inc.com
*/
public abstract class StorageTestUnit {
protected abstract Storage getStorage();
@Before
public void setUp() throws Exception {
getStorage().open();
}
@After
public void tearDown() throws Exception {
getStorage().close();
}
@Test
public void testGetAndSet() {
Storage storage = getStorage();
Key key = createKey("test");
Value value = createValue("啊荤万科假日巍峨峻岭123412341234Zhiwer%¥#@!(×&()");
Value vNew = storage.get(key);
assertNull("断言从存储中获取一个不存在的key,应该返回null", vNew);
storage.set(key, value);
vNew = storage.get(key);
assertNotNull(vNew);
assertTrue("断言,set到storage的值可以正常获取。", value.equals(vNew));
Value value2 = createValue("啊荤万科假日巍峨峻岭2");
storage.set(key, value2);
vNew = storage.get(key);
assertEquals("断言,set最新的值需要覆盖原有的值。", value2, vNew);
}
@Test
public void testCas() {
Storage storage = getStorage();
Key key = createKey("test");
Value value = createValue("啊荤万科假日巍峨峻岭2");
storage.set(key, value, true);
Value vNew = storage.get(key);
assertEquals("断言cas,当key在存储中不存在时,cas能够保存数据。", value, vNew);
Value value1 = createValue("啊荤万科假日巍峨峻岭 cas new");
storage.set(key, value1, true);
vNew = storage.get(key);
assertEquals("断言cas,cas能覆盖已有的值。", value1, vNew);
try {
storage.set(key, value, true);
fail("断言,当老版本的value覆盖已有的更新版本的value时,应该抛出VersionConflictException异常。");
} catch (VersionConflictException e) {
}
vNew = storage.get(key);
assertEquals("断言cas,cas不能用老版本的value覆盖存储中已有的版本较新的值。", value1, vNew);
}
@Test
public void testCad() {
Storage storage = getStorage();
Key key = createKey("test");
Value oldValue = createValue("啊荤万科假日巍峨峻岭2");
storage.set(key, oldValue);
Value vNew = storage.get(key);
Value newValue = createValue("啊荤万科假日巍峨峻岭 cas new");
assertTrue("断言,一个带新版value的删除操作,能够删除已有的老版本的value", storage.delete(key, newValue));
vNew = storage.get(key);
assertNull("断言数据已经被删除成功。", vNew);
try {
storage.set(key, newValue);
storage.delete(key, oldValue);
fail("断言,当一个带旧版本value的删除操作,应该抛出异常。");
} catch (VersionConflictException e) {
}
vNew = storage.get(key);
assertEquals("断言用老版本的value,应该无法删除已有的更新版本的value。", newValue, vNew);
}
@Test
public void testDelete() {
Storage storage = getStorage();
Key key = createKey("test");
Value value = createValue("啊荤万科假日巍峨峻岭");
storage.set(key, value);
Value vNew = storage.get(key);
assertNotNull(vNew);
assertTrue(value.equals(vNew));
assertTrue("断言应该成功删除一个已经存在的key", storage.delete(key));
vNew = storage.get(key);
assertNull("断言存储当中key对应的值已经成功删除。", vNew);
assertFalse("断言删除一个不存在的key,应该返回失败。", storage.delete(key));
}
@Test
public void testGetAll() {
Storage storage = getStorage();
Map<Key, Value> map = new HashMap<Key, Value>();
List<Key> keyList = new ArrayList<Key>();
for (int i = 0; i < len; i++) {
Key key = createKey("test" + i);
Value value = createValue("啊荤万科假日巍峨峻岭" + i);
map.put(key, value);
keyList.add(key);
storage.set(key, value);
}
Map<Key, Value> mapNew = storage.getAll(keyList);
assertNotNull(mapNew);
Iterator<Entry<Key, Value>> itr = mapNew.entrySet().iterator();
while (itr.hasNext()) {
Entry<Key, Value> evtry = itr.next();
Value vNew = evtry.getValue();
Key key = evtry.getKey();
Value aspect = map.get(key);
assertTrue("断言key=" + key + " 的值应该和批量从存储中获取的值一致。", vNew.equals(aspect));
}
}
@Test
public void testIterator() {
Storage storage = getStorage();
for (int i = 0; i < len; i++) {
Key key = createKey("test" + i);
Value value = createValue("啊荤万科假日巍峨峻岭" + i);
storage.set(key, value);
}
ClosableIterator<Pair> testPairIterator = (ClosableIterator<Pair>) storage.iterator();
assertNotNull(testPairIterator);
int count = 0;
while (testPairIterator.hasNext()) {
Pair p = testPairIterator.next();
assertNotNull(p);
assertNotNull(p.getKey());
assertNotNull(p.getValue());
count++;
}
testPairIterator.close();
assertTrue("aspact:count==len, actual is count=" + count + ", len=" + len, count == len);
}
@Test
public void testIterator2() {
Storage storage = getStorage();
for (int i = 0; i < len; i++) {
Key key = createKey("test" + i);
Value value = createValue("啊荤万科假日巍峨峻岭" + i);
storage.set(key, value);
}
List<Integer> nodeList = new ArrayList<Integer>(virtualNode.length);
for (int i : virtualNode) {
nodeList.add(i);
}
ClosableIterator<Pair> testPairIterator = (ClosableIterator<Pair>) storage.iterator(nodeList);
assertNotNull(testPairIterator);
int count = 0;
while (testPairIterator.hasNext()) {
Pair p = testPairIterator.next();
assertNotNull(p);
assertNotNull(p.getKey());
assertNotNull(p.getValue());
count++;
}
testPairIterator.close();
assertEquals(len, count);
}
@Test
public void testRemoveDataBase() {
Storage storage = getStorage();
for (int i = 0; i < len; i++) {
Key key = createKey("test" + i);
Value value = createValue("啊荤万科假日巍峨峻岭" + i);
storage.set(key, value);
}
List<Integer> nodeList = new ArrayList<Integer>(virtualNode.length);
for (int i : virtualNode) {
nodeList.add(i);
}
ClosableIterator<Pair> testPairIterator = (ClosableIterator<Pair>) storage.iterator(nodeList);
assertNotNull("断言存储中的数据不为空。", testPairIterator);
Set<Integer> vnodeSet = new HashSet<Integer>();
while (testPairIterator.hasNext()) {
Pair p = testPairIterator.next();
assertNotNull(p);
assertNotNull(p.getKey());
vnodeSet.add(p.getKey().getVNode());
}
testPairIterator.close();
List<Integer> vnodeList = new ArrayList<Integer>(vnodeSet);
storage.delete(vnodeList);
testPairIterator = (ClosableIterator<Pair>) storage.iterator(vnodeList);
assertNotNull("断言指定虚拟节点中的数据被成功删除。", testPairIterator);
assertFalse("断言指定虚拟节点中的数据被成功删除。", testPairIterator.hasNext());
testPairIterator.close();
}
/**
* cas,并发测试代码
*/
public void t1estCas() {
Thread t1 = new ThreadCas();
Thread t2 = new ThreadSet();
t1.start();
t2.start();
}
private class ThreadSet extends Thread {
@Override
public void run() {
Storage storage = getStorage();
Key key = createKey("test");
Value value = createValue("cas");
storage.set(key, value);
}
}
private class ThreadCas extends Thread {
@Override
public void run() {
Storage storage = getStorage();
Key key = createKey("test");
Value value = createValue("啊荤万科假日巍峨峻岭");
storage.set(key, value, true);
}
}
protected Key createKey(String key) {
return new KeyImpl(100, key, getVnode(key));
}
protected Value createValue(String value) {
return new ValueImpl(ByteUtils.stringToByte(value), (new Date()).getTime());
}
private int getVnode(String key) {
return Math.abs(key.hashCode() % virtualNode.length);
}
private int len = 20;
private static int[] virtualNode;
{
int vnodeNum = 20;
virtualNode = new int[vnodeNum];
for (int i = 0; i < vnodeNum; i++) {
virtualNode[i] = i;
}
}
}