package com.alibaba.doris.dataserver.store.log.db;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.math.RandomUtils;
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.ClosableIterator;
import com.alibaba.doris.dataserver.store.log.BaseTestCase;
import com.alibaba.doris.dataserver.store.log.LogStorage;
import com.alibaba.doris.dataserver.store.log.db.impl.DefaultLogClumpImpl;
import com.alibaba.doris.dataserver.store.log.entry.LogEntry;
import com.alibaba.doris.dataserver.store.log.entry.SetLogEntry;
/**
* @author ajun Email:jack.yuj@alibaba-inc.com
*/
public class LogStorageTest extends BaseTestCase {
public void testIterator() throws IOException {
clearDbPath();
ClumpConfigure config = getClumpConfigure();
LogStorage storage = new LogStorage(config);
try {
LogClump clump = new DefaultLogClumpImpl(config, "001");
WriteWindow writeWindow = clump.getWriteWindow();
writeWindow.append(getSetLogEntry(key1, "test", 1));
writeWindow.close();
clump = new DefaultLogClumpImpl(config, "002");
writeWindow = clump.getWriteWindow();
clump.getWriteWindow().append(getSetLogEntry(key2, "test2", 2));
writeWindow.close();
storage.open();
ClosableIterator<Pair> iterator = (ClosableIterator<Pair>) storage.iterator();
assertNotNull(iterator);
Pair pair1 = iterator.next();
Pair pair2 = iterator.next();
assertNotNull(pair1);
assertNotNull(pair2);
assertEquals(key1, pair1.getKey().getKey());
assertEquals(key2, pair2.getKey().getKey());
assertFalse(iterator.hasNext());
iterator.close();
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
} finally {
storage.close();
}
}
private String key1 = "key1";
private String key2 = "key2";
private String key3 = "key3";
/**
* 注意:本测试依赖上一个测试方法,生成的数据。
*
* @throws IOException
*/
public void testDelete() throws IOException {
clearDbPath();
ClumpConfigure config = getClumpConfigure();
LogStorage storage = new LogStorage(config);
List<Integer> vnodeArray = new ArrayList<Integer>();
vnodeArray.add(1);
vnodeArray.add(2);
boolean result = true;
try {
LogClump clump = new DefaultLogClumpImpl(config, "001");
WriteWindow writeWindow = clump.getWriteWindow();
writeWindow.append(getSetLogEntry(key1, "test", vnodeArray.get(0)));
writeWindow.close();
clump = new DefaultLogClumpImpl(config, "002");
writeWindow = clump.getWriteWindow();
clump.getWriteWindow().append(getSetLogEntry(key2, "test2", vnodeArray.get(1)));
writeWindow.close();
storage.open();
assertTrue(storage.delete(vnodeArray));
Thread.sleep(1000);
ClosableIterator<Pair> iterator = (ClosableIterator<Pair>) storage.iterator();
result = iterator.hasNext();
iterator.close();
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
} finally {
storage.close();
}
assertFalse(result);
}
public void testIteratorByVnode() throws IOException {
clearDbPath();
ClumpConfigure config = getClumpConfigure();
LogStorage storage = new LogStorage(config);
try {
LogClump clump = new DefaultLogClumpImpl(config, "001");
WriteWindow writeWindow = clump.getWriteWindow();
writeWindow.append(getSetLogEntry(key1, "test", 1));
writeWindow.close();
clump = new DefaultLogClumpImpl(config, "002");
writeWindow = clump.getWriteWindow();
writeWindow.append(getSetLogEntry(key2, "test2", 2));
writeWindow.close();
List<Integer> vnodeArray = new ArrayList<Integer>();
vnodeArray.add(1);
vnodeArray.add(2);
storage.open();
ClosableIterator<Pair> iterator = (ClosableIterator<Pair>) storage.iterator(vnodeArray);
assertNotNull(iterator);
Pair pair1 = iterator.next();
Pair pair2 = iterator.next();
assertNotNull(pair1);
assertNotNull(pair2);
assertEquals(key1, pair1.getKey().getKey());
assertEquals(key2, pair2.getKey().getKey());
assertFalse(iterator.hasNext());
iterator.close();
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
} finally {
storage.close();
}
}
public void testIteratorByVnode0() throws IOException {
clearDbPath();
ClumpConfigure config = getClumpConfigure();
LogStorage storage = new LogStorage(config);
try {
LogClump clump = new DefaultLogClumpImpl(config, "001");
WriteWindow writeWindow = clump.getWriteWindow();
writeWindow.append(getSetLogEntry(key1, "test", 1));
writeWindow.append(getSetLogEntry(key3, "test3", 3));
writeWindow.close();
clump = new DefaultLogClumpImpl(config, "002");
writeWindow = clump.getWriteWindow();
writeWindow.append(getSetLogEntry(key2, "test2", 2));
writeWindow.close();
List<Integer> vnodeArray = new ArrayList<Integer>();
vnodeArray.add(1);
vnodeArray.add(2);
storage.open();
LogEntry entry = getSetLogEntry(key2, "test2", 2);
storage.set(entry.getKey(), entry.getValue());
ClosableIterator<Pair> iterator = (ClosableIterator<Pair>) storage.iterator(vnodeArray);
assertNotNull(iterator);
Pair pair1 = iterator.next();
Pair pair2 = iterator.next();
assertNotNull(pair1);
assertNotNull(pair2);
assertEquals(key1, pair1.getKey().getKey());
assertEquals(key2, pair2.getKey().getKey());
iterator.next();
assertFalse(iterator.hasNext());
iterator.close();
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
} finally {
storage.close();
}
}
public void testDelete1() throws IOException {
clearDbPath();
ClumpConfigure config = getClumpConfigure();
LogStorage storage = new LogStorage(config);
try {
LogClump clump = new DefaultLogClumpImpl(config, "001");
WriteWindow writeWindow = clump.getWriteWindow();
writeWindow.append(getSetLogEntry(key1, "test", 1));
writeWindow.append(getSetLogEntry(key2, "test2", 2));
writeWindow.close();
storage.open();
List<Integer> vnodeArray = new ArrayList<Integer>();
vnodeArray.add(1);
assertTrue(storage.delete(vnodeArray));
ClosableIterator<Pair> iterator = (ClosableIterator<Pair>) storage.iterator();
// next assert true;
assertTrue(iterator.hasNext());
iterator.close();
assertFalse(storage.delete(vnodeArray));
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
} finally {
storage.close();
}
}
public void testDelete10000() throws IOException {
clearDbPath();
ClumpConfigure config = getClumpConfigure();
LogStorage storage = new LogStorage(config);
try {
List<Integer> vnodeArray = new ArrayList<Integer>();
LogClump clump = new DefaultLogClumpImpl(config, "001");
WriteWindow writeWindow = clump.getWriteWindow();
for (int i = 0; i < 10000; i++) {
writeWindow.append(getSetLogEntry("key" + i, "test" + i, i));
vnodeArray.add(i);
}
writeWindow.close();
storage.open();
ClosableIterator<Pair> iterator = (ClosableIterator<Pair>) storage.iterator();
// next assert true;
assertTrue(iterator.hasNext());
iterator.close();
assertTrue(storage.delete(vnodeArray));
assertFalse(storage.delete(vnodeArray));
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
} finally {
storage.close();
}
}
public void testConcurrentIterator() throws IOException, InterruptedException {
clearDbPath();
ClumpConfigure config = getClumpConfigure();
LogStorage storage = new LogStorage(config);
SetThread setThread = null;
DeleteThread deleteThread = null;
IteratorThread iteratorThread = null;
try {
storage.open();
setThread = new SetThread(storage);
setThread.start();
deleteThread = new DeleteThread(storage);
deleteThread.start();
Thread.sleep(10000);
iteratorThread = new IteratorThread(storage);
iteratorThread.start();
deleteThread.setSlowing();
setThread.setSlowing();
synchronized (iteratorThread) {
iteratorThread.wait();
}
deleteThread.setStop(true);
setThread.setStop(true);
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
} finally {
if (null != setThread) {
setThread.setStop(true);
}
if (null != deleteThread) {
deleteThread.setStop(true);
}
storage.close();
}
Thread.sleep(1000);
}
private class SetThread extends Thread {
public SetThread(LogStorage storage) {
this.storage = storage;
}
@Override
public void run() {
try {
Key keyObj = null;
Value valueObj = new ValueImpl("test value,test value".getBytes(), System.currentTimeMillis());
int i = 0;
while (!isStop) {
keyObj = new KeyImpl(DEFAULT_NAMESPACE, String.valueOf(i++), i);
storage.set(keyObj, valueObj);
if (!isSlowing) {
sleep(RandomUtils.nextInt(2));
} else {
sleep(20);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void setSlowing() {
isSlowing = true;
}
public boolean isStop() {
return isStop;
}
public void setStop(boolean isStop) {
this.isStop = isStop;
}
private volatile boolean isStop = false;
private boolean isSlowing = false;
private LogStorage storage;
}
private class IteratorThread extends Thread {
public IteratorThread(LogStorage storage) {
this.storage = storage;
}
@Override
public void run() {
List<Integer> vnodeList = new ArrayList<Integer>();
for (int i = 0; i < 100; i++) {
vnodeList.add(i);
}
for (int i = 1000; i < 2000; i++) {
vnodeList.add(i);
}
int count = 0;
ClosableIterator<Pair> iterator = (ClosableIterator<Pair>) storage.iterator(vnodeList);
try {
// next assert true;
while (iterator.hasNext()) {
Pair p = iterator.next();
count++;
assertNotNull(p);
assertNotNull(p.getKey());
assertNotNull(p.getValue());
}
} catch (Exception e) {
System.out.println("count=" + count);
e.printStackTrace();
fail();
} finally {
iterator.close();
}
try {
synchronized (this) {
this.notifyAll();
}
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
private LogStorage storage;
}
private class DeleteThread extends Thread {
public DeleteThread(LogStorage storage) {
this.storage = storage;
}
@Override
public void run() {
try {
while (!isStop) {
List<Integer> vnodeList = new ArrayList<Integer>();
vnodeList.add(RandomUtils.nextInt(100000));
storage.delete(vnodeList);
if (!isSlowing) {
sleep(RandomUtils.nextInt(2));
} else {
sleep(20);
}
}
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
public boolean isStop() {
return isStop;
}
public void setSlowing() {
isSlowing = true;
}
public void setStop(boolean isStop) {
this.isStop = isStop;
}
private volatile boolean isStop = false;
private LogStorage storage;
private boolean isSlowing = false;
}
public void testGet() throws IOException {
clearDbPath();
ClumpConfigure config = getClumpConfigure();
LogStorage storage = new LogStorage(config);
try {
LogClump clump = new DefaultLogClumpImpl(config, "001");
WriteWindow writeWindow = clump.getWriteWindow();
writeWindow.append(getSetLogEntry("keytest", "testwerer", 1));
writeWindow.append(getSetLogEntry("keytest1", "testwerer", 2));
writeWindow.append(getSetLogEntry("keytest2", "testwerer", 1));
writeWindow.append(getSetLogEntry(key1, "test", 1));
writeWindow.close();
clump = new DefaultLogClumpImpl(config, "002");
writeWindow = clump.getWriteWindow();
writeWindow.append(getSetLogEntry(key2, "test2", 2));
writeWindow.close();
storage.open();
Key keyObj = new KeyImpl(DEFAULT_NAMESPACE, key1, 1);
Value v = storage.get(keyObj);
assertNotNull(v);
assertEquals("test", ByteUtils.byteToString(v.getValueBytes()));
keyObj = new KeyImpl(DEFAULT_NAMESPACE, key2, 1);
v = storage.get(keyObj);
assertNull("key2的虚拟节点编号为2,断言用vnode=1无法获取到数据。", v);
keyObj = new KeyImpl(DEFAULT_NAMESPACE, key2, 2);
v = storage.get(keyObj);
assertNotNull(v);
assertEquals("test2", ByteUtils.byteToString(v.getValueBytes()));
keyObj = new KeyImpl(DEFAULT_NAMESPACE, "noexists_key", 1);
v = storage.get(keyObj);
assertNull("断言用一个storage中不存在的key去查询,将返回空值。", v);
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
} finally {
storage.close();
}
}
public void testPutAndDelete() throws IOException {
clearDbPath();
ClumpConfigure config = getClumpConfigure();
LogStorage storage = new LogStorage(config);
try {
storage.open();
Key keyObj = new KeyImpl(DEFAULT_NAMESPACE, key1, 1);
Value value = new ValueImpl("test".getBytes());
storage.set(keyObj, value);
keyObj = new KeyImpl(DEFAULT_NAMESPACE, key1, 1);
Value v = storage.get(keyObj);
assertNotNull(v);
assertEquals("test", ByteUtils.byteToString(v.getValueBytes()));
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
} finally {
storage.close();
}
}
public void testCheck() {
ClumpConfigure config = getClumpConfigure();
LogStorage storage = new LogStorage(config);
try {
storage.open();
for (int i = 0; i < 10; i++) {
ClosableIterator<Pair> iterator = (ClosableIterator<Pair>) storage.iterator();
iterator.hasNext();
iterator.close();
}
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
} finally {
storage.close();
}
}
private LogEntry getSetLogEntry(String key, String value, int vnode) {
Key keyObj = new KeyImpl(DEFAULT_NAMESPACE, key, vnode);
Value valueObj = new ValueImpl(value.getBytes(), System.currentTimeMillis());
return new SetLogEntry(keyObj, valueObj);
}
public void clearDbPath() throws IOException {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
ClumpConfigure config = getClumpConfigure();
String dbPath = config.getPath();
FileUtils.deleteDirectory(new File(dbPath));
File f = new File(dbPath);
f.mkdir();
}
protected static final int DEFAULT_NAMESPACE = 1;
}