result = new ArrayList<>();
- result.add(beginStr.getBytes());
- result.add(snapStr.getBytes());
- assertEquals(result.size(), content.size());
- assertArrayEquals(result.get(0), content.get(0));
- assertArrayEquals(result.get(1), content.get(1));
}
}
From 4f45f1862aeda9413651e9e6ce15e8909cbb7508 Mon Sep 17 00:00:00 2001
From: xiaoxineryi <529086017@qq.com>
Date: Fri, 15 Jan 2021 16:46:50 +0800
Subject: [PATCH 09/20] =?UTF-8?q?=E6=97=A5=E5=BF=97=E8=AE=B0=E5=BD=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../kaaass/rumbase/dataitem/IItemStorage.java | 22 +++-
.../kaaass/rumbase/dataitem/ItemManager.java | 27 ++++-
.../kaaass/rumbase/dataitem/ItemStorage.java | 86 ++++++++++++--
.../dataitem/mock/MockItemStorage.java | 18 ++-
.../rumbase/recovery/IRecoveryStorage.java | 16 +--
.../rumbase/recovery/RecoveryManager.java | 4 +-
.../rumbase/recovery/RecoveryStorage.java | 106 +++++++++++++++---
.../recovery/mock/MockRecoveryStorage.java | 2 +-
.../rumbase/dataitem/IItemStorageTest.java | 23 ++--
9 files changed, 256 insertions(+), 48 deletions(-)
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java
index 70c6b17..3c90ec2 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java
@@ -2,6 +2,7 @@
import net.kaaass.rumbase.dataitem.exception.PageCorruptedException;
import net.kaaass.rumbase.dataitem.exception.UUIDException;
+import net.kaaass.rumbase.page.exception.FileException;
import net.kaaass.rumbase.transaction.TransactionContext;
import java.util.List;
@@ -12,14 +13,27 @@
* @author kaito
*/
public interface IItemStorage {
+
+ /**
+ * 将uuid对应的页强制写回
+ */
+ public void flush(long uuid) throws FileException;
/**
* 插入数据项
*
+ * @param txContext 事务上下文
* @param item 数据项
* @return 返回数据项的UUID
*/
long insertItem(TransactionContext txContext, byte[] item);
+ /**
+ * 不用日志进行插入,用于日志的管理
+ * @param item 数据项
+ * @return uuid
+ */
+ long insertItemWithoutLog(byte[] item);
+
/**
* 插入一个有UUID的数据项,唯一使用的地方是日志恢复时使用
*
@@ -30,7 +44,7 @@ public interface IItemStorage {
* @param item 数据项
* @param uuid 编号
*/
- void insertItemWithUuid(TransactionContext txContext, byte[] item, long uuid);
+ void insertItemWithUuid(byte[] item, long uuid);
/**
* 通过UUID查询数据项
@@ -73,6 +87,12 @@ public interface IItemStorage {
*/
void setMetadata(TransactionContext txContext, byte[] metadata) throws PageCorruptedException;
+ /**
+ * 不使用日志设置元数据
+ * @param metadata 头信息
+ */
+ void setMetadataWithoutLog(byte[] metadata) throws PageCorruptedException;
+
/**
* 清理多余的数据项,空间清理时使用。
*
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/ItemManager.java b/src/main/java/net/kaaass/rumbase/dataitem/ItemManager.java
index 609fff6..0ce485a 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/ItemManager.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/ItemManager.java
@@ -3,6 +3,7 @@
import net.kaaass.rumbase.page.exception.FileException;
import net.kaaass.rumbase.page.exception.PageException;
+import net.kaaass.rumbase.recovery.exception.LogException;
import net.kaaass.rumbase.transaction.TransactionContext;
import java.io.IOException;
@@ -25,7 +26,7 @@ public class ItemManager {
* @param fileName 文件名
* @return 数据项管理器,用于管理数据项
*/
- public static IItemStorage fromFile(String fileName) throws FileException, IOException, PageException {
+ public static IItemStorage fromFile(String fileName) throws FileException, IOException, PageException, LogException {
if (maps.containsKey(fileName)) {
return maps.get(fileName);
} else {
@@ -35,6 +36,17 @@ public static IItemStorage fromFile(String fileName) throws FileException, IOExc
}
}
+ public static IItemStorage fromFileWithoutLog(String fileName) throws FileException, IOException, PageException, LogException {
+ if (maps.containsKey(fileName)) {
+ return maps.get(fileName);
+ } else {
+ IItemStorage iItemStorage = ItemStorage.ofFileWithoutLog(fileName);
+ maps.put(fileName, iItemStorage);
+ return iItemStorage;
+ }
+ }
+
+
/**
* 新建一个数据库,并且将上层提供的头信息写入。
*
@@ -44,7 +56,7 @@ public static IItemStorage fromFile(String fileName) throws FileException, IOExc
* @return 数据项管理器
* @throws FileException 想新建的文件已经存在的异常
*/
- public static IItemStorage createFile(TransactionContext txContext, String fileName, byte[] metadata) throws FileException, IOException, PageException {
+ public static IItemStorage createFile(TransactionContext txContext, String fileName, byte[] metadata) throws FileException, IOException, PageException, LogException {
// 如果文件已经存在,那么就抛出文件已存在异常
if (maps.containsKey(fileName)) {
throw new FileException(1);
@@ -54,6 +66,17 @@ public static IItemStorage createFile(TransactionContext txContext, String fileN
maps.put(fileName, iItemStorage);
return iItemStorage;
}
+ }
+ public static IItemStorage createFileWithoutLog(String fileName, byte[] metadata) throws FileException, IOException, PageException, LogException {
+ // 如果文件已经存在,那么就抛出文件已存在异常
+ if (maps.containsKey(fileName)) {
+ throw new FileException(1);
+ } else {
+ // 若文件不存在,则创建文件。
+ IItemStorage iItemStorage = ItemStorage.ofNewFileWithoutLog(fileName, metadata);
+ maps.put(fileName, iItemStorage);
+ return iItemStorage;
+ }
}
}
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
index 7cb3217..e2e023e 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
@@ -12,6 +12,8 @@
import net.kaaass.rumbase.page.exception.FileException;
import net.kaaass.rumbase.page.exception.PageException;
import net.kaaass.rumbase.recovery.IRecoveryStorage;
+import net.kaaass.rumbase.recovery.RecoveryManager;
+import net.kaaass.rumbase.recovery.exception.LogException;
import net.kaaass.rumbase.transaction.TransactionContext;
import java.io.IOException;
@@ -19,6 +21,7 @@
import java.util.List;
import java.util.Optional;
import java.util.Random;
+import java.util.logging.LogManager;
/**
* 数据项管理器的具体实现
@@ -60,6 +63,14 @@ public class ItemStorage implements IItemStorage {
private IRecoveryStorage recoveryStorage;
+ public ItemStorage(String fileName, int tempFreePage, long headerUuid, PageStorage pageStorage,IRecoveryStorage iRecoveryStorage) {
+ this.fileName = fileName;
+ this.tempFreePage = tempFreePage;
+ this.headerUuid = headerUuid;
+ this.pageStorage = pageStorage;
+ this.recoveryStorage = iRecoveryStorage;
+ }
+
public ItemStorage(String fileName, int tempFreePage, long headerUuid, PageStorage pageStorage) {
this.fileName = fileName;
this.tempFreePage = tempFreePage;
@@ -94,7 +105,40 @@ private static boolean checkTableHeader(Page header) {
* @param fileName 文件名
* @return 解析或新建得到的数据项管理器对象
*/
- public static IItemStorage ofFile(String fileName) throws FileException, PageException {
+ public static IItemStorage ofFile(String fileName) throws FileException, PageException, IOException, LogException {
+ var pageStorage = PageManager.fromFile(fileName);
+ var header = pageStorage.get(0);
+ header.pin();
+ if (checkTableHeader(header)) {
+ // 如果表头标志存在,就解析对应表头信息
+ var h = parseHeader(header);
+ header.unpin();
+ var logStorage = RecoveryManager.getRecoveryStorage(fileName);
+ return new ItemStorage(fileName, h.tempFreePage, h.headerUuid, pageStorage,logStorage);
+ } else {
+ // 若表头标志不存在,就初始化对应的表信息。
+ // 只初始化headerFlag和tempFreePage,表头信息位置统一由setMetadata来实现
+ byte[] bytes;
+ try {
+ bytes = JBBPOut.BeginBin().
+ Byte(1, 2, 3, 4).
+ Int(1).
+ End().toByteArray();
+ } catch (IOException e) {
+ header.unpin();
+ throw new PageCorruptedException(1, e);
+ }
+ header.patchData(0, bytes);
+ header.unpin();
+ var logStorage = RecoveryManager.createRecoveryStorage(fileName);
+ return new ItemStorage(fileName, 1, 0, pageStorage,logStorage);
+ }
+ }
+
+ /**
+ * 不使用日志打开文件
+ */
+ public static IItemStorage ofFileWithoutLog(String fileName) throws FileException, PageException, IOException, LogException {
var pageStorage = PageManager.fromFile(fileName);
var header = pageStorage.get(0);
header.pin();
@@ -129,12 +173,21 @@ public static IItemStorage ofFile(String fileName) throws FileException, PageExc
* @param metadata 表头信息
* @return 数据项管理器
*/
- public static IItemStorage ofNewFile(TransactionContext txContext, String fileName, byte[] metadata) throws IOException, FileException, PageException {
+ public static IItemStorage ofNewFile(TransactionContext txContext, String fileName, byte[] metadata) throws IOException, FileException, PageException, LogException {
var pageStorage = ItemStorage.ofFile(fileName);
pageStorage.setMetadata(txContext, metadata);
return pageStorage;
}
+ /**
+ * 不使用日志的创建文件
+ */
+ public static IItemStorage ofNewFileWithoutLog(String fileName, byte[] metadata) throws IOException, LogException, FileException, PageException {
+ var pageStorage = ItemStorage.ofFileWithoutLog(fileName);
+ pageStorage.setMetadataWithoutLog(metadata);
+ return pageStorage;
+ }
+
/**
* 根据uuid获取后面的随机位置
*/
@@ -275,8 +328,19 @@ private void addTempFreePage() {
}
}
+ @Override
+ public void flush(long uuid) throws FileException {
+ var page = getPage(uuid);
+ page.flush();
+ }
+
@Override
public synchronized long insertItem(TransactionContext txContext, byte[] item) {
+ long uuid = insertItemWithoutLog(item);
+ return uuid;
+ }
+ @Override
+ public synchronized long insertItemWithoutLog(byte[] item) {
var page = getPage(this.tempFreePage);
try {
var pageHeaderOp = getPageHeader(page);
@@ -288,7 +352,7 @@ public synchronized long insertItem(TransactionContext txContext, byte[] item) {
if (pageHeader.leftSpace - Math.min(item.length, MAX_RECORD_SIZE) <= MIN_LEFT_SPACE) {
// 如果剩余空间过小的话,就切换到下一个页进行,同时修改表头信息.并且,若数据过大则使用拉链,所以取512和数据大小较小的
addTempFreePage();
- return insertItem(txContext, item);
+ return insertItemWithoutLog( item);
} else {
// 剩余空间足够,则插入
int rnd = Math.abs(new Random().nextInt());
@@ -299,7 +363,7 @@ public synchronized long insertItem(TransactionContext txContext, byte[] item) {
rnd = Math.abs(new Random().nextInt());
uuid = ((s << 32) + (long) (rnd));
}
- insertToPage(page, pageHeader, txContext, item, rnd);
+ insertToPage(page, pageHeader,item, rnd);
return uuid;
}
} catch (PageCorruptedException e) {
@@ -314,7 +378,7 @@ public synchronized long insertItem(TransactionContext txContext, byte[] item) {
/**
* 将数据插入到页内对应位置,并修改页头信息
*/
- private void insertToPage(Page page, PageHeader pageHeader, TransactionContext txContext, byte[] item, int rnd) {
+ private void insertToPage(Page page, PageHeader pageHeader,byte[] item, int rnd) {
if (item.length < MAX_RECORD_SIZE) {
int offset = 0;
if (pageHeader.recordNumber == 0) {
@@ -354,7 +418,7 @@ private void insertToPage(Page page, PageHeader pageHeader, TransactionContext t
}
@Override
- public synchronized void insertItemWithUuid(TransactionContext txContext, byte[] item, long uuid) {
+ public synchronized void insertItemWithUuid(byte[] item, long uuid) {
if (!checkUuidExist(uuid)) {
// 若不存在,则要恢复
var page = getPage(uuid);
@@ -365,7 +429,7 @@ public synchronized void insertItemWithUuid(TransactionContext txContext, byte[]
pageHeaderOp = Optional.of(initPage(page));
}
int rnd = getRndByUuid(uuid);
- insertToPage(page, pageHeaderOp.get(), txContext, item, rnd);
+ insertToPage(page, pageHeaderOp.get(), item, rnd);
} catch (Exception e) {
throw new PageCorruptedException(3);
} finally {
@@ -515,9 +579,15 @@ public byte[] getMetadata() {
@Override
public void setMetadata(TransactionContext txContext, byte[] metadata) throws PageCorruptedException {
+ setMetadataWithoutLog(metadata);
+
+ }
+
+ @Override
+ public void setMetadataWithoutLog(byte[] metadata) throws PageCorruptedException {
var page = getPage(0);
try {
- var headerUuid = insertItem(txContext, metadata);
+ var headerUuid = insertItemWithoutLog(metadata);
var bytes = JBBPOut.BeginBin().
Byte(HAS_HEADER).
Long(headerUuid).End().toByteArray();
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java
index 19e6fd5..3ffe357 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java
@@ -2,6 +2,7 @@
import lombok.Data;
import net.kaaass.rumbase.dataitem.IItemStorage;
+import net.kaaass.rumbase.dataitem.exception.PageCorruptedException;
import net.kaaass.rumbase.dataitem.exception.UUIDException;
import net.kaaass.rumbase.transaction.TransactionContext;
@@ -79,6 +80,11 @@ public static IItemStorage ofNewFile(TransactionContext txContext, String fileNa
}
+ @Override
+ public void flush(long uuid) {
+
+ }
+
@Override
public long insertItem(TransactionContext txContext, byte[] item) {
Random ran = new Random();
@@ -88,7 +94,12 @@ public long insertItem(TransactionContext txContext, byte[] item) {
}
@Override
- public void insertItemWithUuid(TransactionContext txContext, byte[] item, long uuid) {
+ public long insertItemWithoutLog( byte[] item) {
+ return 0;
+ }
+
+ @Override
+ public void insertItemWithUuid(byte[] item, long uuid) {
maps.put(uuid, item);
}
@@ -125,6 +136,11 @@ public void setMetadata(TransactionContext txContext, byte[] metadata) {
this.meta = metadata;
}
+ @Override
+ public void setMetadataWithoutLog(byte[] metadata) throws PageCorruptedException {
+
+ }
+
@Override
public void removeItems(List uuids) {
diff --git a/src/main/java/net/kaaass/rumbase/recovery/IRecoveryStorage.java b/src/main/java/net/kaaass/rumbase/recovery/IRecoveryStorage.java
index 0684071..372e8a3 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/IRecoveryStorage.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/IRecoveryStorage.java
@@ -1,5 +1,8 @@
package net.kaaass.rumbase.recovery;
+import net.kaaass.rumbase.page.exception.FileException;
+
+import java.io.IOException;
import java.util.List;
/**
@@ -14,21 +17,21 @@ public interface IRecoveryStorage {
* @param xid 事务编号
* @param snapshots 快照集合
*/
- void begin(int xid, List snapshots);
+ void begin(int xid, List snapshots) throws IOException, FileException;
/**
* 记录事务失败回滚
*
* @param xid
*/
- void rollback(int xid);
+ void rollback(int xid) throws IOException, FileException;
/**
* 记录事务完成
*
* @param xid
*/
- void commit(int xid);
+ void commit(int xid) throws IOException, FileException;
/**
* 插入数据项的日志记录
@@ -37,16 +40,15 @@ public interface IRecoveryStorage {
* @param uuid 数据项的对应编号
* @param item 插入的数据内容
*/
- void insert(int xid, long uuid, byte[] item);
+ void insert(int xid, long uuid, byte[] item) throws IOException, FileException;
/**
* 更新数据项的日志记录
*
* @param xid
* @param uuid
- * @param item
*/
- void update(int xid, long uuid, byte[] item);
+ void update(int xid, long uuid, byte[] item_before,byte[] item_after) throws IOException, FileException;
/**
* 更新数据项的日志头
@@ -54,7 +56,7 @@ public interface IRecoveryStorage {
* @param xid
* @param metaUUID 头信息的UUID
*/
- void updateMeta(int xid, long metaUUID);
+ void updateMeta(int xid, long metaUUID) throws IOException, FileException;
/**
* 模拟打印日志资料
diff --git a/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java b/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java
index a846723..3957bca 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java
@@ -24,11 +24,11 @@ public static void recovery(String fileName) {
}
- public static IRecoveryStorage getRecoveryStorage(String fileName) throws FileException, IOException, LogException {
+ public static IRecoveryStorage getRecoveryStorage(String fileName) throws FileException, IOException, LogException, PageException {
return RecoveryStorage.ofFile(fileName + ".log");
}
- public static IRecoveryStorage createRecoveryStorage(String fileName) throws IOException, FileException, PageException {
+ public static IRecoveryStorage createRecoveryStorage(String fileName) throws IOException, FileException, PageException, LogException {
return RecoveryStorage.ofNewFile(fileName + ".log");
}
}
diff --git a/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java b/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java
index 44e7d93..7ca44cd 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java
@@ -3,12 +3,15 @@
import com.igormaznitsa.jbbp.JBBPParser;
import com.igormaznitsa.jbbp.io.JBBPOut;
import com.igormaznitsa.jbbp.mapper.Bin;
+import net.kaaass.rumbase.dataitem.IItemStorage;
import net.kaaass.rumbase.dataitem.ItemManager;
import net.kaaass.rumbase.page.PageManager;
import net.kaaass.rumbase.page.PageStorage;
import net.kaaass.rumbase.page.exception.FileException;
import net.kaaass.rumbase.page.exception.PageException;
import net.kaaass.rumbase.recovery.exception.LogException;
+import net.kaaass.rumbase.transaction.TransactionContext;
+import net.kaaass.rumbase.transaction.mock.MockTransactionContext;
import java.io.IOException;
import java.util.List;
@@ -20,13 +23,20 @@
*/
public class RecoveryStorage implements IRecoveryStorage {
+ private IItemStorage itemStorage;
+
+ public RecoveryStorage(IItemStorage itemStorage) {
+ this.itemStorage = itemStorage;
+ }
+
/**
* 读取日志文件并且解析得到日志管理器
* @param fileName
* @return 日志管理器
*/
- public static IRecoveryStorage ofFile(String fileName) throws FileException, IOException, LogException {
- return new RecoveryStorage();
+ public static IRecoveryStorage ofFile(String fileName) throws FileException, IOException, LogException, PageException {
+ var itemStorage = ItemManager.fromFileWithoutLog(fileName + ".log");
+ return new RecoveryStorage(itemStorage);
}
/**
@@ -34,37 +44,84 @@ public static IRecoveryStorage ofFile(String fileName) throws FileException, IOE
* @param fileName 文件名
* @return
*/
- public static IRecoveryStorage ofNewFile(String fileName) throws FileException, IOException, PageException {
- return new RecoveryStorage();
+ public static IRecoveryStorage ofNewFile(String fileName) throws FileException, IOException, PageException, LogException {
+ var metadata = JBBPOut.BeginBin().Int(HEADER).End().toByteArray();
+ var itemStorage = ItemManager.createFileWithoutLog(fileName + ".log",metadata);
+ return new RecoveryStorage(itemStorage);
}
@Override
- public void begin(int xid, List snapshots) {
-
+ public void begin(int xid, List snapshots) throws IOException, FileException {
+ var jbbp = JBBPOut.BeginBin().
+ String(TX_BEGIN).
+ Int(xid).
+ Int(snapshots.size());
+ for ( var i : snapshots){
+ jbbp = jbbp.Int(i);
+ }
+ var bytes = jbbp.End().toByteArray();
+ var uuid = itemStorage.insertItemWithoutLog(bytes);
+ itemStorage.flush(uuid);
}
@Override
- public void rollback(int xid) {
-
+ public void rollback(int xid) throws IOException, FileException {
+ var bytes = JBBPOut.BeginBin().
+ String(TX_ABORT).
+ Int(xid).
+ End().toByteArray();
+ var uuid = itemStorage.insertItemWithoutLog(bytes);
+ itemStorage.flush(uuid);
}
@Override
- public void commit(int xid) {
-
+ public void commit(int xid) throws IOException, FileException {
+ var bytes = JBBPOut.BeginBin().
+ String(TX_COMMIT).
+ Int(xid).
+ End().toByteArray();
+ var uuid = itemStorage.insertItemWithoutLog(bytes);
+ itemStorage.flush(uuid);
}
@Override
- public void insert(int xid, long uuid, byte[] item) {
+ public void insert(int xid, long uuid, byte[] item) throws IOException, FileException {
+ var bytes = JBBPOut.BeginBin().
+ String(INSERT_FLAG).
+ Int(xid).
+ Long(uuid).
+ Int(item.length).
+ Byte(item).
+ End().toByteArray();
+ var id = itemStorage.insertItemWithoutLog(bytes);
+ itemStorage.flush(id);
}
@Override
- public void update(int xid, long uuid, byte[] item) {
-
+ public void update(int xid, long uuid, byte[] item_before,byte[] item_after) throws IOException, FileException {
+ var bytes = JBBPOut.BeginBin().
+ String(UPDATE_FLAG).
+ Int(xid).
+ Long(uuid).
+ Int(item_before.length).
+ Byte(item_before).
+ Int(item_after.length).
+ Byte(item_after).
+ End().toByteArray();
+ var id = itemStorage.insertItemWithoutLog(bytes);
+ itemStorage.flush(id);
}
@Override
- public void updateMeta(int xid, long metaUUID) {
+ public void updateMeta(int xid, long metaUUID) throws IOException, FileException {
+ var bytes =JBBPOut.BeginBin().
+ String(METADATA_UPDATE_FLAG).
+ Int(xid).
+ Long(metaUUID).
+ End().toByteArray();
+ var uuid = itemStorage.insertItemWithoutLog(bytes);
+ itemStorage.flush(uuid);
}
@@ -81,6 +138,25 @@ public static class LogHeader{
@Bin
int header;
}
- final private static int HEADER = 1234;
+
+ /**
+ * 日志标志
+ */
+ final private static int HEADER = 4567;
+
+ final private static String INSERT_FLAG = "i";
+
+ final private static String TX_BEGIN = "b";
+
+ final private static String TX_ABORT = "a";
+
+ final private static String TX_COMMIT = "c";
+
+ final private static String UPDATE_FLAG = "u";
+
+ final private static String METADATA_UPDATE_FLAG = "m";
+
+
+
}
diff --git a/src/main/java/net/kaaass/rumbase/recovery/mock/MockRecoveryStorage.java b/src/main/java/net/kaaass/rumbase/recovery/mock/MockRecoveryStorage.java
index fa8c4e9..461cf2e 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/mock/MockRecoveryStorage.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/mock/MockRecoveryStorage.java
@@ -49,7 +49,7 @@ public void insert(int xid, long uuid, byte[] item) {
}
@Override
- public void update(int xid, long uuid, byte[] item) {
+ public void update(int xid, long uuid, byte[] item,byte[] item_after) {
String updateStr = "update " + xid + " " + uuid + " ";
// 对控制语句、数据两部分进行合并得到最终日志记录
byte[] first = updateStr.getBytes();
diff --git a/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java b/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java
index 588a8e7..ca0bb4c 100644
--- a/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java
+++ b/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java
@@ -6,6 +6,7 @@
import net.kaaass.rumbase.dataitem.exception.UUIDException;
import net.kaaass.rumbase.page.exception.FileException;
import net.kaaass.rumbase.page.exception.PageException;
+import net.kaaass.rumbase.recovery.exception.LogException;
import net.kaaass.rumbase.transaction.TransactionContext;
import java.io.IOException;
@@ -29,7 +30,7 @@ public class IItemStorageTest extends TestCase {
/**
* 测试能否从已有文件中解析得到数据项管理器
*/
- public void testGetFromFile() throws FileException, IOException, PageException {
+ public void testGetFromFile() throws FileException, IOException, PageException, LogException {
String fileName = "testGetFromFile.db";
var itemStorage = ItemManager.fromFile(fileName);
// 如果表中没有对应的文件,那么就抛出错误
@@ -44,7 +45,7 @@ public void testGetFromFile() throws FileException, IOException, PageException {
/**
* 测试能否新建文件并得到数据项管理器
*/
- public void testCreateFile() throws IOException, FileException, PageException {
+ public void testCreateFile() throws IOException, FileException, PageException, LogException {
TransactionContext txContext = TransactionContext.empty();
String fileName = "testCreateFile.db";
byte[] metadata = new byte[1024];
@@ -62,7 +63,7 @@ public void testCreateFile() throws IOException, FileException, PageException {
/**
* 进行插入的测试
*/
- public void testInsert() throws FileException, IOException, PageException, UUIDException, PageCorruptedException {
+ public void testInsert() throws FileException, IOException, PageException, UUIDException, PageCorruptedException, LogException {
String fileName = "testInsert.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
@@ -79,7 +80,7 @@ public void testInsert() throws FileException, IOException, PageException, UUIDE
/**
* 对插入一个已分配UUID的测试
*/
- public void testInsertWithUUID() throws FileException, IOException, PageException {
+ public void testInsertWithUUID() throws FileException, IOException, PageException, LogException {
String fileName = "testInsertWithUUID.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
@@ -88,7 +89,7 @@ public void testInsertWithUUID() throws FileException, IOException, PageExceptio
long uuid = (s << 32) + rnd;
TransactionContext txContext = TransactionContext.empty();
// 第一次插入,表中没有该UUID,可以正常执行
- iItemStorage.insertItemWithUuid(txContext, bytes, uuid);
+ iItemStorage.insertItemWithUuid(bytes, uuid);
try {
assertArrayEquals(bytes, iItemStorage.queryItemByUuid(uuid));
} catch (UUIDException | PageCorruptedException e) {
@@ -96,14 +97,14 @@ public void testInsertWithUUID() throws FileException, IOException, PageExceptio
}
// 第二次插入
- iItemStorage.insertItemWithUuid(txContext, bytes, uuid);
+ iItemStorage.insertItemWithUuid(bytes, uuid);
}
/**
* 对插入大量数据进行测试
*/
- public void testManyInsert() throws FileException, IOException, PageException, UUIDException, PageCorruptedException {
+ public void testManyInsert() throws FileException, IOException, PageException, UUIDException, PageCorruptedException, LogException {
String fileName = "testInsertMany.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
@@ -123,7 +124,7 @@ public void testManyInsert() throws FileException, IOException, PageException, U
/**
* 获取整个页的数据项进行测试
*/
- public void testQueryByPageID() throws FileException, IOException, PageException, PageCorruptedException {
+ public void testQueryByPageID() throws FileException, IOException, PageException, PageCorruptedException, LogException {
String fileName = "testQueryByPageID.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
@@ -186,7 +187,7 @@ public void run() {
/**
* 测试并发下插入是否有问题
*/
- public void testSynInsert() throws IOException, FileException, PageException {
+ public void testSynInsert() throws IOException, FileException, PageException, LogException {
String fileName = "testInsert.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
@@ -201,7 +202,7 @@ public void testSynInsert() throws IOException, FileException, PageException {
/**
* 对更新进行测试
*/
- public void testUpdate() throws FileException, IOException, PageException, UUIDException, PageCorruptedException {
+ public void testUpdate() throws FileException, IOException, PageException, UUIDException, PageCorruptedException, LogException {
String fileName = "testUpdate.db";
TransactionContext txContext = TransactionContext.empty();
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
@@ -228,7 +229,7 @@ public void testUpdate() throws FileException, IOException, PageException, UUIDE
/**
* 测试修改和获取表头信息
*/
- public void testMeta() throws FileException, IOException, PageException, UUIDException, PageCorruptedException {
+ public void testMeta() throws FileException, IOException, PageException, UUIDException, PageCorruptedException, LogException {
String fileName = "testMeta.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] result = new byte[]{1, 2, 3, 4};
From c18e172525bf5444af1baa43ad513754c795c25a Mon Sep 17 00:00:00 2001
From: xiaoxineryi <529086017@qq.com>
Date: Sat, 16 Jan 2021 12:29:00 +0800
Subject: [PATCH 10/20] =?UTF-8?q?=E6=97=A5=E5=BF=97=E6=93=8D=E4=BD=9C?=
=?UTF-8?q?=E5=AE=8C=E6=88=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../kaaass/rumbase/dataitem/IItemStorage.java | 27 +-
.../kaaass/rumbase/dataitem/ItemStorage.java | 65 +++-
.../dataitem/mock/MockItemStorage.java | 24 +-
.../kaaass/rumbase/record/IRecordStorage.java | 4 +-
.../rumbase/record/MvccRecordStorage.java | 4 +-
.../rumbase/recovery/IRecoveryStorage.java | 12 +-
.../rumbase/recovery/RecoveryManager.java | 4 +-
.../rumbase/recovery/RecoveryStorage.java | 319 +++++++++++++++---
.../recovery/exception/LogException.java | 1 +
.../recovery/mock/MockRecoveryStorage.java | 16 +-
.../rumbase/dataitem/IItemStorageTest.java | 2 +-
.../rumbase/record/IRecordStorageTest.java | 4 +-
.../rumbase/recovery/IRecoveryTest.java | 20 +-
13 files changed, 426 insertions(+), 76 deletions(-)
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java
index 3c90ec2..161e96a 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java
@@ -3,8 +3,11 @@
import net.kaaass.rumbase.dataitem.exception.PageCorruptedException;
import net.kaaass.rumbase.dataitem.exception.UUIDException;
import net.kaaass.rumbase.page.exception.FileException;
+import net.kaaass.rumbase.page.exception.PageException;
+import net.kaaass.rumbase.recovery.IRecoveryStorage;
import net.kaaass.rumbase.transaction.TransactionContext;
+import java.io.IOException;
import java.util.List;
/**
@@ -14,6 +17,20 @@
*/
public interface IItemStorage {
+ void setMetaUuid(long uuid) throws IOException, PageException;
+
+ /**
+ * 获得日志管理器
+ * @return
+ */
+ IRecoveryStorage getRecoveryStorage();
+
+ /**
+ * 获取表的tempFreePage
+ * @return
+ */
+ public int getMaxPageId();
+
/**
* 将uuid对应的页强制写回
*/
@@ -25,7 +42,7 @@ public interface IItemStorage {
* @param item 数据项
* @return 返回数据项的UUID
*/
- long insertItem(TransactionContext txContext, byte[] item);
+ long insertItem(TransactionContext txContext, byte[] item) throws IOException, FileException;
/**
* 不用日志进行插入,用于日志的管理
@@ -71,7 +88,9 @@ public interface IItemStorage {
* @param item 数据项
* @throws UUIDException 没有找到对应UUID的异常
*/
- void updateItemByUuid(TransactionContext txContext, long uuid, byte[] item) throws UUIDException, PageCorruptedException;
+ void updateItemByUuid(TransactionContext txContext, long uuid, byte[] item) throws UUIDException, PageCorruptedException, FileException, IOException;
+
+ byte[] updateItemWithoutLog(long uuid,byte[] item) throws UUIDException;
/**
* 获得数据项存储的元数据(可以用于头)
@@ -85,13 +104,13 @@ public interface IItemStorage {
*
* @param metadata 头信息
*/
- void setMetadata(TransactionContext txContext, byte[] metadata) throws PageCorruptedException;
+ void setMetadata(TransactionContext txContext, byte[] metadata) throws PageCorruptedException, IOException, FileException;
/**
* 不使用日志设置元数据
* @param metadata 头信息
*/
- void setMetadataWithoutLog(byte[] metadata) throws PageCorruptedException;
+ long setMetadataWithoutLog(byte[] metadata) throws PageCorruptedException;
/**
* 清理多余的数据项,空间清理时使用。
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
index e2e023e..21d9d5a 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
@@ -21,7 +21,6 @@
import java.util.List;
import java.util.Optional;
import java.util.Random;
-import java.util.logging.LogManager;
/**
* 数据项管理器的具体实现
@@ -111,7 +110,7 @@ public static IItemStorage ofFile(String fileName) throws FileException, PageExc
header.pin();
if (checkTableHeader(header)) {
// 如果表头标志存在,就解析对应表头信息
- var h = parseHeader(header);
+ var h = parseTableHeader(header);
header.unpin();
var logStorage = RecoveryManager.getRecoveryStorage(fileName);
return new ItemStorage(fileName, h.tempFreePage, h.headerUuid, pageStorage,logStorage);
@@ -144,7 +143,7 @@ public static IItemStorage ofFileWithoutLog(String fileName) throws FileExceptio
header.pin();
if (checkTableHeader(header)) {
// 如果表头标志存在,就解析对应表头信息
- var h = parseHeader(header);
+ var h = parseTableHeader(header);
header.unpin();
return new ItemStorage(fileName, h.tempFreePage, h.headerUuid, pageStorage);
} else {
@@ -228,7 +227,7 @@ private void releasePage(Page page) {
*
* @return 解析得到的表头对象
*/
- private static TableHeader parseHeader(Page page) throws PageCorruptedException {
+ private static TableHeader parseTableHeader(Page page) throws PageCorruptedException {
try {
return JBBPParser.prepare("int headerFlag;int tempFreePage;byte hasHeaderInfo;long headerUuid;").
parse(page.getData()).mapTo(new TableHeader());
@@ -328,6 +327,32 @@ private void addTempFreePage() {
}
}
+ @Override
+ public void setMetaUuid(long uuid) throws IOException, PageException {
+ var page = getPage(0);
+ try {
+ var bytes = JBBPOut.BeginBin().
+ Byte(HAS_HEADER).
+ Long(uuid).End().toByteArray();
+ page.patchData(HEADER_OFFSET, bytes);
+ }finally {
+ releasePage(page);
+ }
+
+ }
+
+ @Override
+ public IRecoveryStorage getRecoveryStorage() {
+ return this.recoveryStorage;
+ }
+
+ @Override
+ public int getMaxPageId() {
+ var page = getPage(0);
+ var header = parseTableHeader(page);
+ return header.tempFreePage;
+ }
+
@Override
public void flush(long uuid) throws FileException {
var page = getPage(uuid);
@@ -335,8 +360,9 @@ public void flush(long uuid) throws FileException {
}
@Override
- public synchronized long insertItem(TransactionContext txContext, byte[] item) {
+ public synchronized long insertItem(TransactionContext txContext, byte[] item) throws IOException, FileException {
long uuid = insertItemWithoutLog(item);
+ recoveryStorage.insert(txContext.getXid(),uuid,item);
return uuid;
}
@Override
@@ -352,7 +378,7 @@ public synchronized long insertItemWithoutLog(byte[] item) {
if (pageHeader.leftSpace - Math.min(item.length, MAX_RECORD_SIZE) <= MIN_LEFT_SPACE) {
// 如果剩余空间过小的话,就切换到下一个页进行,同时修改表头信息.并且,若数据过大则使用拉链,所以取512和数据大小较小的
addTempFreePage();
- return insertItemWithoutLog( item);
+ return insertItemWithoutLog(item);
} else {
// 剩余空间足够,则插入
int rnd = Math.abs(new Random().nextInt());
@@ -524,15 +550,23 @@ public List listItemByPageId(int pageId) {
}
@Override
- public void updateItemByUuid(TransactionContext txContext, long uuid, byte[] item) throws UUIDException, PageCorruptedException {
+ public void updateItemByUuid(TransactionContext txContext, long uuid, byte[] item) throws UUIDException, PageCorruptedException, FileException, IOException {
+ var item_before = updateItemWithoutLog(uuid, item);
+ recoveryStorage.update(txContext.getXid(),uuid,item_before,item);
+ }
+
+ @Override
+ public byte[] updateItemWithoutLog(long uuid, byte[] item) throws UUIDException {
var page = getPage(uuid);
try {
if (checkUuidExist(uuid)) {
+ // 若uuid存在
var pageHeader = getPageHeader(page);
var items = pageHeader.get().item;
try {
for (var i : items) {
if (i.uuid == getRndByUuid(uuid)) {
+ var item_before = parseData(page,i);
var offset = i.offset;
var bytes = JBBPOut.BeginBin().
Byte(NORMAL_DATA).
@@ -540,24 +574,26 @@ public void updateItemByUuid(TransactionContext txContext, long uuid, byte[] ite
.Byte(item)
.End().toByteArray();
page.patchData(offset, bytes);
- return;
+ return item_before;
}
}
} catch (PageException | IOException e) {
throw new PageCorruptedException(2, e);
}
} else {
+ // uuid不存在一般是恢复的时候 前面事务被取消.
throw new UUIDException(2);
}
} finally {
releasePage(page);
}
+ return new byte[1];
}
@Override
public byte[] getMetadata() {
var page = getPage(0);
- var header = parseHeader(page);
+ var header = parseTableHeader(page);
if (checkTableHeader(page) && header.hasHeaderInfo == HAS_HEADER) {
// 若表头已经被初始化并且有标志位的话,就说明有表头信息,进行获取.
byte[] h;
@@ -578,13 +614,15 @@ public byte[] getMetadata() {
}
@Override
- public void setMetadata(TransactionContext txContext, byte[] metadata) throws PageCorruptedException {
- setMetadataWithoutLog(metadata);
-
+ public void setMetadata(TransactionContext txContext, byte[] metadata) throws PageCorruptedException, IOException, FileException {
+ var page = getPage(0);
+ var header = parseTableHeader(page);
+ var uuid = setMetadataWithoutLog(metadata);
+ recoveryStorage.updateMeta(txContext.getXid(),header.headerUuid,metadata);
}
@Override
- public void setMetadataWithoutLog(byte[] metadata) throws PageCorruptedException {
+ public long setMetadataWithoutLog(byte[] metadata) throws PageCorruptedException {
var page = getPage(0);
try {
var headerUuid = insertItemWithoutLog(metadata);
@@ -592,6 +630,7 @@ public void setMetadataWithoutLog(byte[] metadata) throws PageCorruptedException
Byte(HAS_HEADER).
Long(headerUuid).End().toByteArray();
page.patchData(HEADER_OFFSET, bytes);
+ return headerUuid;
} catch (Exception e) {
throw new PageCorruptedException(1, e);
} finally {
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java
index 3ffe357..223d691 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java
@@ -4,6 +4,7 @@
import net.kaaass.rumbase.dataitem.IItemStorage;
import net.kaaass.rumbase.dataitem.exception.PageCorruptedException;
import net.kaaass.rumbase.dataitem.exception.UUIDException;
+import net.kaaass.rumbase.recovery.IRecoveryStorage;
import net.kaaass.rumbase.transaction.TransactionContext;
import java.util.*;
@@ -80,6 +81,21 @@ public static IItemStorage ofNewFile(TransactionContext txContext, String fileNa
}
+ @Override
+ public void setMetaUuid(long uuid) {
+
+ }
+
+ @Override
+ public IRecoveryStorage getRecoveryStorage() {
+ return null;
+ }
+
+ @Override
+ public int getMaxPageId() {
+ return 0;
+ }
+
@Override
public void flush(long uuid) {
@@ -126,6 +142,11 @@ public void updateItemByUuid(TransactionContext txContext, long uuid, byte[] ite
}
}
+ @Override
+ public byte[] updateItemWithoutLog(long uuid, byte[] item) throws UUIDException {
+ return new byte[0];
+ }
+
@Override
public byte[] getMetadata() {
return meta;
@@ -137,8 +158,9 @@ public void setMetadata(TransactionContext txContext, byte[] metadata) {
}
@Override
- public void setMetadataWithoutLog(byte[] metadata) throws PageCorruptedException {
+ public long setMetadataWithoutLog(byte[] metadata) throws PageCorruptedException {
+ return 0;
}
diff --git a/src/main/java/net/kaaass/rumbase/record/IRecordStorage.java b/src/main/java/net/kaaass/rumbase/record/IRecordStorage.java
index fb751a0..2ee1022 100644
--- a/src/main/java/net/kaaass/rumbase/record/IRecordStorage.java
+++ b/src/main/java/net/kaaass/rumbase/record/IRecordStorage.java
@@ -1,8 +1,10 @@
package net.kaaass.rumbase.record;
+import net.kaaass.rumbase.page.exception.FileException;
import net.kaaass.rumbase.record.exception.RecordNotFoundException;
import net.kaaass.rumbase.transaction.TransactionContext;
+import java.io.IOException;
import java.util.Optional;
/**
@@ -63,5 +65,5 @@ default byte[] query(TransactionContext txContext, long recordId) throws RecordN
*
* @param metadata 元信息数据
*/
- void setMetadata(TransactionContext txContext, byte[] metadata);
+ void setMetadata(TransactionContext txContext, byte[] metadata) throws IOException, FileException;
}
diff --git a/src/main/java/net/kaaass/rumbase/record/MvccRecordStorage.java b/src/main/java/net/kaaass/rumbase/record/MvccRecordStorage.java
index a3b1a28..ffb4551 100644
--- a/src/main/java/net/kaaass/rumbase/record/MvccRecordStorage.java
+++ b/src/main/java/net/kaaass/rumbase/record/MvccRecordStorage.java
@@ -6,6 +6,7 @@
import lombok.extern.slf4j.Slf4j;
import net.kaaass.rumbase.dataitem.IItemStorage;
import net.kaaass.rumbase.dataitem.exception.UUIDException;
+import net.kaaass.rumbase.page.exception.FileException;
import net.kaaass.rumbase.record.exception.NeedRollbackException;
import net.kaaass.rumbase.record.exception.RecordNotFoundException;
import net.kaaass.rumbase.record.exception.StorageCorruptedException;
@@ -13,6 +14,7 @@
import net.kaaass.rumbase.transaction.TransactionIsolation;
import net.kaaass.rumbase.transaction.TransactionStatus;
+import java.io.IOException;
import java.util.Optional;
/**
@@ -205,7 +207,7 @@ public byte[] getMetadata(TransactionContext txContext) {
}
@Override
- public void setMetadata(TransactionContext txContext, byte[] metadata) {
+ public void setMetadata(TransactionContext txContext, byte[] metadata) throws IOException, FileException {
// TODO 申请全表锁,用this锁代替
// 主要逻辑:为了保证事务性,使用UUID数组,结合可见性选择对应的记录。倒序记录便于存储。
synchronized (this) {
diff --git a/src/main/java/net/kaaass/rumbase/recovery/IRecoveryStorage.java b/src/main/java/net/kaaass/rumbase/recovery/IRecoveryStorage.java
index 372e8a3..5d2585b 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/IRecoveryStorage.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/IRecoveryStorage.java
@@ -1,6 +1,8 @@
package net.kaaass.rumbase.recovery;
import net.kaaass.rumbase.page.exception.FileException;
+import net.kaaass.rumbase.page.exception.PageException;
+import net.kaaass.rumbase.recovery.exception.LogException;
import java.io.IOException;
import java.util.List;
@@ -48,18 +50,22 @@ public interface IRecoveryStorage {
* @param xid
* @param uuid
*/
- void update(int xid, long uuid, byte[] item_before,byte[] item_after) throws IOException, FileException;
+ void update(int xid, long uuid, byte[] itemBefore, byte[] itemAfter) throws IOException, FileException;
/**
* 更新数据项的日志头
*
* @param xid
- * @param metaUUID 头信息的UUID
*/
- void updateMeta(int xid, long metaUUID) throws IOException, FileException;
+ void updateMeta(int xid, long beforeUuid,byte[] metadata) throws IOException, FileException;
/**
* 模拟打印日志资料
*/
List getContent();
+
+ /**
+ * 恢复数据
+ */
+ void recovery() throws IOException, LogException, FileException, PageException;
}
diff --git a/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java b/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java
index 3957bca..8385d08 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java
@@ -25,10 +25,10 @@ public static void recovery(String fileName) {
}
public static IRecoveryStorage getRecoveryStorage(String fileName) throws FileException, IOException, LogException, PageException {
- return RecoveryStorage.ofFile(fileName + ".log");
+ return RecoveryStorage.ofFile(fileName);
}
public static IRecoveryStorage createRecoveryStorage(String fileName) throws IOException, FileException, PageException, LogException {
- return RecoveryStorage.ofNewFile(fileName + ".log");
+ return RecoveryStorage.ofNewFile(fileName);
}
}
diff --git a/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java b/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java
index 7ca44cd..cfea86d 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java
@@ -5,16 +5,16 @@
import com.igormaznitsa.jbbp.mapper.Bin;
import net.kaaass.rumbase.dataitem.IItemStorage;
import net.kaaass.rumbase.dataitem.ItemManager;
-import net.kaaass.rumbase.page.PageManager;
-import net.kaaass.rumbase.page.PageStorage;
+import net.kaaass.rumbase.dataitem.exception.UUIDException;
import net.kaaass.rumbase.page.exception.FileException;
import net.kaaass.rumbase.page.exception.PageException;
import net.kaaass.rumbase.recovery.exception.LogException;
-import net.kaaass.rumbase.transaction.TransactionContext;
-import net.kaaass.rumbase.transaction.mock.MockTransactionContext;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* 日志记录相关内容
@@ -23,10 +23,19 @@
*/
public class RecoveryStorage implements IRecoveryStorage {
- private IItemStorage itemStorage;
- public RecoveryStorage(IItemStorage itemStorage) {
- this.itemStorage = itemStorage;
+ /**
+ * 用于对自己的日志记录进行管理
+ */
+ private IItemStorage logStorage;
+ /**
+ * 要恢复的对象对应的文件名
+ */
+ private String fileName;
+
+ public RecoveryStorage(IItemStorage itemStorage,String fileName) {
+ this.logStorage = itemStorage;
+ this.fileName = fileName;
}
/**
@@ -36,7 +45,7 @@ public RecoveryStorage(IItemStorage itemStorage) {
*/
public static IRecoveryStorage ofFile(String fileName) throws FileException, IOException, LogException, PageException {
var itemStorage = ItemManager.fromFileWithoutLog(fileName + ".log");
- return new RecoveryStorage(itemStorage);
+ return new RecoveryStorage(itemStorage,fileName);
}
/**
@@ -47,87 +56,237 @@ public static IRecoveryStorage ofFile(String fileName) throws FileException, IOE
public static IRecoveryStorage ofNewFile(String fileName) throws FileException, IOException, PageException, LogException {
var metadata = JBBPOut.BeginBin().Int(HEADER).End().toByteArray();
var itemStorage = ItemManager.createFileWithoutLog(fileName + ".log",metadata);
- return new RecoveryStorage(itemStorage);
+ return new RecoveryStorage(itemStorage,fileName);
}
@Override
public void begin(int xid, List snapshots) throws IOException, FileException {
var jbbp = JBBPOut.BeginBin().
- String(TX_BEGIN).
+ Byte(TX_BEGIN).
Int(xid).
Int(snapshots.size());
for ( var i : snapshots){
jbbp = jbbp.Int(i);
}
var bytes = jbbp.End().toByteArray();
- var uuid = itemStorage.insertItemWithoutLog(bytes);
- itemStorage.flush(uuid);
+ var uuid = logStorage.insertItemWithoutLog(bytes);
+ logStorage.flush(uuid);
}
@Override
public void rollback(int xid) throws IOException, FileException {
var bytes = JBBPOut.BeginBin().
- String(TX_ABORT).
+ Byte(TX_ABORT).
Int(xid).
End().toByteArray();
- var uuid = itemStorage.insertItemWithoutLog(bytes);
- itemStorage.flush(uuid);
+ var uuid = logStorage.insertItemWithoutLog(bytes);
+ logStorage.flush(uuid);
}
@Override
public void commit(int xid) throws IOException, FileException {
var bytes = JBBPOut.BeginBin().
- String(TX_COMMIT).
+ Byte(TX_COMMIT).
Int(xid).
End().toByteArray();
- var uuid = itemStorage.insertItemWithoutLog(bytes);
- itemStorage.flush(uuid);
+ var uuid = logStorage.insertItemWithoutLog(bytes);
+ logStorage.flush(uuid);
}
@Override
public void insert(int xid, long uuid, byte[] item) throws IOException, FileException {
var bytes = JBBPOut.BeginBin().
- String(INSERT_FLAG).
+ Byte(INSERT_FLAG).
Int(xid).
Long(uuid).
Int(item.length).
Byte(item).
End().toByteArray();
- var id = itemStorage.insertItemWithoutLog(bytes);
- itemStorage.flush(id);
-
+ var id = logStorage.insertItemWithoutLog(bytes);
+ logStorage.flush(id);
}
@Override
- public void update(int xid, long uuid, byte[] item_before,byte[] item_after) throws IOException, FileException {
+ public void update(int xid, long uuid, byte[] itemBefore, byte[] itemAfter) throws IOException, FileException {
var bytes = JBBPOut.BeginBin().
- String(UPDATE_FLAG).
+ Byte(UPDATE_FLAG).
Int(xid).
Long(uuid).
- Int(item_before.length).
- Byte(item_before).
- Int(item_after.length).
- Byte(item_after).
+ Int(itemBefore.length).
+ Byte(itemBefore).
+ Int(itemAfter.length).
+ Byte(itemAfter).
End().toByteArray();
- var id = itemStorage.insertItemWithoutLog(bytes);
- itemStorage.flush(id);
+ var id = logStorage.insertItemWithoutLog(bytes);
+ logStorage.flush(id);
}
@Override
- public void updateMeta(int xid, long metaUUID) throws IOException, FileException {
+ public void updateMeta(int xid, long beforeUuid,byte[] metadata) throws IOException, FileException {
var bytes =JBBPOut.BeginBin().
- String(METADATA_UPDATE_FLAG).
+ Byte(METADATA_UPDATE_FLAG).
Int(xid).
- Long(metaUUID).
+ Long(beforeUuid).
+ Int(metadata.length).
+ Byte(metadata).
End().toByteArray();
- var uuid = itemStorage.insertItemWithoutLog(bytes);
- itemStorage.flush(uuid);
+ var uuid = logStorage.insertItemWithoutLog(bytes);
+ logStorage.flush(uuid);
}
@Override
public List getContent() {
- return null;
+ List logList = new ArrayList<>();
+ var maxPageId = logStorage.getMaxPageId();
+ for (int i = 1;i <= maxPageId ; i ++){
+ var logs = logStorage.listItemByPageId(i);
+ for(var l : logs){
+ if (l.length > 4){
+ logList.add(l);
+ }
+ }
+ }
+ return logList;
+ }
+
+ @Override
+ public void recovery() throws IOException, LogException, FileException, PageException {
+ var itemStorage = ItemManager.fromFile(this.fileName);
+ var logs = getContent();
+ var xidMaps = parseXid(logs);
+ for (var log : logs){
+ parseLog(log,itemStorage,xidMaps);
+ }
+ }
+
+ /**
+ * 先进行一遍解析,得到所有已完成的事务和未完成的事务,来决定redo还是undo
+ */
+ private Map> parseXid(List logs) throws IOException {
+ List commitXids = new ArrayList<>();
+ List abortXids = new ArrayList<>();
+
+ for (var log : logs){
+ var tx = parseTx(log);
+ switch (tx.type){
+ case TX_COMMIT:
+ // 若是commit 则放入commitXid并将对应的xid移出abort
+ abortXids.remove(tx.xid);
+ commitXids.add(tx.xid);
+ break;
+ case TX_ABORT:
+ // 因为begin就放入abort,所以abort不用管
+ break;
+ case TX_BEGIN:
+ abortXids.add(tx.xid);
+ break;
+ default:
+ }
+ }
+
+ Map> maps = new HashMap<>();
+ maps.put('C',commitXids);
+ maps.put('A',abortXids);
+ return maps;
+ }
+
+ /**
+ * 解析事务状态
+ */
+ private Tx parseTx(byte[] log) throws IOException {
+ var tx = JBBPParser.prepare("byte type;int xid;").parse(log).mapTo(new Tx());
+ return tx;
+ }
+
+ /**
+ * 解析类型
+ */
+ private byte parseType(byte[] log) throws IOException {
+ var type = JBBPParser.prepare("byte type;").parse(log).mapTo(new Type()).type;
+ return type ;
+ }
+
+ /**
+ * 解析插入
+ */
+ private InsertLog parseInsert(byte[] log) throws IOException {
+ var insertLog = JBBPParser.prepare("byte type;int xid;long uuid;int length;byte[length] item;")
+ .parse(log).mapTo(new InsertLog());
+ return insertLog;
+ }
+
+ /**
+ * 解析更新
+ */
+ private UpdateLog parseUpdate(byte[] log) throws IOException {
+ var updateLog = JBBPParser.prepare("byte type;int xid;long uuid;int length1;" +
+ "byte[length1] itemBefore;int length2;byte[length2] itemAfter;").parse(log).mapTo(new UpdateLog());
+ return updateLog;
+ }
+
+ private UpdateMetaLog parseUpdateMeta(byte[] log) throws IOException {
+ var updateMeta = JBBPParser.prepare("byte type;int xid;long beforeUuid;" +
+ "int length;byte[length] metadata").
+ parse(log).mapTo(new UpdateMetaLog());
+ return updateMeta;
+ }
+
+ private boolean checkCommit(int xid,Map> maps) throws LogException {
+ if (maps.get('C').contains(xid)){
+ return true;
+ }else if (maps.get('A').contains(xid)){
+ return false;
+ }else {
+ throw new LogException(2);
+ }
+ }
+ private void parseLog(byte[] log, IItemStorage itemStorage, Map> xidMaps) throws IOException, LogException, PageException {
+ var type = parseType(log);
+ switch (type){
+ case INSERT_FLAG:
+ System.out.println("正在解析插入");
+ var insertLog = parseInsert(log);
+ if (checkCommit(insertLog.xid,xidMaps)){
+ // 如果事务已经提交,则redo
+ itemStorage.insertItemWithUuid(insertLog.item,insertLog.uuid);
+ }else {
+ // 如果事务没有提交,则undo
+ }
+ break;
+ case UPDATE_FLAG:
+ System.out.println("正在解析更新");
+ var updateLog = parseUpdate(log);
+ if (checkCommit(updateLog.xid,xidMaps)){
+ // 若事务已经提交则redo
+ try {
+ itemStorage.updateItemWithoutLog(updateLog.uuid,updateLog.itemAfter);
+ } catch (UUIDException ignored) {
+ // uuid不存在说明对应之前的事务没有执行,是正常
+ }
+ }else {
+ // 若事务没有提交,则undo,恢复之前的数据
+ try {
+ itemStorage.updateItemWithoutLog(updateLog.uuid,updateLog.itemBefore);
+ } catch (UUIDException ignored) {
+
+ }
+ }
+ break;
+ case METADATA_UPDATE_FLAG:
+ System.out.println("正在解析头信息更新");
+ var updateMetaLog = parseUpdateMeta(log);
+ if (checkCommit(updateMetaLog.xid,xidMaps)){
+ // redo
+ itemStorage.setMetadataWithoutLog(updateMetaLog.metadata);
+ }else {
+ // undo
+ itemStorage.setMetaUuid(updateMetaLog.beforeUuid);
+ }
+ break;
+ default:
+ return;
+ }
}
/**
@@ -139,22 +298,98 @@ public static class LogHeader{
int header;
}
+ /**
+ * 解析类型
+ */
+ public static class Type{
+ @Bin
+ byte type;
+ }
+
+ /**
+ * 事务状态的解析
+ */
+ public static class Tx{
+ @Bin
+ byte type;
+ @Bin
+ int xid;
+ }
+
+ /**
+ * 插入的解析
+ */
+ public static class InsertLog{
+ @Bin
+ byte type;
+ @Bin
+ int xid;
+ @Bin
+ long uuid;
+ @Bin
+ int length;
+ @Bin
+ byte[] item;
+ public Object newInstance(Class> klazz) {
+ return klazz == InsertLog.class ? new InsertLog() : null;
+ }
+ }
+
+ /**
+ * 更新的解析
+ */
+ public static class UpdateLog{
+ @Bin
+ Byte type;
+ @Bin
+ int xid;
+ @Bin
+ long uuid;
+ @Bin
+ int length1;
+ @Bin
+ byte[] itemBefore;
+ @Bin
+ int length2;
+ @Bin
+ byte[] itemAfter;
+ public Object newInstance(Class> klazz) {
+ return klazz == UpdateLog.class ? new UpdateLog() : null;
+ }
+ }
+
+ public static class UpdateMetaLog{
+ @Bin
+ Byte type;
+ @Bin
+ int xid;
+ @Bin
+ long beforeUuid;
+ @Bin
+ int length;
+ @Bin
+ byte[] metadata;
+ public Object newInstance(Class> klazz) {
+ return klazz == UpdateMetaLog.class ? new UpdateMetaLog() : null;
+ }
+ }
+
/**
* 日志标志
*/
final private static int HEADER = 4567;
- final private static String INSERT_FLAG = "i";
+ final private static byte INSERT_FLAG = 'i';
- final private static String TX_BEGIN = "b";
+ final private static byte TX_BEGIN = 'b';
- final private static String TX_ABORT = "a";
+ final private static byte TX_ABORT = 'a';
- final private static String TX_COMMIT = "c";
+ final private static byte TX_COMMIT = 'c';
- final private static String UPDATE_FLAG = "u";
+ final private static byte UPDATE_FLAG = 'u';
- final private static String METADATA_UPDATE_FLAG = "m";
+ final private static byte METADATA_UPDATE_FLAG = 'm';
diff --git a/src/main/java/net/kaaass/rumbase/recovery/exception/LogException.java b/src/main/java/net/kaaass/rumbase/recovery/exception/LogException.java
index d15b0a5..e22f074 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/exception/LogException.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/exception/LogException.java
@@ -13,6 +13,7 @@ public class LogException extends RumbaseException {
public static final Map REASONS = new HashMap() {{
put(1, "日志文件无法解析");
+ put(2,"事务ID不存在");
}};
public LogException(int subId) {
diff --git a/src/main/java/net/kaaass/rumbase/recovery/mock/MockRecoveryStorage.java b/src/main/java/net/kaaass/rumbase/recovery/mock/MockRecoveryStorage.java
index 461cf2e..b872dbe 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/mock/MockRecoveryStorage.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/mock/MockRecoveryStorage.java
@@ -2,6 +2,7 @@
import net.kaaass.rumbase.recovery.IRecoveryStorage;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -49,19 +50,17 @@ public void insert(int xid, long uuid, byte[] item) {
}
@Override
- public void update(int xid, long uuid, byte[] item,byte[] item_after) {
+ public void update(int xid, long uuid, byte[] itemBefore, byte[] itemAfter) {
String updateStr = "update " + xid + " " + uuid + " ";
// 对控制语句、数据两部分进行合并得到最终日志记录
byte[] first = updateStr.getBytes();
- byte[] result = Arrays.copyOf(first, first.length + item.length);
- System.arraycopy(item, 0, result, first.length, item.length);
+ byte[] result = Arrays.copyOf(first, first.length + itemBefore.length);
+ System.arraycopy(itemBefore, 0, result, first.length, itemBefore.length);
bytes.add(result);
}
@Override
- public void updateMeta(int xid, long metaUUID) {
- String updateMetaStr = "meta " + xid + " " + metaUUID;
- bytes.add(updateMetaStr.getBytes());
+ public void updateMeta(int xid,long beforeUuid,byte[] metadata) {
}
@Override
@@ -69,5 +68,10 @@ public List getContent() {
return bytes;
}
+ @Override
+ public void recovery() throws IOException {
+
+ }
+
}
diff --git a/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java b/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java
index ca0bb4c..8f8fb91 100644
--- a/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java
+++ b/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java
@@ -109,7 +109,7 @@ public void testManyInsert() throws FileException, IOException, PageException, U
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
TransactionContext txContext = TransactionContext.empty();
- for (int i = 0; i < 1000; i++) {
+ for (int i = 0; i < 500; i++) {
long uuid = iItemStorage.insertItem(txContext, bytes);
long uuid2 = iItemStorage.insertItem(txContext, bytes);
long uuid3 = iItemStorage.insertItem(txContext, bytes);
diff --git a/src/test/java/net/kaaass/rumbase/record/IRecordStorageTest.java b/src/test/java/net/kaaass/rumbase/record/IRecordStorageTest.java
index f7d9ed5..0fe2f8b 100644
--- a/src/test/java/net/kaaass/rumbase/record/IRecordStorageTest.java
+++ b/src/test/java/net/kaaass/rumbase/record/IRecordStorageTest.java
@@ -2,9 +2,11 @@
import junit.framework.TestCase;
import lombok.extern.slf4j.Slf4j;
+import net.kaaass.rumbase.page.exception.FileException;
import net.kaaass.rumbase.record.exception.RecordNotFoundException;
import net.kaaass.rumbase.transaction.TransactionContext;
+import java.io.IOException;
import java.util.UUID;
import static org.junit.Assert.assertArrayEquals;
@@ -57,7 +59,7 @@ public void testDelete() throws RecordNotFoundException {
assertTrue("record should be deleted", result.isEmpty());
}
- public void testMetadata() {
+ public void testMetadata() throws IOException, FileException {
var storage = RecordManager.fromFile("test_metadata");
var context = TransactionContext.empty();
diff --git a/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java b/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java
index 118b2d2..425a4bc 100644
--- a/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java
+++ b/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java
@@ -2,7 +2,15 @@
import junit.framework.TestCase;
import lombok.extern.slf4j.Slf4j;
+import net.kaaass.rumbase.dataitem.IItemStorage;
+import net.kaaass.rumbase.dataitem.ItemManager;
+import net.kaaass.rumbase.dataitem.exception.UUIDException;
+import net.kaaass.rumbase.page.exception.FileException;
+import net.kaaass.rumbase.page.exception.PageException;
+import net.kaaass.rumbase.recovery.exception.LogException;
+import net.kaaass.rumbase.transaction.TransactionContext;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -14,7 +22,17 @@
@Slf4j
public class IRecoveryTest extends TestCase {
- public void testBegin() {
+ public void testBegin() throws PageException, LogException, FileException, IOException, UUIDException {
+ String fileName = "testInsert.db";
+ IItemStorage iItemStorage = ItemManager.fromFile(fileName);
+ byte[] bytes = new byte[]{1, 2, 3, 4};
+ TransactionContext txContext = TransactionContext.empty();
+ long uuid = iItemStorage.insertItem(txContext, bytes);
+ assertArrayEquals(bytes, iItemStorage.queryItemByUuid(uuid));
+
+ var recoveryStorage = iItemStorage.getRecoveryStorage();
+ var logs = recoveryStorage.getContent();
+ recoveryStorage.recovery();
}
}
From bf377d12388609d94cf645b2ad6ecbe1a0c78d40 Mon Sep 17 00:00:00 2001
From: xiaoxineryi <529086017@qq.com>
Date: Sat, 16 Jan 2021 15:34:42 +0800
Subject: [PATCH 11/20] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=97=A5=E5=BF=97?=
=?UTF-8?q?=E6=B5=8B=E8=AF=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../kaaass/rumbase/dataitem/IItemStorage.java | 2 +-
.../kaaass/rumbase/dataitem/ItemStorage.java | 3 +-
.../dataitem/mock/MockItemStorage.java | 3 +-
.../rumbase/recovery/RecoveryStorage.java | 9 +-
.../rumbase/recovery/IRecoveryTest.java | 130 +++++++++++++++++-
5 files changed, 135 insertions(+), 12 deletions(-)
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java
index 161e96a..3c98f32 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java
@@ -104,7 +104,7 @@ public interface IItemStorage {
*
* @param metadata 头信息
*/
- void setMetadata(TransactionContext txContext, byte[] metadata) throws PageCorruptedException, IOException, FileException;
+ long setMetadata(TransactionContext txContext, byte[] metadata) throws PageCorruptedException, IOException, FileException;
/**
* 不使用日志设置元数据
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
index 21d9d5a..7275833 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
@@ -614,11 +614,12 @@ public byte[] getMetadata() {
}
@Override
- public void setMetadata(TransactionContext txContext, byte[] metadata) throws PageCorruptedException, IOException, FileException {
+ public long setMetadata(TransactionContext txContext, byte[] metadata) throws PageCorruptedException, IOException, FileException {
var page = getPage(0);
var header = parseTableHeader(page);
var uuid = setMetadataWithoutLog(metadata);
recoveryStorage.updateMeta(txContext.getXid(),header.headerUuid,metadata);
+ return uuid;
}
@Override
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java
index 223d691..241f2ab 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java
@@ -153,8 +153,9 @@ public byte[] getMetadata() {
}
@Override
- public void setMetadata(TransactionContext txContext, byte[] metadata) {
+ public long setMetadata(TransactionContext txContext, byte[] metadata) {
this.meta = metadata;
+ return 0;
}
@Override
diff --git a/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java b/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java
index cfea86d..446a854 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java
@@ -172,7 +172,8 @@ private Map> parseXid(List logs) throws IOExcept
switch (tx.type){
case TX_COMMIT:
// 若是commit 则放入commitXid并将对应的xid移出abort
- abortXids.remove(tx.xid);
+ Integer id = tx.xid;
+ abortXids.remove(id);
commitXids.add(tx.xid);
break;
case TX_ABORT:
@@ -227,7 +228,7 @@ private UpdateLog parseUpdate(byte[] log) throws IOException {
private UpdateMetaLog parseUpdateMeta(byte[] log) throws IOException {
var updateMeta = JBBPParser.prepare("byte type;int xid;long beforeUuid;" +
- "int length;byte[length] metadata").
+ "int length;byte[length] metadata;").
parse(log).mapTo(new UpdateMetaLog());
return updateMeta;
}
@@ -340,7 +341,7 @@ public Object newInstance(Class> klazz) {
*/
public static class UpdateLog{
@Bin
- Byte type;
+ byte type;
@Bin
int xid;
@Bin
@@ -360,7 +361,7 @@ public Object newInstance(Class> klazz) {
public static class UpdateMetaLog{
@Bin
- Byte type;
+ byte type;
@Bin
int xid;
@Bin
diff --git a/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java b/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java
index 425a4bc..a569c15 100644
--- a/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java
+++ b/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java
@@ -12,7 +12,9 @@
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.Random;
import static org.junit.Assert.assertArrayEquals;
@@ -22,17 +24,135 @@
@Slf4j
public class IRecoveryTest extends TestCase {
- public void testBegin() throws PageException, LogException, FileException, IOException, UUIDException {
+ public void testInsert() throws PageException, LogException, FileException, IOException, UUIDException {
String fileName = "testInsert.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
- TransactionContext txContext = TransactionContext.empty();
- long uuid = iItemStorage.insertItem(txContext, bytes);
+ var txContext = TransactionContext.empty();
+ var recoveryStorage = iItemStorage.getRecoveryStorage();
+ var xid = 1;
+ var xid2 = 0;
+ List snaps = new ArrayList<>();
+ // 测试日志中存在,但是表中不存在进行恢复
+ recoveryStorage.begin(xid,snaps);
+ long a = 1;
+ long uuid = (a << 32) + Math.abs(new Random().nextInt());
+ recoveryStorage.insert(xid,uuid,bytes);
+ recoveryStorage.commit(xid);
+
+ // 测试日志中存在,且数据中也存在,会不会重复插入
+
+ recoveryStorage.begin(xid2,snaps);
+ iItemStorage.insertItem(txContext,bytes);
+ recoveryStorage.commit(xid2);
- assertArrayEquals(bytes, iItemStorage.queryItemByUuid(uuid));
+ recoveryStorage.recovery();
+ // 测试日志有额外的数据有没有被插入
+ var result = iItemStorage.queryItemByUuid(uuid);
+ assertTrue(Arrays.equals(result,bytes));
+ // 测试表中有的数据是否被重复插入
+ var list = iItemStorage.listItemByPageId(1);
+ assertEquals(2,list.size());
+ }
+ public void testUpdate() throws PageException, LogException, FileException, IOException, UUIDException {
+ String fileName = "testUpdate.db";
+ IItemStorage iItemStorage = ItemManager.fromFile(fileName);
+ byte[] bytes = new byte[]{1, 2, 3, 4};
+ byte[] bytesUpdate = new byte[]{2,3,4,5};
+ var txContext = TransactionContext.empty();
var recoveryStorage = iItemStorage.getRecoveryStorage();
- var logs = recoveryStorage.getContent();
+
+ int xid = 0;
+ List snaps = new ArrayList<>();
+
+ // 测试在表中存在的redo
+ recoveryStorage.begin(xid,snaps);
+ long uuid = iItemStorage.insertItem(txContext,bytes);
+ iItemStorage.updateItemByUuid(txContext,uuid,bytesUpdate);
+ recoveryStorage.commit(xid);
+
+ // 测试在表中不存在的redo
+ int xid2 = 1;
+ recoveryStorage.begin(xid2,snaps);
+ long a = 1;
+ long uuid2 = (a << 32) + Math.abs(new Random().nextInt());
+ recoveryStorage.insert(xid2,uuid2,bytes);
+ recoveryStorage.update(xid2,uuid2,bytes,bytesUpdate);
+ recoveryStorage.commit(xid2);
+
+ // 测试abort的事务
+ int xid3 = 2;
+ recoveryStorage.begin(xid3,snaps);
+ long b = 1;
+ long uuid3 = (b << 32) + Math.abs(new Random().nextInt());
+ recoveryStorage.insert(xid3,uuid3,bytes);
+ recoveryStorage.commit(xid3);
+ int xid4 = 3;
+ recoveryStorage.begin(xid4,snaps);
+ recoveryStorage.update(xid4,uuid3,bytes,bytesUpdate);
+ recoveryStorage.rollback(xid4);
+
recoveryStorage.recovery();
+
+ assertTrue(Arrays.equals(bytesUpdate,iItemStorage.queryItemByUuid(uuid)));
+ assertTrue(Arrays.equals(bytesUpdate,iItemStorage.queryItemByUuid(uuid2)));
+ assertTrue(Arrays.equals(bytes,iItemStorage.queryItemByUuid(uuid3)));
+ var list = iItemStorage.listItemByPageId(1);
+ assertEquals(3,list.size());
}
+
+ public void testUpdateMeta() throws PageException, LogException, FileException, IOException {
+ String fileName = "testUpdateMeta.db";
+ IItemStorage iItemStorage = ItemManager.fromFile(fileName);
+ byte[] bytes = new byte[]{1, 2, 3, 4};
+ byte[] bytesUpdate = new byte[]{2,3,4,5};
+ var txContext = TransactionContext.empty();
+ var recoveryStorage = iItemStorage.getRecoveryStorage();
+
+ // 测试表中有
+ int xid = 0;
+ List snaps = new ArrayList<>();
+ recoveryStorage.begin(xid,snaps);
+ var uuid = iItemStorage.setMetadata(txContext,bytes);
+ recoveryStorage.commit(xid);
+
+ assertTrue(Arrays.equals(bytes,iItemStorage.getMetadata()));
+ // 测试表中没有头信息时更新
+ int xid2 = 1;
+ recoveryStorage.begin(xid2,snaps);
+ recoveryStorage.updateMeta(xid2,uuid,bytesUpdate);
+ recoveryStorage.commit(xid2);
+ recoveryStorage.recovery();
+ assertTrue(Arrays.equals(bytesUpdate,iItemStorage.getMetadata()));
+
+ }
+
+ public void testUpdateMetaFail() throws PageException, LogException, FileException, IOException {
+ String fileName = "testUpdateMetaFail.db";
+ IItemStorage iItemStorage = ItemManager.fromFile(fileName);
+ byte[] bytes = new byte[]{1, 2, 3, 4};
+ byte[] bytesUpdate = new byte[]{2,3,4,5};
+ var txContext = TransactionContext.empty();
+ var recoveryStorage = iItemStorage.getRecoveryStorage();
+
+ // 测试表中有
+ int xid = 0;
+ List snaps = new ArrayList<>();
+ recoveryStorage.begin(xid,snaps);
+ var uuid = iItemStorage.setMetadata(txContext,bytes);
+ recoveryStorage.commit(xid);
+
+ assertTrue(Arrays.equals(bytes,iItemStorage.getMetadata()));
+ // 测试事务失败
+ int xid2 = 1;
+ recoveryStorage.begin(xid2,snaps);
+ recoveryStorage.updateMeta(xid2,uuid,bytesUpdate);
+ recoveryStorage.rollback(xid2);
+ recoveryStorage.recovery();
+ assertTrue(Arrays.equals(bytes,iItemStorage.getMetadata()));
+
+ }
+
+
}
From 30a70aafbf970718de1466f3f59880b456bd1083 Mon Sep 17 00:00:00 2001
From: xiaoxineryi <529086017@qq.com>
Date: Sat, 16 Jan 2021 15:58:02 +0800
Subject: [PATCH 12/20] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8F=92=E5=85=A5?=
=?UTF-8?q?=E7=9A=84=E5=9B=9E=E6=BB=9A?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../kaaass/rumbase/dataitem/IItemStorage.java | 6 ++
.../kaaass/rumbase/dataitem/ItemStorage.java | 57 ++++++++++++++++---
.../dataitem/mock/MockItemStorage.java | 7 +++
.../rumbase/recovery/RecoveryStorage.java | 1 +
.../rumbase/recovery/IRecoveryTest.java | 21 +++++++
5 files changed, 84 insertions(+), 8 deletions(-)
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java
index 3c98f32..b829d7f 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java
@@ -118,6 +118,12 @@ public interface IItemStorage {
* @param uuids 数据项UUID的编号列表
*/
void removeItems(List uuids);
+
+ /**
+ * 删除对应的uuid
+ * @param uuid
+ */
+ void deleteUuid(long uuid) throws IOException, PageException;
}
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
index 7275833..e23c548 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
@@ -349,13 +349,18 @@ public IRecoveryStorage getRecoveryStorage() {
@Override
public int getMaxPageId() {
var page = getPage(0);
- var header = parseTableHeader(page);
- return header.tempFreePage;
+ try{
+ var header = parseTableHeader(page);
+ return header.tempFreePage;
+ }finally {
+ releasePage(page);
+ }
}
@Override
public void flush(long uuid) throws FileException {
var page = getPage(uuid);
+ releasePage(page);
page.flush();
}
@@ -465,6 +470,33 @@ public synchronized void insertItemWithUuid(byte[] item, long uuid) {
// 若存在则不需要恢复,直接返回
}
+ /**
+ * 日志恢复时用,回退对应的insert操作
+ * @param uuid
+ */
+ @Override
+ public void deleteUuid(long uuid) throws IOException, PageException {
+ var page = getPage(uuid);
+ try {
+ var rnd = getRndByUuid(uuid);
+ var header = getPageHeader(page);
+ if (header.isPresent()){
+ var items = header.get().item;
+ for (int i = 0;i < items.length ; i ++){
+ if (rnd == items[i].uuid){
+ // 该item对应的起止位置,将其数据项变为-1
+ int offset = ITEM_OFFSET + i * ITEM_SIZE;
+ var bytes = JBBPOut.BeginBin().Int(-1).Int(0).End().toByteArray();
+ page.patchData(offset,bytes);
+ return;
+ }
+ }
+ }
+ }finally {
+ releasePage(page);
+ }
+ }
+
/**
* 检查uuid是否存在,若Uuid的页号超过当前可用页,则直接返回False
*
@@ -537,8 +569,12 @@ public List listItemByPageId(int pageId) {
if (pageHeaderOp.isPresent()) {
var pageHeader = pageHeaderOp.get();
for (var item : pageHeader.item) {
- var data = parseData(page, item);
- bytes.add(data);
+ if (item.uuid < 0){
+ continue;
+ }else {
+ var data = parseData(page, item);
+ bytes.add(data);
+ }
}
}
return bytes;
@@ -616,10 +652,15 @@ public byte[] getMetadata() {
@Override
public long setMetadata(TransactionContext txContext, byte[] metadata) throws PageCorruptedException, IOException, FileException {
var page = getPage(0);
- var header = parseTableHeader(page);
- var uuid = setMetadataWithoutLog(metadata);
- recoveryStorage.updateMeta(txContext.getXid(),header.headerUuid,metadata);
- return uuid;
+ try{
+ var header = parseTableHeader(page);
+ var uuid = setMetadataWithoutLog(metadata);
+ recoveryStorage.updateMeta(txContext.getXid(),header.headerUuid,metadata);
+ return uuid;
+ }finally {
+ releasePage(page);
+ }
+
}
@Override
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java
index 241f2ab..5010d7d 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java
@@ -4,9 +4,11 @@
import net.kaaass.rumbase.dataitem.IItemStorage;
import net.kaaass.rumbase.dataitem.exception.PageCorruptedException;
import net.kaaass.rumbase.dataitem.exception.UUIDException;
+import net.kaaass.rumbase.page.exception.PageException;
import net.kaaass.rumbase.recovery.IRecoveryStorage;
import net.kaaass.rumbase.transaction.TransactionContext;
+import java.io.IOException;
import java.util.*;
/**
@@ -170,6 +172,11 @@ public void removeItems(List uuids) {
System.out.println("已经清除文件对应uuid的信息");
}
+ @Override
+ public void deleteUuid(long uuid) throws IOException, PageException {
+
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
diff --git a/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java b/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java
index 446a854..80b7e04 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java
@@ -253,6 +253,7 @@ private void parseLog(byte[] log, IItemStorage itemStorage, Map snaps = new ArrayList<>();
+ recoveryStorage.begin(xid,snaps);
+ long uuid = iItemStorage.insertItem(txContext,bytes);
+ recoveryStorage.rollback(xid);
+ recoveryStorage.recovery();
+ try {
+ var item = iItemStorage.queryItemByUuid(uuid);
+ assertFalse(Arrays.equals(bytes,item));
+ }catch (Exception e){
+
+ }
+
+ }
+
public void testUpdate() throws PageException, LogException, FileException, IOException, UUIDException {
String fileName = "testUpdate.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
From 9d221a5be6d92f2a81d49b2371fc6839531fdc6b Mon Sep 17 00:00:00 2001
From: xiaoxineryi <529086017@qq.com>
Date: Sat, 16 Jan 2021 15:59:07 +0800
Subject: [PATCH 13/20] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8F=92=E5=85=A5?=
=?UTF-8?q?=E7=9A=84=E5=9B=9E=E6=BB=9A?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java b/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java
index c5413c9..e7ba030 100644
--- a/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java
+++ b/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java
@@ -56,7 +56,7 @@ public void testInsert() throws PageException, LogException, FileException, IOEx
}
public void testInsertFail() throws PageException, LogException, FileException, IOException, UUIDException {
- String fileName = "testInsert.db";
+ String fileName = "testInsertFailed.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
var txContext = TransactionContext.empty();
From 749c5f85158beefa3ccfa69f1a8e3033b74eb6d2 Mon Sep 17 00:00:00 2001
From: xiaoxineryi <529086017@qq.com>
Date: Sat, 16 Jan 2021 16:34:22 +0800
Subject: [PATCH 14/20] =?UTF-8?q?=E5=90=AF=E5=8A=A8=E6=81=A2=E5=A4=8D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../java/net/kaaass/rumbase/recovery/RecoveryManager.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java b/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java
index 8385d08..1d7d98e 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java
@@ -19,9 +19,9 @@ public class RecoveryManager {
* @param fileName 文件名
* @return 数据库日志管理器
*/
- public static void recovery(String fileName) {
+ public static void recovery(String fileName) throws PageException, LogException, FileException, IOException {
// TODO:对数据进行恢复
-
+ RecoveryStorage.ofFile(fileName).recovery();
}
public static IRecoveryStorage getRecoveryStorage(String fileName) throws FileException, IOException, LogException, PageException {
From bf583151a78849476fc9bbb2be82df240acc46b0 Mon Sep 17 00:00:00 2001
From: xiaoxineryi <529086017@qq.com>
Date: Sat, 16 Jan 2021 16:34:35 +0800
Subject: [PATCH 15/20] =?UTF-8?q?=E5=90=AF=E5=8A=A8=E6=81=A2=E5=A4=8D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java b/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java
index 1d7d98e..6fb4be7 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java
@@ -20,7 +20,7 @@ public class RecoveryManager {
* @return 数据库日志管理器
*/
public static void recovery(String fileName) throws PageException, LogException, FileException, IOException {
- // TODO:对数据进行恢复
+
RecoveryStorage.ofFile(fileName).recovery();
}
From 0220686301fd30ca3f0f7f118840a6bb82635dbd Mon Sep 17 00:00:00 2001
From: KAAAsS
Date: Sat, 16 Jan 2021 21:19:48 +0800
Subject: [PATCH 16/20] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=96=B9=E6=B3=95?=
=?UTF-8?q?=E7=AD=BE=E5=90=8D=E5=8F=98=E5=8A=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../kaaass/rumbase/record/IRecordStorage.java | 2 +-
.../rumbase/record/MvccRecordStorage.java | 20 ++++++++++++++++---
2 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/src/main/java/net/kaaass/rumbase/record/IRecordStorage.java b/src/main/java/net/kaaass/rumbase/record/IRecordStorage.java
index ea5582b..26d1e8b 100644
--- a/src/main/java/net/kaaass/rumbase/record/IRecordStorage.java
+++ b/src/main/java/net/kaaass/rumbase/record/IRecordStorage.java
@@ -65,5 +65,5 @@ default byte[] query(TransactionContext txContext, long recordId) throws RecordN
*
* @param metadata 元信息数据
*/
- void setMetadata(TransactionContext txContext, byte[] metadata) throws IOException, FileException;
+ void setMetadata(TransactionContext txContext, byte[] metadata);
}
diff --git a/src/main/java/net/kaaass/rumbase/record/MvccRecordStorage.java b/src/main/java/net/kaaass/rumbase/record/MvccRecordStorage.java
index ec12262..541d964 100644
--- a/src/main/java/net/kaaass/rumbase/record/MvccRecordStorage.java
+++ b/src/main/java/net/kaaass/rumbase/record/MvccRecordStorage.java
@@ -47,7 +47,13 @@ public long insert(TransactionContext txContext, byte[] rawData) {
writePayload(data, rawData);
// 不用检查版本跳跃的原因是,插入本身不用;更新操作必定先删除,而删除检查
// 插入记录
- return storage.insertItem(txContext, data);
+ try {
+ return storage.insertItem(txContext, data);
+ } catch (IOException | FileException e) {
+ e.printStackTrace();
+ // FIXME
+ return -1;
+ }
}
@Override
@@ -114,6 +120,9 @@ public void delete(TransactionContext txContext, long recordId) throws RecordNot
storage.updateItemByUuid(txContext, recordId, data);
} catch (UUIDException e) {
throw new RecordNotFoundException(1, e);
+ } catch (IOException | FileException e) {
+ e.printStackTrace();
+ // FIXME
}
}
@@ -222,7 +231,7 @@ public byte[] getMetadata(TransactionContext txContext) {
}
@Override
- public void setMetadata(TransactionContext txContext, byte[] metadata) throws IOException, FileException {
+ public void setMetadata(TransactionContext txContext, byte[] metadata) {
// TODO 申请全表锁,用this锁代替
// 主要逻辑:为了保证事务性,使用UUID数组,结合可见性选择对应的记录。倒序记录便于存储。
synchronized (this) {
@@ -233,7 +242,12 @@ public void setMetadata(TransactionContext txContext, byte[] metadata) throws IO
var newMetadata = new byte[oldMetadata.length + 8];
System.arraycopy(oldMetadata, 0, newMetadata, 8, oldMetadata.length);
MvccUtil.writeLong(newMetadata, 0, newId);
- storage.setMetadata(txContext, newMetadata);
+ try {
+ storage.setMetadata(txContext, newMetadata);
+ } catch (IOException | FileException e) {
+ e.printStackTrace();
+ // FIXME
+ }
// 缓存取消
this.metadataCache = null;
}
From 67e8b873296d87731e95c186e6e9b3138788b352 Mon Sep 17 00:00:00 2001
From: xiaoxineryi <529086017@qq.com>
Date: Sat, 16 Jan 2021 22:07:58 +0800
Subject: [PATCH 17/20] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8D=95=E5=85=83?=
=?UTF-8?q?=E6=B5=8B=E8=AF=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../rumbase/recovery/IRecoveryTest.java | 22 ++++++++++++++----
testInsert.db | Bin 0 -> 40960 bytes
2 files changed, 17 insertions(+), 5 deletions(-)
create mode 100644 testInsert.db
diff --git a/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java b/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java
index e7ba030..3197f88 100644
--- a/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java
+++ b/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java
@@ -10,6 +10,7 @@
import net.kaaass.rumbase.recovery.exception.LogException;
import net.kaaass.rumbase.transaction.TransactionContext;
+import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -25,7 +26,9 @@
public class IRecoveryTest extends TestCase {
public void testInsert() throws PageException, LogException, FileException, IOException, UUIDException {
- String fileName = "testInsert.db";
+ new File("test_gen_files/testInsert.db").delete();
+ new File("test_gen_files/testInsert.db.log").delete();
+ String fileName = "test_gen_files/testInsert.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
var txContext = TransactionContext.empty();
@@ -53,10 +56,13 @@ public void testInsert() throws PageException, LogException, FileException, IOEx
// 测试表中有的数据是否被重复插入
var list = iItemStorage.listItemByPageId(1);
assertEquals(2,list.size());
+
}
public void testInsertFail() throws PageException, LogException, FileException, IOException, UUIDException {
- String fileName = "testInsertFailed.db";
+ new File("test_gen_files/testInsertFailed.db").delete();
+ new File("test_gen_files/testInsertFailed.db.log").delete();
+ String fileName = "test_gen_files/testInsertFailed.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
var txContext = TransactionContext.empty();
@@ -77,7 +83,9 @@ public void testInsertFail() throws PageException, LogException, FileException,
}
public void testUpdate() throws PageException, LogException, FileException, IOException, UUIDException {
- String fileName = "testUpdate.db";
+ new File("test_gen_files/testUpdate.db").delete();
+ new File("test_gen_files/testUpdate.db.log").delete();
+ String fileName = "test_gen_files/testUpdate.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
byte[] bytesUpdate = new byte[]{2,3,4,5};
@@ -124,7 +132,9 @@ public void testUpdate() throws PageException, LogException, FileException, IOEx
}
public void testUpdateMeta() throws PageException, LogException, FileException, IOException {
- String fileName = "testUpdateMeta.db";
+ new File("test_gen_files/testUpdateMeta.db").delete();
+ new File("test_gen_files/testUpdateMeta.db.log").delete();
+ String fileName = "test_gen_files/testUpdateMeta.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
byte[] bytesUpdate = new byte[]{2,3,4,5};
@@ -150,7 +160,9 @@ public void testUpdateMeta() throws PageException, LogException, FileException,
}
public void testUpdateMetaFail() throws PageException, LogException, FileException, IOException {
- String fileName = "testUpdateMetaFail.db";
+ new File("test_gen_files/testUpdateMetaFail.db").delete();
+ new File("test_gen_files/testUpdateMetaFail.db.log").delete();
+ String fileName = "test_gen_files/testUpdateMetaFail.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
byte[] bytesUpdate = new byte[]{2,3,4,5};
diff --git a/testInsert.db b/testInsert.db
new file mode 100644
index 0000000000000000000000000000000000000000..ca5ea44f24f65b3d8acaaf654c430de8c51b16e2
GIT binary patch
literal 40960
zcmeIu0Sy2E0K%a6Pi+o2h(KY$fB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM
z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*
z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd
t0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0Rsm92L_-300961
literal 0
HcmV?d00001
From d472e36f5ddebd1f4f4f4887ee71bf92c255d00b Mon Sep 17 00:00:00 2001
From: xiaoxineryi <529086017@qq.com>
Date: Sat, 16 Jan 2021 23:30:13 +0800
Subject: [PATCH 18/20] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=BC=82=E5=B8=B8?=
=?UTF-8?q?=E5=A4=84=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../kaaass/rumbase/dataitem/IItemStorage.java | 15 +-
.../kaaass/rumbase/dataitem/ItemManager.java | 9 +-
.../kaaass/rumbase/dataitem/ItemStorage.java | 33 +--
.../rumbase/recovery/IRecoveryStorage.java | 14 +-
.../rumbase/recovery/RecoveryManager.java | 6 +-
.../rumbase/recovery/RecoveryStorage.java | 278 ++++++++++--------
.../recovery/exception/LogException.java | 13 +-
7 files changed, 212 insertions(+), 156 deletions(-)
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java
index b829d7f..fb94da3 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java
@@ -5,6 +5,7 @@
import net.kaaass.rumbase.page.exception.FileException;
import net.kaaass.rumbase.page.exception.PageException;
import net.kaaass.rumbase.recovery.IRecoveryStorage;
+import net.kaaass.rumbase.recovery.exception.LogException;
import net.kaaass.rumbase.transaction.TransactionContext;
import java.io.IOException;
@@ -17,7 +18,7 @@
*/
public interface IItemStorage {
- void setMetaUuid(long uuid) throws IOException, PageException;
+ void setMetaUuid(long uuid) throws PageException, IOException;
/**
* 获得日志管理器
@@ -42,7 +43,7 @@ public interface IItemStorage {
* @param item 数据项
* @return 返回数据项的UUID
*/
- long insertItem(TransactionContext txContext, byte[] item) throws IOException, FileException;
+ long insertItem(TransactionContext txContext, byte[] item) throws LogException,PageCorruptedException;
/**
* 不用日志进行插入,用于日志的管理
@@ -88,7 +89,7 @@ public interface IItemStorage {
* @param item 数据项
* @throws UUIDException 没有找到对应UUID的异常
*/
- void updateItemByUuid(TransactionContext txContext, long uuid, byte[] item) throws UUIDException, PageCorruptedException, FileException, IOException;
+ void updateItemByUuid(TransactionContext txContext, long uuid, byte[] item) throws UUIDException, LogException,PageCorruptedException;
byte[] updateItemWithoutLog(long uuid,byte[] item) throws UUIDException;
@@ -104,13 +105,13 @@ public interface IItemStorage {
*
* @param metadata 头信息
*/
- long setMetadata(TransactionContext txContext, byte[] metadata) throws PageCorruptedException, IOException, FileException;
+ long setMetadata(TransactionContext txContext, byte[] metadata) throws LogException;
/**
* 不使用日志设置元数据
* @param metadata 头信息
*/
- long setMetadataWithoutLog(byte[] metadata) throws PageCorruptedException;
+ long setMetadataWithoutLog(byte[] metadata);
/**
* 清理多余的数据项,空间清理时使用。
@@ -120,10 +121,10 @@ public interface IItemStorage {
void removeItems(List uuids);
/**
- * 删除对应的uuid
+ * 日志恢复时用,回退对应的insert操作,做法是删除对应的uuid
* @param uuid
*/
- void deleteUuid(long uuid) throws IOException, PageException;
+ void deleteUuid(long uuid) throws PageException, IOException;
}
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/ItemManager.java b/src/main/java/net/kaaass/rumbase/dataitem/ItemManager.java
index 0ce485a..8c5148e 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/ItemManager.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/ItemManager.java
@@ -1,6 +1,7 @@
package net.kaaass.rumbase.dataitem;
+import net.kaaass.rumbase.dataitem.exception.PageCorruptedException;
import net.kaaass.rumbase.page.exception.FileException;
import net.kaaass.rumbase.page.exception.PageException;
import net.kaaass.rumbase.recovery.exception.LogException;
@@ -26,7 +27,7 @@ public class ItemManager {
* @param fileName 文件名
* @return 数据项管理器,用于管理数据项
*/
- public static IItemStorage fromFile(String fileName) throws FileException, IOException, PageException, LogException {
+ public static IItemStorage fromFile(String fileName) throws FileException, PageException, LogException {
if (maps.containsKey(fileName)) {
return maps.get(fileName);
} else {
@@ -36,7 +37,7 @@ public static IItemStorage fromFile(String fileName) throws FileException, IOExc
}
}
- public static IItemStorage fromFileWithoutLog(String fileName) throws FileException, IOException, PageException, LogException {
+ public static IItemStorage fromFileWithoutLog(String fileName) throws FileException,PageException, PageCorruptedException {
if (maps.containsKey(fileName)) {
return maps.get(fileName);
} else {
@@ -56,7 +57,7 @@ public static IItemStorage fromFileWithoutLog(String fileName) throws FileExcept
* @return 数据项管理器
* @throws FileException 想新建的文件已经存在的异常
*/
- public static IItemStorage createFile(TransactionContext txContext, String fileName, byte[] metadata) throws FileException, IOException, PageException, LogException {
+ public static IItemStorage createFile(TransactionContext txContext, String fileName, byte[] metadata) throws FileException, PageException, LogException {
// 如果文件已经存在,那么就抛出文件已存在异常
if (maps.containsKey(fileName)) {
throw new FileException(1);
@@ -68,7 +69,7 @@ public static IItemStorage createFile(TransactionContext txContext, String fileN
}
}
- public static IItemStorage createFileWithoutLog(String fileName, byte[] metadata) throws FileException, IOException, PageException, LogException {
+ public static IItemStorage createFileWithoutLog(String fileName, byte[] metadata) throws FileException, PageException {
// 如果文件已经存在,那么就抛出文件已存在异常
if (maps.containsKey(fileName)) {
throw new FileException(1);
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
index e23c548..99217c7 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
@@ -87,7 +87,7 @@ public ItemStorage(String fileName, int tempFreePage, long headerUuid, PageStora
* @param header 第一页的Page对象
* @return 是否是表的第一页
*/
- private static boolean checkTableHeader(Page header) {
+ private static boolean checkTableHeader(Page header) throws PageCorruptedException{
var data = header.getData();
byte[] flag = new byte[4];
try {
@@ -104,7 +104,7 @@ private static boolean checkTableHeader(Page header) {
* @param fileName 文件名
* @return 解析或新建得到的数据项管理器对象
*/
- public static IItemStorage ofFile(String fileName) throws FileException, PageException, IOException, LogException {
+ public static IItemStorage ofFile(String fileName) throws FileException, PageException, LogException {
var pageStorage = PageManager.fromFile(fileName);
var header = pageStorage.get(0);
header.pin();
@@ -137,7 +137,7 @@ public static IItemStorage ofFile(String fileName) throws FileException, PageExc
/**
* 不使用日志打开文件
*/
- public static IItemStorage ofFileWithoutLog(String fileName) throws FileException, PageException, IOException, LogException {
+ public static IItemStorage ofFileWithoutLog(String fileName) throws FileException, PageException, PageCorruptedException {
var pageStorage = PageManager.fromFile(fileName);
var header = pageStorage.get(0);
header.pin();
@@ -172,7 +172,7 @@ public static IItemStorage ofFileWithoutLog(String fileName) throws FileExceptio
* @param metadata 表头信息
* @return 数据项管理器
*/
- public static IItemStorage ofNewFile(TransactionContext txContext, String fileName, byte[] metadata) throws IOException, FileException, PageException, LogException {
+ public static IItemStorage ofNewFile(TransactionContext txContext, String fileName, byte[] metadata) throws FileException, PageException, LogException {
var pageStorage = ItemStorage.ofFile(fileName);
pageStorage.setMetadata(txContext, metadata);
return pageStorage;
@@ -181,7 +181,7 @@ public static IItemStorage ofNewFile(TransactionContext txContext, String fileNa
/**
* 不使用日志的创建文件
*/
- public static IItemStorage ofNewFileWithoutLog(String fileName, byte[] metadata) throws IOException, LogException, FileException, PageException {
+ public static IItemStorage ofNewFileWithoutLog(String fileName, byte[] metadata) throws FileException, PageException {
var pageStorage = ItemStorage.ofFileWithoutLog(fileName);
pageStorage.setMetadataWithoutLog(metadata);
return pageStorage;
@@ -264,7 +264,7 @@ private static byte[] parseData(Page page, Item item) throws PageCorruptedExcept
* @param page 页
* @return 该页是否已经被初始化
*/
- private boolean checkPageHeader(Page page) {
+ private boolean checkPageHeader(Page page) throws PageCorruptedException{
byte[] pageFlag = new byte[4];
try {
var n = page.getData().read(pageFlag);
@@ -291,7 +291,7 @@ private Optional getPageHeader(Page page) {
return Optional.empty();
}
- private PageHeader initPage(Page page) {
+ private PageHeader initPage(Page page) throws PageCorruptedException {
final byte[] bytes;
try {
bytes = JBBPOut.BeginBin().
@@ -310,7 +310,7 @@ private PageHeader initPage(Page page) {
/**
* 修改当前第一个可用页
*/
- private void addTempFreePage() {
+ private void addTempFreePage() throws PageCorruptedException {
this.tempFreePage += 1;
var page = pageStorage.get(0);
page.pin();
@@ -328,7 +328,7 @@ private void addTempFreePage() {
}
@Override
- public void setMetaUuid(long uuid) throws IOException, PageException {
+ public void setMetaUuid(long uuid) throws PageException, IOException {
var page = getPage(0);
try {
var bytes = JBBPOut.BeginBin().
@@ -365,13 +365,13 @@ public void flush(long uuid) throws FileException {
}
@Override
- public synchronized long insertItem(TransactionContext txContext, byte[] item) throws IOException, FileException {
+ public synchronized long insertItem(TransactionContext txContext, byte[] item) throws LogException,PageCorruptedException {
long uuid = insertItemWithoutLog(item);
recoveryStorage.insert(txContext.getXid(),uuid,item);
return uuid;
}
@Override
- public synchronized long insertItemWithoutLog(byte[] item) {
+ public synchronized long insertItemWithoutLog(byte[] item) throws PageCorruptedException{
var page = getPage(this.tempFreePage);
try {
var pageHeaderOp = getPageHeader(page);
@@ -470,12 +470,9 @@ public synchronized void insertItemWithUuid(byte[] item, long uuid) {
// 若存在则不需要恢复,直接返回
}
- /**
- * 日志恢复时用,回退对应的insert操作
- * @param uuid
- */
+
@Override
- public void deleteUuid(long uuid) throws IOException, PageException {
+ public void deleteUuid(long uuid) throws PageException, IOException {
var page = getPage(uuid);
try {
var rnd = getRndByUuid(uuid);
@@ -586,7 +583,7 @@ public List listItemByPageId(int pageId) {
}
@Override
- public void updateItemByUuid(TransactionContext txContext, long uuid, byte[] item) throws UUIDException, PageCorruptedException, FileException, IOException {
+ public void updateItemByUuid(TransactionContext txContext, long uuid, byte[] item) throws UUIDException, PageCorruptedException, LogException {
var item_before = updateItemWithoutLog(uuid, item);
recoveryStorage.update(txContext.getXid(),uuid,item_before,item);
}
@@ -650,7 +647,7 @@ public byte[] getMetadata() {
}
@Override
- public long setMetadata(TransactionContext txContext, byte[] metadata) throws PageCorruptedException, IOException, FileException {
+ public long setMetadata(TransactionContext txContext, byte[] metadata) throws PageCorruptedException, LogException {
var page = getPage(0);
try{
var header = parseTableHeader(page);
diff --git a/src/main/java/net/kaaass/rumbase/recovery/IRecoveryStorage.java b/src/main/java/net/kaaass/rumbase/recovery/IRecoveryStorage.java
index 5d2585b..d692842 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/IRecoveryStorage.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/IRecoveryStorage.java
@@ -19,21 +19,21 @@ public interface IRecoveryStorage {
* @param xid 事务编号
* @param snapshots 快照集合
*/
- void begin(int xid, List snapshots) throws IOException, FileException;
+ void begin(int xid, List snapshots) throws LogException;
/**
* 记录事务失败回滚
*
* @param xid
*/
- void rollback(int xid) throws IOException, FileException;
+ void rollback(int xid) throws LogException;
/**
* 记录事务完成
*
* @param xid
*/
- void commit(int xid) throws IOException, FileException;
+ void commit(int xid) throws LogException;
/**
* 插入数据项的日志记录
@@ -42,7 +42,7 @@ public interface IRecoveryStorage {
* @param uuid 数据项的对应编号
* @param item 插入的数据内容
*/
- void insert(int xid, long uuid, byte[] item) throws IOException, FileException;
+ void insert(int xid, long uuid, byte[] item) throws LogException;
/**
* 更新数据项的日志记录
@@ -50,14 +50,14 @@ public interface IRecoveryStorage {
* @param xid
* @param uuid
*/
- void update(int xid, long uuid, byte[] itemBefore, byte[] itemAfter) throws IOException, FileException;
+ void update(int xid, long uuid, byte[] itemBefore, byte[] itemAfter) throws LogException;
/**
* 更新数据项的日志头
*
* @param xid
*/
- void updateMeta(int xid, long beforeUuid,byte[] metadata) throws IOException, FileException;
+ void updateMeta(int xid, long beforeUuid,byte[] metadata) throws LogException;
/**
* 模拟打印日志资料
@@ -67,5 +67,5 @@ public interface IRecoveryStorage {
/**
* 恢复数据
*/
- void recovery() throws IOException, LogException, FileException, PageException;
+ void recovery() throws LogException;
}
diff --git a/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java b/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java
index 6fb4be7..ae3b0b0 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java
@@ -19,16 +19,16 @@ public class RecoveryManager {
* @param fileName 文件名
* @return 数据库日志管理器
*/
- public static void recovery(String fileName) throws PageException, LogException, FileException, IOException {
+ public static void recovery(String fileName) throws LogException {
RecoveryStorage.ofFile(fileName).recovery();
}
- public static IRecoveryStorage getRecoveryStorage(String fileName) throws FileException, IOException, LogException, PageException {
+ public static IRecoveryStorage getRecoveryStorage(String fileName) throws LogException {
return RecoveryStorage.ofFile(fileName);
}
- public static IRecoveryStorage createRecoveryStorage(String fileName) throws IOException, FileException, PageException, LogException {
+ public static IRecoveryStorage createRecoveryStorage(String fileName) throws LogException {
return RecoveryStorage.ofNewFile(fileName);
}
}
diff --git a/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java b/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java
index 80b7e04..d0c0f91 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java
@@ -6,6 +6,7 @@
import net.kaaass.rumbase.dataitem.IItemStorage;
import net.kaaass.rumbase.dataitem.ItemManager;
import net.kaaass.rumbase.dataitem.exception.UUIDException;
+import net.kaaass.rumbase.page.Page;
import net.kaaass.rumbase.page.exception.FileException;
import net.kaaass.rumbase.page.exception.PageException;
import net.kaaass.rumbase.recovery.exception.LogException;
@@ -43,9 +44,13 @@ public RecoveryStorage(IItemStorage itemStorage,String fileName) {
* @param fileName
* @return 日志管理器
*/
- public static IRecoveryStorage ofFile(String fileName) throws FileException, IOException, LogException, PageException {
- var itemStorage = ItemManager.fromFileWithoutLog(fileName + ".log");
- return new RecoveryStorage(itemStorage,fileName);
+ public static IRecoveryStorage ofFile(String fileName) throws LogException {
+ try {
+ var itemStorage = ItemManager.fromFileWithoutLog(fileName + ".log");
+ return new RecoveryStorage(itemStorage,fileName);
+ }catch (FileException | PageException e){
+ throw new LogException(10);
+ }
}
/**
@@ -53,85 +58,114 @@ public static IRecoveryStorage ofFile(String fileName) throws FileException, IOE
* @param fileName 文件名
* @return
*/
- public static IRecoveryStorage ofNewFile(String fileName) throws FileException, IOException, PageException, LogException {
- var metadata = JBBPOut.BeginBin().Int(HEADER).End().toByteArray();
- var itemStorage = ItemManager.createFileWithoutLog(fileName + ".log",metadata);
- return new RecoveryStorage(itemStorage,fileName);
+ public static IRecoveryStorage ofNewFile(String fileName) throws LogException {
+ try {
+ var metadata = JBBPOut.BeginBin().Int(HEADER).End().toByteArray();
+ var itemStorage = ItemManager.createFileWithoutLog(fileName + ".log",metadata);
+ return new RecoveryStorage(itemStorage,fileName);
+ }catch (IOException | FileException | PageException e) {
+ throw new LogException(9);
+ }
}
@Override
- public void begin(int xid, List snapshots) throws IOException, FileException {
- var jbbp = JBBPOut.BeginBin().
- Byte(TX_BEGIN).
- Int(xid).
- Int(snapshots.size());
- for ( var i : snapshots){
- jbbp = jbbp.Int(i);
+ public void begin(int xid, List snapshots) throws LogException {
+ try {
+ var jbbp = JBBPOut.BeginBin().
+ Byte(TX_BEGIN).
+ Int(xid).
+ Int(snapshots.size());
+ for ( var i : snapshots){
+ jbbp = jbbp.Int(i);
+ }
+ var bytes = jbbp.End().toByteArray();
+ var uuid = logStorage.insertItemWithoutLog(bytes);
+ logStorage.flush(uuid);
+ } catch (IOException | FileException e) {
+ throw new LogException(3);
}
- var bytes = jbbp.End().toByteArray();
- var uuid = logStorage.insertItemWithoutLog(bytes);
- logStorage.flush(uuid);
}
@Override
- public void rollback(int xid) throws IOException, FileException {
- var bytes = JBBPOut.BeginBin().
- Byte(TX_ABORT).
- Int(xid).
- End().toByteArray();
- var uuid = logStorage.insertItemWithoutLog(bytes);
- logStorage.flush(uuid);
+ public void rollback(int xid) throws LogException {
+ try {
+ var bytes = JBBPOut.BeginBin().
+ Byte(TX_ABORT).
+ Int(xid).
+ End().toByteArray();
+ var uuid = logStorage.insertItemWithoutLog(bytes);
+ logStorage.flush(uuid);
+ }catch (FileException | IOException e){
+ throw new LogException(4);
+ }
}
@Override
- public void commit(int xid) throws IOException, FileException {
- var bytes = JBBPOut.BeginBin().
- Byte(TX_COMMIT).
- Int(xid).
- End().toByteArray();
- var uuid = logStorage.insertItemWithoutLog(bytes);
- logStorage.flush(uuid);
+ public void commit(int xid) throws LogException {
+ try {
+ var bytes = JBBPOut.BeginBin().
+ Byte(TX_COMMIT).
+ Int(xid).
+ End().toByteArray();
+ var uuid = logStorage.insertItemWithoutLog(bytes);
+ logStorage.flush(uuid);
+ }catch (FileException | IOException e){
+ throw new LogException(5);
+ }
+
}
@Override
- public void insert(int xid, long uuid, byte[] item) throws IOException, FileException {
- var bytes = JBBPOut.BeginBin().
- Byte(INSERT_FLAG).
- Int(xid).
- Long(uuid).
- Int(item.length).
- Byte(item).
- End().toByteArray();
- var id = logStorage.insertItemWithoutLog(bytes);
- logStorage.flush(id);
+ public void insert(int xid, long uuid, byte[] item) throws LogException {
+ try {
+ var bytes = JBBPOut.BeginBin().
+ Byte(INSERT_FLAG).
+ Int(xid).
+ Long(uuid).
+ Int(item.length).
+ Byte(item).
+ End().toByteArray();
+ var id = logStorage.insertItemWithoutLog(bytes);
+ logStorage.flush(id);
+ }catch (FileException | IOException e){
+ throw new LogException(6);
+ }
}
@Override
- public void update(int xid, long uuid, byte[] itemBefore, byte[] itemAfter) throws IOException, FileException {
- var bytes = JBBPOut.BeginBin().
- Byte(UPDATE_FLAG).
- Int(xid).
- Long(uuid).
- Int(itemBefore.length).
- Byte(itemBefore).
- Int(itemAfter.length).
- Byte(itemAfter).
- End().toByteArray();
- var id = logStorage.insertItemWithoutLog(bytes);
- logStorage.flush(id);
+ public void update(int xid, long uuid, byte[] itemBefore, byte[] itemAfter) throws LogException {
+ try{
+ var bytes = JBBPOut.BeginBin().
+ Byte(UPDATE_FLAG).
+ Int(xid).
+ Long(uuid).
+ Int(itemBefore.length).
+ Byte(itemBefore).
+ Int(itemAfter.length).
+ Byte(itemAfter).
+ End().toByteArray();
+ var id = logStorage.insertItemWithoutLog(bytes);
+ logStorage.flush(id);
+ }catch (FileException | IOException e){
+ throw new LogException(7);
+ }
}
@Override
- public void updateMeta(int xid, long beforeUuid,byte[] metadata) throws IOException, FileException {
- var bytes =JBBPOut.BeginBin().
- Byte(METADATA_UPDATE_FLAG).
- Int(xid).
- Long(beforeUuid).
- Int(metadata.length).
- Byte(metadata).
- End().toByteArray();
- var uuid = logStorage.insertItemWithoutLog(bytes);
- logStorage.flush(uuid);
+ public void updateMeta(int xid, long beforeUuid,byte[] metadata) throws LogException {
+ try {
+ var bytes =JBBPOut.BeginBin().
+ Byte(METADATA_UPDATE_FLAG).
+ Int(xid).
+ Long(beforeUuid).
+ Int(metadata.length).
+ Byte(metadata).
+ End().toByteArray();
+ var uuid = logStorage.insertItemWithoutLog(bytes);
+ logStorage.flush(uuid);
+ }catch (FileException | IOException e){
+ throw new LogException(8);
+ }
}
@@ -151,24 +185,33 @@ public List getContent() {
}
@Override
- public void recovery() throws IOException, LogException, FileException, PageException {
- var itemStorage = ItemManager.fromFile(this.fileName);
- var logs = getContent();
- var xidMaps = parseXid(logs);
- for (var log : logs){
- parseLog(log,itemStorage,xidMaps);
+ public void recovery() throws LogException{
+ try {
+ var itemStorage = ItemManager.fromFile(this.fileName);
+ var logs = getContent();
+ var xidMaps = parseXid(logs);
+ for (var log : logs){
+ parseLog(log,itemStorage,xidMaps);
+ }
+ }catch (FileException | PageException e){
+ throw new LogException(11);
}
}
/**
* 先进行一遍解析,得到所有已完成的事务和未完成的事务,来决定redo还是undo
*/
- private Map> parseXid(List logs) throws IOException {
+ private Map> parseXid(List logs) throws LogException {
List commitXids = new ArrayList<>();
List abortXids = new ArrayList<>();
for (var log : logs){
- var tx = parseTx(log);
+ Tx tx = null;
+ try {
+ tx = parseTx(log);
+ } catch (IOException e) {
+ throw new LogException(1);
+ }
switch (tx.type){
case TX_COMMIT:
// 若是commit 则放入commitXid并将对应的xid移出abort
@@ -242,52 +285,57 @@ private boolean checkCommit(int xid,Map> maps) throws Lo
throw new LogException(2);
}
}
- private void parseLog(byte[] log, IItemStorage itemStorage, Map> xidMaps) throws IOException, LogException, PageException {
- var type = parseType(log);
- switch (type){
- case INSERT_FLAG:
- System.out.println("正在解析插入");
- var insertLog = parseInsert(log);
- if (checkCommit(insertLog.xid,xidMaps)){
- // 如果事务已经提交,则redo
- itemStorage.insertItemWithUuid(insertLog.item,insertLog.uuid);
- }else {
- // 如果事务没有提交,则undo
- itemStorage.deleteUuid(insertLog.uuid);
- }
- break;
- case UPDATE_FLAG:
- System.out.println("正在解析更新");
- var updateLog = parseUpdate(log);
- if (checkCommit(updateLog.xid,xidMaps)){
- // 若事务已经提交则redo
- try {
- itemStorage.updateItemWithoutLog(updateLog.uuid,updateLog.itemAfter);
- } catch (UUIDException ignored) {
- // uuid不存在说明对应之前的事务没有执行,是正常
- }
- }else {
- // 若事务没有提交,则undo,恢复之前的数据
- try {
- itemStorage.updateItemWithoutLog(updateLog.uuid,updateLog.itemBefore);
- } catch (UUIDException ignored) {
+ private void parseLog(byte[] log, IItemStorage itemStorage, Map> xidMaps) throws LogException {
+ try {
+ var type = parseType(log);
+ switch (type){
+ case INSERT_FLAG:
+ System.out.println("正在解析插入");
+ var insertLog = parseInsert(log);
+ if (checkCommit(insertLog.xid,xidMaps)){
+ // 如果事务已经提交,则redo
+ itemStorage.insertItemWithUuid(insertLog.item,insertLog.uuid);
+ }else {
+ // 如果事务没有提交,则undo
+ itemStorage.deleteUuid(insertLog.uuid);
}
- }
- break;
- case METADATA_UPDATE_FLAG:
- System.out.println("正在解析头信息更新");
- var updateMetaLog = parseUpdateMeta(log);
- if (checkCommit(updateMetaLog.xid,xidMaps)){
- // redo
- itemStorage.setMetadataWithoutLog(updateMetaLog.metadata);
- }else {
- // undo
- itemStorage.setMetaUuid(updateMetaLog.beforeUuid);
- }
- break;
- default:
- return;
+ break;
+ case UPDATE_FLAG:
+ System.out.println("正在解析更新");
+ var updateLog = parseUpdate(log);
+ if (checkCommit(updateLog.xid,xidMaps)){
+ // 若事务已经提交则redo
+ try {
+ itemStorage.updateItemWithoutLog(updateLog.uuid,updateLog.itemAfter);
+ } catch (UUIDException ignored) {
+ // uuid不存在说明对应之前的事务没有执行,是正常
+ }
+ }else {
+ // 若事务没有提交,则undo,恢复之前的数据
+ try {
+ itemStorage.updateItemWithoutLog(updateLog.uuid,updateLog.itemBefore);
+ } catch (UUIDException ignored) {
+
+ }
+ }
+ break;
+ case METADATA_UPDATE_FLAG:
+ System.out.println("正在解析头信息更新");
+ var updateMetaLog = parseUpdateMeta(log);
+ if (checkCommit(updateMetaLog.xid,xidMaps)){
+ // redo
+ itemStorage.setMetadataWithoutLog(updateMetaLog.metadata);
+ }else {
+ // undo
+ itemStorage.setMetaUuid(updateMetaLog.beforeUuid);
+ }
+ break;
+ default:
+ return;
+ }
+ }catch (IOException | PageException e){
+ throw new LogException(1);
}
}
diff --git a/src/main/java/net/kaaass/rumbase/recovery/exception/LogException.java b/src/main/java/net/kaaass/rumbase/recovery/exception/LogException.java
index e22f074..6b6ae8a 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/exception/LogException.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/exception/LogException.java
@@ -13,10 +13,19 @@ public class LogException extends RumbaseException {
public static final Map REASONS = new HashMap() {{
put(1, "日志文件无法解析");
- put(2,"事务ID不存在");
+ put(2, "事务ID不存在");
+ put(3, "事务提交日志写回错误");
+ put(4, "事务回滚日志写回错误");
+ put(5, "事务提交日志写回错误");
+ put(6, "插入数据项日志写回错误");
+ put(7, "更新数据项日志写回错误");
+ put(8, "更新头信息日志写回错误");
+ put(9, "日志文件创建失败");
+ put(10, "日志文件打开失败");
+ put(11, "日志获取原文件失败");
}};
public LogException(int subId) {
- super(9001,subId,REASONS.get(subId));
+ super(3001,subId,REASONS.get(subId));
}
}
From 88f3055ea0ff9a73b885ead3ace96926fb6985e5 Mon Sep 17 00:00:00 2001
From: KAAAsS
Date: Sun, 17 Jan 2021 13:58:22 +0800
Subject: [PATCH 19/20] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=BB=A5=E9=80=9A?=
=?UTF-8?q?=E8=BF=87=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../kaaass/rumbase/dataitem/IItemStorage.java | 25 +++-
.../kaaass/rumbase/dataitem/ItemStorage.java | 32 ++++-
.../dataitem/mock/MockItemStorage.java | 4 +
.../kaaass/rumbase/page/RumPageStorage.java | 25 ++--
.../rumbase/record/MvccRecordStorage.java | 19 +--
.../recovery/mock/MockRecoveryStorage.java | 5 +-
.../rumbase/dataitem/IItemStorageTest.java | 83 ++++++------
.../rumbase/recovery/IRecoveryTest.java | 128 +++++++++---------
testInsert.db | Bin 40960 -> 0 bytes
9 files changed, 174 insertions(+), 147 deletions(-)
delete mode 100644 testInsert.db
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java
index fb94da3..bc0c2e3 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java
@@ -22,31 +22,35 @@ public interface IItemStorage {
/**
* 获得日志管理器
+ *
* @return
*/
IRecoveryStorage getRecoveryStorage();
/**
* 获取表的tempFreePage
+ *
* @return
*/
public int getMaxPageId();
/**
- * 将uuid对应的页强制写回
+ * 将uuid对应的页强制写回
*/
public void flush(long uuid) throws FileException;
+
/**
* 插入数据项
*
* @param txContext 事务上下文
- * @param item 数据项
+ * @param item 数据项
* @return 返回数据项的UUID
*/
- long insertItem(TransactionContext txContext, byte[] item) throws LogException,PageCorruptedException;
+ long insertItem(TransactionContext txContext, byte[] item) throws PageCorruptedException;
/**
* 不用日志进行插入,用于日志的管理
+ *
* @param item 数据项
* @return uuid
*/
@@ -89,9 +93,9 @@ public interface IItemStorage {
* @param item 数据项
* @throws UUIDException 没有找到对应UUID的异常
*/
- void updateItemByUuid(TransactionContext txContext, long uuid, byte[] item) throws UUIDException, LogException,PageCorruptedException;
+ void updateItemByUuid(TransactionContext txContext, long uuid, byte[] item) throws UUIDException, PageCorruptedException;
- byte[] updateItemWithoutLog(long uuid,byte[] item) throws UUIDException;
+ byte[] updateItemWithoutLog(long uuid, byte[] item) throws UUIDException;
/**
* 获得数据项存储的元数据(可以用于头)
@@ -105,10 +109,11 @@ public interface IItemStorage {
*
* @param metadata 头信息
*/
- long setMetadata(TransactionContext txContext, byte[] metadata) throws LogException;
+ long setMetadata(TransactionContext txContext, byte[] metadata);
/**
- * 不使用日志设置元数据
+ * 不使用日志设置元数据
+ *
* @param metadata 头信息
*/
long setMetadataWithoutLog(byte[] metadata);
@@ -122,9 +127,15 @@ public interface IItemStorage {
/**
* 日志恢复时用,回退对应的insert操作,做法是删除对应的uuid
+ *
* @param uuid
*/
void deleteUuid(long uuid) throws PageException, IOException;
+
+ /**
+ * 建议存储进行一次回写
+ */
+ void flush();
}
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
index a21e5c8..016c8d1 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java
@@ -368,9 +368,14 @@ public void flush(long uuid) throws FileException {
}
@Override
- public synchronized long insertItem(TransactionContext txContext, byte[] item) throws LogException,PageCorruptedException {
+ public synchronized long insertItem(TransactionContext txContext, byte[] item) throws PageCorruptedException {
long uuid = insertItemWithoutLog(item);
- recoveryStorage.insert(txContext.getXid(),uuid,item);
+ try {
+ recoveryStorage.insert(txContext.getXid(),uuid,item);
+ } catch (LogException e) {
+ log.warn("文件 {} 日志写入出现故障,触发回写", this.fileName, e);
+ flush();
+ }
return uuid;
}
@Override
@@ -497,6 +502,11 @@ public void deleteUuid(long uuid) throws PageException, IOException {
}
}
+ @Override
+ public void flush() {
+ pageStorage.flush();
+ }
+
/**
* 检查uuid是否存在,若Uuid的页号超过当前可用页,则直接返回False
*
@@ -586,9 +596,14 @@ public List listItemByPageId(int pageId) {
}
@Override
- public void updateItemByUuid(TransactionContext txContext, long uuid, byte[] item) throws UUIDException, PageCorruptedException, LogException {
+ public void updateItemByUuid(TransactionContext txContext, long uuid, byte[] item) throws UUIDException, PageCorruptedException {
var item_before = updateItemWithoutLog(uuid, item);
- recoveryStorage.update(txContext.getXid(),uuid,item_before,item);
+ try {
+ recoveryStorage.update(txContext.getXid(),uuid,item_before,item);
+ } catch (LogException e) {
+ log.warn("文件 {} 日志写入出现故障,触发回写", this.fileName, e);
+ flush();
+ }
}
@Override
@@ -650,12 +665,17 @@ public byte[] getMetadata() {
}
@Override
- public long setMetadata(TransactionContext txContext, byte[] metadata) throws PageCorruptedException, LogException {
+ public long setMetadata(TransactionContext txContext, byte[] metadata) throws PageCorruptedException {
var page = getPage(0);
try{
var header = parseTableHeader(page);
var uuid = setMetadataWithoutLog(metadata);
- recoveryStorage.updateMeta(txContext.getXid(),header.headerUuid,metadata);
+ try {
+ recoveryStorage.updateMeta(txContext.getXid(),header.headerUuid,metadata);
+ } catch (LogException e) {
+ log.warn("文件 {} 日志写入出现故障,触发回写", this.fileName, e);
+ flush();
+ }
return uuid;
}finally {
releasePage(page);
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java
index 5010d7d..e2fdad7 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java
@@ -177,6 +177,10 @@ public void deleteUuid(long uuid) throws IOException, PageException {
}
+ @Override
+ public void flush() {
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
diff --git a/src/main/java/net/kaaass/rumbase/page/RumPageStorage.java b/src/main/java/net/kaaass/rumbase/page/RumPageStorage.java
index d94dc23..1f20f82 100644
--- a/src/main/java/net/kaaass/rumbase/page/RumPageStorage.java
+++ b/src/main/java/net/kaaass/rumbase/page/RumPageStorage.java
@@ -1,21 +1,22 @@
package net.kaaass.rumbase.page;
+import lombok.extern.slf4j.Slf4j;
import net.kaaass.rumbase.page.exception.BufferException;
import net.kaaass.rumbase.page.exception.FileException;
import java.io.*;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.Map;
-import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
/**
* @author 11158
*/
+@Slf4j
public class RumPageStorage implements PageStorage {
- public RumPageStorage(String filepath) throws FileException {
+ public RumPageStorage(String filepath) {
this.filepath = filepath;
- pageMap = new HashMap<>();
+ pageMap = new ConcurrentHashMap<>();
}
@Override
@@ -40,7 +41,7 @@ public Page get(long pageId) {
while (in.available() < (pageId + 1 + PageManager.FILE_HEAD_SIZE) * PageManager.PAGE_SIZE) {
FileWriter fw = new FileWriter(file, true);
char[] blank = new char[PageManager.PAGE_SIZE * (in.available() / PageManager.PAGE_SIZE)];
- Arrays.fill(blank, (char)0);
+ Arrays.fill(blank, (char) 0);
fw.write(blank);
fw.close();
}
@@ -59,7 +60,8 @@ public Page get(long pageId) {
}
int offset = -1;
while (offset < 0) {
- synchronized (RumBuffer.getInstance()) {//并非区间锁,而是将整个内存全部锁住
+ //并非区间锁,而是将整个内存全部锁住
+ synchronized (RumBuffer.getInstance()) {
try {
offset = RumBuffer.getInstance().getFreeOffset();
RumBuffer.getInstance().put(offset, data);
@@ -86,12 +88,15 @@ public Page get(long pageId) {
@Override
public void flush() {
- Set> entrySet = this.pageMap.entrySet();
- for (Map.Entry entry : entrySet) {
+ var entrySet = this.pageMap.entrySet();
+ for (var entry : entrySet) {
+ var page = entry.getValue();
try {
- entry.getValue().flush();
+ if (page instanceof RumPage && ((RumPage) page).dirty()) {
+ page.flush();
+ }
} catch (Exception e) {
- e.printStackTrace();
+ log.warn("回写页面 {} 发生异常", entry.getKey());
}
}
}
diff --git a/src/main/java/net/kaaass/rumbase/record/MvccRecordStorage.java b/src/main/java/net/kaaass/rumbase/record/MvccRecordStorage.java
index d33ac44..de87af2 100644
--- a/src/main/java/net/kaaass/rumbase/record/MvccRecordStorage.java
+++ b/src/main/java/net/kaaass/rumbase/record/MvccRecordStorage.java
@@ -11,6 +11,7 @@
import net.kaaass.rumbase.record.exception.NeedRollbackException;
import net.kaaass.rumbase.record.exception.RecordNotFoundException;
import net.kaaass.rumbase.record.exception.StorageCorruptedException;
+import net.kaaass.rumbase.recovery.exception.LogException;
import net.kaaass.rumbase.transaction.TransactionContext;
import net.kaaass.rumbase.transaction.TransactionIsolation;
import net.kaaass.rumbase.transaction.TransactionStatus;
@@ -49,13 +50,7 @@ public long insert(TransactionContext txContext, byte[] rawData) {
writePayload(data, rawData);
// 不用检查版本跳跃的原因是,插入本身不用;更新操作必定先删除,而删除检查
// 插入记录
- try {
- return storage.insertItem(txContext, data);
- } catch (IOException | FileException e) {
- e.printStackTrace();
- // FIXME
- return -1;
- }
+ return storage.insertItem(txContext, data);
}
@Override
@@ -122,9 +117,6 @@ public void delete(TransactionContext txContext, long recordId) throws RecordNot
storage.updateItemByUuid(txContext, recordId, data);
} catch (UUIDException e) {
throw new RecordNotFoundException(1, e);
- } catch (IOException | FileException e) {
- e.printStackTrace();
- // FIXME
}
}
@@ -244,12 +236,7 @@ public void setMetadata(TransactionContext txContext, byte[] metadata) {
var newMetadata = new byte[oldMetadata.length + 8];
System.arraycopy(oldMetadata, 0, newMetadata, 8, oldMetadata.length);
MvccUtil.writeLong(newMetadata, 0, newId);
- try {
- storage.setMetadata(txContext, newMetadata);
- } catch (IOException | FileException e) {
- e.printStackTrace();
- // FIXME
- }
+ storage.setMetadata(txContext, newMetadata);
// 缓存取消
this.metadataCache = null;
}
diff --git a/src/main/java/net/kaaass/rumbase/recovery/mock/MockRecoveryStorage.java b/src/main/java/net/kaaass/rumbase/recovery/mock/MockRecoveryStorage.java
index b872dbe..b22049d 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/mock/MockRecoveryStorage.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/mock/MockRecoveryStorage.java
@@ -69,9 +69,6 @@ public List getContent() {
}
@Override
- public void recovery() throws IOException {
-
+ public void recovery() {
}
-
-
}
diff --git a/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java b/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java
index 3e8ccfa..c0fad1f 100644
--- a/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java
+++ b/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java
@@ -1,7 +1,7 @@
package net.kaaass.rumbase.dataitem;
-import junit.framework.TestCase;
import lombok.extern.slf4j.Slf4j;
+import net.kaaass.rumbase.FileUtil;
import net.kaaass.rumbase.dataitem.exception.PageCorruptedException;
import net.kaaass.rumbase.dataitem.exception.UUIDException;
import net.kaaass.rumbase.page.exception.FileException;
@@ -9,7 +9,6 @@
import net.kaaass.rumbase.recovery.exception.LogException;
import net.kaaass.rumbase.transaction.TransactionContext;
import org.junit.AfterClass;
-import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -32,6 +31,8 @@
@Slf4j
public class IItemStorageTest {
+ private static final String PATH = FileUtil.TEST_PATH;
+
@BeforeClass
public static void createDataFolder() {
FileUtil.prepare();
@@ -42,19 +43,17 @@ public static void clearDataFolder() {
FileUtil.clear();
}
- private static final String PATH = FileUtil.TEST_PATH;
-
/**
* 测试能否从已有文件中解析得到数据项管理器
*/
@Test
- public void testGetFromFile() throws FileException, IOException, PageException, LogException {
+ public void testGetFromFile() throws FileException, PageException, LogException {
String fileName = PATH + "testGetFromFile.db";
- var itemStorage = ItemManager.fromFile(fileName);
+ ItemManager.fromFile(fileName);
// 如果表中没有对应的文件,那么就抛出错误
String failFileName = "error.db";
try {
- IItemStorage iItemStorage1 = ItemManager.fromFile(failFileName);
+ ItemManager.fromFile(failFileName);
} catch (FileException f) {
log.error("Exception Error :", f);
}
@@ -64,15 +63,15 @@ public void testGetFromFile() throws FileException, IOException, PageException,
* 测试能否新建文件并得到数据项管理器
*/
@Test
- public void testCreateFile() throws IOException, FileException, PageException, LogException {
+ public void testCreateFile() throws FileException, PageException, LogException {
TransactionContext txContext = TransactionContext.empty();
String fileName = PATH + "testCreateFile.db";
byte[] metadata = new byte[1024];
// 第一次执行的时候,表中没有数据,不会报错
- var iItemStorage = ItemManager.createFile(txContext, fileName, metadata);
+ ItemManager.createFile(txContext, fileName, metadata);
try {
- iItemStorage = ItemManager.createFile(txContext, fileName, metadata);
+ ItemManager.createFile(txContext, fileName, metadata);
fail("should get exception");
} catch (Exception e) {
log.error("Exception Error :", e);
@@ -82,7 +81,7 @@ public void testCreateFile() throws IOException, FileException, PageException, L
/**
* 进行插入的测试
*/
- public void testInsert() throws FileException, IOException, PageException, UUIDException, PageCorruptedException {
+ public void testInsert() throws FileException, IOException, PageException, UUIDException, PageCorruptedException, LogException {
String fileName = PATH + "testInsert.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
@@ -99,7 +98,7 @@ public void testInsert() throws FileException, IOException, PageException, UUIDE
/**
* 对插入一个已分配UUID的测试
*/
- public void testInsertWithUUID() throws FileException, IOException, PageException {
+ public void testInsertWithUUID() throws FileException, IOException, PageException, LogException {
String fileName = PATH + "testInsertWithUUID.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
@@ -123,7 +122,7 @@ public void testInsertWithUUID() throws FileException, IOException, PageExceptio
/**
* 对插入大量数据进行测试
*/
- public void testManyInsert() throws FileException, IOException, PageException, UUIDException, PageCorruptedException {
+ public void testManyInsert() throws FileException, IOException, PageException, UUIDException, PageCorruptedException, LogException {
String fileName = PATH + "testInsertMany.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
@@ -143,7 +142,7 @@ public void testManyInsert() throws FileException, IOException, PageException, U
/**
* 获取整个页的数据项进行测试
*/
- public void testQueryByPageID() throws FileException, IOException, PageException, PageCorruptedException {
+ public void testQueryByPageID() throws FileException, IOException, PageException, PageCorruptedException, LogException {
String fileName = PATH + "testQueryByPageID.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
@@ -178,35 +177,10 @@ public void testQueryByPageID() throws FileException, IOException, PageException
}
}
-
- static class Insert implements Runnable {
- IItemStorage iItemStorage;
- TransactionContext txContext;
-
- public Insert(IItemStorage iItemStorage, TransactionContext txContext) {
- this.iItemStorage = iItemStorage;
- this.txContext = txContext;
- }
-
- @Override
- public void run() {
- var bytes = new byte[]{1, 2, 3, 4};
- try {
- for (int i = 0; i < 100; i++) {
- long uuid = iItemStorage.insertItem(txContext, bytes);
- assertArrayEquals(bytes, iItemStorage.queryItemByUuid(uuid));
- }
- } catch (Exception e) {
- e.printStackTrace();
- fail("Exception caught");
- }
- }
- }
-
/**
* 测试并发下插入是否有问题
*/
- public void testSynInsert() throws IOException, FileException, PageException {
+ public void testSynInsert() throws IOException, FileException, PageException, LogException {
String fileName = PATH + "testInsert.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
@@ -217,11 +191,10 @@ public void testSynInsert() throws IOException, FileException, PageException {
new Thread(new Insert(iItemStorage, txContext)).start();
}
-
/**
* 对更新进行测试
*/
- public void testUpdate() throws FileException, IOException, PageException, UUIDException, PageCorruptedException {
+ public void testUpdate() throws FileException, IOException, PageException, UUIDException, PageCorruptedException, LogException {
String fileName = PATH + "testUpdate.db";
TransactionContext txContext = TransactionContext.empty();
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
@@ -248,7 +221,7 @@ public void testUpdate() throws FileException, IOException, PageException, UUIDE
/**
* 测试修改和获取表头信息
*/
- public void testMeta() throws FileException, IOException, PageException, UUIDException, PageCorruptedException {
+ public void testMeta() throws FileException, IOException, PageException, UUIDException, PageCorruptedException, LogException {
String fileName = PATH + "testMeta.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] result = new byte[]{1, 2, 3, 4};
@@ -258,4 +231,28 @@ public void testMeta() throws FileException, IOException, PageException, UUIDExc
assertArrayEquals(result, bs);
}
+ static class Insert implements Runnable {
+ IItemStorage iItemStorage;
+ TransactionContext txContext;
+
+ public Insert(IItemStorage iItemStorage, TransactionContext txContext) {
+ this.iItemStorage = iItemStorage;
+ this.txContext = txContext;
+ }
+
+ @Override
+ public void run() {
+ var bytes = new byte[]{1, 2, 3, 4};
+ try {
+ for (int i = 0; i < 100; i++) {
+ long uuid = iItemStorage.insertItem(txContext, bytes);
+ assertArrayEquals(bytes, iItemStorage.queryItemByUuid(uuid));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Exception caught");
+ }
+ }
+ }
+
}
diff --git a/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java b/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java
index 3197f88..9de183a 100644
--- a/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java
+++ b/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java
@@ -2,6 +2,7 @@
import junit.framework.TestCase;
import lombok.extern.slf4j.Slf4j;
+import net.kaaass.rumbase.FileUtil;
import net.kaaass.rumbase.dataitem.IItemStorage;
import net.kaaass.rumbase.dataitem.ItemManager;
import net.kaaass.rumbase.dataitem.exception.UUIDException;
@@ -9,26 +10,38 @@
import net.kaaass.rumbase.page.exception.PageException;
import net.kaaass.rumbase.recovery.exception.LogException;
import net.kaaass.rumbase.transaction.TransactionContext;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
-import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
-import static org.junit.Assert.assertArrayEquals;
-
/**
* 对日志进行保存和恢复
*/
@Slf4j
-public class IRecoveryTest extends TestCase {
+public class IRecoveryTest {
+
+ @BeforeClass
+ public static void createDataFolder() {
+ FileUtil.prepare();
+ }
+
+ @AfterClass
+ public static void clearDataFolder() {
+ FileUtil.clear();
+ }
+ public static final String PATH = FileUtil.TEST_PATH;
+
+ @Test
public void testInsert() throws PageException, LogException, FileException, IOException, UUIDException {
- new File("test_gen_files/testInsert.db").delete();
- new File("test_gen_files/testInsert.db.log").delete();
- String fileName = "test_gen_files/testInsert.db";
+ String fileName = PATH + "testInsert.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
var txContext = TransactionContext.empty();
@@ -37,58 +50,56 @@ public void testInsert() throws PageException, LogException, FileException, IOEx
var xid2 = 0;
List snaps = new ArrayList<>();
// 测试日志中存在,但是表中不存在进行恢复
- recoveryStorage.begin(xid,snaps);
+ recoveryStorage.begin(xid, snaps);
long a = 1;
long uuid = (a << 32) + Math.abs(new Random().nextInt());
- recoveryStorage.insert(xid,uuid,bytes);
+ recoveryStorage.insert(xid, uuid, bytes);
recoveryStorage.commit(xid);
// 测试日志中存在,且数据中也存在,会不会重复插入
- recoveryStorage.begin(xid2,snaps);
- iItemStorage.insertItem(txContext,bytes);
+ recoveryStorage.begin(xid2, snaps);
+ iItemStorage.insertItem(txContext, bytes);
recoveryStorage.commit(xid2);
recoveryStorage.recovery();
// 测试日志有额外的数据有没有被插入
var result = iItemStorage.queryItemByUuid(uuid);
- assertTrue(Arrays.equals(result,bytes));
+ Assert.assertTrue(Arrays.equals(result, bytes));
// 测试表中有的数据是否被重复插入
var list = iItemStorage.listItemByPageId(1);
- assertEquals(2,list.size());
+ Assert.assertEquals(2, list.size());
}
+ @Test
public void testInsertFail() throws PageException, LogException, FileException, IOException, UUIDException {
- new File("test_gen_files/testInsertFailed.db").delete();
- new File("test_gen_files/testInsertFailed.db.log").delete();
- String fileName = "test_gen_files/testInsertFailed.db";
+ String fileName = PATH + "testInsertFailed.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
var txContext = TransactionContext.empty();
var recoveryStorage = iItemStorage.getRecoveryStorage();
var xid = 0;
List snaps = new ArrayList<>();
- recoveryStorage.begin(xid,snaps);
- long uuid = iItemStorage.insertItem(txContext,bytes);
+ recoveryStorage.begin(xid, snaps);
+ long uuid = iItemStorage.insertItem(txContext, bytes);
recoveryStorage.rollback(xid);
recoveryStorage.recovery();
try {
var item = iItemStorage.queryItemByUuid(uuid);
- assertFalse(Arrays.equals(bytes,item));
- }catch (Exception e){
+ Assert.assertFalse(Arrays.equals(bytes, item));
+ } catch (Exception e) {
}
}
+ @Test
public void testUpdate() throws PageException, LogException, FileException, IOException, UUIDException {
- new File("test_gen_files/testUpdate.db").delete();
- new File("test_gen_files/testUpdate.db.log").delete();
- String fileName = "test_gen_files/testUpdate.db";
+ String fileName = PATH + "testUpdate.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
- byte[] bytesUpdate = new byte[]{2,3,4,5};
+ byte[] bytesUpdate = new byte[]{2, 3, 4, 5};
var txContext = TransactionContext.empty();
var recoveryStorage = iItemStorage.getRecoveryStorage();
@@ -96,96 +107,91 @@ public void testUpdate() throws PageException, LogException, FileException, IOEx
List snaps = new ArrayList<>();
// 测试在表中存在的redo
- recoveryStorage.begin(xid,snaps);
- long uuid = iItemStorage.insertItem(txContext,bytes);
- iItemStorage.updateItemByUuid(txContext,uuid,bytesUpdate);
+ recoveryStorage.begin(xid, snaps);
+ long uuid = iItemStorage.insertItem(txContext, bytes);
+ iItemStorage.updateItemByUuid(txContext, uuid, bytesUpdate);
recoveryStorage.commit(xid);
// 测试在表中不存在的redo
int xid2 = 1;
- recoveryStorage.begin(xid2,snaps);
+ recoveryStorage.begin(xid2, snaps);
long a = 1;
long uuid2 = (a << 32) + Math.abs(new Random().nextInt());
- recoveryStorage.insert(xid2,uuid2,bytes);
- recoveryStorage.update(xid2,uuid2,bytes,bytesUpdate);
+ recoveryStorage.insert(xid2, uuid2, bytes);
+ recoveryStorage.update(xid2, uuid2, bytes, bytesUpdate);
recoveryStorage.commit(xid2);
// 测试abort的事务
int xid3 = 2;
- recoveryStorage.begin(xid3,snaps);
+ recoveryStorage.begin(xid3, snaps);
long b = 1;
long uuid3 = (b << 32) + Math.abs(new Random().nextInt());
- recoveryStorage.insert(xid3,uuid3,bytes);
+ recoveryStorage.insert(xid3, uuid3, bytes);
recoveryStorage.commit(xid3);
int xid4 = 3;
- recoveryStorage.begin(xid4,snaps);
- recoveryStorage.update(xid4,uuid3,bytes,bytesUpdate);
+ recoveryStorage.begin(xid4, snaps);
+ recoveryStorage.update(xid4, uuid3, bytes, bytesUpdate);
recoveryStorage.rollback(xid4);
recoveryStorage.recovery();
- assertTrue(Arrays.equals(bytesUpdate,iItemStorage.queryItemByUuid(uuid)));
- assertTrue(Arrays.equals(bytesUpdate,iItemStorage.queryItemByUuid(uuid2)));
- assertTrue(Arrays.equals(bytes,iItemStorage.queryItemByUuid(uuid3)));
+ Assert.assertTrue(Arrays.equals(bytesUpdate, iItemStorage.queryItemByUuid(uuid)));
+ Assert.assertTrue(Arrays.equals(bytesUpdate, iItemStorage.queryItemByUuid(uuid2)));
+ Assert.assertTrue(Arrays.equals(bytes, iItemStorage.queryItemByUuid(uuid3)));
var list = iItemStorage.listItemByPageId(1);
- assertEquals(3,list.size());
+ Assert.assertEquals(3, list.size());
}
+ @Test
public void testUpdateMeta() throws PageException, LogException, FileException, IOException {
- new File("test_gen_files/testUpdateMeta.db").delete();
- new File("test_gen_files/testUpdateMeta.db.log").delete();
- String fileName = "test_gen_files/testUpdateMeta.db";
+ String fileName = PATH + "testUpdateMeta.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
- byte[] bytesUpdate = new byte[]{2,3,4,5};
+ byte[] bytesUpdate = new byte[]{2, 3, 4, 5};
var txContext = TransactionContext.empty();
var recoveryStorage = iItemStorage.getRecoveryStorage();
// 测试表中有
int xid = 0;
List snaps = new ArrayList<>();
- recoveryStorage.begin(xid,snaps);
- var uuid = iItemStorage.setMetadata(txContext,bytes);
+ recoveryStorage.begin(xid, snaps);
+ var uuid = iItemStorage.setMetadata(txContext, bytes);
recoveryStorage.commit(xid);
- assertTrue(Arrays.equals(bytes,iItemStorage.getMetadata()));
+ Assert.assertTrue(Arrays.equals(bytes, iItemStorage.getMetadata()));
// 测试表中没有头信息时更新
int xid2 = 1;
- recoveryStorage.begin(xid2,snaps);
- recoveryStorage.updateMeta(xid2,uuid,bytesUpdate);
+ recoveryStorage.begin(xid2, snaps);
+ recoveryStorage.updateMeta(xid2, uuid, bytesUpdate);
recoveryStorage.commit(xid2);
recoveryStorage.recovery();
- assertTrue(Arrays.equals(bytesUpdate,iItemStorage.getMetadata()));
+ Assert.assertTrue(Arrays.equals(bytesUpdate, iItemStorage.getMetadata()));
}
+ @Test
public void testUpdateMetaFail() throws PageException, LogException, FileException, IOException {
- new File("test_gen_files/testUpdateMetaFail.db").delete();
- new File("test_gen_files/testUpdateMetaFail.db.log").delete();
- String fileName = "test_gen_files/testUpdateMetaFail.db";
+ String fileName = PATH + "testUpdateMetaFail.db";
IItemStorage iItemStorage = ItemManager.fromFile(fileName);
byte[] bytes = new byte[]{1, 2, 3, 4};
- byte[] bytesUpdate = new byte[]{2,3,4,5};
+ byte[] bytesUpdate = new byte[]{2, 3, 4, 5};
var txContext = TransactionContext.empty();
var recoveryStorage = iItemStorage.getRecoveryStorage();
// 测试表中有
int xid = 0;
List snaps = new ArrayList<>();
- recoveryStorage.begin(xid,snaps);
- var uuid = iItemStorage.setMetadata(txContext,bytes);
+ recoveryStorage.begin(xid, snaps);
+ var uuid = iItemStorage.setMetadata(txContext, bytes);
recoveryStorage.commit(xid);
- assertTrue(Arrays.equals(bytes,iItemStorage.getMetadata()));
+ Assert.assertTrue(Arrays.equals(bytes, iItemStorage.getMetadata()));
// 测试事务失败
int xid2 = 1;
- recoveryStorage.begin(xid2,snaps);
- recoveryStorage.updateMeta(xid2,uuid,bytesUpdate);
+ recoveryStorage.begin(xid2, snaps);
+ recoveryStorage.updateMeta(xid2, uuid, bytesUpdate);
recoveryStorage.rollback(xid2);
recoveryStorage.recovery();
- assertTrue(Arrays.equals(bytes,iItemStorage.getMetadata()));
-
+ Assert.assertTrue(Arrays.equals(bytes, iItemStorage.getMetadata()));
}
-
-
}
diff --git a/testInsert.db b/testInsert.db
deleted file mode 100644
index ca5ea44f24f65b3d8acaaf654c430de8c51b16e2..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 40960
zcmeIu0Sy2E0K%a6Pi+o2h(KY$fB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM
z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*
z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd
t0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0Rsm92L_-300961
From f31d3a7df83dac262659189c67311c18a4e7c753 Mon Sep 17 00:00:00 2001
From: KAAAsS
Date: Sun, 17 Jan 2021 14:51:58 +0800
Subject: [PATCH 20/20] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E5=8F=AF=E5=8F=91?=
=?UTF-8?q?=E7=8E=B0=E7=9A=84=E7=B3=BB=E5=88=97=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../kaaass/rumbase/dataitem/ItemManager.java | 9 +-
.../kaaass/rumbase/page/RumPageStorage.java | 3 +-
.../rumbase/recovery/RecoveryManager.java | 13 +-
.../rumbase/recovery/RecoveryStorage.java | 132 ++++++++++--------
.../recovery/exception/LogException.java | 4 +
.../net/kaaass/rumbase/server/Server.java | 26 +++-
.../kaaass/rumbase/table/TableManager.java | 52 +++++--
.../transaction/TransactionContextImpl.java | 2 +
8 files changed, 155 insertions(+), 86 deletions(-)
diff --git a/src/main/java/net/kaaass/rumbase/dataitem/ItemManager.java b/src/main/java/net/kaaass/rumbase/dataitem/ItemManager.java
index 8c5148e..f86143d 100644
--- a/src/main/java/net/kaaass/rumbase/dataitem/ItemManager.java
+++ b/src/main/java/net/kaaass/rumbase/dataitem/ItemManager.java
@@ -7,7 +7,6 @@
import net.kaaass.rumbase.recovery.exception.LogException;
import net.kaaass.rumbase.transaction.TransactionContext;
-import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@@ -37,7 +36,7 @@ public static IItemStorage fromFile(String fileName) throws FileException, PageE
}
}
- public static IItemStorage fromFileWithoutLog(String fileName) throws FileException,PageException, PageCorruptedException {
+ public static IItemStorage fromFileWithoutLog(String fileName) throws FileException, PageException, PageCorruptedException {
if (maps.containsKey(fileName)) {
return maps.get(fileName);
} else {
@@ -69,10 +68,10 @@ public static IItemStorage createFile(TransactionContext txContext, String fileN
}
}
- public static IItemStorage createFileWithoutLog(String fileName, byte[] metadata) throws FileException, PageException {
- // 如果文件已经存在,那么就抛出文件已存在异常
+ public static IItemStorage createFileWithoutLog(String fileName, byte[] metadata) throws FileException, PageException {
+ // 如果文件已经存在,那就返回
if (maps.containsKey(fileName)) {
- throw new FileException(1);
+ return maps.get(fileName);
} else {
// 若文件不存在,则创建文件。
IItemStorage iItemStorage = ItemStorage.ofNewFileWithoutLog(fileName, metadata);
diff --git a/src/main/java/net/kaaass/rumbase/page/RumPageStorage.java b/src/main/java/net/kaaass/rumbase/page/RumPageStorage.java
index 1f20f82..1a827af 100644
--- a/src/main/java/net/kaaass/rumbase/page/RumPageStorage.java
+++ b/src/main/java/net/kaaass/rumbase/page/RumPageStorage.java
@@ -29,7 +29,8 @@ public Page get(long pageId) {
FileOutputStream out = new FileOutputStream(file);
out.write(new byte[PageManager.PAGE_SIZE * 10]);
} catch (IOException e) {
- e.printStackTrace();
+ log.error("创建文件失败", e);
+ System.exit(1);
}
}
//文件会预留5页作为文件头
diff --git a/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java b/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java
index ae3b0b0..509fff8 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java
@@ -1,5 +1,6 @@
package net.kaaass.rumbase.recovery;
+import lombok.extern.slf4j.Slf4j;
import net.kaaass.rumbase.page.exception.FileException;
import net.kaaass.rumbase.page.exception.PageException;
import net.kaaass.rumbase.recovery.exception.LogException;
@@ -9,9 +10,11 @@
/**
* 日志恢复的管理器,用来对每个数据库文件进行恢复
+ * FIXME 需要同时在所有文件记录事务的发生
*
* @author kaito
*/
+@Slf4j
public class RecoveryManager {
/**
* 对某个数据库文件进行恢复
@@ -20,8 +23,14 @@ public class RecoveryManager {
* @return 数据库日志管理器
*/
public static void recovery(String fileName) throws LogException {
-
- RecoveryStorage.ofFile(fileName).recovery();
+ IRecoveryStorage recoveryStorage;
+ try {
+ recoveryStorage = RecoveryStorage.ofFile(fileName);
+ } catch (LogException e) {
+ log.debug("恢复日志不存在,忽略该文件的恢复", e);
+ return;
+ }
+ recoveryStorage.recovery();
}
public static IRecoveryStorage getRecoveryStorage(String fileName) throws LogException {
diff --git a/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java b/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java
index d0c0f91..700a7e2 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/RecoveryStorage.java
@@ -3,10 +3,11 @@
import com.igormaznitsa.jbbp.JBBPParser;
import com.igormaznitsa.jbbp.io.JBBPOut;
import com.igormaznitsa.jbbp.mapper.Bin;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
import net.kaaass.rumbase.dataitem.IItemStorage;
import net.kaaass.rumbase.dataitem.ItemManager;
import net.kaaass.rumbase.dataitem.exception.UUIDException;
-import net.kaaass.rumbase.page.Page;
import net.kaaass.rumbase.page.exception.FileException;
import net.kaaass.rumbase.page.exception.PageException;
import net.kaaass.rumbase.recovery.exception.LogException;
@@ -18,11 +19,12 @@
import java.util.Map;
/**
- * 日志记录相关内容
+ * 日志记录相关内容
*
* @author kaito
*/
-public class RecoveryStorage implements IRecoveryStorage {
+@Slf4j
+public class RecoveryStorage implements IRecoveryStorage {
/**
@@ -34,37 +36,39 @@ public class RecoveryStorage implements IRecoveryStorage {
*/
private String fileName;
- public RecoveryStorage(IItemStorage itemStorage,String fileName) {
+ public RecoveryStorage(IItemStorage itemStorage, String fileName) {
this.logStorage = itemStorage;
this.fileName = fileName;
}
/**
* 读取日志文件并且解析得到日志管理器
+ *
* @param fileName
* @return 日志管理器
*/
public static IRecoveryStorage ofFile(String fileName) throws LogException {
try {
var itemStorage = ItemManager.fromFileWithoutLog(fileName + ".log");
- return new RecoveryStorage(itemStorage,fileName);
- }catch (FileException | PageException e){
+ return new RecoveryStorage(itemStorage, fileName);
+ } catch (FileException | PageException e) {
throw new LogException(10);
}
}
/**
* 创建日志文件
+ *
* @param fileName 文件名
* @return
*/
public static IRecoveryStorage ofNewFile(String fileName) throws LogException {
try {
var metadata = JBBPOut.BeginBin().Int(HEADER).End().toByteArray();
- var itemStorage = ItemManager.createFileWithoutLog(fileName + ".log",metadata);
- return new RecoveryStorage(itemStorage,fileName);
- }catch (IOException | FileException | PageException e) {
- throw new LogException(9);
+ var itemStorage = ItemManager.createFileWithoutLog(fileName + ".log", metadata);
+ return new RecoveryStorage(itemStorage, fileName);
+ } catch (IOException | FileException | PageException e) {
+ throw new LogException(9, e);
}
}
@@ -75,13 +79,13 @@ public void begin(int xid, List snapshots) throws LogException {
Byte(TX_BEGIN).
Int(xid).
Int(snapshots.size());
- for ( var i : snapshots){
+ for (var i : snapshots) {
jbbp = jbbp.Int(i);
}
var bytes = jbbp.End().toByteArray();
var uuid = logStorage.insertItemWithoutLog(bytes);
logStorage.flush(uuid);
- } catch (IOException | FileException e) {
+ } catch (IOException | FileException e) {
throw new LogException(3);
}
}
@@ -95,7 +99,7 @@ public void rollback(int xid) throws LogException {
End().toByteArray();
var uuid = logStorage.insertItemWithoutLog(bytes);
logStorage.flush(uuid);
- }catch (FileException | IOException e){
+ } catch (FileException | IOException e) {
throw new LogException(4);
}
}
@@ -109,7 +113,7 @@ public void commit(int xid) throws LogException {
End().toByteArray();
var uuid = logStorage.insertItemWithoutLog(bytes);
logStorage.flush(uuid);
- }catch (FileException | IOException e){
+ } catch (FileException | IOException e) {
throw new LogException(5);
}
@@ -127,14 +131,14 @@ public void insert(int xid, long uuid, byte[] item) throws LogException {
End().toByteArray();
var id = logStorage.insertItemWithoutLog(bytes);
logStorage.flush(id);
- }catch (FileException | IOException e){
+ } catch (FileException | IOException e) {
throw new LogException(6);
}
}
@Override
public void update(int xid, long uuid, byte[] itemBefore, byte[] itemAfter) throws LogException {
- try{
+ try {
var bytes = JBBPOut.BeginBin().
Byte(UPDATE_FLAG).
Int(xid).
@@ -146,15 +150,15 @@ public void update(int xid, long uuid, byte[] itemBefore, byte[] itemAfter) thro
End().toByteArray();
var id = logStorage.insertItemWithoutLog(bytes);
logStorage.flush(id);
- }catch (FileException | IOException e){
+ } catch (FileException | IOException e) {
throw new LogException(7);
}
}
@Override
- public void updateMeta(int xid, long beforeUuid,byte[] metadata) throws LogException {
+ public void updateMeta(int xid, long beforeUuid, byte[] metadata) throws LogException {
try {
- var bytes =JBBPOut.BeginBin().
+ var bytes = JBBPOut.BeginBin().
Byte(METADATA_UPDATE_FLAG).
Int(xid).
Long(beforeUuid).
@@ -163,7 +167,7 @@ public void updateMeta(int xid, long beforeUuid,byte[] metadata) throws LogExcep
End().toByteArray();
var uuid = logStorage.insertItemWithoutLog(bytes);
logStorage.flush(uuid);
- }catch (FileException | IOException e){
+ } catch (FileException | IOException e) {
throw new LogException(8);
}
@@ -173,10 +177,10 @@ public void updateMeta(int xid, long beforeUuid,byte[] metadata) throws LogExcep
public List getContent() {
List logList = new ArrayList<>();
var maxPageId = logStorage.getMaxPageId();
- for (int i = 1;i <= maxPageId ; i ++){
+ for (int i = 1; i <= maxPageId; i++) {
var logs = logStorage.listItemByPageId(i);
- for(var l : logs){
- if (l.length > 4){
+ for (var l : logs) {
+ if (l.length > 4) {
logList.add(l);
}
}
@@ -185,15 +189,19 @@ public List getContent() {
}
@Override
- public void recovery() throws LogException{
+ public void recovery() throws LogException {
try {
var itemStorage = ItemManager.fromFile(this.fileName);
+ // TODO 判断是否进行恢复
+ log.info("开始恢复文件 {}...", this.fileName);
var logs = getContent();
var xidMaps = parseXid(logs);
- for (var log : logs){
- parseLog(log,itemStorage,xidMaps);
+ log.debug("文件 {} 回滚事务:{}", this.fileName, xidMaps);
+ // 逐条回滚
+ for (var log : logs) {
+ parseLog(log, itemStorage, xidMaps);
}
- }catch (FileException | PageException e){
+ } catch (FileException | PageException e) {
throw new LogException(11);
}
}
@@ -201,18 +209,18 @@ public void recovery() throws LogException{
/**
* 先进行一遍解析,得到所有已完成的事务和未完成的事务,来决定redo还是undo
*/
- private Map> parseXid(List logs) throws LogException {
- List commitXids = new ArrayList<>();
+ private Map> parseXid(List logs) throws LogException {
+ List commitXids = List.of(0);
List abortXids = new ArrayList<>();
- for (var log : logs){
- Tx tx = null;
+ for (var binLog : logs) {
+ Tx tx;
try {
- tx = parseTx(log);
+ tx = parseTx(binLog);
} catch (IOException e) {
throw new LogException(1);
}
- switch (tx.type){
+ switch (tx.type) {
case TX_COMMIT:
// 若是commit 则放入commitXid并将对应的xid移出abort
Integer id = tx.xid;
@@ -229,9 +237,9 @@ private Map> parseXid(List logs) throws LogExcep
}
}
- Map> maps = new HashMap<>();
- maps.put('C',commitXids);
- maps.put('A',abortXids);
+ Map> maps = new HashMap<>();
+ maps.put('C', commitXids);
+ maps.put('A', abortXids);
return maps;
}
@@ -248,7 +256,7 @@ private Tx parseTx(byte[] log) throws IOException {
*/
private byte parseType(byte[] log) throws IOException {
var type = JBBPParser.prepare("byte type;").parse(log).mapTo(new Type()).type;
- return type ;
+ return type;
}
/**
@@ -272,16 +280,16 @@ private UpdateLog parseUpdate(byte[] log) throws IOException {
private UpdateMetaLog parseUpdateMeta(byte[] log) throws IOException {
var updateMeta = JBBPParser.prepare("byte type;int xid;long beforeUuid;" +
"int length;byte[length] metadata;").
- parse(log).mapTo(new UpdateMetaLog());
+ parse(log).mapTo(new UpdateMetaLog());
return updateMeta;
}
- private boolean checkCommit(int xid,Map> maps) throws LogException {
- if (maps.get('C').contains(xid)){
+ private boolean checkCommit(int xid, Map> maps) throws LogException {
+ if (maps.get('C').contains(xid)) {
return true;
- }else if (maps.get('A').contains(xid)){
+ } else if (maps.get('A').contains(xid)) {
return false;
- }else {
+ } else {
throw new LogException(2);
}
}
@@ -289,14 +297,14 @@ private boolean checkCommit(int xid,Map> maps) throws Lo
private void parseLog(byte[] log, IItemStorage itemStorage, Map> xidMaps) throws LogException {
try {
var type = parseType(log);
- switch (type){
+ switch (type) {
case INSERT_FLAG:
System.out.println("正在解析插入");
var insertLog = parseInsert(log);
- if (checkCommit(insertLog.xid,xidMaps)){
+ if (checkCommit(insertLog.xid, xidMaps)) {
// 如果事务已经提交,则redo
- itemStorage.insertItemWithUuid(insertLog.item,insertLog.uuid);
- }else {
+ itemStorage.insertItemWithUuid(insertLog.item, insertLog.uuid);
+ } else {
// 如果事务没有提交,则undo
itemStorage.deleteUuid(insertLog.uuid);
}
@@ -304,17 +312,17 @@ private void parseLog(byte[] log, IItemStorage itemStorage, Map klazz) {
return klazz == InsertLog.class ? new InsertLog() : null;
}
@@ -388,7 +398,7 @@ public Object newInstance(Class> klazz) {
/**
* 更新的解析
*/
- public static class UpdateLog{
+ public static class UpdateLog {
@Bin
byte type;
@Bin
@@ -403,12 +413,13 @@ public static class UpdateLog{
int length2;
@Bin
byte[] itemAfter;
+
public Object newInstance(Class> klazz) {
return klazz == UpdateLog.class ? new UpdateLog() : null;
}
}
- public static class UpdateMetaLog{
+ public static class UpdateMetaLog {
@Bin
byte type;
@Bin
@@ -419,6 +430,7 @@ public static class UpdateMetaLog{
int length;
@Bin
byte[] metadata;
+
public Object newInstance(Class> klazz) {
return klazz == UpdateMetaLog.class ? new UpdateMetaLog() : null;
}
@@ -442,6 +454,4 @@ public Object newInstance(Class> klazz) {
final private static byte METADATA_UPDATE_FLAG = 'm';
-
-
}
diff --git a/src/main/java/net/kaaass/rumbase/recovery/exception/LogException.java b/src/main/java/net/kaaass/rumbase/recovery/exception/LogException.java
index 6b6ae8a..bc44422 100644
--- a/src/main/java/net/kaaass/rumbase/recovery/exception/LogException.java
+++ b/src/main/java/net/kaaass/rumbase/recovery/exception/LogException.java
@@ -28,4 +28,8 @@ public class LogException extends RumbaseException {
public LogException(int subId) {
super(3001,subId,REASONS.get(subId));
}
+
+ public LogException(int subId, Throwable e) {
+ super(3001,subId,REASONS.get(subId), e);
+ }
}
diff --git a/src/main/java/net/kaaass/rumbase/server/Server.java b/src/main/java/net/kaaass/rumbase/server/Server.java
index d3783d9..ba6a9ee 100644
--- a/src/main/java/net/kaaass/rumbase/server/Server.java
+++ b/src/main/java/net/kaaass/rumbase/server/Server.java
@@ -8,6 +8,8 @@
import net.kaaass.rumbase.page.exception.FileException;
import net.kaaass.rumbase.query.exception.ArgumentException;
import net.kaaass.rumbase.record.exception.RecordNotFoundException;
+import net.kaaass.rumbase.recovery.RecoveryManager;
+import net.kaaass.rumbase.recovery.exception.LogException;
import net.kaaass.rumbase.table.TableManager;
import net.kaaass.rumbase.table.exception.TableConflictException;
import net.kaaass.rumbase.table.exception.TableExistenceException;
@@ -51,10 +53,14 @@ public class Server {
*/
public void prepare() {
// 准备文件夹
- var tableFolder = new File("data/table/a");
- assert tableFolder.exists() || tableFolder.mkdirs();
- var indexFolder = new File("data/index/a");
- assert indexFolder.exists() || indexFolder.mkdirs();
+ var tableFolder = new File("data/table/");
+ if (!tableFolder.exists()) {
+ tableFolder.mkdirs();
+ }
+ var indexFolder = new File("data/index/");
+ if (!indexFolder.exists()) {
+ indexFolder.mkdirs();
+ }
// 初始化事务管理器
log.info("初始化事务管理器...");
try {
@@ -63,15 +69,23 @@ public void prepare() {
log.error("初始化事务管理器失败", e);
System.exit(1);
}
+ // 恢复表管理器
+ try {
+ RecoveryManager.recovery("data/metadata.db");
+ } catch (LogException e) {
+ log.error("无法恢复表管理器,数据可能损坏!", e);
+ System.exit(1);
+ }
// 初始化表管理器
log.info("初始化表管理器...");
- // TODO 先恢复metadata
try {
tableManager = new TableManager();
- } catch (TableExistenceException | TableConflictException | RecordNotFoundException | ArgumentException | IndexAlreadyExistException e) {
+ } catch (IndexAlreadyExistException e) {
log.error("初始化表管理器失败", e);
System.exit(1);
}
+ // 恢复、载入其他表
+ tableManager.prepare();
// 初始化线程池
log.info("初始化线程池...");
var namedThreadFactory = Executors.defaultThreadFactory();
diff --git a/src/main/java/net/kaaass/rumbase/table/TableManager.java b/src/main/java/net/kaaass/rumbase/table/TableManager.java
index ecb925a..b4ff1c8 100644
--- a/src/main/java/net/kaaass/rumbase/table/TableManager.java
+++ b/src/main/java/net/kaaass/rumbase/table/TableManager.java
@@ -1,11 +1,14 @@
package net.kaaass.rumbase.table;
import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
import net.kaaass.rumbase.index.exception.IndexAlreadyExistException;
import net.kaaass.rumbase.query.exception.ArgumentException;
import net.kaaass.rumbase.record.IRecordStorage;
import net.kaaass.rumbase.record.RecordManager;
import net.kaaass.rumbase.record.exception.RecordNotFoundException;
+import net.kaaass.rumbase.recovery.RecoveryManager;
+import net.kaaass.rumbase.recovery.exception.LogException;
import net.kaaass.rumbase.table.exception.TableConflictException;
import net.kaaass.rumbase.table.field.BaseField;
import net.kaaass.rumbase.table.exception.TableExistenceException;
@@ -25,7 +28,7 @@
*
* @author @KveinAxel
*/
-
+@Slf4j
public class TableManager {
static {
@@ -68,11 +71,11 @@ public void abort(TransactionContext context) {
context.rollback();
}
- public TableManager() throws TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException, IndexAlreadyExistException {
+ public TableManager() throws IndexAlreadyExistException {
load();
}
- public void load() throws TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException, IndexAlreadyExistException {
+ public void load() throws IndexAlreadyExistException {
var context = TransactionContext.empty();
Table metaTable;
try {
@@ -102,29 +105,56 @@ public void load() throws TableExistenceException, TableConflictException, Recor
metaTable.persist(context);
tableCache.put("metadata", metaTable);
}
- var data = metaTable.readAll(context);
+ }
+
+ /**
+ * 启动服务器前进行的准备
+ */
+ public void prepare() {
+ var context = TransactionContext.empty();
+ var metaTable = tableCache.get("metadata");
+ List> data = null;
+ try {
+ data = metaTable.readAll(context);
+ } catch (TableExistenceException | TableConflictException | ArgumentException | RecordNotFoundException e) {
+ log.error("无法读入元数据表,数据可能损坏!", e);
+ System.exit(1);
+ }
+ // 载入所有已有表
var map = new HashMap();
data.forEach(row -> map.put((String) row.get(0), (String) row.get(1)));
if (!map.containsKey("table_num")) {
- metaTable.insert(context, new ArrayList<>(){{
- add("'table_num'");
- add("'0'");
- }});
+ try {
+ metaTable.insert(context, new ArrayList<>(){{
+ add("'table_num'");
+ add("'0'");
+ }});
+ } catch (TableConflictException | TableExistenceException | ArgumentException e) {
+ log.error("无法初始化元数据表", e);
+ System.exit(1);
+ }
map.put("table_num", "0");
}
for (var item: map.entrySet()) {
if (item.getKey().startsWith("tablePath$")) {
var tableName = item.getKey().split("\\$")[1];
+ var tablePath = item.getValue();
+ // 恢复表
+ try {
+ RecoveryManager.recovery(tablePath);
+ } catch (LogException e) {
+ log.error("无法恢复表 {} 于 {},数据可能损坏!", tableName, tablePath, e);
+ System.exit(1);
+ }
+ // 读入表
var record = RecordManager.fromFile(item.getValue());
- recordPaths.add(item.getValue());
+ recordPaths.add(tablePath);
var table = Table.load(record);
tableCache.put(tableName, table);
}
}
-
-
}
/**
diff --git a/src/main/java/net/kaaass/rumbase/transaction/TransactionContextImpl.java b/src/main/java/net/kaaass/rumbase/transaction/TransactionContextImpl.java
index bb803bd..6a0f04e 100644
--- a/src/main/java/net/kaaass/rumbase/transaction/TransactionContextImpl.java
+++ b/src/main/java/net/kaaass/rumbase/transaction/TransactionContextImpl.java
@@ -2,6 +2,8 @@
import lombok.Getter;
import lombok.Setter;
+import net.kaaass.rumbase.recovery.RecoveryManager;
+import net.kaaass.rumbase.recovery.RecoveryStorage;
import net.kaaass.rumbase.transaction.exception.DeadlockException;
import net.kaaass.rumbase.transaction.lock.LockTable;
import net.kaaass.rumbase.transaction.lock.LockTableImpl;