|
@@ -3,11 +3,11 @@ package com.github.ltsopensource.kv.index;
|
|
import com.github.ltsopensource.core.commons.file.FileUtils;
|
|
import com.github.ltsopensource.core.commons.file.FileUtils;
|
|
import com.github.ltsopensource.core.commons.io.UnsafeByteArrayInputStream;
|
|
import com.github.ltsopensource.core.commons.io.UnsafeByteArrayInputStream;
|
|
import com.github.ltsopensource.core.commons.io.UnsafeByteArrayOutputStream;
|
|
import com.github.ltsopensource.core.commons.io.UnsafeByteArrayOutputStream;
|
|
|
|
+import com.github.ltsopensource.core.json.TypeReference;
|
|
import com.github.ltsopensource.kv.StoreConfig;
|
|
import com.github.ltsopensource.kv.StoreConfig;
|
|
import com.github.ltsopensource.kv.replay.TxLogReplay;
|
|
import com.github.ltsopensource.kv.replay.TxLogReplay;
|
|
import com.github.ltsopensource.kv.serializer.StoreSerializer;
|
|
import com.github.ltsopensource.kv.serializer.StoreSerializer;
|
|
import com.github.ltsopensource.kv.txlog.StoreTxLogPosition;
|
|
import com.github.ltsopensource.kv.txlog.StoreTxLogPosition;
|
|
-import com.github.ltsopensource.core.json.TypeReference;
|
|
|
|
|
|
|
|
import java.io.File;
|
|
import java.io.File;
|
|
import java.io.FilenameFilter;
|
|
import java.io.FilenameFilter;
|
|
@@ -20,6 +20,7 @@ import java.util.Arrays;
|
|
import java.util.Comparator;
|
|
import java.util.Comparator;
|
|
import java.util.concurrent.ConcurrentMap;
|
|
import java.util.concurrent.ConcurrentMap;
|
|
import java.util.concurrent.ConcurrentSkipListMap;
|
|
import java.util.concurrent.ConcurrentSkipListMap;
|
|
|
|
+import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
|
|
|
/**
|
|
/**
|
|
* @author Robert HG (254963746@qq.com) on 12/19/15.
|
|
* @author Robert HG (254963746@qq.com) on 12/19/15.
|
|
@@ -27,6 +28,7 @@ import java.util.concurrent.ConcurrentSkipListMap;
|
|
public class MemIndexSnapshot<K, V> extends AbstractIndexSnapshot<K, V> {
|
|
public class MemIndexSnapshot<K, V> extends AbstractIndexSnapshot<K, V> {
|
|
|
|
|
|
private TxLogReplay<K, V> txLogReplay;
|
|
private TxLogReplay<K, V> txLogReplay;
|
|
|
|
+ private AtomicBoolean snapshoting = new AtomicBoolean(false);
|
|
|
|
|
|
public MemIndexSnapshot(TxLogReplay<K, V> txLogReplay, Index<K, V> index, StoreConfig storeConfig, StoreSerializer serializer) {
|
|
public MemIndexSnapshot(TxLogReplay<K, V> txLogReplay, Index<K, V> index, StoreConfig storeConfig, StoreSerializer serializer) {
|
|
super(index, storeConfig, serializer);
|
|
super(index, storeConfig, serializer);
|
|
@@ -137,46 +139,56 @@ public class MemIndexSnapshot<K, V> extends AbstractIndexSnapshot<K, V> {
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public void snapshot() throws IOException {
|
|
public void snapshot() throws IOException {
|
|
-
|
|
|
|
- StoreTxLogPosition storeTxLogPosition = index.lastTxLog();
|
|
|
|
-
|
|
|
|
- if (storeTxLogPosition == null) {
|
|
|
|
|
|
+ if (!snapshoting.compareAndSet(false, true)) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
- if (lastStoreTxLogPosition != null && lastStoreTxLogPosition.getRecordId() == storeTxLogPosition.getRecordId()) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ConcurrentMap<K, IndexItem<K>> indexMap = ((MemIndex<K, V>) index).getIndexMap();
|
|
|
|
|
|
+ try {
|
|
|
|
+ StoreTxLogPosition storeTxLogPosition = index.lastTxLog();
|
|
|
|
|
|
- String name = System.currentTimeMillis() + ".snapshot";
|
|
|
|
- File snapshot = new File(storeConfig.getIndexPath(), name);
|
|
|
|
- FileChannel fileChannel = FileUtils.newFileChannel(snapshot, "rw");
|
|
|
|
|
|
+ if (storeTxLogPosition == null) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ if (lastStoreTxLogPosition != null && lastStoreTxLogPosition.getRecordId() == storeTxLogPosition.getRecordId()) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- IndexSnapshotFileHeader fileHeader = new IndexSnapshotFileHeader();
|
|
|
|
|
|
+ ConcurrentMap<K, IndexItem<K>> indexMap = ((MemIndex<K, V>) index).getIndexMap();
|
|
|
|
|
|
- UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream();
|
|
|
|
- serializer.serialize(indexMap, os);
|
|
|
|
- byte[] payload = os.toByteArray();
|
|
|
|
- ReadableByteChannel src = Channels.newChannel(new UnsafeByteArrayInputStream(payload));
|
|
|
|
|
|
+ String name = System.currentTimeMillis() + ".snapshot";
|
|
|
|
+ File snapshot = new File(storeConfig.getIndexPath(), name);
|
|
|
|
+ FileChannel fileChannel = FileUtils.newFileChannel(snapshot, "rw");
|
|
|
|
|
|
- // 先写一个空的文件头
|
|
|
|
- fileHeader.write(fileChannel);
|
|
|
|
|
|
+ IndexSnapshotFileHeader fileHeader = new IndexSnapshotFileHeader();
|
|
|
|
+ UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream();
|
|
|
|
+ try {
|
|
|
|
+ serializer.serialize(indexMap, os);
|
|
|
|
+ byte[] payload = os.toByteArray();
|
|
|
|
+ ReadableByteChannel src = Channels.newChannel(new UnsafeByteArrayInputStream(payload));
|
|
|
|
+
|
|
|
|
+ // 先写一个空的文件头
|
|
|
|
+ fileHeader.write(fileChannel);
|
|
|
|
+
|
|
|
|
+ // 写内容
|
|
|
|
+ fileChannel.transferFrom(src, fileHeader.getLength(), payload.length);
|
|
|
|
+ } finally {
|
|
|
|
+ os.close();
|
|
|
|
+ }
|
|
|
|
|
|
- // 写内容
|
|
|
|
- fileChannel.transferFrom(src, fileHeader.getLength(), payload.length);
|
|
|
|
- fileChannel.force(true);
|
|
|
|
|
|
+ fileChannel.force(true);
|
|
|
|
|
|
- // 写真实的文件头
|
|
|
|
- fileHeader.setStoreTxLogRecordId(storeTxLogPosition.getRecordId());
|
|
|
|
- fileHeader.write(fileChannel);
|
|
|
|
|
|
+ // 写真实的文件头
|
|
|
|
+ fileHeader.setStoreTxLogRecordId(storeTxLogPosition.getRecordId());
|
|
|
|
+ fileHeader.write(fileChannel);
|
|
|
|
|
|
- // 删除多余的快照数目
|
|
|
|
- deleteOverSnapshot();
|
|
|
|
|
|
+ // 删除多余的快照数目
|
|
|
|
+ deleteOverSnapshot();
|
|
|
|
|
|
- LOGGER.info("snapshot index finished: [" + name + "]");
|
|
|
|
|
|
+ LOGGER.info("snapshot index finished: [" + name + "]");
|
|
|
|
|
|
- lastStoreTxLogPosition = storeTxLogPosition;
|
|
|
|
|
|
+ lastStoreTxLogPosition = storeTxLogPosition;
|
|
|
|
+ } finally {
|
|
|
|
+ snapshoting.set(false);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|