From 20d80390ba99287806c0a80b0e814bf3755b9155 Mon Sep 17 00:00:00 2001 From: KAAAsS Date: Sun, 17 Jan 2021 13:31:24 +0800 Subject: [PATCH] =?UTF-8?q?[+]=E5=AE=9E=E7=8E=B0=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=99=A8=E6=A8=A1=E5=9D=97=20(#19)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 将接口、mock改成普通类 * 将接口、mock改成普通类 * 使用访问者模式替代原先的switch匹配 * 去除visitor, 重构表管理 * 去除visitor, 重构表管理 * 重写jbbp解析方法,增加测试 * 增加表配置信息操作 * 增加表加载测试 * 增加系统表和测试 * 完成Select语句的语法树定义 * 完成Insert语句的语法树定义 * 完成Update语句的语法树定义 * 完成Delete语句的语法树定义 * 完成Create table语句的语法树定义 * 完成Create index语句的语法树定义 * 格式化代码 * 增加空字段,增加field的方法 * 增加query模块 * 更新测试用例的序列化格式 * 修复空值Condition * 增加创建索引测试 * 更改测试文件路径 * 完成服务器程序基本框架 * 字符串解析增加单引号 * 完成echo服务器 * 增加增删改、创建表的执行测试 * 更改测试路径 * 实现访问者模式处理sql语句 * 改进select语句解析 * 完善语句解析的返回值,使用泛型 * 完成语句执行逻辑 * 增加select测试 * 修复delete测试 * 实现指令解析,完成当前所有指令运行的测试 * 将mock换为RecordManager * 完成自动提交 * 完成todo/fixme * 增加获取所有文件路径的api * 修正测试文件路径 * 增加field加载时的索引重建 * 修复未抛出的异常 * 修正执行的系列错误 * 修正自动提交事务上下文更改的问题 * 修正ci重复进行测试 * 修复投影获得空列表的bug * 修复列未空的插入请求 * 修正select输出格式 * 修复metadata写入bug * unpin遗漏 * 增加CreateIndex时的表结构序列化 * 修复物理记录查找问题 * 修复错误@NonNull的问题 * 更新dummy * 修正一系列select解析问题 * 修正between计算问题 * 增加插入列检查 * record提供路径名 * 更改文件目录 * 创建数据文件夹 * 增加flush、exec语句 * 修正null值错误处理 * 通过记录来保存数据字典 * flush错误处理 * 修正系列问题,增加recordapi * 修正测试用例编译 * 修复metadata加载问题 * 修复metadata加载问题 * 修正一处forEach * 修复列persist标志位 * metadata加载的空指针问题 * 修改测试用例 * 修正若干错误测试用例 * 修正表模块单元测试路径 * 统一单元测试文件路径 Co-authored-by: Kevin Axel Manjaro --- .travis.yml | 1 - src/main/java/net/kaaass/rumbase/Main.java | 14 +- .../kaaass/rumbase/dataitem/ItemStorage.java | 39 +- .../java/net/kaaass/rumbase/page/RumPage.java | 2 + .../rumbase/parse/ConditionExpression.java | 11 +- .../kaaass/rumbase/parse/ISqlStatement.java | 2 + .../rumbase/parse/ISqlStatementVisitor.java | 37 ++ .../net/kaaass/rumbase/parse/SqlParser.java | 27 +- .../parse/exception/SqlSyntaxException.java | 6 + .../parse/parser/CommandStatementParser.java | 47 ++ .../parser/command/ExecStatementParser.java | 22 + .../CreateIndexStatementParser.java | 3 +- .../CreateTableStatementParser.java | 9 +- .../{ => jsqlp}/DeleteStatementParser.java | 3 +- .../{ => jsqlp}/InsertStatementParser.java | 4 +- .../parse/parser/{ => jsqlp}/ParserUtil.java | 2 +- .../{ => jsqlp}/SelectStatementParser.java | 64 ++- .../{ => jsqlp}/UpdateStatementParser.java | 3 +- .../rumbase/parse/stmt/CommitStatement.java | 16 + .../parse/stmt/CreateIndexStatement.java | 6 + .../parse/stmt/CreateTableStatement.java | 6 + .../rumbase/parse/stmt/DeleteStatement.java | 6 + .../rumbase/parse/stmt/ExecStatement.java | 23 + .../rumbase/parse/stmt/ExitStatement.java | 16 + .../rumbase/parse/stmt/FlushStatement.java | 16 + .../rumbase/parse/stmt/InsertStatement.java | 6 + .../rumbase/parse/stmt/RollbackStatement.java | 16 + .../rumbase/parse/stmt/SelectStatement.java | 6 + .../rumbase/parse/stmt/ShutdownStatement.java | 16 + .../parse/stmt/StartTransactionStatement.java | 16 + .../rumbase/parse/stmt/UpdateStatement.java | 6 + .../rumbase/query/CreateIndexExecutor.java | 5 + .../rumbase/query/CreateTableExecutor.java | 13 +- .../kaaass/rumbase/query/InsertExecutor.java | 17 +- .../kaaass/rumbase/query/SelectExecutor.java | 2 +- .../kaaass/rumbase/record/IRecordStorage.java | 2 + .../rumbase/record/MvccRecordStorage.java | 2 + .../kaaass/rumbase/record/RecordManager.java | 8 + .../record/mock/MockRecordStorage.java | 5 + .../net/kaaass/rumbase/server/Server.java | 139 +++++ .../net/kaaass/rumbase/server/Session.java | 477 ++++++++++++++++++ .../java/net/kaaass/rumbase/table/Table.java | 24 +- .../kaaass/rumbase/table/TableManager.java | 142 ++++-- .../kaaass/rumbase/table/field/BaseField.java | 55 +- .../rumbase/table/field/FloatField.java | 11 +- .../kaaass/rumbase/table/field/IntField.java | 11 +- .../rumbase/table/field/VarcharField.java | 12 +- .../transaction/TransactionManagerImpl.java | 2 +- .../java/net/kaaass/rumbase/FileUtil.java | 55 ++ .../rumbase/dataitem/IItemStorageTest.java | 29 +- .../net/kaaass/rumbase/index/BTreeTest.java | 59 ++- .../rumbase/index/ConcurrentIndexTest.java | 25 +- .../net/kaaass/rumbase/index/IndexTest.java | 39 +- .../kaaass/rumbase/page/PageStorageTest.java | 25 +- .../net/kaaass/rumbase/page/PageTest.java | 23 +- .../query/CreateIndexExecutorTest.java | 82 +-- .../query/CreateTableExecutorTest.java | 53 +- .../rumbase/query/DeleteExecutorTest.java | 110 ++-- .../rumbase/query/InsertExecutorTest.java | 65 +-- .../rumbase/query/SelectExecutorTest.java | 144 +++--- .../rumbase/query/UpdateExecutorTest.java | 160 +++--- .../rumbase/record/IRecordStorageTest.java | 32 +- .../rumbase/record/MvccReadCommitTest.java | 93 ++-- .../record/MvccReadRepeatableTest.java | 107 ++-- .../kaaass/rumbase/table/BaseFieldTest.java | 216 ++++---- .../rumbase/table/TableManagerTest.java | 98 ++-- .../net/kaaass/rumbase/table/TableTest.java | 253 ++++++---- .../transaction/TransactionContextTest.java | 38 +- 68 files changed, 2218 insertions(+), 866 deletions(-) create mode 100644 src/main/java/net/kaaass/rumbase/parse/ISqlStatementVisitor.java create mode 100644 src/main/java/net/kaaass/rumbase/parse/parser/CommandStatementParser.java create mode 100644 src/main/java/net/kaaass/rumbase/parse/parser/command/ExecStatementParser.java rename src/main/java/net/kaaass/rumbase/parse/parser/{ => jsqlp}/CreateIndexStatementParser.java (91%) rename src/main/java/net/kaaass/rumbase/parse/parser/{ => jsqlp}/CreateTableStatementParser.java (82%) rename src/main/java/net/kaaass/rumbase/parse/parser/{ => jsqlp}/DeleteStatementParser.java (89%) rename src/main/java/net/kaaass/rumbase/parse/parser/{ => jsqlp}/InsertStatementParser.java (90%) rename src/main/java/net/kaaass/rumbase/parse/parser/{ => jsqlp}/ParserUtil.java (96%) rename src/main/java/net/kaaass/rumbase/parse/parser/{ => jsqlp}/SelectStatementParser.java (59%) rename src/main/java/net/kaaass/rumbase/parse/parser/{ => jsqlp}/UpdateStatementParser.java (93%) create mode 100644 src/main/java/net/kaaass/rumbase/parse/stmt/CommitStatement.java create mode 100644 src/main/java/net/kaaass/rumbase/parse/stmt/ExecStatement.java create mode 100644 src/main/java/net/kaaass/rumbase/parse/stmt/ExitStatement.java create mode 100644 src/main/java/net/kaaass/rumbase/parse/stmt/FlushStatement.java create mode 100644 src/main/java/net/kaaass/rumbase/parse/stmt/RollbackStatement.java create mode 100644 src/main/java/net/kaaass/rumbase/parse/stmt/ShutdownStatement.java create mode 100644 src/main/java/net/kaaass/rumbase/parse/stmt/StartTransactionStatement.java create mode 100644 src/main/java/net/kaaass/rumbase/server/Server.java create mode 100644 src/main/java/net/kaaass/rumbase/server/Session.java create mode 100644 src/test/java/net/kaaass/rumbase/FileUtil.java diff --git a/.travis.yml b/.travis.yml index 115da55..336a154 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,5 +4,4 @@ dist: trusty group: edge script: - - ./gradlew check - ./gradlew build --scan -s diff --git a/src/main/java/net/kaaass/rumbase/Main.java b/src/main/java/net/kaaass/rumbase/Main.java index 69e9221..25d9bc6 100644 --- a/src/main/java/net/kaaass/rumbase/Main.java +++ b/src/main/java/net/kaaass/rumbase/Main.java @@ -1,6 +1,7 @@ package net.kaaass.rumbase; import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.server.Server; /** * 入口类 @@ -11,6 +12,17 @@ public class Main { public static void main(String[] args) { - log.debug("Rumbase"); + log.info("Rumbase DBMS"); + // 启动 + log.info("Start preparing..."); + Server.getInstance().prepare(); + // 注册程序退出事件 + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + log.info("Shutdown..."); + Server.getInstance().shutdown(); + }, "Shutdown-thread")); + // 运行 + log.info("Starting server..."); + Server.getInstance().run(); } } diff --git a/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java index 7cb3217..7e054bb 100644 --- a/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java +++ b/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java @@ -98,27 +98,28 @@ public static IItemStorage ofFile(String fileName) throws FileException, PageExc var pageStorage = PageManager.fromFile(fileName); var header = pageStorage.get(0); header.pin(); - if (checkTableHeader(header)) { - // 如果表头标志存在,就解析对应表头信息 - var h = parseHeader(header); - header.unpin(); - return new ItemStorage(fileName, h.tempFreePage, h.headerUuid, pageStorage); - } 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); + try { + if (checkTableHeader(header)) { + // 如果表头标志存在,就解析对应表头信息 + var h = parseHeader(header); + return new ItemStorage(fileName, h.tempFreePage, h.headerUuid, pageStorage); + } else { + // 若表头标志不存在,就初始化对应的表信息。 + // 只初始化headerFlag和tempFreePage,表头信息位置统一由setMetadata来实现 + byte[] bytes; + try { + bytes = JBBPOut.BeginBin(). + Byte(1, 2, 3, 4). + Int(1). + End().toByteArray(); + } catch (IOException e) { + throw new PageCorruptedException(1, e); + } + header.patchData(0, bytes); + return new ItemStorage(fileName, 1, 0, pageStorage); } - header.patchData(0, bytes); + } finally { header.unpin(); - return new ItemStorage(fileName, 1, 0, pageStorage); } } diff --git a/src/main/java/net/kaaass/rumbase/page/RumPage.java b/src/main/java/net/kaaass/rumbase/page/RumPage.java index f7bc3f7..ffa25a6 100644 --- a/src/main/java/net/kaaass/rumbase/page/RumPage.java +++ b/src/main/java/net/kaaass/rumbase/page/RumPage.java @@ -76,6 +76,8 @@ public void flush() throws FileException { throw new FileException(2); } out.close(); + } catch (FileException e) { + throw e; } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/net/kaaass/rumbase/parse/ConditionExpression.java b/src/main/java/net/kaaass/rumbase/parse/ConditionExpression.java index 60ea8a4..5aa10b7 100644 --- a/src/main/java/net/kaaass/rumbase/parse/ConditionExpression.java +++ b/src/main/java/net/kaaass/rumbase/parse/ConditionExpression.java @@ -3,7 +3,7 @@ import lombok.NonNull; import lombok.RequiredArgsConstructor; import net.kaaass.rumbase.parse.exception.EvaluationException; -import net.kaaass.rumbase.parse.parser.ParserUtil; +import net.kaaass.rumbase.parse.parser.jsqlp.ParserUtil; import net.sf.jsqlparser.expression.*; import net.sf.jsqlparser.expression.operators.arithmetic.*; import net.sf.jsqlparser.expression.operators.conditional.AndExpression; @@ -24,7 +24,6 @@ public class ConditionExpression { public static double PRECISION = 0.00001; - @NonNull private final Expression expression; @NonNull @@ -38,6 +37,9 @@ public class ConditionExpression { * @param paramMap 参数列表,其中参数必须是原生类型的装箱对象,如Integer、String */ public boolean evaluate(Map paramMap) { + if (expression == null) { + return true; + } updateParam(); var parser = new DeParser(paramMap); expression.accept(parser); @@ -58,6 +60,9 @@ public boolean evaluate(Map paramMap) { * 获得表达式求值需要的参数 */ public List getParams() { + if (expression == null) { + return List.of(); + } updateParam(); return List.copyOf(paramColumn.values()); } @@ -205,7 +210,7 @@ public void visit(Between between) { var b = stack.pop(); var a = stack.pop(); Comparator cmp = Comparator.naturalOrder(); - stack.push(cmp.compare(a, b) <= 0 && cmp.compare(b, c) < 0); + stack.push(cmp.compare(b, a) <= 0 && cmp.compare(a, c) < 0); } @Override diff --git a/src/main/java/net/kaaass/rumbase/parse/ISqlStatement.java b/src/main/java/net/kaaass/rumbase/parse/ISqlStatement.java index 90236c0..5d58b37 100644 --- a/src/main/java/net/kaaass/rumbase/parse/ISqlStatement.java +++ b/src/main/java/net/kaaass/rumbase/parse/ISqlStatement.java @@ -6,4 +6,6 @@ * @author kaaass */ public interface ISqlStatement { + + T accept(ISqlStatementVisitor visitor); } diff --git a/src/main/java/net/kaaass/rumbase/parse/ISqlStatementVisitor.java b/src/main/java/net/kaaass/rumbase/parse/ISqlStatementVisitor.java new file mode 100644 index 0000000..833849f --- /dev/null +++ b/src/main/java/net/kaaass/rumbase/parse/ISqlStatementVisitor.java @@ -0,0 +1,37 @@ +package net.kaaass.rumbase.parse; + +import net.kaaass.rumbase.parse.stmt.*; + +/** + * SQL语句访问者,用于处理对应SQL语句 + * + * @author kaaass + */ +public interface ISqlStatementVisitor { + + T visit(SelectStatement statement); + + T visit(InsertStatement statement); + + T visit(UpdateStatement statement); + + T visit(DeleteStatement statement); + + T visit(CreateIndexStatement statement); + + T visit(CreateTableStatement statement); + + T visit(StartTransactionStatement statement); + + T visit(CommitStatement statement); + + T visit(RollbackStatement statement); + + T visit(ExitStatement statement); + + T visit(ShutdownStatement statement); + + T visit(FlushStatement statement); + + T visit(ExecStatement statement); +} diff --git a/src/main/java/net/kaaass/rumbase/parse/SqlParser.java b/src/main/java/net/kaaass/rumbase/parse/SqlParser.java index 2e6417e..62e803e 100644 --- a/src/main/java/net/kaaass/rumbase/parse/SqlParser.java +++ b/src/main/java/net/kaaass/rumbase/parse/SqlParser.java @@ -1,7 +1,11 @@ package net.kaaass.rumbase.parse; import net.kaaass.rumbase.parse.exception.SqlSyntaxException; -import net.kaaass.rumbase.parse.parser.*; +import net.kaaass.rumbase.parse.parser.CommandStatementParser; +import net.kaaass.rumbase.parse.parser.JsqlpStatementParser; +import net.kaaass.rumbase.parse.parser.command.ExecStatementParser; +import net.kaaass.rumbase.parse.parser.jsqlp.*; +import net.kaaass.rumbase.parse.stmt.*; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.statement.Statement; @@ -16,7 +20,17 @@ */ public class SqlParser { - private static List jsqlpStatementParsers = new ArrayList<>() {{ + private static final List> STRING_STATEMENT_PARSERS = new ArrayList<>() {{ + add(new CommandStatementParser(StartTransactionStatement.class, "start transaction")); + add(new CommandStatementParser(CommitStatement.class, "commit")); + add(new CommandStatementParser(RollbackStatement.class, "rollback")); + add(new CommandStatementParser(ExitStatement.class, "exit")); + add(new CommandStatementParser(ShutdownStatement.class, "shutdown")); + add(new CommandStatementParser(FlushStatement.class, "flush")); + add(new ExecStatementParser()); + }}; + + private static final List JSQLP_STATEMENT_PARSERS = new ArrayList<>() {{ add(new SelectStatementParser()); add(new InsertStatementParser()); add(new UpdateStatementParser()); @@ -29,7 +43,12 @@ public class SqlParser { * 将语句解析为SQL语法树 */ public static ISqlStatement parseStatement(String sql) throws SqlSyntaxException { - // TODO + // 尝试字符串解析器解析 + for (var parser : STRING_STATEMENT_PARSERS) { + if (parser.checkStatement(sql)) { + return parser.parse(sql); + } + } // 尝试 JSqlParser 解析 Statement stmt; try { @@ -37,7 +56,7 @@ public static ISqlStatement parseStatement(String sql) throws SqlSyntaxException } catch (JSQLParserException e) { throw new SqlSyntaxException(1, e); } - for (var parser : jsqlpStatementParsers) { + for (var parser : JSQLP_STATEMENT_PARSERS) { if (parser.checkStatement(stmt)) { return parser.parse(stmt); } diff --git a/src/main/java/net/kaaass/rumbase/parse/exception/SqlSyntaxException.java b/src/main/java/net/kaaass/rumbase/parse/exception/SqlSyntaxException.java index a8b24ee..cc87add 100644 --- a/src/main/java/net/kaaass/rumbase/parse/exception/SqlSyntaxException.java +++ b/src/main/java/net/kaaass/rumbase/parse/exception/SqlSyntaxException.java @@ -10,6 +10,7 @@ *

* E1001-1 SQL语句语法错误 * E1001-2 不支持的SQL语句 + * E1001-3 语句生成错误,请检查服务器日志 * * @author kaaass */ @@ -18,12 +19,17 @@ public class SqlSyntaxException extends RumbaseException { public static final Map REASONS = new HashMap<>() {{ put(1, "SQL语句语法错误"); put(2, "不支持的SQL语句"); + put(3, "语句生成错误,请检查服务器日志"); }}; public SqlSyntaxException(int subId) { super(5001, subId, REASONS.get(subId)); } + public SqlSyntaxException(int subId, String subReason) { + super(5001, subId, REASONS.get(subId) + ":" + subReason); + } + public SqlSyntaxException(int subId, Throwable e) { super(5001, subId, REASONS.get(subId), e); } diff --git a/src/main/java/net/kaaass/rumbase/parse/parser/CommandStatementParser.java b/src/main/java/net/kaaass/rumbase/parse/parser/CommandStatementParser.java new file mode 100644 index 0000000..341be90 --- /dev/null +++ b/src/main/java/net/kaaass/rumbase/parse/parser/CommandStatementParser.java @@ -0,0 +1,47 @@ +package net.kaaass.rumbase.parse.parser; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.SqlParser; +import net.kaaass.rumbase.parse.exception.SqlSyntaxException; + +import java.lang.reflect.InvocationTargetException; + +/** + * 字符串指令解析器 + * @author kaaass + */ +@Slf4j +@RequiredArgsConstructor +public class CommandStatementParser implements SqlParser.StatementParser { + + /** + * 语句解析结果的类 + */ + private final Class stmtClazz; + + /** + * 指令格式 + */ + private final String command; + + @Override + public ISqlStatement parse(String input) throws SqlSyntaxException { + try { + return stmtClazz.getDeclaredConstructor().newInstance(); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + log.error("无法生成指令对象 {}", input, e); + throw new SqlSyntaxException(3, e); + } + } + + @Override + public boolean checkStatement(String input) { + // 忽略逗号 + if (input.charAt(input.length() - 1) == ';') { + input = input.substring(0, input.length() - 1); + } + return command.compareToIgnoreCase(input) == 0; + } +} diff --git a/src/main/java/net/kaaass/rumbase/parse/parser/command/ExecStatementParser.java b/src/main/java/net/kaaass/rumbase/parse/parser/command/ExecStatementParser.java new file mode 100644 index 0000000..0a373ef --- /dev/null +++ b/src/main/java/net/kaaass/rumbase/parse/parser/command/ExecStatementParser.java @@ -0,0 +1,22 @@ +package net.kaaass.rumbase.parse.parser.command; + +import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.SqlParser; +import net.kaaass.rumbase.parse.stmt.ExecStatement; + +/** + * 将执行SQL文件语句解释为对应语法树 + * + * @author kaaass + */ +public class ExecStatementParser implements SqlParser.StatementParser { + @Override + public ISqlStatement parse(String input) { + return new ExecStatement(input.substring(5).trim()); + } + + @Override + public boolean checkStatement(String input) { + return input.startsWith("exec ") || input.startsWith("EXEC "); + } +} diff --git a/src/main/java/net/kaaass/rumbase/parse/parser/CreateIndexStatementParser.java b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/CreateIndexStatementParser.java similarity index 91% rename from src/main/java/net/kaaass/rumbase/parse/parser/CreateIndexStatementParser.java rename to src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/CreateIndexStatementParser.java index fcb614c..1245ab4 100644 --- a/src/main/java/net/kaaass/rumbase/parse/parser/CreateIndexStatementParser.java +++ b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/CreateIndexStatementParser.java @@ -1,7 +1,8 @@ -package net.kaaass.rumbase.parse.parser; +package net.kaaass.rumbase.parse.parser.jsqlp; import net.kaaass.rumbase.parse.ColumnIdentifier; import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.parser.JsqlpStatementParser; import net.kaaass.rumbase.parse.stmt.CreateIndexStatement; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.create.index.CreateIndex; diff --git a/src/main/java/net/kaaass/rumbase/parse/parser/CreateTableStatementParser.java b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/CreateTableStatementParser.java similarity index 82% rename from src/main/java/net/kaaass/rumbase/parse/parser/CreateTableStatementParser.java rename to src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/CreateTableStatementParser.java index 9bfb26a..7b3cbcb 100644 --- a/src/main/java/net/kaaass/rumbase/parse/parser/CreateTableStatementParser.java +++ b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/CreateTableStatementParser.java @@ -1,6 +1,8 @@ -package net.kaaass.rumbase.parse.parser; +package net.kaaass.rumbase.parse.parser.jsqlp; import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.exception.SqlSyntaxException; +import net.kaaass.rumbase.parse.parser.JsqlpStatementParser; import net.kaaass.rumbase.parse.stmt.CreateTableStatement; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.create.table.ColDataType; @@ -16,11 +18,14 @@ */ public class CreateTableStatementParser implements JsqlpStatementParser { @Override - public ISqlStatement parse(Statement input) { + public ISqlStatement parse(Statement input) throws SqlSyntaxException { var stmt = (CreateTable) input; // 解析表名 var tableName = stmt.getTable().getName(); // 解析字段定义 + if (stmt.getColumnDefinitions() == null) { + throw new SqlSyntaxException(1, "表字段不能为空"); + } var columnDefs = stmt.getColumnDefinitions().stream() .map(def -> new CreateTableStatement.ColumnDefinition( mapColType(def.getColDataType()), diff --git a/src/main/java/net/kaaass/rumbase/parse/parser/DeleteStatementParser.java b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/DeleteStatementParser.java similarity index 89% rename from src/main/java/net/kaaass/rumbase/parse/parser/DeleteStatementParser.java rename to src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/DeleteStatementParser.java index c70d7d1..328579c 100644 --- a/src/main/java/net/kaaass/rumbase/parse/parser/DeleteStatementParser.java +++ b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/DeleteStatementParser.java @@ -1,7 +1,8 @@ -package net.kaaass.rumbase.parse.parser; +package net.kaaass.rumbase.parse.parser.jsqlp; import net.kaaass.rumbase.parse.ConditionExpression; import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.parser.JsqlpStatementParser; import net.kaaass.rumbase.parse.stmt.DeleteStatement; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.delete.Delete; diff --git a/src/main/java/net/kaaass/rumbase/parse/parser/InsertStatementParser.java b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/InsertStatementParser.java similarity index 90% rename from src/main/java/net/kaaass/rumbase/parse/parser/InsertStatementParser.java rename to src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/InsertStatementParser.java index a82ffea..65c12b4 100644 --- a/src/main/java/net/kaaass/rumbase/parse/parser/InsertStatementParser.java +++ b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/InsertStatementParser.java @@ -1,7 +1,8 @@ -package net.kaaass.rumbase.parse.parser; +package net.kaaass.rumbase.parse.parser.jsqlp; import net.kaaass.rumbase.parse.ColumnIdentifier; import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.parser.JsqlpStatementParser; import net.kaaass.rumbase.parse.stmt.InsertStatement; import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.expression.operators.relational.ItemsListVisitorAdapter; @@ -37,6 +38,7 @@ public ISqlStatement parse(Statement input) { public void visit(ExpressionList expressionList) { expressionList.getExpressions().stream() .map(Objects::toString) + .map(s -> "NULL".equals(s) ? null : s) .forEach(values::add); } }); diff --git a/src/main/java/net/kaaass/rumbase/parse/parser/ParserUtil.java b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/ParserUtil.java similarity index 96% rename from src/main/java/net/kaaass/rumbase/parse/parser/ParserUtil.java rename to src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/ParserUtil.java index caa97ab..5ee4447 100644 --- a/src/main/java/net/kaaass/rumbase/parse/parser/ParserUtil.java +++ b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/ParserUtil.java @@ -1,4 +1,4 @@ -package net.kaaass.rumbase.parse.parser; +package net.kaaass.rumbase.parse.parser.jsqlp; import net.kaaass.rumbase.parse.ColumnIdentifier; import net.sf.jsqlparser.schema.Column; diff --git a/src/main/java/net/kaaass/rumbase/parse/parser/SelectStatementParser.java b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/SelectStatementParser.java similarity index 59% rename from src/main/java/net/kaaass/rumbase/parse/parser/SelectStatementParser.java rename to src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/SelectStatementParser.java index dafbdd5..e9e4569 100644 --- a/src/main/java/net/kaaass/rumbase/parse/parser/SelectStatementParser.java +++ b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/SelectStatementParser.java @@ -1,9 +1,11 @@ -package net.kaaass.rumbase.parse.parser; +package net.kaaass.rumbase.parse.parser.jsqlp; import lombok.extern.slf4j.Slf4j; import net.kaaass.rumbase.parse.ColumnIdentifier; import net.kaaass.rumbase.parse.ConditionExpression; import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.exception.SqlSyntaxException; +import net.kaaass.rumbase.parse.parser.JsqlpStatementParser; import net.kaaass.rumbase.parse.stmt.SelectStatement; import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; import net.sf.jsqlparser.schema.Column; @@ -23,7 +25,7 @@ @Slf4j public class SelectStatementParser implements JsqlpStatementParser { @Override - public ISqlStatement parse(Statement input) { + public ISqlStatement parse(Statement input) throws SqlSyntaxException { final PlainSelect[] selectStmtArr = {null}; ((Select) input).getSelectBody().accept(new SelectVisitorAdapter() { @Override @@ -35,6 +37,9 @@ public void visit(PlainSelect plainSelect) { // 解析distinct var distinct = stmt.getDistinct() != null; // 解析表名 + if (stmt.getFromItem() == null) { + throw new SqlSyntaxException(1, "选择的目标表不能为空"); + } var tableName = getTableFromItem(stmt.getFromItem()); // 解析列 List columns = new ArrayList<>(); @@ -58,28 +63,28 @@ public void visit(SelectExpressionItem item) { } })); // 解析join - var joins = stmt.getJoins().stream() - .map(join -> { - ConditionExpression joinOn = null; - if (join.getOnExpression() != null) { - joinOn = new ConditionExpression(join.getOnExpression(), tableName); - } - var table = getTableFromItem(join.getRightItem()); - var result = new SelectStatement.JoinTable(table, joinOn); - result.setOuter(join.isOuter()); - result.setRight(join.isRight()); - result.setLeft(join.isLeft()); - result.setNatural(join.isNatural()); - result.setFull(join.isFull()); - result.setInner(join.isInner()); - result.setSimple(join.isSimple()); - return result; - }) - .collect(Collectors.toList()); + List joins = null; + if (stmt.getJoins() != null) { + joins = stmt.getJoins().stream() + .map(join -> { + ConditionExpression joinOn = joinOn = new ConditionExpression(join.getOnExpression(), tableName); + var table = getTableFromItem(join.getRightItem()); + var result = new SelectStatement.JoinTable(table, joinOn); + result.setOuter(join.isOuter()); + result.setRight(join.isRight()); + result.setLeft(join.isLeft()); + result.setNatural(join.isNatural()); + result.setFull(join.isFull()); + result.setInner(join.isInner()); + result.setSimple(join.isSimple()); + return result; + }) + .collect(Collectors.toList()); + } // 解析where ConditionExpression where = null; if (stmt.getWhere() != null) { - where = new ConditionExpression(stmt.getWhere(), ""); + where = new ConditionExpression(stmt.getWhere(), tableName); } // 解析orderBy ColumnIdentifier[] columnIdentifiers = new ColumnIdentifier[1]; @@ -87,15 +92,18 @@ public void visit(SelectExpressionItem item) { @Override public void visit(Column column) { - columnIdentifiers[0] = new ColumnIdentifier(column.getTable().getName(), column.getColumnName()); + columnIdentifiers[0] = ParserUtil.mapColumn(column, tableName); } }; - var orderBys = stmt.getOrderByElements().stream() - .map(orderByElement -> { - orderByElement.getExpression().accept(orderVisitor); - return new SelectStatement.OrderBy(columnIdentifiers[0], orderByElement.isAsc()); - }) - .collect(Collectors.toList()); + List orderBys = null; + if (stmt.getOrderByElements() != null) { + orderBys = stmt.getOrderByElements().stream() + .map(orderByElement -> { + orderByElement.getExpression().accept(orderVisitor); + return new SelectStatement.OrderBy(columnIdentifiers[0], orderByElement.isAsc()); + }) + .collect(Collectors.toList()); + } // 拼接结果 return new SelectStatement(distinct, columns, tableName, joins, where, orderBys); } diff --git a/src/main/java/net/kaaass/rumbase/parse/parser/UpdateStatementParser.java b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/UpdateStatementParser.java similarity index 93% rename from src/main/java/net/kaaass/rumbase/parse/parser/UpdateStatementParser.java rename to src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/UpdateStatementParser.java index f3e2383..110bb7e 100644 --- a/src/main/java/net/kaaass/rumbase/parse/parser/UpdateStatementParser.java +++ b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/UpdateStatementParser.java @@ -1,8 +1,9 @@ -package net.kaaass.rumbase.parse.parser; +package net.kaaass.rumbase.parse.parser.jsqlp; import net.kaaass.rumbase.parse.ColumnIdentifier; import net.kaaass.rumbase.parse.ConditionExpression; import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.parser.JsqlpStatementParser; import net.kaaass.rumbase.parse.stmt.UpdateStatement; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.update.Update; diff --git a/src/main/java/net/kaaass/rumbase/parse/stmt/CommitStatement.java b/src/main/java/net/kaaass/rumbase/parse/stmt/CommitStatement.java new file mode 100644 index 0000000..2f001d4 --- /dev/null +++ b/src/main/java/net/kaaass/rumbase/parse/stmt/CommitStatement.java @@ -0,0 +1,16 @@ +package net.kaaass.rumbase.parse.stmt; + +import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.ISqlStatementVisitor; + +/** + * SQL语法树:提交事务语句 + * + * @author kaaass + */ +public class CommitStatement implements ISqlStatement { + @Override + public T accept(ISqlStatementVisitor visitor) { + return visitor.visit(this); + } +} diff --git a/src/main/java/net/kaaass/rumbase/parse/stmt/CreateIndexStatement.java b/src/main/java/net/kaaass/rumbase/parse/stmt/CreateIndexStatement.java index 3f5e8fb..92a1527 100644 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/CreateIndexStatement.java +++ b/src/main/java/net/kaaass/rumbase/parse/stmt/CreateIndexStatement.java @@ -4,6 +4,7 @@ import lombok.Data; import net.kaaass.rumbase.parse.ColumnIdentifier; import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.ISqlStatementVisitor; import java.util.List; @@ -30,4 +31,9 @@ public class CreateIndexStatement implements ISqlStatement { * 索引的目标列 */ private List columns; + + @Override + public T accept(ISqlStatementVisitor visitor) { + return visitor.visit(this); + } } diff --git a/src/main/java/net/kaaass/rumbase/parse/stmt/CreateTableStatement.java b/src/main/java/net/kaaass/rumbase/parse/stmt/CreateTableStatement.java index 5a0dd50..6c1b75c 100644 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/CreateTableStatement.java +++ b/src/main/java/net/kaaass/rumbase/parse/stmt/CreateTableStatement.java @@ -3,6 +3,7 @@ import lombok.AllArgsConstructor; import lombok.Data; import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.ISqlStatementVisitor; import java.util.List; @@ -25,6 +26,11 @@ public class CreateTableStatement implements ISqlStatement { */ private List columnDefinitions; + @Override + public T accept(ISqlStatementVisitor visitor) { + return visitor.visit(this); + } + /** * SQL语法树:列定义 */ diff --git a/src/main/java/net/kaaass/rumbase/parse/stmt/DeleteStatement.java b/src/main/java/net/kaaass/rumbase/parse/stmt/DeleteStatement.java index 23590d4..3f92fd2 100644 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/DeleteStatement.java +++ b/src/main/java/net/kaaass/rumbase/parse/stmt/DeleteStatement.java @@ -4,6 +4,7 @@ import lombok.Data; import net.kaaass.rumbase.parse.ConditionExpression; import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.ISqlStatementVisitor; /** * SQL语法树:删除语句 @@ -23,4 +24,9 @@ public class DeleteStatement implements ISqlStatement { * 删除的筛选条件,为null则代表清空表 */ private ConditionExpression where; + + @Override + public T accept(ISqlStatementVisitor visitor) { + return visitor.visit(this); + } } diff --git a/src/main/java/net/kaaass/rumbase/parse/stmt/ExecStatement.java b/src/main/java/net/kaaass/rumbase/parse/stmt/ExecStatement.java new file mode 100644 index 0000000..43ec55b --- /dev/null +++ b/src/main/java/net/kaaass/rumbase/parse/stmt/ExecStatement.java @@ -0,0 +1,23 @@ +package net.kaaass.rumbase.parse.stmt; + +import lombok.Data; +import lombok.RequiredArgsConstructor; +import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.ISqlStatementVisitor; + +/** + * SQL语法树:执行SQL文件 + * + * @author kaaass + */ +@Data +@RequiredArgsConstructor +public class ExecStatement implements ISqlStatement { + + private final String filepath; + + @Override + public T accept(ISqlStatementVisitor visitor) { + return visitor.visit(this); + } +} diff --git a/src/main/java/net/kaaass/rumbase/parse/stmt/ExitStatement.java b/src/main/java/net/kaaass/rumbase/parse/stmt/ExitStatement.java new file mode 100644 index 0000000..c9f399a --- /dev/null +++ b/src/main/java/net/kaaass/rumbase/parse/stmt/ExitStatement.java @@ -0,0 +1,16 @@ +package net.kaaass.rumbase.parse.stmt; + +import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.ISqlStatementVisitor; + +/** + * SQL语法树:退出会话语句 + * + * @author kaaass + */ +public class ExitStatement implements ISqlStatement { + @Override + public T accept(ISqlStatementVisitor visitor) { + return visitor.visit(this); + } +} diff --git a/src/main/java/net/kaaass/rumbase/parse/stmt/FlushStatement.java b/src/main/java/net/kaaass/rumbase/parse/stmt/FlushStatement.java new file mode 100644 index 0000000..4506312 --- /dev/null +++ b/src/main/java/net/kaaass/rumbase/parse/stmt/FlushStatement.java @@ -0,0 +1,16 @@ +package net.kaaass.rumbase.parse.stmt; + +import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.ISqlStatementVisitor; + +/** + * SQL语法树:刷新缓冲区 + * + * @author kaaass + */ +public class FlushStatement implements ISqlStatement { + @Override + public T accept(ISqlStatementVisitor visitor) { + return visitor.visit(this); + } +} diff --git a/src/main/java/net/kaaass/rumbase/parse/stmt/InsertStatement.java b/src/main/java/net/kaaass/rumbase/parse/stmt/InsertStatement.java index c9c3f87..1efce70 100644 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/InsertStatement.java +++ b/src/main/java/net/kaaass/rumbase/parse/stmt/InsertStatement.java @@ -4,6 +4,7 @@ import lombok.Data; import net.kaaass.rumbase.parse.ColumnIdentifier; import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.ISqlStatementVisitor; import java.util.List; @@ -30,4 +31,9 @@ public class InsertStatement implements ISqlStatement { * 插入的数据,以字符串表示 */ private List values; + + @Override + public T accept(ISqlStatementVisitor visitor) { + return visitor.visit(this); + } } diff --git a/src/main/java/net/kaaass/rumbase/parse/stmt/RollbackStatement.java b/src/main/java/net/kaaass/rumbase/parse/stmt/RollbackStatement.java new file mode 100644 index 0000000..fb6cf4d --- /dev/null +++ b/src/main/java/net/kaaass/rumbase/parse/stmt/RollbackStatement.java @@ -0,0 +1,16 @@ +package net.kaaass.rumbase.parse.stmt; + +import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.ISqlStatementVisitor; + +/** + * SQL语法树:回滚事务语句 + * + * @author kaaass + */ +public class RollbackStatement implements ISqlStatement { + @Override + public T accept(ISqlStatementVisitor visitor) { + return visitor.visit(this); + } +} diff --git a/src/main/java/net/kaaass/rumbase/parse/stmt/SelectStatement.java b/src/main/java/net/kaaass/rumbase/parse/stmt/SelectStatement.java index cf21d2a..8625b9a 100644 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/SelectStatement.java +++ b/src/main/java/net/kaaass/rumbase/parse/stmt/SelectStatement.java @@ -6,6 +6,7 @@ import net.kaaass.rumbase.parse.ColumnIdentifier; import net.kaaass.rumbase.parse.ConditionExpression; import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.ISqlStatementVisitor; import java.util.List; @@ -50,6 +51,11 @@ public class SelectStatement implements ISqlStatement { */ private List orderBys; + @Override + public T accept(ISqlStatementVisitor visitor) { + return visitor.visit(this); + } + /** * SQL语法树:Join表 */ diff --git a/src/main/java/net/kaaass/rumbase/parse/stmt/ShutdownStatement.java b/src/main/java/net/kaaass/rumbase/parse/stmt/ShutdownStatement.java new file mode 100644 index 0000000..1f3d052 --- /dev/null +++ b/src/main/java/net/kaaass/rumbase/parse/stmt/ShutdownStatement.java @@ -0,0 +1,16 @@ +package net.kaaass.rumbase.parse.stmt; + +import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.ISqlStatementVisitor; + +/** + * SQL语法树:关闭数据库语句 + * + * @author kaaass + */ +public class ShutdownStatement implements ISqlStatement { + @Override + public T accept(ISqlStatementVisitor visitor) { + return visitor.visit(this); + } +} diff --git a/src/main/java/net/kaaass/rumbase/parse/stmt/StartTransactionStatement.java b/src/main/java/net/kaaass/rumbase/parse/stmt/StartTransactionStatement.java new file mode 100644 index 0000000..6d90030 --- /dev/null +++ b/src/main/java/net/kaaass/rumbase/parse/stmt/StartTransactionStatement.java @@ -0,0 +1,16 @@ +package net.kaaass.rumbase.parse.stmt; + +import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.ISqlStatementVisitor; + +/** + * SQL语法树:开启事务语句 + * + * @author kaaass + */ +public class StartTransactionStatement implements ISqlStatement { + @Override + public T accept(ISqlStatementVisitor visitor) { + return visitor.visit(this); + } +} diff --git a/src/main/java/net/kaaass/rumbase/parse/stmt/UpdateStatement.java b/src/main/java/net/kaaass/rumbase/parse/stmt/UpdateStatement.java index 280aef5..97f00b2 100644 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/UpdateStatement.java +++ b/src/main/java/net/kaaass/rumbase/parse/stmt/UpdateStatement.java @@ -5,6 +5,7 @@ import net.kaaass.rumbase.parse.ColumnIdentifier; import net.kaaass.rumbase.parse.ConditionExpression; import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.ISqlStatementVisitor; import java.util.List; @@ -36,4 +37,9 @@ public class UpdateStatement implements ISqlStatement { * 更新行的条件 */ private ConditionExpression where; + + @Override + public T accept(ISqlStatementVisitor visitor) { + return visitor.visit(this); + } } diff --git a/src/main/java/net/kaaass/rumbase/query/CreateIndexExecutor.java b/src/main/java/net/kaaass/rumbase/query/CreateIndexExecutor.java index 804e756..bd507ca 100644 --- a/src/main/java/net/kaaass/rumbase/query/CreateIndexExecutor.java +++ b/src/main/java/net/kaaass/rumbase/query/CreateIndexExecutor.java @@ -7,6 +7,7 @@ import net.kaaass.rumbase.table.TableManager; import net.kaaass.rumbase.table.exception.TableExistenceException; import net.kaaass.rumbase.table.field.BaseField; +import net.kaaass.rumbase.transaction.TransactionContext; /** * @@ -22,6 +23,9 @@ public class CreateIndexExecutor implements Executable{ @NonNull private final TableManager manager; + @NonNull + private final TransactionContext context; + @Override public void execute() throws TableExistenceException, IndexAlreadyExistException { var table = manager.getTable(statement.getTableName()); @@ -45,6 +49,7 @@ public void execute() throws TableExistenceException, IndexAlreadyExistException if (field != null) { field.createIndex(); + table.persist(context); } else { throw new TableExistenceException(2); } diff --git a/src/main/java/net/kaaass/rumbase/query/CreateTableExecutor.java b/src/main/java/net/kaaass/rumbase/query/CreateTableExecutor.java index f146a0c..3560e27 100644 --- a/src/main/java/net/kaaass/rumbase/query/CreateTableExecutor.java +++ b/src/main/java/net/kaaass/rumbase/query/CreateTableExecutor.java @@ -4,7 +4,7 @@ import lombok.RequiredArgsConstructor; import net.kaaass.rumbase.parse.stmt.CreateTableStatement; import net.kaaass.rumbase.query.exception.ArgumentException; -import net.kaaass.rumbase.table.Table; +import net.kaaass.rumbase.record.exception.RecordNotFoundException; import net.kaaass.rumbase.table.TableManager; import net.kaaass.rumbase.table.exception.TableConflictException; import net.kaaass.rumbase.table.exception.TableExistenceException; @@ -30,10 +30,9 @@ public class CreateTableExecutor implements Executable { private final TransactionContext context; @Override - public void execute() throws TableExistenceException, TableConflictException, ArgumentException { + public void execute() throws TableExistenceException, TableConflictException, ArgumentException, RecordNotFoundException { var tableName = statement.getTableName(); var baseFields = new ArrayList(); - var dummyTable = new Table(tableName, baseFields); boolean nullable; for (var def : statement.getColumnDefinitions()) { nullable = !def.isNotNull(); @@ -43,13 +42,13 @@ public void execute() throws TableExistenceException, TableConflictException, Ar try { switch (fieldType) { case INT: - baseFields.add(new IntField(fieldName, nullable, dummyTable)); + baseFields.add(new IntField(fieldName, nullable, null)); break; case FLOAT: - baseFields.add(new FloatField(fieldName, nullable, dummyTable)); + baseFields.add(new FloatField(fieldName, nullable, null)); break; case VARCHAR: - baseFields.add(new VarcharField(fieldName, Integer.parseInt(def.getColumnType().getArguments().get(0)), nullable, dummyTable)); + baseFields.add(new VarcharField(fieldName, Integer.parseInt(def.getColumnType().getArguments().get(0)), nullable, null)); break; default: throw new TableConflictException(1); @@ -60,6 +59,6 @@ public void execute() throws TableExistenceException, TableConflictException, Ar } - manager.createTable(context, tableName, baseFields, tableName + ".db"); + manager.createTable(context, tableName, baseFields, "data/table/" + tableName + ".db"); } } diff --git a/src/main/java/net/kaaass/rumbase/query/InsertExecutor.java b/src/main/java/net/kaaass/rumbase/query/InsertExecutor.java index b1cf71f..c760397 100644 --- a/src/main/java/net/kaaass/rumbase/query/InsertExecutor.java +++ b/src/main/java/net/kaaass/rumbase/query/InsertExecutor.java @@ -2,6 +2,7 @@ import lombok.NonNull; import lombok.RequiredArgsConstructor; +import net.kaaass.rumbase.parse.ColumnIdentifier; import net.kaaass.rumbase.parse.stmt.InsertStatement; import net.kaaass.rumbase.query.exception.ArgumentException; import net.kaaass.rumbase.table.TableManager; @@ -34,23 +35,29 @@ public void execute() throws TableExistenceException, TableConflictException, Ar var table = manager.getTable(statement.getTableName()); var columns = statement.getColumns(); + if (columns == null || columns.isEmpty()) { + if (columns == null) { + columns = new ArrayList<>(); + } + var finalColumns = columns; + table.getFields().forEach(f -> finalColumns.add(new ColumnIdentifier(table.getTableName(), f.getName()))); + } var len = columns.size(); var insertArray = new ArrayList(); boolean ok; - for (BaseField f : table.getFields()) { + for (int j = 0; j < len; j++) { + var insertField = columns.get(j); ok = false; - for (int j = 0; j < len; j++) { - var insertField = columns.get(j); + for (BaseField f : table.getFields()) { if (f.getName().equals(insertField.getFieldName())) { insertArray.add(statement.getValues().get(j)); ok = true; - } } if (!ok) { - insertArray.add(""); + throw new TableConflictException(1); } } diff --git a/src/main/java/net/kaaass/rumbase/query/SelectExecutor.java b/src/main/java/net/kaaass/rumbase/query/SelectExecutor.java index b079cae..3a49f16 100644 --- a/src/main/java/net/kaaass/rumbase/query/SelectExecutor.java +++ b/src/main/java/net/kaaass/rumbase/query/SelectExecutor.java @@ -71,7 +71,7 @@ public void execute() throws TableConflictException, ArgumentException, TableExi // 投影 var selectCols = statement.getSelectColumns(); - if (selectCols != null) { + if (selectCols != null && !selectCols.isEmpty()) { var projectExe = new ProjectExecutor(resultTable, selectCols, resultData); projectExe.execute(); resultData = projectExe.getProjectedResult(); diff --git a/src/main/java/net/kaaass/rumbase/record/IRecordStorage.java b/src/main/java/net/kaaass/rumbase/record/IRecordStorage.java index 66c562d..abe0919 100644 --- a/src/main/java/net/kaaass/rumbase/record/IRecordStorage.java +++ b/src/main/java/net/kaaass/rumbase/record/IRecordStorage.java @@ -64,4 +64,6 @@ default byte[] query(TransactionContext txContext, long recordId) throws RecordN * @param metadata 元信息数据 */ void setMetadata(TransactionContext txContext, byte[] metadata); + + String getIdentifiedName(); } diff --git a/src/main/java/net/kaaass/rumbase/record/MvccRecordStorage.java b/src/main/java/net/kaaass/rumbase/record/MvccRecordStorage.java index 52807a5..29a6a0a 100644 --- a/src/main/java/net/kaaass/rumbase/record/MvccRecordStorage.java +++ b/src/main/java/net/kaaass/rumbase/record/MvccRecordStorage.java @@ -1,5 +1,6 @@ package net.kaaass.rumbase.record; +import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; @@ -29,6 +30,7 @@ public class MvccRecordStorage implements IRecordStorage { private final IItemStorage storage; @NonNull + @Getter private final String identifiedName; /** diff --git a/src/main/java/net/kaaass/rumbase/record/RecordManager.java b/src/main/java/net/kaaass/rumbase/record/RecordManager.java index b6ff7b4..e7a26bb 100644 --- a/src/main/java/net/kaaass/rumbase/record/RecordManager.java +++ b/src/main/java/net/kaaass/rumbase/record/RecordManager.java @@ -3,6 +3,9 @@ import lombok.SneakyThrows; import net.kaaass.rumbase.dataitem.ItemManager; +import java.io.File; +import java.nio.file.Paths; + /** * 记录管理类 * @@ -23,4 +26,9 @@ public static IRecordStorage fromFile(String filepath) { var identifier = "TBL_" + filepath; return new MvccRecordStorage(itemStorage, identifier); } + + @SneakyThrows + public static IRecordStorage fromFile(String directory, String filename) { + return fromFile(Paths.get(directory, filename).toString()); + } } diff --git a/src/main/java/net/kaaass/rumbase/record/mock/MockRecordStorage.java b/src/main/java/net/kaaass/rumbase/record/mock/MockRecordStorage.java index 3e11d23..031fb21 100644 --- a/src/main/java/net/kaaass/rumbase/record/mock/MockRecordStorage.java +++ b/src/main/java/net/kaaass/rumbase/record/mock/MockRecordStorage.java @@ -73,6 +73,11 @@ public void setMetadata(TransactionContext txContext, byte[] metadata) { this.metadata = metadata; } + @Override + public String getIdentifiedName() { + return this.toString(); + } + public static MockRecordStorage ofFile(String filepath) { var mockId = "file" + filepath; if (MOCK_STORAGES.containsKey(mockId)) { diff --git a/src/main/java/net/kaaass/rumbase/server/Server.java b/src/main/java/net/kaaass/rumbase/server/Server.java new file mode 100644 index 0000000..d3783d9 --- /dev/null +++ b/src/main/java/net/kaaass/rumbase/server/Server.java @@ -0,0 +1,139 @@ +package net.kaaass.rumbase.server; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; +import net.kaaass.rumbase.page.PageManager; +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.table.TableManager; +import net.kaaass.rumbase.table.exception.TableConflictException; +import net.kaaass.rumbase.table.exception.TableExistenceException; +import net.kaaass.rumbase.transaction.TransactionManager; +import net.kaaass.rumbase.transaction.TransactionManagerImpl; + +import java.io.File; +import java.io.IOException; +import java.net.ServerSocket; +import java.net.SocketTimeoutException; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicLong; + +/** + * 管理服务器运行过程中总体的运行状态,使用单例模式 + * + * @author kaaass + */ +@Slf4j +public class Server { + + @Getter + private TransactionManager transactionManager = null; + + private ExecutorService threadPool = null; + + @Getter + @Setter + private boolean acceptNewConnection = true; + + @Getter + private TableManager tableManager = null; + + private final AtomicLong sessionCounter = new AtomicLong(0); + + @Getter + private final ConcurrentSkipListSet activeSession = new ConcurrentSkipListSet<>(); + + /** + * 进行服务器开始前的准备工作 + */ + 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(); + // 初始化事务管理器 + log.info("初始化事务管理器..."); + try { + transactionManager = new TransactionManagerImpl(); + } catch (IOException | FileException e) { + log.error("初始化事务管理器失败", e); + System.exit(1); + } + // 初始化表管理器 + log.info("初始化表管理器..."); + // TODO 先恢复metadata + try { + tableManager = new TableManager(); + } catch (TableExistenceException | TableConflictException | RecordNotFoundException | ArgumentException | IndexAlreadyExistException e) { + log.error("初始化表管理器失败", e); + System.exit(1); + } + // 初始化线程池 + log.info("初始化线程池..."); + var namedThreadFactory = Executors.defaultThreadFactory(); + threadPool = new ThreadPoolExecutor(5, 200, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); + } + + /** + * 运行服务器,监听客户端消息 + */ + public void run() { + // 监听端口 + try (ServerSocket server = new ServerSocket(8889)) { + log.info("开始监听 {}", server.getLocalSocketAddress()); + + server.setSoTimeout(1000); + while (acceptNewConnection) { + try { + var connection = server.accept(); + long sessionId = sessionCounter.incrementAndGet(); + var session = new Session(sessionId, connection, this); + threadPool.submit(session); + log.info("创建会话 {}", sessionId); + } catch (SocketTimeoutException ignore) { + } + } + } catch (IOException e) { + log.error("服务器启动失败", e); + } + } + + /** + * 服务器关闭 + */ + public void shutdown() { + // 关闭线程池 + log.info("正在关闭线程池..."); + if (threadPool != null) { + threadPool.shutdown(); + } + // 关闭所有活动会话 + log.info("正在关闭所有活动会话..."); + for (var session : activeSession) { + session.say("服务器正在关闭...\n"); + session.onClose(); + } + activeSession.clear(); + // 释放文件、写回文件 + log.info("正在写回文件..."); + PageManager.flush(); + } + + private static final Server INSTANCE = new Server(); + + private Server() { + } + + /** + * 获得Server单例 + */ + public static Server getInstance() { + return INSTANCE; + } +} diff --git a/src/main/java/net/kaaass/rumbase/server/Session.java b/src/main/java/net/kaaass/rumbase/server/Session.java new file mode 100644 index 0000000..bcb033d --- /dev/null +++ b/src/main/java/net/kaaass/rumbase/server/Session.java @@ -0,0 +1,477 @@ +package net.kaaass.rumbase.server; + +import lombok.EqualsAndHashCode; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.exception.RumbaseException; +import net.kaaass.rumbase.exception.RumbaseRuntimeException; +import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; +import net.kaaass.rumbase.page.PageManager; +import net.kaaass.rumbase.parse.ISqlStatement; +import net.kaaass.rumbase.parse.ISqlStatementVisitor; +import net.kaaass.rumbase.parse.SqlParser; +import net.kaaass.rumbase.parse.exception.SqlSyntaxException; +import net.kaaass.rumbase.parse.stmt.*; +import net.kaaass.rumbase.query.*; +import net.kaaass.rumbase.query.exception.ArgumentException; +import net.kaaass.rumbase.record.exception.RecordNotFoundException; +import net.kaaass.rumbase.table.exception.TableConflictException; +import net.kaaass.rumbase.table.exception.TableExistenceException; +import net.kaaass.rumbase.transaction.TransactionContext; +import net.kaaass.rumbase.transaction.TransactionIsolation; + +import java.io.*; +import java.net.Socket; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Scanner; +import java.util.stream.Collectors; + +/** + * 存储、管理会话中的数据库状态 + * + * @author kaaass + */ +@Slf4j +@RequiredArgsConstructor +@EqualsAndHashCode(of = "sessionId") +public class Session implements Runnable, Comparable, ISqlStatementVisitor { + + private TransactionContext currentContext = null; + + private final long sessionId; + + private final Socket connection; + + private final Server server; + + private Scanner scanner = null; + + private Writer writer = null; + + private boolean autoCommit = false; + + /** + * 执行SQL语句并输出相关结果 + * @return 是否退出 + */ + public boolean executeSql(String sql) { + // 解析SQL语句 + ISqlStatement stmt; + try { + stmt = SqlParser.parseStatement(sql); + } catch (SqlSyntaxException e) { + log.debug("会话 {} 解析SQL语句失败,输入: {}", sessionId, sql, e); + say(e); + return false; + } catch (Exception e) { + log.warn("会话 {} 解析SQL语句出现异常错误,输入:{}", sessionId, sql, e); + say("解析异常,请检查服务器日志\n"); + return false; + } + log.debug("会话 {} 解析SQL语句: {}", sessionId, stmt); + // 执行SQL + try { + return stmt.accept(this); + // TODO 自动回滚事务、SQL日志 + } catch (RumbaseRuntimeException e) { + log.info("会话 {} 发生错误", sessionId, e); + say(e); + return false; + } catch (Exception e) { + log.warn("会话 {} 运行SQL语句出现未知异常,输入:{}", sessionId, sql, e); + say("发生未知异常,请检查服务器日志\n"); + return false; + } + } + + @Override + public void run() { + // 加载 + onInit(); + // 加载成功,加入活跃会话 + server.getActiveSession().add(this); + // 进入REPL模式 + var exit = false; + while (!exit && !connection.isClosed()) { + // 打印命令提示符 + say("\n> "); + try { + writer.flush(); + } catch (IOException ignore) { + } + try { + // 等待输入 + String input = scanner.nextLine(); + if (input.isBlank()) { + continue; + } + // 执行 + exit = executeSql(input); + } catch (NoSuchElementException e) { + log.info("会话 {} 被强制关闭", sessionId, e); + break; + } catch (Exception e) { + log.info("会话 {} 命令执行错误", sessionId, e); + say("未知错误,请检查服务端日志\n"); + } + } + // 退出 + onClose(); + } + + /** + * 当会话开始加载 + */ + public void onInit() { + // 准备读写 + try { + scanner = new Scanner(new BufferedInputStream(connection.getInputStream())); + writer = new OutputStreamWriter(new BufferedOutputStream(connection.getOutputStream())); + } catch (IOException e) { + log.info("无法处理IO,会话建立失败", e); + } + // 打印欢迎信息 + say("Welcome to Rumbase DMBS\n\n"); + } + + /** + * 当会话被关闭 + */ + public void onClose() { + log.info("正在关闭会话 {} ...", sessionId); + // 提交活动事务 + if (currentContext != null) { + say("正在提交当前事务...\n"); + try { + currentContext.commit(); + } catch (RumbaseRuntimeException e) { + log.warn("退出会话 {} 时提交事务失败", sessionId, e); + say(e); + } + } + // 删除活跃会话 + server.getActiveSession().remove(this); + // 退出成功 + say("Bye\n"); + try { + writer.close(); + scanner.close(); + } catch (IOException ignore) { + } + } + + public void say(CharSequence chars) { + try { + writer.append(chars); + } catch (IOException e) { + log.info("信息发送失败:{},会话:{}", chars, sessionId, e); + } + } + + private void say(RumbaseException e) { + say(e.getMessage() + "\n"); + } + + private void say(RumbaseRuntimeException e) { + say(e.getMessage() + "\n"); + } + + @Override + public int compareTo(Session o) { + return Long.compare(sessionId, o.sessionId); + } + + @Override + public Boolean visit(SelectStatement statement) { + checkAutoCommitBefore(); + // 执行语句 + try { + var executor = new SelectExecutor(statement, + server.getTableManager(), + currentContext); + executor.execute(); + saySelectResult(executor, statement.getFromTable()); + } catch (TableExistenceException | IndexAlreadyExistException | ArgumentException | TableConflictException | RecordNotFoundException e) { + log.debug("会话 {} 执行语句异常", sessionId, e); + say(e); + } catch (Exception e) { + // 发生任何错误都回滚 + checkAutoCommitAfter(true); + throw e; + } + checkAutoCommitAfter(false); + return false; + } + + /** + * 以表格格式输出选择语句的结果 + * @param executor 结果集 + */ + private void saySelectResult(SelectExecutor executor, String defaultTable) { + var columns = + executor.getResultTable().stream() + .map(column -> column.getTableName().equals(defaultTable) ? + column.getFieldName() : + column.getTableName() + "." + column.getFieldName()) + .collect(Collectors.toList()); + var rows = executor.getResultData(); + log.debug("查询结果 {}, {}", columns, rows); + // 格式化为表格 + int[] maxLengths = new int[columns.size()]; + for (int i = 0; i < columns.size(); i++) { + maxLengths[i] = columns.get(i).length(); + } + for (var row : rows) { + for (int i = 0; i < row.size(); i++) { + row.set(i, row.get(i) == null ? "NULL" : row.get(i).toString()); + maxLengths[i] = Math.max(maxLengths[i], ((String) row.get(i)).length()); + } + } + // 生成行格式 + StringBuilder formatBuilder = new StringBuilder("|"); + for (int maxLength : maxLengths) { + formatBuilder.append("%-").append(maxLength + 2).append("s |"); + } + String format = formatBuilder.toString(); + // 输出行首 + var result = new StringBuilder(); + result.append(String.format(format, columns.toArray(new Object[0]))).append("\n"); + for (int i = 0; i < columns.size(); i++) { + result.append(i == 0 ? '|' : '+'); + result.append("-".repeat(Math.max(0, maxLengths[i] + 3))); + } + result.append("|\n"); + // 输出内容 + for (var row : rows) { + result.append(String.format(format, row.toArray(new Object[0]))).append("\n"); + } + say(result); + say("共 " + rows.size() + " 条记录\n"); + } + + @Override + public Boolean visit(InsertStatement statement) { + checkAutoCommitBefore(); + // 执行语句 + try { + var executor = new InsertExecutor(statement, + server.getTableManager(), + currentContext); + executor.execute(); + say("语句执行成功\n"); + } catch (TableExistenceException | ArgumentException | TableConflictException e) { + log.debug("会话 {} 执行语句异常", sessionId, e); + say(e); + } catch (Exception e) { + // 发生任何错误都回滚 + checkAutoCommitAfter(true); + throw e; + } + checkAutoCommitAfter(false); + return false; + } + + @Override + public Boolean visit(UpdateStatement statement) { + checkAutoCommitBefore(); + // 执行语句 + try { + var executor = new UpdateExecutor(statement, + server.getTableManager(), + currentContext); + executor.execute(); + say("语句执行成功\n"); + } catch (TableExistenceException | IndexAlreadyExistException | ArgumentException | TableConflictException | RecordNotFoundException e) { + log.debug("会话 {} 执行语句异常", sessionId, e); + say(e); + } catch (Exception e) { + // 发生任何错误都回滚 + checkAutoCommitAfter(true); + throw e; + } + checkAutoCommitAfter(false); + return false; + } + + @Override + public Boolean visit(DeleteStatement statement) { + checkAutoCommitBefore(); + // 执行语句 + try { + var executor = new DeleteExecutor(statement, + server.getTableManager(), + currentContext); + executor.execute(); + say("语句执行成功\n"); + } catch (TableExistenceException | IndexAlreadyExistException | ArgumentException | TableConflictException | RecordNotFoundException e) { + log.debug("会话 {} 执行语句异常", sessionId, e); + say(e); + } catch (Exception e) { + // 发生任何错误都回滚 + checkAutoCommitAfter(true); + throw e; + } + checkAutoCommitAfter(false); + return false; + } + + @Override + public Boolean visit(CreateIndexStatement statement) { + checkAutoCommitBefore(); + // 执行语句 + try { + var executor = new CreateIndexExecutor(statement, + server.getTableManager(), currentContext); + executor.execute(); + say("成功创建索引\n"); + } catch (TableExistenceException | IndexAlreadyExistException e) { + log.debug("会话 {} 执行语句异常", sessionId, e); + say(e); + } catch (Exception e) { + // 发生任何错误都回滚 + checkAutoCommitAfter(true); + throw e; + } + checkAutoCommitAfter(false); + return false; + } + + @Override + public Boolean visit(CreateTableStatement statement) { + checkAutoCommitBefore(); + // 执行语句 + try { + var executor = new CreateTableExecutor(statement, + server.getTableManager(), + currentContext); + executor.execute(); + say("成功创建表\n"); + } catch (ArgumentException | TableConflictException | TableExistenceException | RecordNotFoundException e) { + log.debug("会话 {} 执行语句异常", sessionId, e); + say(e); + } catch (Exception e) { + // 发生任何错误都回滚 + checkAutoCommitAfter(true); + throw e; + } + checkAutoCommitAfter(false); + return false; + } + + /** + * 执行前尝试自动提交 + */ + private void checkAutoCommitBefore() { + assert !autoCommit; + if (currentContext == null) { + // 自动创建事务 + // TODO 默认使用可重复读隔离度,应该从配置读取 + currentContext = server.getTransactionManager().createTransactionContext(TransactionIsolation.REPEATABLE_READ); + // 设置自动提交 + autoCommit = true; + } + } + + /** + * 执行后尝试自动提交 + * @param rollback 是否需要回滚 + */ + private void checkAutoCommitAfter(boolean rollback) { + if (autoCommit) { + try { + assert currentContext != null; + if (rollback) { + currentContext.rollback(); + } else { + currentContext.commit(); + } + currentContext = null; + } finally { + // 完成自动提交 + autoCommit = false; + } + } + } + + @Override + public Boolean visit(StartTransactionStatement statement) { + if (currentContext != null) { + say("请先提交当前事务!\n"); + return false; + } + // 创建事务 + // TODO 默认使用可重复读隔离度,应该从配置读取 + currentContext = server.getTransactionManager().createTransactionContext(TransactionIsolation.REPEATABLE_READ); + say("成功创建事务" + currentContext.getXid() + "\n"); + return false; + } + + @Override + public Boolean visit(CommitStatement statement) { + if (currentContext == null) { + say("当前会话内无事务\n"); + return false; + } + // 提交事务 + currentContext.commit(); + say("成功提交事务" + currentContext.getXid() + "\n"); + currentContext = null; + return false; + } + + @Override + public Boolean visit(RollbackStatement statement) { + if (currentContext == null) { + say("当前会话内无事务\n"); + return false; + } + // 回滚事务 + currentContext.rollback(); + say("成功回滚事务" + currentContext.getXid() + "\n"); + currentContext = null; + return false; + } + + @Override + public Boolean visit(ExitStatement statement) { + say("正在关闭会话...\n"); + return true; + } + + @Override + public Boolean visit(ShutdownStatement statement) { + say("正在关闭服务器...\n"); + System.exit(0); + return true; + } + + @Override + public Boolean visit(FlushStatement statement) { + PageManager.flush(); + say("已刷新缓冲\n"); + return false; + } + + @Override + public Boolean visit(ExecStatement statement) { + // 读入文件 + List lines; + try { + lines = Files.readAllLines(Paths.get(statement.getFilepath())); + } catch (IOException e) { + say("文件读取失败,请检查文件是否存在\n"); + return false; + } + // 逐行解析 + for (var line : lines) { + if (line.isBlank() || line.startsWith("#")) { + continue; + } + this.executeSql(line); + } + return false; + } +} diff --git a/src/main/java/net/kaaass/rumbase/table/Table.java b/src/main/java/net/kaaass/rumbase/table/Table.java index 2f3110c..c31dd18 100644 --- a/src/main/java/net/kaaass/rumbase/table/Table.java +++ b/src/main/java/net/kaaass/rumbase/table/Table.java @@ -5,6 +5,7 @@ import com.igormaznitsa.jbbp.io.JBBPByteOrder; import lombok.*; import net.kaaass.rumbase.index.Pair; +import net.kaaass.rumbase.index.exception.IndexNotFoundException; import net.kaaass.rumbase.query.exception.ArgumentException; import net.kaaass.rumbase.record.IRecordStorage; import net.kaaass.rumbase.record.RecordManager; @@ -16,6 +17,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.util.*; @@ -84,7 +86,11 @@ public class Table { * @param fields 表的字段结构 */ public Table(@NonNull String tableName, @NonNull List fields) { - this.recordStorage = RecordManager.fromFile(tableName); + var file = new File("data/table/"); + if (!file.exists() && !file.isDirectory()) { + file.mkdirs(); + } + this.recordStorage = RecordManager.fromFile("data/table", tableName + ".db"); this.tableName = tableName; this.fields = fields; this.next = -1; @@ -135,7 +141,6 @@ public void persist(TransactionContext context) { public static Table load(IRecordStorage recordStorage) { - // fixme context var context = TransactionContext.empty(); var meta = recordStorage.getMetadata(context); var stream = new ByteArrayInputStream(meta); @@ -146,20 +151,17 @@ public static Table load(IRecordStorage recordStorage) { var next = in.readLong(JBBPByteOrder.BIG_ENDIAN); var fieldNum = in.readInt(JBBPByteOrder.BIG_ENDIAN); var fieldList = new ArrayList(); - var table = new Table(name, fieldList); + var table = new Table(name, fieldList, recordStorage.getIdentifiedName().substring(4)); for (int i = 0; i < fieldNum; i++) { var f = BaseField.load(stream, table); - if (f != null) { - fieldList.add(f); - } + fieldList.add(f); } table.next = next; table.status = TableStatus.valueOf(status); return table; - } catch (IOException e) { - e.printStackTrace(); + } catch (IOException | IndexNotFoundException e) { + throw new RuntimeException(e); } - return null; } /** @@ -289,9 +291,9 @@ public Optional> read(TransactionContext context, long uuid) throws try { return Optional.of(parseEntry(bytes.get())); } catch (IOException e) { - // fixme 不该出现这样的事情(吧) // 查询到的entry和当前表冲突 - throw new TableConflictException(3); } + throw new TableConflictException(3); + } } else { return Optional.empty(); } diff --git a/src/main/java/net/kaaass/rumbase/table/TableManager.java b/src/main/java/net/kaaass/rumbase/table/TableManager.java index 8ecdc38..ecb925a 100644 --- a/src/main/java/net/kaaass/rumbase/table/TableManager.java +++ b/src/main/java/net/kaaass/rumbase/table/TableManager.java @@ -1,18 +1,18 @@ package net.kaaass.rumbase.table; -import com.igormaznitsa.jbbp.io.JBBPBitInputStream; -import com.igormaznitsa.jbbp.io.JBBPBitOutputStream; -import com.igormaznitsa.jbbp.io.JBBPByteOrder; import lombok.Getter; +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.table.exception.TableConflictException; import net.kaaass.rumbase.table.field.BaseField; import net.kaaass.rumbase.table.exception.TableExistenceException; +import net.kaaass.rumbase.table.field.VarcharField; import net.kaaass.rumbase.transaction.TransactionContext; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; +import java.io.File; import java.util.*; /** @@ -28,7 +28,14 @@ public class TableManager { - private final IRecordStorage metaRecord = RecordManager.fromFile("metadata.db"); + static { + var dataDir = new File("data/"); + if (!dataDir.exists() && !dataDir.isDirectory()) { + dataDir.mkdirs(); + } + } + + private final IRecordStorage metaRecord = RecordManager.fromFile("data/metadata.db"); /** * 对所有的表结构的缓存 @@ -61,40 +68,63 @@ public void abort(TransactionContext context) { context.rollback(); } - public TableManager() { + public TableManager() throws TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException, IndexAlreadyExistException { load(); } - public void load() { + public void load() throws TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException, IndexAlreadyExistException { var context = TransactionContext.empty(); - var meta = metaRecord.getMetadata(context); + Table metaTable; + try { + metaTable = Table.load(metaRecord); + tableCache.put("metadata", metaTable); + } catch (RuntimeException e) { + // 新建表 + var fields = new ArrayList(); + var keyField = new VarcharField("key", 255, false, null); + var valueField = new VarcharField("value", 255, false, null); + fields.add(keyField); + fields.add(valueField); + + var dataDir = new File("data/"); + if (!dataDir.exists() && !dataDir.isDirectory()) { + dataDir.mkdirs(); + } - var byteInStream = new ByteArrayInputStream(meta); - var stream = new JBBPBitInputStream(byteInStream); + metaTable = new Table("metadata", fields, "data/metadata.db"); - int num; - try { - num = stream.readInt(JBBPByteOrder.BIG_ENDIAN); - } catch (IOException e) { - return; + for (var f: fields) { + f.setParentTable(metaTable); + } + + keyField.createIndex("data/"); + + metaTable.persist(context); + tableCache.put("metadata", metaTable); } - for (int i = 0; i < num; i++) { - try { - var key = stream.readString(JBBPByteOrder.BIG_ENDIAN); - var val = stream.readString(JBBPByteOrder.BIG_ENDIAN); - // 加载表 - if (key.startsWith("tablePath$")) { - var tableName = key.split("\\$")[1]; - var record = RecordManager.fromFile(val); - recordPaths.add(val); - var table = Table.load(record); - tableCache.put(tableName, table); - } - } catch (IOException e) { - e.printStackTrace(); + var data = metaTable.readAll(context); + 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'"); + }}); + map.put("table_num", "0"); + } + + for (var item: map.entrySet()) { + if (item.getKey().startsWith("tablePath$")) { + var tableName = item.getKey().split("\\$")[1]; + var record = RecordManager.fromFile(item.getValue()); + recordPaths.add(item.getValue()); + var table = Table.load(record); + tableCache.put(tableName, table); } } + } /** @@ -123,11 +153,16 @@ public void createTable( String tableName, List baseFields, String path - ) throws TableExistenceException { + ) throws TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { if (tableCache.containsKey(tableName)) { throw new TableExistenceException(1); } + var tableDir = new File("data/table/"); + if (!tableDir.exists() && !tableDir.isDirectory()) { + tableDir.mkdirs(); + } + var table = new Table(tableName, baseFields, path); for (var f: baseFields) { @@ -136,30 +171,37 @@ public void createTable( table.persist(context); - var meta = metaRecord.getMetadata(TransactionContext.empty()); + var metaTable = tableCache.get("metadata"); - var in = new ByteArrayInputStream(meta); - var inStream = new JBBPBitInputStream(in); - - int cnt; - try { - cnt = inStream.readInt(JBBPByteOrder.BIG_ENDIAN); + var uuids = metaTable.search("key", "table_num"); - } catch (IOException e) { - cnt = 0; + int cnt = -1; + long cntUuid = -1; + for (var uuid: uuids) { + var res = metaTable.read(TransactionContext.empty(), uuid); + if (res.isPresent()) { + cnt = Integer.parseInt((String) res.get().get(1)); + cntUuid = uuid; + break; + } } - var byteOutStream = new ByteArrayOutputStream(); - var stream = new JBBPBitOutputStream(byteOutStream); - try { - stream.writeInt(cnt + 1, JBBPByteOrder.BIG_ENDIAN); - stream.write(in.readAllBytes()); - stream.writeString("tablePath$" + tableName, JBBPByteOrder.BIG_ENDIAN); - stream.writeString(path, JBBPByteOrder.BIG_ENDIAN); - } catch (IOException e) { - e.printStackTrace(); + if (cnt == -1 || cntUuid == -1 ) { + throw new RuntimeException(); } + cnt = cnt + 1; + var newCntEntry = new ArrayList(); + newCntEntry.add("'table_num'"); + newCntEntry.add("'" + Integer.toString(cnt) + "'"); + metaTable.update(TransactionContext.empty(), cntUuid, newCntEntry); + + var newTableData = new ArrayList(); + newTableData.add("'tablePath$" + tableName + "'"); + newTableData.add("'" + path + "'"); + + metaTable.insert(TransactionContext.empty(), newTableData); + tableCache.put(tableName, table); } diff --git a/src/main/java/net/kaaass/rumbase/table/field/BaseField.java b/src/main/java/net/kaaass/rumbase/table/field/BaseField.java index 40dc924..a0264ed 100644 --- a/src/main/java/net/kaaass/rumbase/table/field/BaseField.java +++ b/src/main/java/net/kaaass/rumbase/table/field/BaseField.java @@ -6,10 +6,12 @@ import net.kaaass.rumbase.index.Index; import net.kaaass.rumbase.index.Pair; import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; +import net.kaaass.rumbase.index.exception.IndexNotFoundException; import net.kaaass.rumbase.table.Table; import net.kaaass.rumbase.table.exception.TableConflictException; import net.kaaass.rumbase.table.exception.TableExistenceException; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -66,11 +68,17 @@ public abstract class BaseField{ /** * 当前列所属的表 */ - @NonNull @Getter @Setter private Table parentTable; + public BaseField(@NonNull String name, @NonNull FieldType type, boolean nullable, Table parentTable) { + this.name = name; + this.type = type; + this.nullable = nullable; + this.parentTable = parentTable; + } + /** * 向输出流中写入当前字段格式信息 *

@@ -99,7 +107,7 @@ public abstract class BaseField{ * @param stream 输入流 * @return 字段 */ - public static BaseField load(InputStream stream, Table table) { + public static BaseField load(InputStream stream, Table table) throws IndexNotFoundException { var in = new JBBPBitInputStream(stream); try { @@ -112,28 +120,34 @@ public static BaseField load(InputStream stream, Table table) { if (indexed) { indexName = in.readString(JBBPByteOrder.BIG_ENDIAN); } - // todo 重建索引 BaseField field; switch (type) { case INT: field = new IntField(name, nullable, table); field.setIndexName(indexName); + if (indexed) { + field.index = Index.getIndex(indexName); + } return field; case FLOAT: field = new FloatField(name, nullable, table); field.setIndexName(indexName); + if (indexed) { + field.index = Index.getIndex(indexName); + } return field; default: field = new VarcharField(name, in.readInt(JBBPByteOrder.BIG_ENDIAN), nullable, table); field.setIndexName(indexName); + if (indexed) { + field.index = Index.getIndex(indexName); + } return field; } } catch (IOException e) { - // todo - e.printStackTrace(); + throw new RuntimeException(e); } - return null; } /** @@ -209,11 +223,38 @@ public static BaseField load(InputStream stream, Table table) { */ public void createIndex() throws IndexAlreadyExistException { var delimiter = "$"; - var indexName = parentTable.getPath() + delimiter + name; + + var indexDir = new File("data/index/"); + if (!indexDir.exists() && !indexDir.isDirectory()) { + indexDir.mkdirs(); + } + + indexName = "data/index/" + parentTable.getTableName() + delimiter + name; + + index = Index.createEmptyIndex(indexName); + } + + + /** + * 创建索引 + * + * @throws IndexAlreadyExistException 索引已存在 + */ + public void createIndex(String path) throws IndexAlreadyExistException { + var delimiter = "$"; + + var indexDir = new File(path); + if (!indexDir.exists() && !indexDir.isDirectory()) { + indexDir.mkdirs(); + } + + indexName = path + parentTable.getTableName() + delimiter + name; index = Index.createEmptyIndex(indexName); } + + /** * 向索引插入一个键值对 * @param value 值对象 diff --git a/src/main/java/net/kaaass/rumbase/table/field/FloatField.java b/src/main/java/net/kaaass/rumbase/table/field/FloatField.java index d8539d2..a8c09b5 100644 --- a/src/main/java/net/kaaass/rumbase/table/field/FloatField.java +++ b/src/main/java/net/kaaass/rumbase/table/field/FloatField.java @@ -24,7 +24,7 @@ */ public class FloatField extends BaseField { - public FloatField(@NonNull String name, boolean nullable, @NonNull Table parentTable) { + public FloatField(@NonNull String name, boolean nullable, Table parentTable) { super(name, FieldType.FLOAT, nullable, parentTable); } @@ -37,7 +37,7 @@ public void persist(OutputStream stream) { out.writeString(getName(), JBBPByteOrder.BIG_ENDIAN); out.writeString(getType().toString().toUpperCase(Locale.ROOT), JBBPByteOrder.BIG_ENDIAN); var flags = new byte[]{0}; - flags[0] |= indexed() ? 1 : 0; + flags[0] |= isNullable() ? 1 : 0; if (indexed()) { flags[0] |= 2; out.writeBytes(flags, 1, JBBPByteOrder.BIG_ENDIAN); @@ -45,7 +45,6 @@ public void persist(OutputStream stream) { } else { out.writeBytes(flags, 1, JBBPByteOrder.BIG_ENDIAN); } - // todo (字段约束) } catch (IOException e) { e.printStackTrace(); } @@ -185,8 +184,7 @@ public void serialize(OutputStream outputStream, String strVal) throws TableConf } } catch (IOException e) { - // fixme 这个给外面可能也不知道如何处理 - throw new RuntimeException(); + throw new RuntimeException(e); } catch (NumberFormatException e) { throw new TableConflictException(1); } @@ -210,8 +208,7 @@ public void serialize(OutputStream outputStream, Object objVal) throws TableConf } } catch (IOException e) { - // fixme 这个给外面可能也不知道如何处理 - throw new RuntimeException(); + throw new RuntimeException(e); } catch (NumberFormatException e) { throw new TableConflictException(1); } diff --git a/src/main/java/net/kaaass/rumbase/table/field/IntField.java b/src/main/java/net/kaaass/rumbase/table/field/IntField.java index 110a879..da204e6 100644 --- a/src/main/java/net/kaaass/rumbase/table/field/IntField.java +++ b/src/main/java/net/kaaass/rumbase/table/field/IntField.java @@ -23,7 +23,7 @@ */ public class IntField extends BaseField { - public IntField(@NonNull String name, boolean nullable, @NonNull Table parentTable) { + public IntField(@NonNull String name, boolean nullable, Table parentTable) { super(name, FieldType.INT, nullable, parentTable); } @@ -35,7 +35,7 @@ public void persist(OutputStream stream) { out.writeString(getName(), JBBPByteOrder.BIG_ENDIAN); out.writeString(getType().toString().toUpperCase(Locale.ROOT), JBBPByteOrder.BIG_ENDIAN); var flags = new byte[]{0}; - flags[0] |= indexed() ? 1 : 0; + flags[0] |= isNullable() ? 1 : 0; if (indexed()) { flags[0] |= 2; out.writeBytes(flags, 1, JBBPByteOrder.BIG_ENDIAN); @@ -43,7 +43,6 @@ public void persist(OutputStream stream) { } else { out.writeBytes(flags, 1, JBBPByteOrder.BIG_ENDIAN); } - // todo (字段约束) } catch (IOException e) { e.printStackTrace(); } @@ -183,8 +182,7 @@ public void serialize(OutputStream outputStream, String strVal) throws TableConf } catch (IOException e) { - // fixme 这个给外面可能也不知道如何处理 - throw new RuntimeException(); + throw new RuntimeException(e); } catch (NumberFormatException e) { throw new TableConflictException(1); } @@ -208,8 +206,7 @@ public void serialize(OutputStream outputStream, Object objVal) throws TableConf } } catch (IOException e) { - // fixme 这个给外面可能也不知道如何处理 - throw new RuntimeException(); + throw new RuntimeException(e); } catch (NumberFormatException e) { throw new TableConflictException(1); } diff --git a/src/main/java/net/kaaass/rumbase/table/field/VarcharField.java b/src/main/java/net/kaaass/rumbase/table/field/VarcharField.java index 93e96e9..24d57c4 100644 --- a/src/main/java/net/kaaass/rumbase/table/field/VarcharField.java +++ b/src/main/java/net/kaaass/rumbase/table/field/VarcharField.java @@ -33,7 +33,7 @@ public class VarcharField extends BaseField { private static final String DELIMIT = "'"; - public VarcharField(@NonNull String name, int limit, boolean nullable, @NonNull Table parentTable) { + public VarcharField(@NonNull String name, int limit, boolean nullable, Table parentTable) { super(name, FieldType.VARCHAR, nullable, parentTable); this.limit = limit; } @@ -46,7 +46,7 @@ public void persist(OutputStream stream) { out.writeString(getName(), JBBPByteOrder.BIG_ENDIAN); out.writeString(getType().toString().toUpperCase(Locale.ROOT), JBBPByteOrder.BIG_ENDIAN); var flags = new byte[]{0}; - flags[0] |= indexed() ? 1 : 0; + flags[0] |= isNullable() ? 1 : 0; if (indexed()) { flags[0] |= 2; out.writeBytes(flags, 1, JBBPByteOrder.BIG_ENDIAN); @@ -55,7 +55,6 @@ public void persist(OutputStream stream) { out.writeBytes(flags, 1, JBBPByteOrder.BIG_ENDIAN); } out.writeInt(limit, JBBPByteOrder.BIG_ENDIAN); - // todo (字段约束) } catch (IOException e) { e.printStackTrace(); } @@ -77,6 +76,11 @@ public long strToHash(String str) { return 0; } + if (str.startsWith(DELIMIT) && str.endsWith(DELIMIT)) { + var substr = str.substring(1, str.length() - 1); + return substr.hashCode(); + } + return str.hashCode(); } @@ -164,7 +168,6 @@ public void serialize(OutputStream outputStream, String strVal) throws TableConf } } catch (IOException e) { - // fixme 这个给外面可能也不知道如何处理 throw new RuntimeException(e); } } @@ -187,7 +190,6 @@ public void serialize(OutputStream outputStream, Object val) throws TableConflic } } catch (IOException e) { - // fixme 这个给外面可能也不知道如何处理 throw new RuntimeException(e); } catch (ClassCastException e){ throw new TableConflictException(1); diff --git a/src/main/java/net/kaaass/rumbase/transaction/TransactionManagerImpl.java b/src/main/java/net/kaaass/rumbase/transaction/TransactionManagerImpl.java index 2b6f1b5..e2d7a6e 100644 --- a/src/main/java/net/kaaass/rumbase/transaction/TransactionManagerImpl.java +++ b/src/main/java/net/kaaass/rumbase/transaction/TransactionManagerImpl.java @@ -61,7 +61,7 @@ public class TransactionManagerImpl implements TransactionManager { * 事务管理器 */ public TransactionManagerImpl() throws IOException, FileException { - this("xid.log"); + this("data/xid.log"); } /** diff --git a/src/test/java/net/kaaass/rumbase/FileUtil.java b/src/test/java/net/kaaass/rumbase/FileUtil.java new file mode 100644 index 0000000..16a2be5 --- /dev/null +++ b/src/test/java/net/kaaass/rumbase/FileUtil.java @@ -0,0 +1,55 @@ +package net.kaaass.rumbase; + +import lombok.extern.slf4j.Slf4j; + +import java.io.File; + +/** + * 单元测试常见文件操作 + */ +@Slf4j +public class FileUtil { + public final static String DATA_PATH = "data/"; + public final static String TABLE_PATH = "data/table/"; + public static final String TEST_PATH = "test_gen_files/"; + + public static void prepare() { + log.info("创建测试文件夹..."); + FileUtil.createDir(FileUtil.TEST_PATH); + FileUtil.createDir(FileUtil.DATA_PATH); + FileUtil.createDir(FileUtil.TABLE_PATH); + } + + public static void clear() { + log.info("清除测试文件夹..."); + FileUtil.removeDir(FileUtil.TEST_PATH); + FileUtil.removeDir(FileUtil.DATA_PATH); + FileUtil.removeDir(FileUtil.TABLE_PATH); + } + + public static void createDir(String path) { + File dir = new File(path); + if (dir.exists()) { + FileUtil.removeDir(dir); + } + assert dir.mkdirs(); + } + + public static void removeDir(String path) { + removeDir(new File(path)); + } + + public static void removeDir(File dir) { + File[] files = dir.listFiles(); + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + removeDir(file); + } else { + assert file.delete(); + } + } + } + dir.delete(); + } +} diff --git a/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java b/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java index 3cdbb00..cd6f433 100644 --- a/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java +++ b/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java @@ -2,11 +2,16 @@ 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; import net.kaaass.rumbase.page.exception.PageException; 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.IOException; import java.util.ArrayList; @@ -15,6 +20,7 @@ import java.util.Random; import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.fail; /** * 对数据项管理部分进行测试 @@ -24,13 +30,24 @@ */ @Slf4j -public class IItemStorageTest extends TestCase { +public class IItemStorageTest { - private static final String PATH = "build/"; + @BeforeClass + public static void createDataFolder() { + FileUtil.prepare(); + } + + @AfterClass + public static void clearDataFolder() { + FileUtil.clear(); + } + + private static final String PATH = FileUtil.TEST_PATH; /** * 测试能否从已有文件中解析得到数据项管理器 */ + @Test public void testGetFromFile() throws FileException, IOException, PageException { String fileName = PATH + "testGetFromFile.db"; var itemStorage = ItemManager.fromFile(fileName); @@ -46,6 +63,7 @@ public void testGetFromFile() throws FileException, IOException, PageException { /** * 测试能否新建文件并得到数据项管理器 */ + @Test public void testCreateFile() throws IOException, FileException, PageException { TransactionContext txContext = TransactionContext.empty(); String fileName = PATH + "testCreateFile.db"; @@ -64,6 +82,7 @@ public void testCreateFile() throws IOException, FileException, PageException { /** * 进行插入的测试 */ + @Test public void testInsert() throws FileException, IOException, PageException, UUIDException, PageCorruptedException { String fileName = PATH + "testInsert.db"; IItemStorage iItemStorage = ItemManager.fromFile(fileName); @@ -81,6 +100,7 @@ public void testInsert() throws FileException, IOException, PageException, UUIDE /** * 对插入一个已分配UUID的测试 */ + @Test public void testInsertWithUUID() throws FileException, IOException, PageException { String fileName = PATH + "testInsertWithUUID.db"; IItemStorage iItemStorage = ItemManager.fromFile(fileName); @@ -105,6 +125,7 @@ public void testInsertWithUUID() throws FileException, IOException, PageExceptio /** * 对插入大量数据进行测试 */ + @Test public void testManyInsert() throws FileException, IOException, PageException, UUIDException, PageCorruptedException { String fileName = PATH + "testInsertMany.db"; IItemStorage iItemStorage = ItemManager.fromFile(fileName); @@ -125,6 +146,7 @@ public void testManyInsert() throws FileException, IOException, PageException, U /** * 获取整个页的数据项进行测试 */ + @Test public void testQueryByPageID() throws FileException, IOException, PageException, PageCorruptedException { String fileName = PATH + "testQueryByPageID.db"; IItemStorage iItemStorage = ItemManager.fromFile(fileName); @@ -188,6 +210,7 @@ public void run() { /** * 测试并发下插入是否有问题 */ + @Test public void testSynInsert() throws IOException, FileException, PageException { String fileName = PATH + "testInsert.db"; IItemStorage iItemStorage = ItemManager.fromFile(fileName); @@ -203,6 +226,7 @@ public void testSynInsert() throws IOException, FileException, PageException { /** * 对更新进行测试 */ + @Test public void testUpdate() throws FileException, IOException, PageException, UUIDException, PageCorruptedException { String fileName = PATH + "testUpdate.db"; TransactionContext txContext = TransactionContext.empty(); @@ -230,6 +254,7 @@ public void testUpdate() throws FileException, IOException, PageException, UUIDE /** * 测试修改和获取表头信息 */ + @Test public void testMeta() throws FileException, IOException, PageException, UUIDException, PageCorruptedException { String fileName = PATH + "testMeta.db"; IItemStorage iItemStorage = ItemManager.fromFile(fileName); diff --git a/src/test/java/net/kaaass/rumbase/index/BTreeTest.java b/src/test/java/net/kaaass/rumbase/index/BTreeTest.java index e9ab737..6e8be60 100644 --- a/src/test/java/net/kaaass/rumbase/index/BTreeTest.java +++ b/src/test/java/net/kaaass/rumbase/index/BTreeTest.java @@ -2,8 +2,13 @@ import junit.framework.TestCase; import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.FileUtil; import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; import net.kaaass.rumbase.index.exception.IndexNotFoundException; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; import java.io.File; import java.util.Iterator; @@ -16,12 +21,23 @@ * @see net.kaaass.rumbase.index.BTreeTest */ @Slf4j -public class BTreeTest extends TestCase { - public static final String fileDir = "build/"; +public class BTreeTest { + public static final String fileDir = FileUtil.TEST_PATH; + + @BeforeClass + public static void createDataFolder() { + FileUtil.prepare(); + } + + @AfterClass + public static void clearDataFolder() { + FileUtil.clear(); + } /** * 测试索引的插入与第一个迭代器功能 */ + @Test public void testInsert() { Index testIndex = null; try { @@ -42,7 +58,7 @@ public void testInsert() { // 测试数据是否符合预期 int cnt = 0; for (var pair : testIndex) { - assertEquals(cnt / 2, + Assert.assertEquals(cnt / 2, pair.getKey()); // log.debug("{}", pair); cnt++; @@ -52,6 +68,7 @@ public void testInsert() { /** * 测试不按顺寻key插入的情况 */ + @Test public void testInsertRandomKey() { Index testIndex = null; try { @@ -72,7 +89,7 @@ public void testInsertRandomKey() { // 测试数据是否符合预期 int cnt = 0; for (var pair : testIndex) { - assertEquals(cnt / 2, + Assert.assertEquals(cnt / 2, pair.getKey()); // log.debug("{}", pair); cnt++; @@ -82,6 +99,7 @@ public void testInsertRandomKey() { /** * 测试索引的查询功能 */ + @Test public void testQuery() { Index testIndex = null; @@ -110,18 +128,18 @@ public void testQuery() { // 测试 findFirst 方法 // keyHash在内的迭代器 1122->334455 Iterator it1 = testIndex.findFirst(3); - assertTrue(it1.hasNext()); - assertEquals(3, it1.next().getKey()); - assertEquals(3, it1.next().getKey()); - assertEquals(4, it1.next().getKey()); + Assert.assertTrue(it1.hasNext()); + Assert.assertEquals(3, it1.next().getKey()); + Assert.assertEquals(3, it1.next().getKey()); + Assert.assertEquals(4, it1.next().getKey()); // 测试 findUpperbound 方法 // 不包括keyHash在内的迭代器 112233->4455 Iterator it2 = testIndex.findUpperbound(3); - assertTrue(it2.hasNext()); - assertEquals(4, it2.next().getKey()); - assertEquals(4, it2.next().getKey()); - assertEquals(5, it2.next().getKey()); + Assert.assertTrue(it2.hasNext()); + Assert.assertEquals(4, it2.next().getKey()); + Assert.assertEquals(4, it2.next().getKey()); + Assert.assertEquals(5, it2.next().getKey()); // 测试 query 方法 var results = testIndex.query(4); @@ -133,6 +151,7 @@ public void testQuery() { /** * 测试multiKey索引的查询功能 */ + @Test public void testMultiKeyQuery() { Index testIndex = null; @@ -166,18 +185,18 @@ public void testMultiKeyQuery() { // 测试 findFirst 方法 // keyHash在内的迭代器 1122->334455 Iterator it1 = testIndex.findFirst(3); - assertTrue(it1.hasNext()); - assertEquals(3, it1.next().getKey()); - assertEquals(3, it1.next().getKey()); - assertEquals(3, it1.next().getKey()); + Assert.assertTrue(it1.hasNext()); + Assert.assertEquals(3, it1.next().getKey()); + Assert.assertEquals(3, it1.next().getKey()); + Assert.assertEquals(3, it1.next().getKey()); // 测试 findUpperbound 方法 // 不包括keyHash在内的迭代器 112233->4455 Iterator it2 = testIndex.findUpperbound(3); - assertTrue(it2.hasNext()); - assertEquals(4, it2.next().getKey()); - assertEquals(4, it2.next().getKey()); - assertEquals(4, it2.next().getKey()); + Assert.assertTrue(it2.hasNext()); + Assert.assertEquals(4, it2.next().getKey()); + Assert.assertEquals(4, it2.next().getKey()); + Assert.assertEquals(4, it2.next().getKey()); for (int i = 0; i < 3; i++) { log.debug("{}", it2.next().getUuid()); } diff --git a/src/test/java/net/kaaass/rumbase/index/ConcurrentIndexTest.java b/src/test/java/net/kaaass/rumbase/index/ConcurrentIndexTest.java index c06af40..db7d77f 100644 --- a/src/test/java/net/kaaass/rumbase/index/ConcurrentIndexTest.java +++ b/src/test/java/net/kaaass/rumbase/index/ConcurrentIndexTest.java @@ -2,18 +2,34 @@ import junit.framework.TestCase; import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.FileUtil; import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; import java.io.File; import java.util.Random; @Slf4j -public class ConcurrentIndexTest extends TestCase { - public static final String fileDir = "build/"; +public class ConcurrentIndexTest { + public static final String fileDir = FileUtil.TEST_PATH; + + @BeforeClass + public static void createDataFolder() { + FileUtil.prepare(); + } + + @AfterClass + public static void clearDataFolder() { + FileUtil.clear(); + } /** * 测试索引的并发功能 */ + @Test public void test() { Index testIndex = null; try { @@ -50,7 +66,7 @@ public void test() { // 测试数据是否符合预期 int cnt = 0; for (var pair : testIndex) { - assertEquals(cnt / 2, + Assert.assertEquals(cnt / 2, pair.getKey()); //log.debug("{}", pair); cnt++; @@ -60,6 +76,7 @@ public void test() { /** * 测试索引的更复杂的并发功能 */ + @Test public void testComplex() { Index testIndex = null; try { @@ -108,7 +125,7 @@ public void testComplex() { // 测试数据是否符合预期 int cnt = 0; for (var pair : testIndex) { - assertEquals(cnt / 3, + Assert.assertEquals(cnt / 3, pair.getKey()); //log.debug("{}", pair); cnt++; diff --git a/src/test/java/net/kaaass/rumbase/index/IndexTest.java b/src/test/java/net/kaaass/rumbase/index/IndexTest.java index 597d7aa..425401f 100644 --- a/src/test/java/net/kaaass/rumbase/index/IndexTest.java +++ b/src/test/java/net/kaaass/rumbase/index/IndexTest.java @@ -2,8 +2,13 @@ import junit.framework.TestCase; import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.FileUtil; import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; import net.kaaass.rumbase.index.exception.IndexNotFoundException; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; import java.io.File; import java.util.ArrayList; @@ -18,12 +23,23 @@ * @see net.kaaass.rumbase.index.Index */ @Slf4j -public class IndexTest extends TestCase { - public static final String fileDir = "build/"; +public class IndexTest { + public static final String fileDir = FileUtil.TEST_PATH; + + @BeforeClass + public static void createDataFolder() { + FileUtil.prepare(); + } + + @AfterClass + public static void clearDataFolder() { + FileUtil.clear(); + } /** * 测试索引的插入与第一个迭代器功能 */ + @Test public void testInsert() { Index testIndex = null; var standardRand = new ArrayList(); @@ -45,7 +61,7 @@ public void testInsert() { // 测试数据是否符合预期 int cnt = 0; for (var pair : testIndex) { - assertEquals(standardRand.get(cnt).longValue(), + Assert.assertEquals(standardRand.get(cnt).longValue(), pair.getUuid()); cnt++; } @@ -54,6 +70,7 @@ public void testInsert() { /** * 测试索引的查询功能 */ + @Test public void testQuery() { Index testIndex = null; var standardRand = new ArrayList(); @@ -85,28 +102,28 @@ public void testQuery() { // 测试 findFirst 方法 // keyHash在内的迭代器 1122->334455 Iterator it1 = testIndex.findFirst(3); - assertTrue(it1.hasNext()); + Assert.assertTrue(it1.hasNext()); var expected = List.of( standardRand.get(2 * 2), standardRand.get(2 * 2 + 1) ); - assertTrue(expected.contains(it1.next().getUuid())); - assertTrue(expected.contains(it1.next().getUuid())); + Assert.assertTrue(expected.contains(it1.next().getUuid())); + Assert.assertTrue(expected.contains(it1.next().getUuid())); // 测试 findUpperbound 方法 // 不包括keyHash在内的迭代器 112233->4455 Iterator it2 = testIndex.findUpperbound(3); - assertTrue(it2.hasNext()); + Assert.assertTrue(it2.hasNext()); expected = List.of( standardRand.get(2), standardRand.get(2 + 1) ); - assertTrue(expected.contains(it2.next().getUuid())); - assertTrue(expected.contains(it2.next().getUuid())); + Assert.assertTrue(expected.contains(it2.next().getUuid())); + Assert.assertTrue(expected.contains(it2.next().getUuid())); // 测试 query 方法 var results = testIndex.query(4); - assertTrue(results.contains(standardRand.get(2))); - assertTrue(results.contains(standardRand.get(2 + 1))); + Assert.assertTrue(results.contains(standardRand.get(2))); + Assert.assertTrue(results.contains(standardRand.get(2 + 1))); } } diff --git a/src/test/java/net/kaaass/rumbase/page/PageStorageTest.java b/src/test/java/net/kaaass/rumbase/page/PageStorageTest.java index 15c1c8e..6a3d08a 100644 --- a/src/test/java/net/kaaass/rumbase/page/PageStorageTest.java +++ b/src/test/java/net/kaaass/rumbase/page/PageStorageTest.java @@ -1,8 +1,13 @@ package net.kaaass.rumbase.page; import junit.framework.TestCase; +import net.kaaass.rumbase.FileUtil; import net.kaaass.rumbase.page.exception.FileException; import net.kaaass.rumbase.page.exception.PageException; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; import java.io.File; import java.io.FileInputStream; @@ -17,9 +22,20 @@ * @author XuanLaoYee * @see net.kaaass.rumbase.page.PageStorage */ -public class PageStorageTest extends TestCase { - public static String filePath = "build/pageTest.db"; +public class PageStorageTest { + public static String filePath = FileUtil.TEST_PATH + "pageTest.db"; + @BeforeClass + public static void createDataFolder() { + FileUtil.prepare(); + } + + @AfterClass + public static void clearDataFolder() { + FileUtil.clear(); + } + + @Test public void testGet() throws IOException { PageStorage rps = null; try { @@ -49,7 +65,7 @@ public void testGet() throws IOException { in.skip((11 + PageManager.FILE_HEAD_SIZE) * PageManager.PAGE_SIZE); int readNumber = in.read(dataFromFile); p11.getData().read(dataFromPage); - assertEquals(readNumber, PageManager.PAGE_SIZE); + Assert.assertEquals(readNumber, PageManager.PAGE_SIZE); assertArrayEquals(dataFromPage, dataFromFile); } catch (Exception e) { throw e; @@ -59,6 +75,7 @@ public void testGet() throws IOException { } } + @Test public void testWriteToFile() throws FileException, PageException { PageStorage storage = PageManager.fromFile(filePath); int[] testPage = new int[]{1, 3, 5, 7, 10, 11}; @@ -85,6 +102,7 @@ public void testWriteToFile() throws FileException, PageException { } } + @Test public void testFlush() throws PageException { PageStorage rps = null; try { @@ -152,6 +170,7 @@ public void testFlush() throws PageException { assertArrayEquals(data4, dataFromFile4); } + @Test public void testFlushAll() throws FileException, PageException { PageStorage storage = PageManager.fromFile(filePath); int[] testPage = new int[]{1, 3, 5, 7, 10, 11}; diff --git a/src/test/java/net/kaaass/rumbase/page/PageTest.java b/src/test/java/net/kaaass/rumbase/page/PageTest.java index 1832c99..3f28b21 100644 --- a/src/test/java/net/kaaass/rumbase/page/PageTest.java +++ b/src/test/java/net/kaaass/rumbase/page/PageTest.java @@ -1,9 +1,13 @@ package net.kaaass.rumbase.page; import junit.framework.TestCase; +import net.kaaass.rumbase.FileUtil; import net.kaaass.rumbase.page.exception.FileException; import net.kaaass.rumbase.page.exception.PageException; +import org.junit.AfterClass; import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; import java.io.File; import java.io.FileInputStream; @@ -18,8 +22,20 @@ * @author XuanLaoYee * @see net.kaaass.rumbase.page.Page */ -public class PageTest extends TestCase { - public static String filePath = "build/pageTest.db"; +public class PageTest { + public static String filePath = FileUtil.TEST_PATH + "pageTest.db"; + + @BeforeClass + public static void createDataFolder() { + FileUtil.prepare(); + } + + @AfterClass + public static void clearDataFolder() { + FileUtil.clear(); + } + + @Test public void testPatchData() { int offset = 99; byte[] data = new byte[PageManager.PAGE_SIZE - offset]; @@ -41,6 +57,7 @@ public void testPatchData() { } } + @Test public void testPatchOffset() throws FileException, PageException { var storage = PageManager.fromFile(filePath); var rand = new Random(); @@ -62,7 +79,7 @@ public void testPatchOffset() throws FileException, PageException { // 检查写入效果 var pageData = page.getDataBytes(); for (int j = st; j < ed; j++) { - assertEquals((byte) st, pageData[j]); + Assert.assertEquals((byte) st, pageData[j]); } } } finally { diff --git a/src/test/java/net/kaaass/rumbase/query/CreateIndexExecutorTest.java b/src/test/java/net/kaaass/rumbase/query/CreateIndexExecutorTest.java index 861fe15..0a52345 100644 --- a/src/test/java/net/kaaass/rumbase/query/CreateIndexExecutorTest.java +++ b/src/test/java/net/kaaass/rumbase/query/CreateIndexExecutorTest.java @@ -2,100 +2,108 @@ import junit.framework.TestCase; import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.FileUtil; import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; import net.kaaass.rumbase.parse.SqlParser; import net.kaaass.rumbase.parse.exception.SqlSyntaxException; import net.kaaass.rumbase.parse.stmt.CreateIndexStatement; -import net.kaaass.rumbase.table.Table; +import net.kaaass.rumbase.query.exception.ArgumentException; +import net.kaaass.rumbase.record.exception.RecordNotFoundException; import net.kaaass.rumbase.table.TableManager; +import net.kaaass.rumbase.table.exception.TableConflictException; import net.kaaass.rumbase.table.exception.TableExistenceException; import net.kaaass.rumbase.table.field.BaseField; import net.kaaass.rumbase.table.field.IntField; import net.kaaass.rumbase.table.field.VarcharField; 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.util.ArrayList; @Slf4j -public class CreateIndexExecutorTest extends TestCase { +public class CreateIndexExecutorTest { - private static final String PATH = "build/"; + @BeforeClass + @AfterClass + public static void clearDataFolder() { + log.info("清除数据文件夹..."); + FileUtil.removeDir(FileUtil.DATA_PATH); + } - public void testParseSingle() throws SqlSyntaxException { + @Test + public void testParseSingle() throws SqlSyntaxException, IndexAlreadyExistException, TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { var sql = "CREATE INDEX PersonIndex ON testParseSingle$Person (LastName) ;"; // 解析 var stmt = SqlParser.parseStatement(sql); - assertTrue(stmt instanceof CreateIndexStatement); + Assert.assertTrue(stmt instanceof CreateIndexStatement); // 准备预期结果 var manager = new TableManager(); var context = TransactionContext.empty(); var fields = new ArrayList(); - var dummy = new Table("testParseSingle.__reserved__", fields); - fields.add(new VarcharField("LastName", 20, false, dummy)); + fields.add(new VarcharField("LastName", 20, false, null)); try { - manager.createTable(context, "testParseSingle$Person", fields, PATH + "testParseSingle.Person.db"); - } catch (TableExistenceException e) { + manager.createTable(context, "testParseSingle$Person", fields, FileUtil.TABLE_PATH + "testParseSingle.Person.db"); + } catch (TableExistenceException | RecordNotFoundException | ArgumentException | TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { var table = manager.getTable("testParseSingle$Person"); var field = table.getField("LastName"); - assertTrue(field.isPresent()); - assertFalse(field.get().indexed()); + Assert.assertTrue(field.isPresent()); + Assert.assertFalse(field.get().indexed()); - var createExe = new CreateIndexExecutor((CreateIndexStatement) stmt, manager); + var createExe = new CreateIndexExecutor((CreateIndexStatement) stmt, manager, context); createExe.execute(); - assertTrue(field.get().indexed()); - assertEquals("PersonIndex", field.get().getIndexName()); + Assert.assertTrue(field.get().indexed()); + Assert.assertEquals("data/index/testParseSingle$Person$LastName", field.get().getIndexName()); } catch (TableExistenceException | IndexAlreadyExistException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } - - new File("metadata.db").deleteOnExit(); } - public void testParseMulti() throws SqlSyntaxException { + @Test + public void testParseMulti() throws SqlSyntaxException, IndexAlreadyExistException, TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { var sql = "CREATE INDEX PersonIndex ON testParseMulti$Person (LastName, ID) ;"; // 解析 var stmt = SqlParser.parseStatement(sql); - assertTrue(stmt instanceof CreateIndexStatement); + Assert.assertTrue(stmt instanceof CreateIndexStatement); // 准备预期结果 var manager = new TableManager(); var context = TransactionContext.empty(); var fields = new ArrayList(); - var dummy = new Table("testParseMulti.__reserved__", fields); - fields.add(new VarcharField("LastName", 20, false, dummy)); - fields.add(new IntField("ID", false, dummy)); + fields.add(new VarcharField("LastName", 20, false, null)); + fields.add(new IntField("ID", false, null)); try { - manager.createTable(context, "testParseMulti$Person", fields, PATH + "testParseMulti.Person.db"); - } catch (TableExistenceException e) { + manager.createTable(context, "testParseMulti$Person", fields, FileUtil.TABLE_PATH + "testParseMulti.Person.db"); + } catch (TableExistenceException | RecordNotFoundException | ArgumentException | TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { var table = manager.getTable("testParseMulti$Person"); var field1 = table.getField("LastName"); var field2 = table.getField("ID"); - assertTrue(field1.isPresent()); - assertFalse(field1.get().indexed()); - assertTrue(field2.isPresent()); - assertFalse(field2.get().indexed()); + Assert.assertTrue(field1.isPresent()); + Assert.assertFalse(field1.get().indexed()); + Assert.assertTrue(field2.isPresent()); + Assert.assertFalse(field2.get().indexed()); - var createExe = new CreateIndexExecutor((CreateIndexStatement) stmt, manager); + var createExe = new CreateIndexExecutor((CreateIndexStatement) stmt, manager, context); createExe.execute(); - assertTrue(field1.get().indexed()); - assertFalse(field2.get().indexed()); - assertEquals("PersonIndex", field1.get().getIndexName()); + Assert.assertTrue(field1.get().indexed()); + Assert.assertFalse(field2.get().indexed()); + Assert.assertEquals("data/index/testParseMulti$Person$LastName", field1.get().getIndexName()); } catch (TableExistenceException | IndexAlreadyExistException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } - - new File("metadata.db").deleteOnExit(); } } diff --git a/src/test/java/net/kaaass/rumbase/query/CreateTableExecutorTest.java b/src/test/java/net/kaaass/rumbase/query/CreateTableExecutorTest.java index 59733fe..7c1b01d 100644 --- a/src/test/java/net/kaaass/rumbase/query/CreateTableExecutorTest.java +++ b/src/test/java/net/kaaass/rumbase/query/CreateTableExecutorTest.java @@ -2,10 +2,13 @@ import junit.framework.TestCase; import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.FileUtil; +import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; import net.kaaass.rumbase.parse.SqlParser; import net.kaaass.rumbase.parse.exception.SqlSyntaxException; import net.kaaass.rumbase.parse.stmt.CreateTableStatement; import net.kaaass.rumbase.query.exception.ArgumentException; +import net.kaaass.rumbase.record.exception.RecordNotFoundException; import net.kaaass.rumbase.table.Table; import net.kaaass.rumbase.table.TableManager; import net.kaaass.rumbase.table.exception.TableConflictException; @@ -13,13 +16,25 @@ import net.kaaass.rumbase.table.field.FieldType; import net.kaaass.rumbase.table.field.VarcharField; 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; @Slf4j -public class CreateTableExecutorTest extends TestCase { +public class CreateTableExecutorTest { - public void testCreate() throws SqlSyntaxException { + @BeforeClass + @AfterClass + public static void clearDataFolder() { + log.info("清除数据文件夹..."); + FileUtil.removeDir(new File(FileUtil.DATA_PATH)); + } + + @Test + public void testCreate() throws SqlSyntaxException, IndexAlreadyExistException, TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { var sql = "CREATE TABLE testCreate$Persons\n" + "(\n" + "Id_P int not null,\n" + @@ -28,7 +43,7 @@ public void testCreate() throws SqlSyntaxException { ")"; // 解析 var stmt = SqlParser.parseStatement(sql); - assertTrue(stmt instanceof CreateTableStatement); + Assert.assertTrue(stmt instanceof CreateTableStatement); // 执行 var manager = new TableManager(); var context = TransactionContext.empty(); @@ -37,7 +52,7 @@ public void testCreate() throws SqlSyntaxException { exe.execute(); } catch (TableExistenceException | TableConflictException | ArgumentException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 确认结果 Table table = null; @@ -45,28 +60,26 @@ public void testCreate() throws SqlSyntaxException { table = manager.getTable("testCreate$Persons"); } catch (TableExistenceException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } - assertNotNull(table); + Assert.assertNotNull(table); var fields = table.getFields(); - assertEquals(3, fields.size()); - - assertEquals("Id_P", fields.get(0).getName()); - assertEquals(FieldType.INT, fields.get(0).getType()); - assertFalse(fields.get(0).isNullable()); + Assert.assertEquals(3, fields.size()); + Assert.assertEquals("Id_P", fields.get(0).getName()); + Assert.assertEquals(FieldType.INT, fields.get(0).getType()); + Assert.assertFalse(fields.get(0).isNullable()); - assertEquals("LastName", fields.get(1).getName()); - assertEquals(FieldType.VARCHAR, fields.get(1).getType()); - assertEquals(255, ((VarcharField)fields.get(1)).getLimit()); - assertTrue(fields.get(1).isNullable()); + Assert.assertEquals("LastName", fields.get(1).getName()); + Assert.assertEquals(FieldType.VARCHAR, fields.get(1).getType()); + Assert.assertEquals(255, ((VarcharField) fields.get(1)).getLimit()); + Assert.assertTrue(fields.get(1).isNullable()); - assertEquals("FirstName", fields.get(2).getName()); - assertEquals(FieldType.VARCHAR, fields.get(2).getType()); - assertEquals(255, ((VarcharField)fields.get(1)).getLimit()); - assertFalse(fields.get(2).isNullable()); - new File("metadata.db").deleteOnExit(); + Assert.assertEquals("FirstName", fields.get(2).getName()); + Assert.assertEquals(FieldType.VARCHAR, fields.get(2).getType()); + Assert.assertEquals(255, ((VarcharField) fields.get(1)).getLimit()); + Assert.assertFalse(fields.get(2).isNullable()); } } diff --git a/src/test/java/net/kaaass/rumbase/query/DeleteExecutorTest.java b/src/test/java/net/kaaass/rumbase/query/DeleteExecutorTest.java index 322761a..0a8387d 100644 --- a/src/test/java/net/kaaass/rumbase/query/DeleteExecutorTest.java +++ b/src/test/java/net/kaaass/rumbase/query/DeleteExecutorTest.java @@ -2,6 +2,7 @@ import junit.framework.TestCase; import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.FileUtil; import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; import net.kaaass.rumbase.parse.SqlParser; import net.kaaass.rumbase.parse.exception.SqlSyntaxException; @@ -16,39 +17,48 @@ import net.kaaass.rumbase.table.field.IntField; import net.kaaass.rumbase.table.field.VarcharField; 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.util.ArrayList; @Slf4j -public class DeleteExecutorTest extends TestCase { +public class DeleteExecutorTest { - private static final String PATH = "build/"; + @BeforeClass + @AfterClass + public static void clearDataFolder() { + log.info("清除数据文件夹..."); + FileUtil.removeDir(new File(FileUtil.DATA_PATH)); + } - public void testDelete() throws SqlSyntaxException { + @Test + public void testDelete() throws SqlSyntaxException, IndexAlreadyExistException, TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { var sql = "DELETE FROM testDelete$Person WHERE LastName = 'KevinAxel'"; // 解析 var stmt = SqlParser.parseStatement(sql); - assertTrue(stmt instanceof DeleteStatement); + Assert.assertTrue(stmt instanceof DeleteStatement); var manager = new TableManager(); var context = TransactionContext.empty(); var fields = new ArrayList(); - var dummy = new Table("testDelete.__reserved__", fields); - var id = new IntField("ID", false, dummy); - fields.add(new VarcharField("LastName", 20, false, dummy)); + var id = new IntField("ID", false, null); + fields.add(new VarcharField("LastName", 20, false, null)); fields.add(id); Table table = null; try { - manager.createTable(context, "testDelete$Person", fields, PATH + "testDelete.Person.db"); + manager.createTable(context, "testDelete$Person", fields, FileUtil.TABLE_PATH + "testDelete.Person.db"); id.createIndex(); table = manager.getTable("testDelete$Person"); - } catch (TableExistenceException | IndexAlreadyExistException e) { + } catch (TableExistenceException | IndexAlreadyExistException | RecordNotFoundException | ArgumentException | TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } - assertNotNull(table); + Assert.assertNotNull(table); try { table.insert(context, new ArrayList<>() {{ add(0, "'KevinAxel'"); @@ -61,25 +71,25 @@ public void testDelete() throws SqlSyntaxException { } catch (TableConflictException | TableExistenceException | ArgumentException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 测试插入结果 try { var data = table.readAll(context); - assertEquals(2, data.size()); + Assert.assertEquals(2, data.size()); - assertEquals(2, data.get(0).size()); - assertEquals("KevinAxel", (String) data.get(0).get(0)); - assertEquals(1, (int) data.get(0).get(1)); + Assert.assertEquals(2, data.get(0).size()); + Assert.assertEquals("KevinAxel", (String) data.get(0).get(0)); + Assert.assertEquals(1, (int) data.get(0).get(1)); - assertEquals(2, data.get(1).size()); - assertEquals("KAAAsS", (String) data.get(1).get(0)); - assertEquals(2, (int) data.get(1).get(1)); + Assert.assertEquals(2, data.get(1).size()); + Assert.assertEquals("KAAAsS", (String) data.get(1).get(0)); + Assert.assertEquals(2, (int) data.get(1).get(1)); } catch (TableExistenceException | TableConflictException | ArgumentException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 执行 @@ -88,51 +98,48 @@ public void testDelete() throws SqlSyntaxException { exe.execute(); } catch (TableExistenceException | ArgumentException | IndexAlreadyExistException | TableConflictException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 测试执行结果 try { var data = table.readAll(context); - assertEquals(1, data.size()); + Assert.assertEquals(1, data.size()); - assertEquals(2, data.get(0).size()); - assertEquals("KAAAsS", (String) data.get(0).get(0)); - assertEquals(2, (int) data.get(0).get(1)); + Assert.assertEquals(2, data.get(0).size()); + Assert.assertEquals("KAAAsS", (String) data.get(0).get(0)); + Assert.assertEquals(2, (int) data.get(0).get(1)); } catch (TableExistenceException | TableConflictException | ArgumentException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } - - new File("metadata.db").deleteOnExit(); - } - public void testDeleteAll() throws SqlSyntaxException { + @Test + public void testDeleteAll() throws SqlSyntaxException, IndexAlreadyExistException, TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { var sql = "DELETE FROM testDeleteAll$Person "; // 解析 var stmt = SqlParser.parseStatement(sql); - assertTrue(stmt instanceof DeleteStatement); + Assert.assertTrue(stmt instanceof DeleteStatement); var manager = new TableManager(); var context = TransactionContext.empty(); var fields = new ArrayList(); - var dummy = new Table("testDeleteAll.__reserved__", fields); - var id = new IntField("ID", false, dummy); - fields.add(new VarcharField("LastName", 20, false, dummy)); + var id = new IntField("ID", false, null); + fields.add(new VarcharField("LastName", 20, false, null)); fields.add(id); Table table = null; try { - manager.createTable(context, "testDeleteAll$Person", fields, PATH + "testDeleteAll.Person.db"); + manager.createTable(context, "testDeleteAll$Person", fields, FileUtil.TABLE_PATH + "testDeleteAll.Person.db"); id.createIndex(); table = manager.getTable("testDeleteAll$Person"); - } catch (TableExistenceException | IndexAlreadyExistException e) { + } catch (TableExistenceException | IndexAlreadyExistException | RecordNotFoundException | ArgumentException | TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } - assertNotNull(table); + Assert.assertNotNull(table); try { table.insert(context, new ArrayList<>() {{ add(0, "'KevinAxel'"); @@ -145,25 +152,25 @@ public void testDeleteAll() throws SqlSyntaxException { } catch (TableConflictException | TableExistenceException | ArgumentException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 测试插入结果 try { var data = table.readAll(context); - assertEquals(2, data.size()); + Assert.assertEquals(2, data.size()); - assertEquals(2, data.get(0).size()); - assertEquals("KevinAxel", (String) data.get(0).get(0)); - assertEquals(1, (int) data.get(0).get(1)); + Assert.assertEquals(2, data.get(0).size()); + Assert.assertEquals("KevinAxel", (String) data.get(0).get(0)); + Assert.assertEquals(1, (int) data.get(0).get(1)); - assertEquals(2, data.get(1).size()); - assertEquals("KAAAsS", (String) data.get(1).get(0)); - assertEquals(2, (int) data.get(1).get(1)); + Assert.assertEquals(2, data.get(1).size()); + Assert.assertEquals("KAAAsS", (String) data.get(1).get(0)); + Assert.assertEquals(2, (int) data.get(1).get(1)); } catch (TableExistenceException | TableConflictException | ArgumentException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 执行 @@ -172,20 +179,17 @@ public void testDeleteAll() throws SqlSyntaxException { exe.execute(); } catch (TableExistenceException | ArgumentException | IndexAlreadyExistException | TableConflictException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 测试执行结果 try { var data = table.readAll(context); - assertEquals(0, data.size()); + Assert.assertEquals(0, data.size()); } catch (TableExistenceException | TableConflictException | ArgumentException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } - - new File("metadata.db").deleteOnExit(); - } } diff --git a/src/test/java/net/kaaass/rumbase/query/InsertExecutorTest.java b/src/test/java/net/kaaass/rumbase/query/InsertExecutorTest.java index 45d2624..2755b12 100644 --- a/src/test/java/net/kaaass/rumbase/query/InsertExecutorTest.java +++ b/src/test/java/net/kaaass/rumbase/query/InsertExecutorTest.java @@ -2,6 +2,7 @@ import junit.framework.TestCase; import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.FileUtil; import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; import net.kaaass.rumbase.parse.SqlParser; import net.kaaass.rumbase.parse.exception.SqlSyntaxException; @@ -16,39 +17,48 @@ import net.kaaass.rumbase.table.field.IntField; import net.kaaass.rumbase.table.field.VarcharField; 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.util.ArrayList; @Slf4j -public class InsertExecutorTest extends TestCase { +public class InsertExecutorTest { - private static final String PATH = "build/"; + @BeforeClass + @AfterClass + public static void clearDataFolder() { + log.info("清除数据文件夹..."); + FileUtil.removeDir(new File(FileUtil.DATA_PATH)); + } - public void testInsertColumnValue() throws SqlSyntaxException { + @Test + public void testInsertColumnValue() throws SqlSyntaxException, IndexAlreadyExistException, TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { var sql = "INSERT INTO Persons (Persons.LastName, Address) VALUES ('Wilson', 'Champs-Elysees')"; // 解析 var stmt = SqlParser.parseStatement(sql); - assertTrue(stmt instanceof InsertStatement); + Assert.assertTrue(stmt instanceof InsertStatement); var manager = new TableManager(); var context = TransactionContext.empty(); var fields = new ArrayList(); - var dummy = new Table("testInsertColumnValue.__reserved__", fields); - var lastName = new VarcharField("LastName", 20, false, dummy); + var lastName = new VarcharField("LastName", 20, false, null); fields.add(lastName); - fields.add(new VarcharField("Address", 255, false, dummy)); + fields.add(new VarcharField("Address", 255, false, null)); Table table = null; try { - manager.createTable(context, "Persons", fields, PATH + "testInsertColumnValue.Persons.db"); + manager.createTable(context, "Persons", fields, FileUtil.TABLE_PATH + "testInsertColumnValue.Persons.db"); lastName.createIndex(); table = manager.getTable("Persons"); - } catch (TableExistenceException | IndexAlreadyExistException e) { + } catch (TableExistenceException | IndexAlreadyExistException | RecordNotFoundException | ArgumentException | TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } - assertNotNull(table); + Assert.assertNotNull(table); // 执行 var exe = new InsertExecutor((InsertStatement) stmt, manager, context); @@ -56,49 +66,44 @@ public void testInsertColumnValue() throws SqlSyntaxException { exe.execute(); } catch (TableExistenceException | TableConflictException | ArgumentException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 确认结果 try { var data = table.readAll(context); - assertEquals(1, data.size()); - assertEquals("Wilson", data.get(0).get(0)); - assertEquals("Champs-Elysees", data.get(0).get(1)); + Assert.assertEquals(1, data.size()); + Assert.assertEquals("Wilson", data.get(0).get(0)); + Assert.assertEquals("Champs-Elysees", data.get(0).get(1)); } catch (TableExistenceException | TableConflictException | ArgumentException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } - - new File("metadata.db").deleteOnExit(); - } - public void testInsertValue() throws SqlSyntaxException { + @Test + public void testInsertValue() throws SqlSyntaxException, IndexAlreadyExistException, TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { var sql = "INSERT INTO stu VALUES (20200101, 'KAAAsS', true, 3.9)"; // 解析 var stmt = SqlParser.parseStatement(sql); - assertTrue(stmt instanceof InsertStatement); + Assert.assertTrue(stmt instanceof InsertStatement); var manager = new TableManager(); var context = TransactionContext.empty(); var fields = new ArrayList(); - var dummy = new Table("testInsertValue.__reserved__", fields); - var id = new IntField("ID", false, dummy); - fields.add(new VarcharField("LastName", 20, false, dummy)); + var id = new IntField("ID", false, null); + fields.add(new VarcharField("LastName", 20, false, null)); fields.add(id); Table table = null; try { - manager.createTable(context, "Person", fields, PATH + "testInsertValue.Person.db"); + manager.createTable(context, "Person", fields, FileUtil.TABLE_PATH + "testInsertValue.Person.db"); id.createIndex(); table = manager.getTable("Person"); - } catch (TableExistenceException | IndexAlreadyExistException e) { + } catch (TableExistenceException | IndexAlreadyExistException | RecordNotFoundException | ArgumentException | TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } - assertNotNull(table); - new File("metadata.db").deleteOnExit(); - + Assert.assertNotNull(table); } } diff --git a/src/test/java/net/kaaass/rumbase/query/SelectExecutorTest.java b/src/test/java/net/kaaass/rumbase/query/SelectExecutorTest.java index 8e86c7a..7b3f7c9 100644 --- a/src/test/java/net/kaaass/rumbase/query/SelectExecutorTest.java +++ b/src/test/java/net/kaaass/rumbase/query/SelectExecutorTest.java @@ -2,6 +2,7 @@ import junit.framework.TestCase; import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.FileUtil; import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; import net.kaaass.rumbase.parse.SqlParser; import net.kaaass.rumbase.parse.exception.SqlSyntaxException; @@ -17,16 +18,26 @@ import net.kaaass.rumbase.table.field.IntField; import net.kaaass.rumbase.table.field.VarcharField; 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.util.ArrayList; @Slf4j -public class SelectExecutorTest extends TestCase { +public class SelectExecutorTest { - private static final String PATH = "build/"; + @BeforeClass + @AfterClass + public static void clearDataFolder() { + log.info("清除数据文件夹..."); + FileUtil.removeDir(new File(FileUtil.DATA_PATH)); + } - public void testSelect() throws SqlSyntaxException { + @Test + public void testSelect() throws SqlSyntaxException, IndexAlreadyExistException, TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { var sql = "SELECT distinct name, testSelect$account.ID, testSelect$account.balance \n" + "from testSelect$account join testSelect$payment on testSelect$account.ID = testSelect$payment.ID\n" + "WHERE testSelect$account.ID > 1 and (testSelect$payment.type = 'N' or testSelect$payment.type = 'T') \n" + @@ -40,22 +51,20 @@ public void testSelect() throws SqlSyntaxException { // 创建account表 var accountFields = new ArrayList(); - var accountDummy = new Table("testSelect.__reserved__", accountFields); - var id = new IntField("ID", false, accountDummy); + var id = new IntField("ID", false, null); accountFields.add(id); - accountFields.add(new VarcharField("name", 20, false, accountDummy)); - accountFields.add(new FloatField("balance", false, accountDummy)); + accountFields.add(new VarcharField("name", 20, false, null)); + accountFields.add(new FloatField("balance", false, null)); Table account = null; try { - manager.createTable(context, "testSelect$account", accountFields, PATH + "testSelect.account.db"); + manager.createTable(context, "testSelect$account", accountFields, FileUtil.TABLE_PATH + "testSelect.account.db"); id.createIndex(); account = manager.getTable("testSelect$account"); - } catch (TableExistenceException | IndexAlreadyExistException e) { + } catch (TableExistenceException | IndexAlreadyExistException | RecordNotFoundException | ArgumentException | TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } - - assertNotNull(account); + Assert.assertNotNull(account); try { account.insert(context, new ArrayList<>() {{ add(0, "1"); @@ -75,52 +84,51 @@ public void testSelect() throws SqlSyntaxException { } catch (TableConflictException | TableExistenceException | ArgumentException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 测试插入结果 try { var data = account.readAll(context); - assertEquals(3, data.size()); + Assert.assertEquals(3, data.size()); - assertEquals(3, data.get(0).size()); - assertEquals(1, (int) data.get(0).get(0)); - assertEquals("KevinAxel", (String) data.get(0).get(1)); - assertEquals(5000f, data.get(0).get(2)); + Assert.assertEquals(3, data.get(0).size()); + Assert.assertEquals(1, (int) data.get(0).get(0)); + Assert.assertEquals("KevinAxel", (String) data.get(0).get(1)); + Assert.assertEquals(5000f, data.get(0).get(2)); - assertEquals(3, data.get(1).size()); - assertEquals(2, (int) data.get(1).get(0)); - assertEquals("KAAAsS", (String) data.get(1).get(1)); - assertEquals(8000f, data.get(1).get(2)); + Assert.assertEquals(3, data.get(1).size()); + Assert.assertEquals(2, (int) data.get(1).get(0)); + Assert.assertEquals("KAAAsS", (String) data.get(1).get(1)); + Assert.assertEquals(8000f, data.get(1).get(2)); - assertEquals(3, data.get(2).size()); - assertEquals(3, (int) data.get(2).get(0)); - assertEquals("kkk", (String) data.get(2).get(1)); - assertEquals(8000f, data.get(2).get(2)); + Assert.assertEquals(3, data.get(2).size()); + Assert.assertEquals(3, (int) data.get(2).get(0)); + Assert.assertEquals("kkk", (String) data.get(2).get(1)); + Assert.assertEquals(8000f, data.get(2).get(2)); } catch (TableExistenceException | TableConflictException | ArgumentException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 创建payment表 var paymentFields = new ArrayList(); - var paymentDummy = new Table("testSelect.__reserved__", paymentFields); - var paymentId = new IntField("ID", false, paymentDummy); + var paymentId = new IntField("ID", false, null); paymentFields.add(paymentId); - paymentFields.add(new VarcharField("type", 1, false, paymentDummy)); + paymentFields.add(new VarcharField("type", 1, false, null)); Table payment = null; try { - manager.createTable(context, "testSelect$payment", paymentFields, PATH + "testSelect.payment.db"); + manager.createTable(context, "testSelect$payment", paymentFields, FileUtil.TABLE_PATH + "testSelect.payment.db"); paymentId.createIndex(); payment = manager.getTable("testSelect$payment"); - } catch (TableExistenceException | IndexAlreadyExistException e) { + } catch (TableExistenceException | IndexAlreadyExistException | RecordNotFoundException | ArgumentException | TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } - assertNotNull(payment); + Assert.assertNotNull(payment); try { payment.insert(context, new ArrayList<>() {{ add(0, "1"); @@ -137,30 +145,30 @@ public void testSelect() throws SqlSyntaxException { } catch (TableConflictException | TableExistenceException | ArgumentException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 测试插入结果 try { var data = payment.readAll(context); - assertEquals(3, data.size()); + Assert.assertEquals(3, data.size()); - assertEquals(2, data.get(0).size()); - assertEquals(1, (int) data.get(0).get(0)); - assertEquals("N", (String) data.get(0).get(1)); + Assert.assertEquals(2, data.get(0).size()); + Assert.assertEquals(1, (int) data.get(0).get(0)); + Assert.assertEquals("N", (String) data.get(0).get(1)); - assertEquals(2, data.get(1).size()); - assertEquals(2, (int) data.get(1).get(0)); - assertEquals("T", (String) data.get(1).get(1)); + Assert.assertEquals(2, data.get(1).size()); + Assert.assertEquals(2, (int) data.get(1).get(0)); + Assert.assertEquals("T", (String) data.get(1).get(1)); - assertEquals(2, data.get(2).size()); - assertEquals(3, (int) data.get(2).get(0)); - assertEquals("T", (String) data.get(2).get(1)); + Assert.assertEquals(2, data.get(2).size()); + Assert.assertEquals(3, (int) data.get(2).get(0)); + Assert.assertEquals("T", (String) data.get(2).get(1)); } catch (TableExistenceException | TableConflictException | ArgumentException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 执行语句 @@ -169,33 +177,29 @@ public void testSelect() throws SqlSyntaxException { exe.execute(); } catch (TableConflictException | ArgumentException | TableExistenceException | IndexAlreadyExistException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } var cols = exe.getResultTable(); var data = exe.getResultData(); - assertEquals(3, cols.size()); - assertEquals("testSelect$account", cols.get(0).getTableName()); - assertEquals("name", cols.get(0).getFieldName()); - assertEquals("testSelect$account", cols.get(1).getTableName()); - assertEquals("ID", cols.get(1).getFieldName()); - assertEquals("testSelect$account", cols.get(2).getTableName()); - assertEquals("balance", cols.get(2).getFieldName()); - - assertEquals(2, data.size()); - - assertEquals(3, data.get(0).size()); - assertEquals(3, data.get(0).get(0)); - assertEquals("kkk", data.get(0).get(1)); - assertEquals(8000f, data.get(0).get(2)); - - assertEquals(3, data.get(0).size()); - assertEquals(2, data.get(1).get(0)); - assertEquals("KAAAsS", data.get(1).get(1)); - assertEquals(8000f, data.get(1).get(2)); - - - new File("metadata.db").deleteOnExit(); - + Assert.assertEquals(3, cols.size()); + Assert.assertEquals("testSelect$account", cols.get(0).getTableName()); + Assert.assertEquals("name", cols.get(0).getFieldName()); + Assert.assertEquals("testSelect$account", cols.get(1).getTableName()); + Assert.assertEquals("ID", cols.get(1).getFieldName()); + Assert.assertEquals("testSelect$account", cols.get(2).getTableName()); + Assert.assertEquals("balance", cols.get(2).getFieldName()); + + Assert.assertEquals(2, data.size()); + + Assert.assertEquals(3, data.get(0).size()); + Assert.assertEquals(3, data.get(0).get(0)); + Assert.assertEquals("kkk", data.get(0).get(1)); + Assert.assertEquals(8000f, data.get(0).get(2)); + + Assert.assertEquals(3, data.get(0).size()); + Assert.assertEquals(2, data.get(1).get(0)); + Assert.assertEquals("KAAAsS", data.get(1).get(1)); + Assert.assertEquals(8000f, data.get(1).get(2)); } } diff --git a/src/test/java/net/kaaass/rumbase/query/UpdateExecutorTest.java b/src/test/java/net/kaaass/rumbase/query/UpdateExecutorTest.java index c2f594d..0de8f0a 100644 --- a/src/test/java/net/kaaass/rumbase/query/UpdateExecutorTest.java +++ b/src/test/java/net/kaaass/rumbase/query/UpdateExecutorTest.java @@ -1,7 +1,7 @@ package net.kaaass.rumbase.query; -import junit.framework.TestCase; import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.FileUtil; import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; import net.kaaass.rumbase.parse.SqlParser; import net.kaaass.rumbase.parse.exception.SqlSyntaxException; @@ -13,78 +13,90 @@ import net.kaaass.rumbase.table.exception.TableConflictException; import net.kaaass.rumbase.table.exception.TableExistenceException; import net.kaaass.rumbase.table.field.BaseField; +import net.kaaass.rumbase.table.field.IntField; import net.kaaass.rumbase.table.field.VarcharField; 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.util.ArrayList; @Slf4j -public class UpdateExecutorTest extends TestCase { +public class UpdateExecutorTest { - private static final String PATH = "build/"; + @BeforeClass + @AfterClass + public static void clearDataFolder() { + log.info("清除数据文件夹..."); + FileUtil.removeDir(new File(FileUtil.DATA_PATH)); + } - public void testUpdateWithCondition() throws SqlSyntaxException { + @Test + public void testUpdateWithCondition() throws SqlSyntaxException, IndexAlreadyExistException, TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { var sql = "UPDATE testUpdateWithCondition$Person SET Address = 'Zhongshan 23', City = 'Nanjing'\n" + - "WHERE LastName = 'Wilson'"; + "WHERE ID = 2"; // 解析 var stmt = SqlParser.parseStatement(sql); - assertTrue(stmt instanceof UpdateStatement); + Assert.assertTrue(stmt instanceof UpdateStatement); var manager = new TableManager(); var context = TransactionContext.empty(); var fields = new ArrayList(); var dummy = new Table("testUpdateWithCondition.__reserved__", fields); - var lastName = new VarcharField("LastName", 20, false, dummy); + var lastName = new IntField("ID", false, dummy); fields.add(lastName); fields.add(new VarcharField("City", 20, false, dummy)); fields.add(new VarcharField("Address", 20, false, dummy)); Table table = null; try { - manager.createTable(context, "testUpdateWithCondition$Person", fields, PATH + "testUpdateWithCondition.Person.db"); + manager.createTable(context, "testUpdateWithCondition$Person", fields, FileUtil.TABLE_PATH + "testUpdateWithCondition.Person.db"); lastName.createIndex(); table = manager.getTable("testUpdateWithCondition$Person"); - } catch (TableExistenceException | IndexAlreadyExistException e) { + } catch (TableExistenceException | IndexAlreadyExistException | RecordNotFoundException | ArgumentException | TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } - assertNotNull(table); + Assert.assertNotNull(table); try { table.insert(context, new ArrayList<>() {{ - add(0, "'Wilson'"); - add(1, "'JiaXing'"); - add(2, "'Zhongshan 45'"); - }}); - table.insert(context, new ArrayList<>() {{ - add(0, "'KAAAsS'"); + add(0, "1"); add(1, "'WenZhou'"); add(2, "'Zhongshan 78'"); }}); + table.insert(context, new ArrayList<>() {{ + add(0, "2"); + add(1, "'JiaXing'"); + add(2, "'Zhongshan 45'"); + }}); } catch (TableConflictException | TableExistenceException | ArgumentException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 测试插入结果 try { var data = table.readAll(context); - assertEquals(2, data.size()); + Assert.assertEquals(2, data.size()); - assertEquals(3, data.get(0).size()); - assertEquals("Wilson", (String) data.get(0).get(0)); - assertEquals("JiaXing", (String) data.get(0).get(1)); - assertEquals("Zhongshan 45", (String) data.get(0).get(2)); + Assert.assertEquals(3, data.get(0).size()); + Assert.assertEquals(1, data.get(0).get(0)); + Assert.assertEquals("WenZhou", data.get(0).get(1)); + Assert.assertEquals("Zhongshan 78", data.get(0).get(2)); + + Assert.assertEquals(3, data.get(1).size()); + Assert.assertEquals(2, data.get(1).get(0)); + Assert.assertEquals("JiaXing", data.get(1).get(1)); + Assert.assertEquals("Zhongshan 45", data.get(1).get(2)); - assertEquals(3, data.get(1).size()); - assertEquals("KAAAsS", (String) data.get(1).get(0)); - assertEquals("WenZhou", (String) data.get(1).get(1)); - assertEquals("Zhongshan 78", (String) data.get(1).get(2)); } catch (TableExistenceException | TableConflictException | ArgumentException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 执行 @@ -93,33 +105,33 @@ public void testUpdateWithCondition() throws SqlSyntaxException { exe.execute(); } catch (TableExistenceException | ArgumentException | IndexAlreadyExistException | TableConflictException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 检查执行结果 try { var data = table.readAll(context); - assertEquals(2, data.size()); + log.info("Result: {}", data); + Assert.assertEquals(2, data.size()); - assertEquals(3, data.get(0).size()); - assertEquals("Wilson", (String) data.get(0).get(0)); - assertEquals("Nanjing", (String) data.get(0).get(1)); - assertEquals("Zhongshan 23", (String) data.get(0).get(2)); + Assert.assertEquals(3, data.get(1).size()); + Assert.assertEquals(2, data.get(1).get(0)); + Assert.assertEquals("Nanjing", data.get(1).get(1)); + Assert.assertEquals("Zhongshan 23", data.get(1).get(2)); - assertEquals(3, data.get(1).size()); - assertEquals("KAAAsS", (String) data.get(1).get(0)); - assertEquals("WenZhou", (String) data.get(1).get(1)); - assertEquals("Zhongshan 78", (String) data.get(1).get(2)); + Assert.assertEquals(3, data.get(0).size()); + Assert.assertEquals(1, data.get(0).get(0)); + Assert.assertEquals("WenZhou", data.get(0).get(1)); + Assert.assertEquals("Zhongshan 78", data.get(0).get(2)); } catch (TableExistenceException | TableConflictException | ArgumentException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } - new File("metadata.db").deleteOnExit(); - } - public void testUpdateWithoutCondition() throws SqlSyntaxException { + @Test + public void testUpdateWithoutCondition() throws SqlSyntaxException, IndexAlreadyExistException, TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { var sql = "UPDATE testUpdateWithoutCondition$Person SET Address = 'Zhongshan 23', City = 'Nanjing'"; // 解析 var stmt = SqlParser.parseStatement(sql); @@ -128,57 +140,56 @@ public void testUpdateWithoutCondition() throws SqlSyntaxException { var manager = new TableManager(); var context = TransactionContext.empty(); var fields = new ArrayList(); - var dummy = new Table("testUpdateWithoutCondition.__reserved__", fields); - var lastName = new VarcharField("LastName", 20, false, dummy); + var lastName = new IntField("ID", false, null); fields.add(lastName); - fields.add(new VarcharField("City", 20, false, dummy)); - fields.add(new VarcharField("Address", 20, false, dummy)); + fields.add(new VarcharField("City", 20, false, null)); + fields.add(new VarcharField("Address", 20, false, null)); Table table = null; try { - manager.createTable(context, "testUpdateWithoutCondition$Person", fields, PATH + "testUpdateWithoutCondition.Person.db"); + manager.createTable(context, "testUpdateWithoutCondition$Person", fields, FileUtil.TABLE_PATH + "testUpdateWithoutCondition.Person.db"); lastName.createIndex(); table = manager.getTable("testUpdateWithoutCondition$Person"); } catch (TableExistenceException | IndexAlreadyExistException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } - assertNotNull(table); + Assert.assertNotNull(table); try { table.insert(context, new ArrayList<>() {{ - add(0, "'Wilson'"); + add(0, "1"); add(1, "'JiaXing'"); add(2, "'Zhongshan 45'"); }}); table.insert(context, new ArrayList<>() {{ - add(0, "'KAAAsS'"); + add(0, "2"); add(1, "'WenZhou'"); add(2, "'Zhongshan 78'"); }}); } catch (TableConflictException | TableExistenceException | ArgumentException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 测试插入结果 try { var data = table.readAll(context); - assertEquals(2, data.size()); + Assert.assertEquals(2, data.size()); - assertEquals(3, data.get(0).size()); - assertEquals("Wilson", (String) data.get(0).get(0)); - assertEquals("JiaXing", (String) data.get(0).get(1)); - assertEquals("Zhongshan 45", (String) data.get(0).get(2)); + Assert.assertEquals(3, data.get(0).size()); + Assert.assertEquals(1, data.get(0).get(0)); + Assert.assertEquals("JiaXing", data.get(0).get(1)); + Assert.assertEquals("Zhongshan 45", data.get(0).get(2)); - assertEquals(3, data.get(1).size()); - assertEquals("KAAAsS", (String) data.get(1).get(0)); - assertEquals("WenZhou", (String) data.get(1).get(1)); - assertEquals("Zhongshan 78", (String) data.get(1).get(2)); + Assert.assertEquals(3, data.get(1).size()); + Assert.assertEquals(2, data.get(1).get(0)); + Assert.assertEquals("WenZhou", data.get(1).get(1)); + Assert.assertEquals("Zhongshan 78", data.get(1).get(2)); } catch (TableExistenceException | TableConflictException | ArgumentException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 执行 @@ -187,29 +198,28 @@ public void testUpdateWithoutCondition() throws SqlSyntaxException { exe.execute(); } catch (TableExistenceException | ArgumentException | IndexAlreadyExistException | TableConflictException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 检查执行结果 try { var data = table.readAll(context); - assertEquals(2, data.size()); + log.info("Result: {}", data); + Assert.assertEquals(2, data.size()); - assertEquals(3, data.get(0).size()); - assertEquals("KAAAsS", (String) data.get(0).get(0)); - assertEquals("Nanjing", (String) data.get(0).get(1)); - assertEquals("Zhongshan 23", (String) data.get(0).get(2)); + Assert.assertEquals(3, data.get(0).size()); + Assert.assertEquals(1, data.get(0).get(0)); + Assert.assertEquals("Nanjing", data.get(0).get(1)); + Assert.assertEquals("Zhongshan 23", data.get(0).get(2)); - assertEquals(3, data.get(1).size()); - assertEquals("Wilson", (String) data.get(1).get(0)); - assertEquals("Nanjing", (String) data.get(1).get(1)); - assertEquals("Zhongshan 23", (String) data.get(1).get(2)); + Assert.assertEquals(3, data.get(1).size()); + Assert.assertEquals(2, data.get(1).get(0)); + Assert.assertEquals("Nanjing", data.get(1).get(1)); + Assert.assertEquals("Zhongshan 23", data.get(1).get(2)); } catch (TableExistenceException | TableConflictException | ArgumentException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } - new File("metadata.db").deleteOnExit(); - } } diff --git a/src/test/java/net/kaaass/rumbase/record/IRecordStorageTest.java b/src/test/java/net/kaaass/rumbase/record/IRecordStorageTest.java index 8ab58a2..5667e1e 100644 --- a/src/test/java/net/kaaass/rumbase/record/IRecordStorageTest.java +++ b/src/test/java/net/kaaass/rumbase/record/IRecordStorageTest.java @@ -2,8 +2,13 @@ import junit.framework.TestCase; import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.FileUtil; import net.kaaass.rumbase.record.exception.RecordNotFoundException; 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.util.UUID; @@ -17,22 +22,34 @@ * @see net.kaaass.rumbase.record.IRecordStorage */ @Slf4j -public class IRecordStorageTest extends TestCase { +public class IRecordStorageTest { - public final static String PATH = "build/"; + @BeforeClass + public static void createDataFolder() { + FileUtil.prepare(); + } + + @AfterClass + public static void clearDataFolder() { + FileUtil.clear(); + } + + public final static String PATH = FileUtil.TEST_PATH; + @Test public void testQuery() { var storage = RecordManager.fromFile(PATH + "test_query"); var context = TransactionContext.empty(); try { storage.query(context, UUID.randomUUID().getLeastSignificantBits()); - fail("unknown physical record should get exception"); + Assert.fail("unknown physical record should get exception"); } catch (RecordNotFoundException e) { log.error("Exception expected: ", e); } } + @Test public void testInsert() throws RecordNotFoundException { var storage = RecordManager.fromFile(PATH + "test_insert"); var context = TransactionContext.empty(); @@ -40,10 +57,11 @@ public void testInsert() throws RecordNotFoundException { var id = storage.insert(context, new byte[]{0x1, 0x2, 0x1f}); var result = storage.queryOptional(context, id); - assertTrue("result should present", result.isPresent()); + Assert.assertTrue("result should present", result.isPresent()); assertArrayEquals(new byte[]{0x1, 0x2, 0x1f}, result.get()); } + @Test public void testDelete() throws RecordNotFoundException { var storage = RecordManager.fromFile(PATH + "test_delete"); var context = TransactionContext.empty(); @@ -52,16 +70,16 @@ public void testDelete() throws RecordNotFoundException { storage.insert(context, new byte[]{0x7, 0x3, 0x1f}); var id = storage.insert(context, new byte[]{0x54, 0x23, 0x23, 0x44}); var result = storage.queryOptional(context, id); - assertTrue("result should present", result.isPresent()); + Assert.assertTrue("result should present", result.isPresent()); storage.delete(context, id); result = storage.queryOptional(context, id); - assertTrue("record should be deleted", result.isEmpty()); + Assert.assertTrue("record should be deleted", result.isEmpty()); } + @Test public void testMetadata() { - new File(PATH + "test_metadata").deleteOnExit(); var storage = RecordManager.fromFile(PATH + "test_metadata"); var context = TransactionContext.empty(); diff --git a/src/test/java/net/kaaass/rumbase/record/MvccReadCommitTest.java b/src/test/java/net/kaaass/rumbase/record/MvccReadCommitTest.java index fac8a73..e12d1bb 100644 --- a/src/test/java/net/kaaass/rumbase/record/MvccReadCommitTest.java +++ b/src/test/java/net/kaaass/rumbase/record/MvccReadCommitTest.java @@ -2,19 +2,35 @@ import junit.framework.TestCase; import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.FileUtil; import net.kaaass.rumbase.page.exception.FileException; import net.kaaass.rumbase.record.exception.RecordNotFoundException; import net.kaaass.rumbase.transaction.TransactionIsolation; import net.kaaass.rumbase.transaction.TransactionManager; import net.kaaass.rumbase.transaction.TransactionManagerImpl; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; import java.io.IOException; @Slf4j -public class MvccReadCommitTest extends TestCase { +public class MvccReadCommitTest { - public final static String PATH = "build/"; + @BeforeClass + public static void createDataFolder() { + FileUtil.prepare(); + } + + @AfterClass + public static void clearDataFolder() { + FileUtil.clear(); + } + + public final static String PATH = FileUtil.TEST_PATH; + @Test public void testReadSelf() throws RecordNotFoundException { var storage = RecordManager.fromFile(PATH + "testReadSelf"); var manager = new FakeTxManager(TransactionIsolation.READ_COMMITTED); @@ -22,17 +38,18 @@ public void testReadSelf() throws RecordNotFoundException { var tx1 = manager.begin(); // 事务1的记录自身可见 var a1 = storage.insert(tx1, new byte[]{0x23, 0x63}); - assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); + Assert.assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); // 事务2不可见a1 var tx2 = manager.begin(); - assertTrue("tx2 blind a1", storage.queryOptional(tx2, a1).isEmpty()); + Assert.assertTrue("tx2 blind a1", storage.queryOptional(tx2, a1).isEmpty()); // 事务1新纪录也可见 for (int i = 0; i < 100; i++) { var uuid = storage.insert(tx1, new byte[]{0x23, 0x63, 0x44}); - assertTrue("uuid see a1", storage.queryOptional(tx1, uuid).isPresent()); + Assert.assertTrue("uuid see a1", storage.queryOptional(tx1, uuid).isPresent()); } } + @Test public void testReadOther() throws RecordNotFoundException { var storage = RecordManager.fromFile(PATH + "testReadOther"); var manager = new FakeTxManager(TransactionIsolation.READ_COMMITTED); @@ -41,25 +58,26 @@ public void testReadOther() throws RecordNotFoundException { var tx2 = manager.begin(); // 事务2创建的b1,事务1不可见 var b1 = storage.insert(tx2, new byte[]{0x1, 0x2, 0x3}); - assertTrue("tx2 see b1", storage.queryOptional(tx2, b1).isPresent()); - assertTrue("tx1 blind b1", storage.queryOptional(tx1, b1).isEmpty()); + Assert.assertTrue("tx2 see b1", storage.queryOptional(tx2, b1).isPresent()); + Assert.assertTrue("tx1 blind b1", storage.queryOptional(tx1, b1).isEmpty()); // 事务1创建的a1,事务2不可见 var a1 = storage.insert(tx1, new byte[]{0x6, 0x5, 0x4, 0x32}); - assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); - assertTrue("tx2 blind a1", storage.queryOptional(tx2, a1).isEmpty()); + Assert.assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); + Assert.assertTrue("tx2 blind a1", storage.queryOptional(tx2, a1).isEmpty()); // 事务2提交,则事务1可见b1 tx2.commit(); - assertTrue("tx1 see b1 after commit", storage.queryOptional(tx1, b1).isPresent()); + Assert.assertTrue("tx1 see b1 after commit", storage.queryOptional(tx1, b1).isPresent()); // 新建事务3 var tx3 = manager.begin(); // 事务3可以看到b1,但是不能看到a1 - assertTrue("tx3 see b1 after commit", storage.queryOptional(tx3, b1).isPresent()); - assertTrue("tx3 blind a1 before commit", storage.queryOptional(tx3, a1).isEmpty()); + Assert.assertTrue("tx3 see b1 after commit", storage.queryOptional(tx3, b1).isPresent()); + Assert.assertTrue("tx3 blind a1 before commit", storage.queryOptional(tx3, a1).isEmpty()); // 提交事务1,a1可见 tx1.commit(); - assertTrue("tx3 see a1 after commit", storage.queryOptional(tx3, a1).isPresent()); + Assert.assertTrue("tx3 see a1 after commit", storage.queryOptional(tx3, a1).isPresent()); } + @Test public void testDelete() throws RecordNotFoundException { var storage = RecordManager.fromFile(PATH + "testDelete"); var manager = new FakeTxManager(TransactionIsolation.READ_COMMITTED); @@ -67,24 +85,25 @@ public void testDelete() throws RecordNotFoundException { var tx1 = manager.begin(); var a1 = storage.insert(tx1, new byte[]{0x1, 0x2, 0x3}); var a2 = storage.insert(tx1, new byte[]{0x5, 0x6, 0x7}); - assertTrue(storage.queryOptional(tx1, a1).isPresent()); - assertTrue(storage.queryOptional(tx1, a2).isPresent()); + Assert.assertTrue(storage.queryOptional(tx1, a1).isPresent()); + Assert.assertTrue(storage.queryOptional(tx1, a2).isPresent()); // 自身删除 storage.delete(tx1, a1); - assertTrue("a1 should be deleted", storage.queryOptional(tx1, a1).isEmpty()); + Assert.assertTrue("a1 should be deleted", storage.queryOptional(tx1, a1).isEmpty()); // 提交事务1 tx1.commit(); // 事务2删除,事务3仍然可见a2 var tx2 = manager.begin(); var tx3 = manager.begin(); storage.delete(tx2, a2); - assertTrue("tx2 blind a2 after delete", storage.queryOptional(tx2, a2).isEmpty()); - assertTrue("tx3 see a2 before commit", storage.queryOptional(tx3, a2).isPresent()); + Assert.assertTrue("tx2 blind a2 after delete", storage.queryOptional(tx2, a2).isEmpty()); + Assert.assertTrue("tx3 see a2 before commit", storage.queryOptional(tx3, a2).isPresent()); // 事务2提交,事务3不可见a2 tx2.commit(); - assertTrue("tx3 blind a2 after commit", storage.queryOptional(tx3, a2).isEmpty()); + Assert.assertTrue("tx3 blind a2 after commit", storage.queryOptional(tx3, a2).isEmpty()); } + @Test public void testReadSelfReal() throws RecordNotFoundException, IOException, FileException { var storage = RecordManager.fromFile(PATH + "testReadSelfReal"); var manager = new TransactionManagerImpl(); @@ -93,21 +112,22 @@ public void testReadSelfReal() throws RecordNotFoundException, IOException, File tx1.start(); // 事务1的记录自身可见 var a1 = storage.insert(tx1, new byte[]{0x23, 0x63}); - assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); + Assert.assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); // 事务2不可见a1 var tx2 = manager.createTransactionContext(TransactionIsolation.READ_COMMITTED); tx2.start(); - assertTrue("tx2 blind a1", storage.queryOptional(tx2, a1).isEmpty()); + Assert.assertTrue("tx2 blind a1", storage.queryOptional(tx2, a1).isEmpty()); // 事务1新纪录也可见 for (int i = 0; i < 100; i++) { var uuid = storage.insert(tx1, new byte[]{0x23, 0x63, 0x44}); - assertTrue("uuid see a1", storage.queryOptional(tx1, uuid).isPresent()); + Assert.assertTrue("uuid see a1", storage.queryOptional(tx1, uuid).isPresent()); } // tx1.commit(); tx2.commit(); } + @Test public void testReadOtherReal() throws RecordNotFoundException, IOException, FileException { var storage = RecordManager.fromFile(PATH + "testReadOtherReal"); var manager = new TransactionManagerImpl(); @@ -118,27 +138,28 @@ public void testReadOtherReal() throws RecordNotFoundException, IOException, Fil tx2.start(); // 事务2创建的b1,事务1不可见 var b1 = storage.insert(tx2, new byte[]{0x1, 0x2, 0x3}); - assertTrue("tx2 see b1", storage.queryOptional(tx2, b1).isPresent()); - assertTrue("tx1 blind b1", storage.queryOptional(tx1, b1).isEmpty()); + Assert.assertTrue("tx2 see b1", storage.queryOptional(tx2, b1).isPresent()); + Assert.assertTrue("tx1 blind b1", storage.queryOptional(tx1, b1).isEmpty()); // 事务1创建的a1,事务2不可见 var a1 = storage.insert(tx1, new byte[]{0x6, 0x5, 0x4, 0x32}); - assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); - assertTrue("tx2 blind a1", storage.queryOptional(tx2, a1).isEmpty()); + Assert.assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); + Assert.assertTrue("tx2 blind a1", storage.queryOptional(tx2, a1).isEmpty()); // 事务2提交,则事务1可见b1 tx2.commit(); - assertTrue("tx1 see b1 after commit", storage.queryOptional(tx1, b1).isPresent()); + Assert.assertTrue("tx1 see b1 after commit", storage.queryOptional(tx1, b1).isPresent()); // 新建事务3 var tx3 = manager.createTransactionContext(TransactionIsolation.READ_COMMITTED); tx3.start(); // 事务3可以看到b1,但是不能看到a1 - assertTrue("tx3 see b1 after commit", storage.queryOptional(tx3, b1).isPresent()); - assertTrue("tx3 blind a1 before commit", storage.queryOptional(tx3, a1).isEmpty()); + Assert.assertTrue("tx3 see b1 after commit", storage.queryOptional(tx3, b1).isPresent()); + Assert.assertTrue("tx3 blind a1 before commit", storage.queryOptional(tx3, a1).isEmpty()); // 提交事务1,a1可见 tx1.commit(); - assertTrue("tx3 see a1 after commit", storage.queryOptional(tx3, a1).isPresent()); + Assert.assertTrue("tx3 see a1 after commit", storage.queryOptional(tx3, a1).isPresent()); tx3.commit(); } + @Test public void testDeleteReal() throws RecordNotFoundException, IOException, FileException { var storage = RecordManager.fromFile(PATH + "testDeleteReal"); var manager = new TransactionManagerImpl(); @@ -147,11 +168,11 @@ public void testDeleteReal() throws RecordNotFoundException, IOException, FileEx tx1.start(); var a1 = storage.insert(tx1, new byte[]{0x1, 0x2, 0x3}); var a2 = storage.insert(tx1, new byte[]{0x5, 0x6, 0x7}); - assertTrue(storage.queryOptional(tx1, a1).isPresent()); - assertTrue(storage.queryOptional(tx1, a2).isPresent()); + Assert.assertTrue(storage.queryOptional(tx1, a1).isPresent()); + Assert.assertTrue(storage.queryOptional(tx1, a2).isPresent()); // 自身删除 storage.delete(tx1, a1); - assertTrue("a1 should be deleted", storage.queryOptional(tx1, a1).isEmpty()); + Assert.assertTrue("a1 should be deleted", storage.queryOptional(tx1, a1).isEmpty()); // 提交事务1 tx1.commit(); // 事务2删除,事务3仍然可见a2 @@ -160,11 +181,11 @@ public void testDeleteReal() throws RecordNotFoundException, IOException, FileEx var tx3 = manager.createTransactionContext(TransactionIsolation.READ_COMMITTED); tx3.start(); storage.delete(tx2, a2); - assertTrue("tx2 blind a2 after delete", storage.queryOptional(tx2, a2).isEmpty()); - assertTrue("tx3 see a2 before commit", storage.queryOptional(tx3, a2).isPresent()); + Assert.assertTrue("tx2 blind a2 after delete", storage.queryOptional(tx2, a2).isEmpty()); + Assert.assertTrue("tx3 see a2 before commit", storage.queryOptional(tx3, a2).isPresent()); // 事务2提交,事务3不可见a2 tx2.commit(); - assertTrue("tx3 blind a2 after commit", storage.queryOptional(tx3, a2).isEmpty()); + Assert.assertTrue("tx3 blind a2 after commit", storage.queryOptional(tx3, a2).isEmpty()); tx3.commit(); } } diff --git a/src/test/java/net/kaaass/rumbase/record/MvccReadRepeatableTest.java b/src/test/java/net/kaaass/rumbase/record/MvccReadRepeatableTest.java index ac0fce2..3f35268 100644 --- a/src/test/java/net/kaaass/rumbase/record/MvccReadRepeatableTest.java +++ b/src/test/java/net/kaaass/rumbase/record/MvccReadRepeatableTest.java @@ -2,6 +2,7 @@ import junit.framework.TestCase; import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.FileUtil; import net.kaaass.rumbase.page.exception.FileException; import net.kaaass.rumbase.record.exception.NeedRollbackException; import net.kaaass.rumbase.record.exception.RecordNotFoundException; @@ -9,14 +10,29 @@ import net.kaaass.rumbase.transaction.TransactionIsolation; import net.kaaass.rumbase.transaction.TransactionManager; import net.kaaass.rumbase.transaction.TransactionManagerImpl; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; import java.io.IOException; @Slf4j -public class MvccReadRepeatableTest extends TestCase { +public class MvccReadRepeatableTest { - public final static String PATH = "build/"; + @BeforeClass + public static void createDataFolder() { + FileUtil.prepare(); + } + + @AfterClass + public static void clearDataFolder() { + FileUtil.clear(); + } + + public final static String PATH = FileUtil.TEST_PATH; + @Test public void testReadSelf() throws RecordNotFoundException { var storage = RecordManager.fromFile(PATH + "testReadSelf"); var manager = new FakeTxManager(TransactionIsolation.REPEATABLE_READ); @@ -24,17 +40,18 @@ public void testReadSelf() throws RecordNotFoundException { var tx1 = manager.begin(); // 事务1的记录自身可见 var a1 = storage.insert(tx1, new byte[]{0x23, 0x63}); - assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); + Assert.assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); // 事务2不可见a1 var tx2 = manager.begin(); - assertTrue("tx2 blind a1", storage.queryOptional(tx2, a1).isEmpty()); + Assert.assertTrue("tx2 blind a1", storage.queryOptional(tx2, a1).isEmpty()); // 事务1新纪录也可见 for (int i = 0; i < 100; i++) { var uuid = storage.insert(tx1, new byte[]{0x23, 0x63, 0x44}); - assertTrue("uuid see a1", storage.queryOptional(tx1, uuid).isPresent()); + Assert.assertTrue("uuid see a1", storage.queryOptional(tx1, uuid).isPresent()); } } + @Test public void testReadOther() throws RecordNotFoundException { var storage = RecordManager.fromFile(PATH + "testReadOther"); var manager = new FakeTxManager(TransactionIsolation.REPEATABLE_READ); @@ -43,25 +60,26 @@ public void testReadOther() throws RecordNotFoundException { var tx2 = manager.begin(); // 事务2创建的b1,事务1不可见 var b1 = storage.insert(tx2, new byte[]{0x1, 0x2, 0x3}); - assertTrue("tx2 see b1", storage.queryOptional(tx2, b1).isPresent()); - assertTrue("tx1 blind b1", storage.queryOptional(tx1, b1).isEmpty()); + Assert.assertTrue("tx2 see b1", storage.queryOptional(tx2, b1).isPresent()); + Assert.assertTrue("tx1 blind b1", storage.queryOptional(tx1, b1).isEmpty()); // 事务1创建的a1,事务2不可见 var a1 = storage.insert(tx1, new byte[]{0x6, 0x5, 0x4, 0x32}); - assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); - assertTrue("tx2 blind a1", storage.queryOptional(tx2, a1).isEmpty()); + Assert.assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); + Assert.assertTrue("tx2 blind a1", storage.queryOptional(tx2, a1).isEmpty()); // 事务2提交,则事务1依旧不可见b1,因为事务1不可见事务2 tx2.commit(); - assertTrue("tx1 blind b1 after commit", storage.queryOptional(tx1, b1).isEmpty()); + Assert.assertTrue("tx1 blind b1 after commit", storage.queryOptional(tx1, b1).isEmpty()); // 新建事务3 var tx3 = manager.begin(); // 事务3可以看到b1,但是不能看到a1 - assertTrue("tx3 see b1 after commit", storage.queryOptional(tx3, b1).isPresent()); - assertTrue("tx3 blind a1 before commit", storage.queryOptional(tx3, a1).isEmpty()); + Assert.assertTrue("tx3 see b1 after commit", storage.queryOptional(tx3, b1).isPresent()); + Assert.assertTrue("tx3 blind a1 before commit", storage.queryOptional(tx3, a1).isEmpty()); // 提交事务1,a1还是不可见,因为事务3创建时事务1还在运行 tx1.commit(); - assertTrue("tx3 blind a1 after commit", storage.queryOptional(tx3, a1).isEmpty()); + Assert.assertTrue("tx3 blind a1 after commit", storage.queryOptional(tx3, a1).isEmpty()); } + @Test public void testDelete() throws RecordNotFoundException { var storage = RecordManager.fromFile(PATH + "testDelete"); var manager = new FakeTxManager(TransactionIsolation.REPEATABLE_READ); @@ -69,24 +87,25 @@ public void testDelete() throws RecordNotFoundException { var tx1 = manager.begin(); var a1 = storage.insert(tx1, new byte[]{0x1, 0x2, 0x3}); var a2 = storage.insert(tx1, new byte[]{0x5, 0x6, 0x7}); - assertTrue(storage.queryOptional(tx1, a1).isPresent()); - assertTrue(storage.queryOptional(tx1, a2).isPresent()); + Assert.assertTrue(storage.queryOptional(tx1, a1).isPresent()); + Assert.assertTrue(storage.queryOptional(tx1, a2).isPresent()); // 自身删除 storage.delete(tx1, a1); - assertTrue("a1 should be deleted", storage.queryOptional(tx1, a1).isEmpty()); + Assert.assertTrue("a1 should be deleted", storage.queryOptional(tx1, a1).isEmpty()); // 提交事务1 tx1.commit(); // 事务2删除,事务3仍然可见a2 var tx2 = manager.begin(); var tx3 = manager.begin(); storage.delete(tx2, a2); - assertTrue("tx2 blind a2 after delete", storage.queryOptional(tx2, a2).isEmpty()); - assertTrue("tx3 see a2 before commit", storage.queryOptional(tx3, a2).isPresent()); + Assert.assertTrue("tx2 blind a2 after delete", storage.queryOptional(tx2, a2).isEmpty()); + Assert.assertTrue("tx3 see a2 before commit", storage.queryOptional(tx3, a2).isPresent()); // 事务2提交,事务3依旧可见a2,因为事务3开始时事务2没有结束 tx2.commit(); - assertTrue("tx3 see a2 after commit", storage.queryOptional(tx3, a2).isPresent()); + Assert.assertTrue("tx3 see a2 after commit", storage.queryOptional(tx3, a2).isPresent()); } + @Test public void testVersionSkip() throws RecordNotFoundException, NeedRollbackException { var storage = RecordManager.fromFile(PATH + "testDelete"); var manager = new FakeTxManager(TransactionIsolation.REPEATABLE_READ); @@ -95,19 +114,20 @@ public void testVersionSkip() throws RecordNotFoundException, NeedRollbackExcept // 进行版本跳跃操作 var tx1 = manager.begin(); var tx2 = manager.begin(); - assertTrue(storage.queryOptional(tx1, r).isPresent()); - assertTrue(storage.queryOptional(tx2, r).isPresent()); + Assert.assertTrue(storage.queryOptional(tx1, r).isPresent()); + Assert.assertTrue(storage.queryOptional(tx2, r).isPresent()); storage.delete(tx1, r); tx1.commit(); try { storage.delete(tx2, r); - fail("Should rollback tx2 at here"); + Assert.fail("Should rollback tx2 at here"); tx2.commit(); } catch (NeedRollbackException e) { log.info("Expected runtime exception: ", e); } } + @Test public void testReadSelfReal() throws RecordNotFoundException, IOException, FileException { var storage = RecordManager.fromFile(PATH + "testReadSelfReal"); var manager = new TransactionManagerImpl(); @@ -116,21 +136,22 @@ public void testReadSelfReal() throws RecordNotFoundException, IOException, File tx1.start(); // 事务1的记录自身可见 var a1 = storage.insert(tx1, new byte[]{0x23, 0x63}); - assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); + Assert.assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); // 事务2不可见a1 var tx2 = manager.createTransactionContext(TransactionIsolation.REPEATABLE_READ); tx2.start(); - assertTrue("tx2 blind a1", storage.queryOptional(tx2, a1).isEmpty()); + Assert.assertTrue("tx2 blind a1", storage.queryOptional(tx2, a1).isEmpty()); // 事务1新纪录也可见 for (int i = 0; i < 100; i++) { var uuid = storage.insert(tx1, new byte[]{0x23, 0x63, 0x44}); - assertTrue("uuid see a1", storage.queryOptional(tx1, uuid).isPresent()); + Assert.assertTrue("uuid see a1", storage.queryOptional(tx1, uuid).isPresent()); } // tx1.commit(); tx2.commit(); } + @Test public void testReadOtherReal() throws RecordNotFoundException, IOException, FileException { var storage = RecordManager.fromFile(PATH + "testReadOtherReal"); var manager = new TransactionManagerImpl(); @@ -141,28 +162,29 @@ public void testReadOtherReal() throws RecordNotFoundException, IOException, Fil tx2.start(); // 事务2创建的b1,事务1不可见 var b1 = storage.insert(tx2, new byte[]{0x1, 0x2, 0x3}); - assertTrue("tx2 see b1", storage.queryOptional(tx2, b1).isPresent()); - assertTrue("tx1 blind b1", storage.queryOptional(tx1, b1).isEmpty()); + Assert.assertTrue("tx2 see b1", storage.queryOptional(tx2, b1).isPresent()); + Assert.assertTrue("tx1 blind b1", storage.queryOptional(tx1, b1).isEmpty()); // 事务1创建的a1,事务2不可见 var a1 = storage.insert(tx1, new byte[]{0x6, 0x5, 0x4, 0x32}); - assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); - assertTrue("tx2 blind a1", storage.queryOptional(tx2, a1).isEmpty()); + Assert.assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); + Assert.assertTrue("tx2 blind a1", storage.queryOptional(tx2, a1).isEmpty()); // 事务2提交,则事务1依旧不可见b1,因为事务1不可见事务2 tx2.commit(); - assertTrue("tx1 blind b1 after commit", storage.queryOptional(tx1, b1).isEmpty()); + Assert.assertTrue("tx1 blind b1 after commit", storage.queryOptional(tx1, b1).isEmpty()); // 新建事务3 var tx3 = manager.createTransactionContext(TransactionIsolation.REPEATABLE_READ); tx3.start(); // 事务3可以看到b1,但是不能看到a1 - assertTrue("tx3 see b1 after commit", storage.queryOptional(tx3, b1).isPresent()); - assertTrue("tx3 blind a1 before commit", storage.queryOptional(tx3, a1).isEmpty()); + Assert.assertTrue("tx3 see b1 after commit", storage.queryOptional(tx3, b1).isPresent()); + Assert.assertTrue("tx3 blind a1 before commit", storage.queryOptional(tx3, a1).isEmpty()); // 提交事务1,a1还是不可见,因为事务3创建时事务1还在运行 tx1.commit(); - assertTrue("tx3 blind a1 after commit", storage.queryOptional(tx3, a1).isEmpty()); + Assert.assertTrue("tx3 blind a1 after commit", storage.queryOptional(tx3, a1).isEmpty()); // tx3.commit(); } + @Test public void testDeleteReal() throws RecordNotFoundException, IOException, FileException { var storage = RecordManager.fromFile(PATH + "testDeleteReal"); var manager = new TransactionManagerImpl(); @@ -171,11 +193,11 @@ public void testDeleteReal() throws RecordNotFoundException, IOException, FileEx tx1.start(); var a1 = storage.insert(tx1, new byte[]{0x1, 0x2, 0x3}); var a2 = storage.insert(tx1, new byte[]{0x5, 0x6, 0x7}); - assertTrue(storage.queryOptional(tx1, a1).isPresent()); - assertTrue(storage.queryOptional(tx1, a2).isPresent()); + Assert.assertTrue(storage.queryOptional(tx1, a1).isPresent()); + Assert.assertTrue(storage.queryOptional(tx1, a2).isPresent()); // 自身删除 storage.delete(tx1, a1); - assertTrue("a1 should be deleted", storage.queryOptional(tx1, a1).isEmpty()); + Assert.assertTrue("a1 should be deleted", storage.queryOptional(tx1, a1).isEmpty()); // 提交事务1 tx1.commit(); // 事务2删除,事务3仍然可见a2 @@ -184,15 +206,16 @@ public void testDeleteReal() throws RecordNotFoundException, IOException, FileEx var tx3 = manager.createTransactionContext(TransactionIsolation.REPEATABLE_READ); tx3.start(); storage.delete(tx2, a2); - assertTrue("tx2 blind a2 after delete", storage.queryOptional(tx2, a2).isEmpty()); - assertTrue("tx3 see a2 before commit", storage.queryOptional(tx3, a2).isPresent()); + Assert.assertTrue("tx2 blind a2 after delete", storage.queryOptional(tx2, a2).isEmpty()); + Assert.assertTrue("tx3 see a2 before commit", storage.queryOptional(tx3, a2).isPresent()); // 事务2提交,事务3依旧可见a2,因为事务3开始时事务2没有结束 tx2.commit(); - assertTrue("tx3 see a2 after commit", storage.queryOptional(tx3, a2).isPresent()); + Assert.assertTrue("tx3 see a2 after commit", storage.queryOptional(tx3, a2).isPresent()); // tx3.commit(); } + @Test public void testVersionSkipReal() throws RecordNotFoundException, NeedRollbackException, IOException, FileException { var storage = RecordManager.fromFile(PATH + "testDeleteReal"); var manager = new TransactionManagerImpl(); @@ -203,13 +226,13 @@ public void testVersionSkipReal() throws RecordNotFoundException, NeedRollbackEx tx1.start(); var tx2 = manager.createTransactionContext(TransactionIsolation.REPEATABLE_READ); tx2.start(); - assertTrue(storage.queryOptional(tx1, r).isPresent()); - assertTrue(storage.queryOptional(tx2, r).isPresent()); + Assert.assertTrue(storage.queryOptional(tx1, r).isPresent()); + Assert.assertTrue(storage.queryOptional(tx2, r).isPresent()); storage.delete(tx1, r); tx1.commit(); try { storage.delete(tx2, r); - fail("Should rollback tx2 at here"); + Assert.fail("Should rollback tx2 at here"); tx2.commit(); } catch (NeedRollbackException e) { log.info("Expected runtime exception: ", e); diff --git a/src/test/java/net/kaaass/rumbase/table/BaseFieldTest.java b/src/test/java/net/kaaass/rumbase/table/BaseFieldTest.java index 19cfde1..b9076df 100644 --- a/src/test/java/net/kaaass/rumbase/table/BaseFieldTest.java +++ b/src/test/java/net/kaaass/rumbase/table/BaseFieldTest.java @@ -2,10 +2,16 @@ import junit.framework.TestCase; import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.FileUtil; import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; +import net.kaaass.rumbase.index.exception.IndexNotFoundException; import net.kaaass.rumbase.table.exception.TableConflictException; import net.kaaass.rumbase.table.exception.TableExistenceException; import net.kaaass.rumbase.table.field.*; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -20,37 +26,40 @@ * @see BaseField */ @Slf4j -public class BaseFieldTest extends TestCase { +public class BaseFieldTest { - private static final String PATH = "build/"; + @BeforeClass + @AfterClass + public static void clearDataFolder() { + log.info("清除数据文件夹..."); + FileUtil.removeDir(FileUtil.DATA_PATH); + } + @Test public void testCheckStr() { - var dummy = new Table(PATH + "testCheckStrTable", new ArrayList<>()); - // test int - var intField = new IntField("testCheckStrInt", false, dummy); - assertTrue(intField.checkStr("1")); - assertFalse(intField.checkStr("1.2")); - assertFalse(intField.checkStr("1aa")); + var intField = new IntField("testCheckStrInt", false, null); + Assert.assertTrue(intField.checkStr("1")); + Assert.assertFalse(intField.checkStr("1.2")); + Assert.assertFalse(intField.checkStr("1aa")); // test float - var floatField = new FloatField("testCheckStrFloat", false, dummy); - assertTrue(floatField.checkStr("1")); - assertTrue(floatField.checkStr("1.2")); - assertFalse(floatField.checkStr("1aa")); + var floatField = new FloatField("testCheckStrFloat", false, null); + Assert.assertTrue(floatField.checkStr("1")); + Assert.assertTrue(floatField.checkStr("1.2")); + Assert.assertFalse(floatField.checkStr("1aa")); // test varchar - var varcharField = new VarcharField("testCheckStrVarchar", 20, false, dummy); - assertTrue(varcharField.checkStr("'aaaa'")); - assertFalse(varcharField.checkStr("'aaaa aaaa aaaa aaaa aaaa'")); + var varcharField = new VarcharField("testCheckStrVarchar", 20, false, null); + Assert.assertTrue(varcharField.checkStr("'aaaa'")); + Assert.assertFalse(varcharField.checkStr("'aaaa aaaa aaaa aaaa aaaa'")); } + @Test public void testDeserialize() { - var dummy = new Table(PATH + "testDeserializeTable", new ArrayList<>()); - // 测试数据 var bytes = new byte[]{ 0, @@ -65,40 +74,39 @@ public void testDeserialize() { }; var inputStream = new ByteArrayInputStream(bytes); - var intField = new IntField("testDeserializeInt", false, dummy); + var intField = new IntField("testDeserializeInt", false, null); try { var intRes = (int) intField.deserialize(inputStream); - assertEquals(33, intRes); + Assert.assertEquals(33, intRes); } catch (TableConflictException e) { log.error("Exception expected: ", e); - fail("proper format should not fail to parse"); + Assert.fail("proper format should not fail to parse"); } - var floatField = new FloatField("testDeserializeFloat", false, dummy); + var floatField = new FloatField("testDeserializeFloat", false, null); try { var floatRes = (float) floatField.deserialize(inputStream); - assertEquals(1.2f, floatRes); + Assert.assertTrue(1.2f - floatRes < 0.0001); } catch (TableConflictException e) { log.error("Exception expected: ", e); - fail("proper format should not fail to parse"); + Assert.fail("proper format should not fail to parse"); } - var varcharField = new VarcharField("testDeserializeVarchar", 20, false, dummy); + var varcharField = new VarcharField("testDeserializeVarchar", 20, false, null); try { var varcharRes = (String) varcharField.deserialize(inputStream); - assertEquals("test varchar", varcharRes); + Assert.assertEquals("test varchar", varcharRes); } catch (TableConflictException e) { - fail("proper format should not fail to parse"); + Assert.fail("proper format should not fail to parse"); } - assertEquals(0, inputStream.available()); + Assert.assertEquals(0, inputStream.available()); } + @Test public void testCheckInputStream() { - var dummy = new Table(PATH + "testCheckInputStreamTable", new ArrayList<>()); - // 测试数据 var bytes = new byte[]{ 0, @@ -113,23 +121,23 @@ public void testCheckInputStream() { }; var inputStream = new ByteArrayInputStream(bytes); - var intField = new IntField("testCheckInputStreamInt", false, dummy); - assertTrue(intField.checkInputStream(inputStream)); + var intField = new IntField("testCheckInputStreamInt", false, null); + Assert.assertTrue(intField.checkInputStream(inputStream)); - var floatField = new FloatField("testCheckInputStreamFloat", false, dummy); - assertTrue(floatField.checkInputStream(inputStream)); + var floatField = new FloatField("testCheckInputStreamFloat", false, null); + Assert.assertTrue(floatField.checkInputStream(inputStream)); - var varcharField = new VarcharField("testCheckInputStreamVarchar", 20, false, dummy); - assertTrue(varcharField.checkInputStream(inputStream)); + var varcharField = new VarcharField("testCheckInputStreamVarchar", 20, false, null); + Assert.assertTrue(varcharField.checkInputStream(inputStream)); - assertEquals(0, inputStream.available()); + Assert.assertEquals(0, inputStream.available()); } + @Test public void testSerialize() { - var dummy = new Table(PATH + "testSerialize", new ArrayList<>()); - var intField = new IntField("testSerializeInt", false, dummy); + var intField = new IntField("testSerializeInt", false, null); var intBos1 = new ByteArrayOutputStream(); var intBos2 = new ByteArrayOutputStream(); @@ -142,17 +150,17 @@ public void testSerialize() { assertArrayEquals(expected, intBos1.toByteArray()); } catch (TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { intField.serialize(intBos2, "'xx'"); - fail(); + Assert.fail(); } catch (TableConflictException e) { log.error("Exception expected: ", e); } - var floatField = new FloatField("testSerializeFloat", false, dummy); + var floatField = new FloatField("testSerializeFloat", false, null); var floatBos1 = new ByteArrayOutputStream(); var floatBos2 = new ByteArrayOutputStream(); @@ -165,17 +173,17 @@ public void testSerialize() { assertArrayEquals(expected, floatBos1.toByteArray()); } catch (TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { floatField.serialize(floatBos2, "'xx'"); - fail(); + Assert.fail(); } catch (TableConflictException e) { log.error("Exception expected: ", e); } - var varcharField = new VarcharField("testSerializeVarchar", 20, false, dummy); + var varcharField = new VarcharField("testSerializeVarchar", 20, false, null); var varcharBos1 = new ByteArrayOutputStream(); var varcharBos2 = new ByteArrayOutputStream(); @@ -191,45 +199,47 @@ public void testSerialize() { assertArrayEquals(expected, varcharBos1.toByteArray()); } catch (TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { varcharField.serialize(varcharBos2, "'test varchar too looooooooooooong'"); - fail(); + Assert.fail(); } catch (TableConflictException e) { log.error("Exception expected: ", e); } } + @Test public void testDoubleCreateIndex() { - var dummy = new Table(PATH + "testCreateIndexTable", new ArrayList<>()); + var dummy = new Table("testCreateIndexTable", new ArrayList<>()); BaseField field = new IntField("testCreateIndexField", false, dummy); try { field.createIndex(); } catch (IndexAlreadyExistException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { field.createIndex(); - fail(); + Assert.fail(); } catch (IndexAlreadyExistException e) { log.error("Exception expected: ", e); } } + @Test public void testInsertIndex() { - var dummy = new Table(PATH + "testInsertIndexTable", new ArrayList<>()); + var dummy = new Table("testInsertIndexTable", new ArrayList<>()); var intField = new IntField("testInsertIndexInt", false, dummy); try { intField.insertIndex("1", 1); - fail(); + Assert.fail(); } catch (TableExistenceException | TableConflictException e) { log.error("Exception expected: ", e); } @@ -238,7 +248,7 @@ public void testInsertIndex() { intField.createIndex(); } catch (IndexAlreadyExistException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { @@ -246,12 +256,12 @@ public void testInsertIndex() { intField.insertIndex("1", 1); } catch (TableExistenceException | TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { intField.insertIndex("1xx", 1); - fail(); + Assert.fail(); } catch (TableExistenceException | TableConflictException e) { log.error("Exception expected: ", e); } @@ -260,7 +270,7 @@ public void testInsertIndex() { try { floatField.insertIndex("1.2", 1); - fail(); + Assert.fail(); } catch (TableExistenceException | TableConflictException e) { log.error("Exception expected: ", e); } @@ -269,7 +279,7 @@ public void testInsertIndex() { floatField.createIndex(); } catch (IndexAlreadyExistException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { @@ -277,12 +287,12 @@ public void testInsertIndex() { floatField.insertIndex("1.2", 1); } catch (TableExistenceException | TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { floatField.insertIndex("1xx", 1); - fail(); + Assert.fail(); } catch (TableExistenceException | TableConflictException e) { log.error("Exception expected: ", e); } @@ -292,7 +302,7 @@ public void testInsertIndex() { try { varcharField.insertIndex("xxx", 1); - fail(); + Assert.fail(); } catch (TableExistenceException e) { log.error("Exception expected: ", e); } @@ -301,7 +311,7 @@ public void testInsertIndex() { varcharField.createIndex(); } catch (IndexAlreadyExistException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { @@ -309,13 +319,15 @@ public void testInsertIndex() { varcharField.insertIndex("xxx", 1); } catch (TableExistenceException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } } + @Test public void testQueryIndex() { - var dummy = new Table(PATH + "testQueryIndexTable", new ArrayList<>()); + + var dummy = new Table("testQueryIndexTable", new ArrayList<>()); var intField = new IntField("testQueryIndexInt", false, dummy); @@ -323,7 +335,7 @@ public void testQueryIndex() { intField.createIndex(); } catch (IndexAlreadyExistException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { @@ -331,24 +343,24 @@ public void testQueryIndex() { intField.insertIndex("1", 1); } catch (TableExistenceException | TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { var uuid = intField.queryIndex("1"); - assertEquals(1, uuid.get(0).longValue()); - assertEquals(1, uuid.get(1).longValue()); + Assert.assertEquals(1, uuid.get(0).longValue()); + Assert.assertEquals(1, uuid.get(1).longValue()); } catch (TableExistenceException | TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { var uuid = intField.queryIndex("2"); - assertTrue(uuid.isEmpty()); + Assert.assertTrue(uuid.isEmpty()); } catch (TableExistenceException | TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } var floatField = new FloatField("testQueryIndexFloat", false, dummy); @@ -357,7 +369,7 @@ public void testQueryIndex() { floatField.createIndex(); } catch (IndexAlreadyExistException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { @@ -365,24 +377,24 @@ public void testQueryIndex() { floatField.insertIndex("1.2", 1); } catch (TableExistenceException | TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { var uuid = floatField.queryIndex("1.2"); - assertEquals(1, uuid.get(0).longValue()); - assertEquals(1, uuid.get(1).longValue()); + Assert.assertEquals(1, uuid.get(0).longValue()); + Assert.assertEquals(1, uuid.get(1).longValue()); } catch (TableExistenceException | TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { var uuid = floatField.queryIndex("2.2"); - assertTrue(uuid.isEmpty()); + Assert.assertTrue(uuid.isEmpty()); } catch (TableExistenceException | TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } var varcharField = new VarcharField("testQueryIndexVarchar", 20, false, dummy); @@ -391,7 +403,7 @@ public void testQueryIndex() { varcharField.createIndex(); } catch (IndexAlreadyExistException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { @@ -399,28 +411,29 @@ public void testQueryIndex() { varcharField.insertIndex("xxx", 1); } catch (TableExistenceException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { var uuid = varcharField.queryIndex("xxx"); - assertEquals(1, uuid.get(0).longValue()); - assertEquals(1, uuid.get(1).longValue()); + Assert.assertEquals(1, uuid.get(0).longValue()); + Assert.assertEquals(1, uuid.get(1).longValue()); } catch (TableExistenceException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { var uuid = varcharField.queryIndex("x"); - assertTrue(uuid.isEmpty()); + Assert.assertTrue(uuid.isEmpty()); } catch (TableExistenceException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } } - public void testLoad() { + @Test + public void testLoad() throws IndexNotFoundException { var bytes = new byte[]{ // testLoadInt 11, @@ -466,33 +479,32 @@ public void testLoad() { }; var stream = new ByteArrayInputStream(bytes); - var dummy = new Table(PATH + "testLoadTable", new ArrayList<>()); - var intField = BaseField.load(stream, dummy); - assertNotNull(intField); - assertEquals("testLoadInt", intField.getName()); - assertEquals(FieldType.INT, intField.getType()); + var intField = BaseField.load(stream, null); + Assert.assertNotNull(intField); + Assert.assertEquals("testLoadInt", intField.getName()); + Assert.assertEquals(FieldType.INT, intField.getType()); - var floatField = BaseField.load(stream, dummy); - assertNotNull(floatField); - assertEquals("testLoadFloat", floatField.getName()); - assertEquals(FieldType.FLOAT, floatField.getType()); + var floatField = BaseField.load(stream, null); + Assert.assertNotNull(floatField); + Assert.assertEquals("testLoadFloat", floatField.getName()); + Assert.assertEquals(FieldType.FLOAT, floatField.getType()); - var varcharField = BaseField.load(stream, dummy); - assertNotNull(varcharField); - assertEquals("testLoadVarchar", varcharField.getName()); - assertEquals(FieldType.VARCHAR, varcharField.getType()); - assertEquals(12, ((VarcharField) varcharField).getLimit()); + var varcharField = BaseField.load(stream, null); + Assert.assertNotNull(varcharField); + Assert.assertEquals("testLoadVarchar", varcharField.getName()); + Assert.assertEquals(FieldType.VARCHAR, varcharField.getType()); + Assert.assertEquals(12, ((VarcharField) varcharField).getLimit()); } + @Test public void testPersist() { - var dummy = new Table(PATH + "testLoadTable", new ArrayList<>()); var out = new ByteArrayOutputStream(); - var intField = new IntField("testPersistInt", false, dummy); - var floatField = new FloatField("testPersistFloat", false, dummy); - var varcharField = new VarcharField("testPersistVarchar", 12, false, dummy); + var intField = new IntField("testPersistInt", false, null); + var floatField = new FloatField("testPersistFloat", false, null); + var varcharField = new VarcharField("testPersistVarchar", 12, false, null); intField.persist(out); floatField.persist(out); diff --git a/src/test/java/net/kaaass/rumbase/table/TableManagerTest.java b/src/test/java/net/kaaass/rumbase/table/TableManagerTest.java index 3031a0b..9128abf 100644 --- a/src/test/java/net/kaaass/rumbase/table/TableManagerTest.java +++ b/src/test/java/net/kaaass/rumbase/table/TableManagerTest.java @@ -1,13 +1,21 @@ package net.kaaass.rumbase.table; -import junit.framework.TestCase; import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.FileUtil; +import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; +import net.kaaass.rumbase.query.exception.ArgumentException; +import net.kaaass.rumbase.record.exception.RecordNotFoundException; +import net.kaaass.rumbase.table.exception.TableConflictException; import net.kaaass.rumbase.table.exception.TableExistenceException; import net.kaaass.rumbase.table.field.BaseField; import net.kaaass.rumbase.table.field.FloatField; import net.kaaass.rumbase.table.field.IntField; import net.kaaass.rumbase.table.field.VarcharField; 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.util.ArrayList; @@ -19,106 +27,104 @@ * @see net.kaaass.rumbase.table.TableManager */ @Slf4j -public class TableManagerTest extends TestCase { +public class TableManagerTest { - private static final String PATH = "build/"; + @BeforeClass + @AfterClass + public static void clearDataFolder() { + log.info("清除数据文件夹..."); + FileUtil.removeDir(new File(FileUtil.DATA_PATH)); + } - public void testShowTables() { - var prefix = PATH + "testShowTables"; + @Test + public void testShowTables() throws IndexAlreadyExistException, TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { + var prefix = "testShowTables"; var tbm = new TableManager(); var fieldList = new ArrayList(); - var table = new Table(prefix + "Table", fieldList); // 增加测试表字段 - var intField = new IntField(prefix + "age", false, table); - var floatField = new FloatField(prefix + "balance", false, table); - var varcharField = new VarcharField(prefix + "name", 20, false, table); + var intField = new IntField(prefix + "age", false, null); + var floatField = new FloatField(prefix + "balance", false, null); + var varcharField = new VarcharField(prefix + "name", 20, false, null); fieldList.add(intField); fieldList.add(floatField); fieldList.add(varcharField); try { - tbm.createTable(TransactionContext.empty(), prefix + "Table", fieldList, prefix + ".db"); - } catch (TableExistenceException e) { + tbm.createTable(TransactionContext.empty(), prefix + "Table", fieldList, FileUtil.TABLE_PATH + prefix + ".db"); + } catch (TableExistenceException | RecordNotFoundException | ArgumentException | TableConflictException e) { e.printStackTrace(); - fail(); + Assert.fail(); } var tables = tbm.showTables(); - assertEquals(1, tables.size()); - assertEquals(prefix + "Table", tables.get(0)); - - new File("metadata.db").deleteOnExit(); + Assert.assertEquals(4, tables.size()); + Assert.assertEquals(prefix + "Table", tables.get(0)); } - public void testCreateTable() { - var prefix = PATH + "testCreateTable"; + @Test + public void testCreateTable() throws IndexAlreadyExistException, TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { + var prefix = "testCreateTable"; var tbm = new TableManager(); var fieldList = new ArrayList(); - var table = new Table(prefix + "Table", fieldList); // 增加测试表字段 - var intField = new IntField(prefix + "age", false, table); - var floatField = new FloatField(prefix + "balance", false, table); - var varcharField = new VarcharField(prefix + "name", 20, false, table); + var intField = new IntField(prefix + "age", false, null); + var floatField = new FloatField(prefix + "balance", false, null); + var varcharField = new VarcharField(prefix + "name", 20, false, null); fieldList.add(intField); fieldList.add(floatField); fieldList.add(varcharField); try { - tbm.createTable(TransactionContext.empty(), prefix + "Table", fieldList, prefix + ".db"); + tbm.createTable(TransactionContext.empty(), prefix + "Table", fieldList, FileUtil.TABLE_PATH + prefix + ".db"); } catch (TableExistenceException e) { e.printStackTrace(); - fail(); + Assert.fail(); } - - new File("metadata.db").deleteOnExit(); - } - public void testGetTable() { - var prefix = PATH + "testGetTable"; + @Test + public void testGetTable() throws IndexAlreadyExistException, TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { + var prefix = "testGetTable"; var tbm = new TableManager(); var fieldList = new ArrayList(); - var table = new Table(prefix + "Table", fieldList); // 增加测试表字段 - var intField = new IntField(prefix + "age", false, table); - var floatField = new FloatField(prefix + "balance", false, table); - var varcharField = new VarcharField(prefix + "name", 20, false, table); + var intField = new IntField(prefix + "age", false, null); + var floatField = new FloatField(prefix + "balance", false, null); + var varcharField = new VarcharField(prefix + "name", 20, false, null); fieldList.add(intField); fieldList.add(floatField); fieldList.add(varcharField); try { - tbm.createTable(TransactionContext.empty(), prefix + "Table", fieldList, prefix + ".db"); + tbm.createTable(TransactionContext.empty(), prefix + "Table", fieldList, FileUtil.TABLE_PATH + prefix + ".db"); } catch (TableExistenceException e) { e.printStackTrace(); - fail(); + Assert.fail(); } try { var t = tbm.getTable(prefix + "Table"); - assertEquals(prefix + "Table", t.tableName); - assertEquals(intField.getName(), t.fields.get(0).getName()); - assertEquals(intField.getType(), t.fields.get(0).getType()); - assertEquals(floatField.getName(), t.fields.get(1).getName()); - assertEquals(floatField.getType(), t.fields.get(1).getType()); - assertEquals(varcharField.getName(), t.fields.get(2).getName()); - assertEquals(varcharField.getType(), t.fields.get(2).getType()); - assertEquals(varcharField.getLimit(), ((VarcharField) t.fields.get(2)).getLimit()); + Assert.assertEquals(prefix + "Table", t.tableName); + Assert.assertEquals(intField.getName(), t.fields.get(0).getName()); + Assert.assertEquals(intField.getType(), t.fields.get(0).getType()); + Assert.assertEquals(floatField.getName(), t.fields.get(1).getName()); + Assert.assertEquals(floatField.getType(), t.fields.get(1).getType()); + Assert.assertEquals(varcharField.getName(), t.fields.get(2).getName()); + Assert.assertEquals(varcharField.getType(), t.fields.get(2).getType()); + Assert.assertEquals(varcharField.getLimit(), ((VarcharField) t.fields.get(2)).getLimit()); } catch (TableExistenceException e) { - fail(); + Assert.fail(); } - - new File("metadata.db").deleteOnExit(); } } diff --git a/src/test/java/net/kaaass/rumbase/table/TableTest.java b/src/test/java/net/kaaass/rumbase/table/TableTest.java index 575d799..100edf8 100644 --- a/src/test/java/net/kaaass/rumbase/table/TableTest.java +++ b/src/test/java/net/kaaass/rumbase/table/TableTest.java @@ -4,7 +4,9 @@ import com.igormaznitsa.jbbp.io.JBBPByteOrder; import junit.framework.TestCase; import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.FileUtil; import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; +import net.kaaass.rumbase.index.exception.IndexNotFoundException; import net.kaaass.rumbase.query.exception.ArgumentException; import net.kaaass.rumbase.record.RecordManager; import net.kaaass.rumbase.record.exception.RecordNotFoundException; @@ -12,8 +14,13 @@ import net.kaaass.rumbase.table.exception.TableExistenceException; import net.kaaass.rumbase.table.field.*; 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.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -27,12 +34,25 @@ * @see Table */ @Slf4j -public class TableTest extends TestCase { +public class TableTest { - private static final String PATH = "build/"; + @BeforeClass + public static void createDataFolder() { + log.info("创建测试文件夹..."); + FileUtil.createDir(FileUtil.TEST_PATH); + FileUtil.removeDir(FileUtil.DATA_PATH); + } + + @AfterClass + public static void clearDataFolder() { + log.info("清除测试文件夹..."); + FileUtil.removeDir(FileUtil.TEST_PATH); + FileUtil.removeDir(FileUtil.DATA_PATH); + } + @Test public void testLoad() { - var prefix = PATH + "testLoad"; + var prefix = "testLoad"; var byteOS = new ByteArrayOutputStream(); var out = new JBBPBitOutputStream(byteOS); @@ -53,29 +73,30 @@ public void testLoad() { out.writeInt(12, JBBPByteOrder.BIG_ENDIAN); } catch (IOException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } - var storage = RecordManager.fromFile(prefix + "Table"); + var storage = RecordManager.fromFile(FileUtil.TEST_PATH + prefix + "Table"); storage.setMetadata(TransactionContext.empty(), byteOS.toByteArray()); - var table = Table.load(RecordManager.fromFile(prefix + "Table")); + var table = Table.load(RecordManager.fromFile(FileUtil.TEST_PATH + prefix + "Table")); - assertNotNull(table); - assertEquals("testLoadTable", table.getTableName()); - assertEquals(-1L, table.getNext()); - assertEquals(TableStatus.NORMAL, table.getStatus()); + Assert.assertNotNull(table); + Assert.assertEquals("testLoadTable", table.getTableName()); + Assert.assertEquals(-1L, table.getNext()); + Assert.assertEquals(TableStatus.NORMAL, table.getStatus()); var fields = table.getFields(); - assertEquals("testLoadInt", fields.get(0).getName()); - assertEquals(FieldType.INT, fields.get(0).getType()); - assertEquals("testLoadFloat", fields.get(1).getName()); - assertEquals(FieldType.FLOAT, fields.get(1).getType()); - assertEquals("testLoadVarchar", fields.get(2).getName()); - assertEquals(FieldType.VARCHAR, fields.get(2).getType()); - assertEquals(12, ((VarcharField) fields.get(2)).getLimit()); + Assert.assertEquals("testLoadInt", fields.get(0).getName()); + Assert.assertEquals(FieldType.INT, fields.get(0).getType()); + Assert.assertEquals("testLoadFloat", fields.get(1).getName()); + Assert.assertEquals(FieldType.FLOAT, fields.get(1).getType()); + Assert.assertEquals("testLoadVarchar", fields.get(2).getName()); + Assert.assertEquals(FieldType.VARCHAR, fields.get(2).getType()); + Assert.assertEquals(12, ((VarcharField) fields.get(2)).getLimit()); } + @Test public void testPersist() { var fieldList = new ArrayList(); @@ -105,7 +126,7 @@ public void testPersist() { out.writeInt(12, JBBPByteOrder.BIG_ENDIAN); } catch (IOException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } assertArrayEquals(new byte[0], table.getRecordStorage().getMetadata(context)); @@ -116,7 +137,7 @@ public void testPersist() { Table createTestTable(String prefix) { var fieldList = new ArrayList(); - var table = new Table(PATH + prefix + "Table", fieldList); + var table = new Table(prefix + "Table", fieldList); // 增加测试表字段 var intField = new IntField(prefix + "age", false, table); @@ -132,12 +153,13 @@ Table createTestTable(String prefix) { floatField.createIndex(); } catch (IndexAlreadyExistException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } return table; } + @Test public void testCURD() { var prefix = "testCURD"; @@ -163,73 +185,73 @@ public void testCURD() { table.insert(context, data2); } catch (TableConflictException | TableExistenceException | ArgumentException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { // 查询记录,测试插入情况与查询情况 var iter = table.searchFirst(prefix + "age", "0"); - assertTrue(iter.hasNext()); + Assert.assertTrue(iter.hasNext()); var pair1 = iter.next(); - assertTrue(iter.hasNext()); + Assert.assertTrue(iter.hasNext()); var pair2 = iter.next(); - assertFalse(iter.hasNext()); - assertEquals(1L, pair1.getKey()); - assertEquals(33L, pair2.getKey()); + Assert.assertFalse(iter.hasNext()); + Assert.assertEquals(1L, pair1.getKey()); + Assert.assertEquals(33L, pair2.getKey()); var res1 = table.read(context, pair1.getUuid()); var res2 = table.read(context, pair2.getUuid()); - assertTrue(res1.isPresent()); - assertTrue(res2.isPresent()); + Assert.assertTrue(res1.isPresent()); + Assert.assertTrue(res2.isPresent()); - assertEquals(1, (int) res1.get().get(0)); - assertEquals(-0.4f, res1.get().get(1)); - assertEquals("ya test varchar", (String) res1.get().get(2)); + Assert.assertEquals(1, (int) res1.get().get(0)); + Assert.assertEquals(-0.4f, res1.get().get(1)); + Assert.assertEquals("ya test varchar", (String) res1.get().get(2)); - assertEquals(33, (int) res2.get().get(0)); - assertEquals(1.2f, res2.get().get(1)); - assertEquals("test varchar", (String) res2.get().get(2)); + Assert.assertEquals(33, (int) res2.get().get(0)); + Assert.assertEquals(1.2f, res2.get().get(1)); + Assert.assertEquals("test varchar", (String) res2.get().get(2)); // 测试删除记录 table.delete(context, pair2.getUuid()); var iter2 = table.searchFirst(prefix + "age", "33"); - assertTrue(iter2.hasNext()); + Assert.assertTrue(iter2.hasNext()); var pair3 = iter2.next(); - assertEquals(33L, pair3.getKey()); + Assert.assertEquals(33L, pair3.getKey()); var res3 = table.read(context, pair3.getUuid()); - assertTrue(res3.isEmpty()); // 记录不存在 + Assert.assertTrue(res3.isEmpty()); // 记录不存在 // 测试更新记录 table.update(context, pair1.getUuid(), data); var iter3 = table.searchFirst(prefix + "age", "33"); - assertTrue(iter3.hasNext()); + Assert.assertTrue(iter3.hasNext()); var pair4 = iter3.next(); - assertTrue(iter3.hasNext()); + Assert.assertTrue(iter3.hasNext()); var pair5 = iter3.next(); // 有效的被更新记录 - assertEquals(33L, pair4.getKey()); + Assert.assertEquals(33L, pair4.getKey()); var res4 = table.read(context, pair4.getUuid()); - assertTrue(res4.isPresent()); + Assert.assertTrue(res4.isPresent()); // 四记录 - assertEquals(33L, pair5.getKey()); + Assert.assertEquals(33L, pair5.getKey()); var res5 = table.read(context, pair5.getUuid()); - assertTrue(res5.isEmpty()); + Assert.assertTrue(res5.isEmpty()); // 测试记录是否被更新 - assertEquals(33, (int) res4.get().get(0)); - assertEquals(1.2f, res4.get().get(1)); - assertEquals("test varchar", (String) res4.get().get(2)); + Assert.assertEquals(33, (int) res4.get().get(0)); + Assert.assertEquals(1.2f, res4.get().get(1)); + Assert.assertEquals("test varchar", (String) res4.get().get(2)); } catch (TableExistenceException | TableConflictException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } } @@ -287,6 +309,7 @@ void addTestData(TransactionContext context, Table table) throws TableConflictEx }}); } + @Test public void testSearch() { var prefix = "testSearch"; @@ -300,7 +323,7 @@ public void testSearch() { addTestData(context, table); } catch (TableConflictException | TableExistenceException | ArgumentException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 查询记录 @@ -312,21 +335,22 @@ public void testSearch() { var res = table.read(context, uuid); res.ifPresent(resList::add); } - assertEquals(7, (int) resList.get(0).get(0)); - assertEquals(1.2f, resList.get(0).get(1)); - assertEquals("test varchar", (String) resList.get(0).get(2)); + Assert.assertEquals(7, (int) resList.get(0).get(0)); + Assert.assertEquals(1.2f, resList.get(0).get(1)); + Assert.assertEquals("test varchar", (String) resList.get(0).get(2)); - assertEquals(7, (int) resList.get(1).get(0)); - assertEquals(1.2f, resList.get(1).get(1)); - assertEquals("test varchar", (String) resList.get(1).get(2)); + Assert.assertEquals(7, (int) resList.get(1).get(0)); + Assert.assertEquals(1.2f, resList.get(1).get(1)); + Assert.assertEquals("test varchar", (String) resList.get(1).get(2)); } catch (TableExistenceException | TableConflictException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } } + @Test public void testSearchAll() { var prefix = "testSearchAll"; @@ -340,7 +364,7 @@ public void testSearchAll() { addTestData(context, table); } catch (TableConflictException | TableExistenceException | ArgumentException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } @@ -353,53 +377,54 @@ public void testSearchAll() { table.read(context, uuid.getUuid()).ifPresent(resList::add); } - assertEquals(1, (int) resList.get(0).get(0)); - assertEquals(1.2f, resList.get(0).get(1)); - assertEquals("test varchar", (String) resList.get(0).get(2)); + Assert.assertEquals(1, (int) resList.get(0).get(0)); + Assert.assertEquals(1.2f, resList.get(0).get(1)); + Assert.assertEquals("test varchar", (String) resList.get(0).get(2)); - assertEquals(2, (int) resList.get(1).get(0)); - assertEquals(1.2f, resList.get(1).get(1)); - assertEquals("test varchar", (String) resList.get(1).get(2)); + Assert.assertEquals(2, (int) resList.get(1).get(0)); + Assert.assertEquals(1.2f, resList.get(1).get(1)); + Assert.assertEquals("test varchar", (String) resList.get(1).get(2)); - assertEquals(3, (int) resList.get(2).get(0)); - assertEquals(1.2f, resList.get(2).get(1)); - assertEquals("test varchar", (String) resList.get(2).get(2)); + Assert.assertEquals(3, (int) resList.get(2).get(0)); + Assert.assertEquals(1.2f, resList.get(2).get(1)); + Assert.assertEquals("test varchar", (String) resList.get(2).get(2)); - assertEquals(3, (int) resList.get(3).get(0)); - assertEquals(1.2f, resList.get(3).get(1)); - assertEquals("test varchar", (String) resList.get(3).get(2)); + Assert.assertEquals(3, (int) resList.get(3).get(0)); + Assert.assertEquals(1.2f, resList.get(3).get(1)); + Assert.assertEquals("test varchar", (String) resList.get(3).get(2)); - assertEquals(4, (int) resList.get(4).get(0)); - assertEquals(1.2f, resList.get(4).get(1)); - assertEquals("test varchar", (String) resList.get(4).get(2)); + Assert.assertEquals(4, (int) resList.get(4).get(0)); + Assert.assertEquals(1.2f, resList.get(4).get(1)); + Assert.assertEquals("test varchar", (String) resList.get(4).get(2)); - assertEquals(5, (int) resList.get(5).get(0)); - assertEquals(1.2f, resList.get(5).get(1)); - assertEquals("test varchar", (String) resList.get(5).get(2)); + Assert.assertEquals(5, (int) resList.get(5).get(0)); + Assert.assertEquals(1.2f, resList.get(5).get(1)); + Assert.assertEquals("test varchar", (String) resList.get(5).get(2)); - assertEquals(6, (int) resList.get(6).get(0)); - assertEquals(1.2f, resList.get(6).get(1)); - assertEquals("test varchar", (String) resList.get(6).get(2)); + Assert.assertEquals(6, (int) resList.get(6).get(0)); + Assert.assertEquals(1.2f, resList.get(6).get(1)); + Assert.assertEquals("test varchar", (String) resList.get(6).get(2)); - assertEquals(7, (int) resList.get(7).get(0)); - assertEquals(1.2f, resList.get(7).get(1)); - assertEquals("test varchar", (String) resList.get(7).get(2)); + Assert.assertEquals(7, (int) resList.get(7).get(0)); + Assert.assertEquals(1.2f, resList.get(7).get(1)); + Assert.assertEquals("test varchar", (String) resList.get(7).get(2)); - assertEquals(7, (int) resList.get(8).get(0)); - assertEquals(1.2f, resList.get(8).get(1)); - assertEquals("test varchar", (String) resList.get(8).get(2)); + Assert.assertEquals(7, (int) resList.get(8).get(0)); + Assert.assertEquals(1.2f, resList.get(8).get(1)); + Assert.assertEquals("test varchar", (String) resList.get(8).get(2)); - assertEquals(8, (int) resList.get(9).get(0)); - assertEquals(1.2f, resList.get(9).get(1)); - assertEquals("test varchar", (String) resList.get(9).get(2)); + Assert.assertEquals(8, (int) resList.get(9).get(0)); + Assert.assertEquals(1.2f, resList.get(9).get(1)); + Assert.assertEquals("test varchar", (String) resList.get(9).get(2)); } catch (TableExistenceException | TableConflictException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } } + @Test public void testSearchFirst() { var prefix = "testSearchFirst"; @@ -412,7 +437,7 @@ public void testSearchFirst() { addTestData(context, table); } catch (TableConflictException | TableExistenceException | ArgumentException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 测试searchFirst try { @@ -423,24 +448,25 @@ public void testSearchFirst() { table.read(context, uuid.getUuid()).ifPresent(resList::add); } - assertEquals(3, (int) resList.get(0).get(0)); - assertEquals(1.2f, resList.get(0).get(1)); - assertEquals("test varchar", (String) resList.get(0).get(2)); + Assert.assertEquals(3, (int) resList.get(0).get(0)); + Assert.assertEquals(1.2f, resList.get(0).get(1)); + Assert.assertEquals("test varchar", (String) resList.get(0).get(2)); - assertEquals(3, (int) resList.get(1).get(0)); - assertEquals(1.2f, resList.get(1).get(1)); - assertEquals("test varchar", (String) resList.get(1).get(2)); + Assert.assertEquals(3, (int) resList.get(1).get(0)); + Assert.assertEquals(1.2f, resList.get(1).get(1)); + Assert.assertEquals("test varchar", (String) resList.get(1).get(2)); - assertEquals(4, (int) resList.get(2).get(0)); - assertEquals(1.2f, resList.get(2).get(1)); - assertEquals("test varchar", (String) resList.get(2).get(2)); + Assert.assertEquals(4, (int) resList.get(2).get(0)); + Assert.assertEquals(1.2f, resList.get(2).get(1)); + Assert.assertEquals("test varchar", (String) resList.get(2).get(2)); } catch (TableExistenceException | TableConflictException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } } + @Test public void testSearchFirstNotEqual() { var prefix = "testSearchFirstNotEqual"; @@ -453,7 +479,7 @@ public void testSearchFirstNotEqual() { addTestData(context, table); } catch (TableConflictException | TableExistenceException | ArgumentException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } // 测试searchFirstNotEqual @@ -465,16 +491,17 @@ public void testSearchFirstNotEqual() { table.read(context, uuid.getUuid()).ifPresent(resList::add); } - assertEquals(4, (int) resList.get(0).get(0)); - assertEquals(1.2f, resList.get(0).get(1)); - assertEquals("test varchar", (String) resList.get(0).get(2)); + Assert.assertEquals(4, (int) resList.get(0).get(0)); + Assert.assertEquals(1.2f, resList.get(0).get(1)); + Assert.assertEquals("test varchar", (String) resList.get(0).get(2)); } catch (TableExistenceException | TableConflictException | RecordNotFoundException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } } + @Test public void testCheckStringEntry() { var passEntry = new ArrayList(); passEntry.add("33"); @@ -495,11 +522,12 @@ public void testCheckStringEntry() { fieldList.add(floatField); fieldList.add(varcharField); - assertTrue(table.checkStringEntry(passEntry)); - assertFalse(table.checkStringEntry(failEntry)); + Assert.assertTrue(table.checkStringEntry(passEntry)); + Assert.assertFalse(table.checkStringEntry(failEntry)); } + @Test public void testStringEntryToBytes() { var passEntry = new ArrayList(); passEntry.add("33"); @@ -536,17 +564,18 @@ public void testStringEntryToBytes() { assertArrayEquals(expected, bytes); } catch (TableConflictException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { table.stringEntryToBytes(failEntry); - fail(""); + Assert.fail(""); } catch (TableConflictException e) { log.error("Exception expected: ", e); } } + @Test public void testParseEntry() { var passEntry = new byte[]{ 0, @@ -583,17 +612,17 @@ public void testParseEntry() { try { var list = table.parseEntry(passEntry); - assertEquals(33, (int) list.get(0)); - assertEquals(1.2f, list.get(1)); - assertEquals("test varchar", (String) list.get(2)); + Assert.assertEquals(33, (int) list.get(0)); + Assert.assertEquals(1.2f, list.get(1)); + Assert.assertEquals("test varchar", (String) list.get(2)); } catch (TableConflictException | IOException e) { log.error("Exception expected: ", e); - fail(); + Assert.fail(); } try { table.parseEntry(failEntry); - fail(); + Assert.fail(); } catch (TableConflictException | IOException e) { log.error("Exception expected: ", e); } diff --git a/src/test/java/net/kaaass/rumbase/transaction/TransactionContextTest.java b/src/test/java/net/kaaass/rumbase/transaction/TransactionContextTest.java index 9b97c6d..fa4fa23 100644 --- a/src/test/java/net/kaaass/rumbase/transaction/TransactionContextTest.java +++ b/src/test/java/net/kaaass/rumbase/transaction/TransactionContextTest.java @@ -1,7 +1,7 @@ package net.kaaass.rumbase.transaction; -import junit.framework.TestCase; import lombok.extern.slf4j.Slf4j; +import net.kaaass.rumbase.FileUtil; import net.kaaass.rumbase.page.exception.FileException; import net.kaaass.rumbase.transaction.exception.DeadlockException; import org.junit.AfterClass; @@ -21,33 +21,16 @@ @Slf4j public class TransactionContextTest { - public static void removeDir(File dir) { - File[] files = dir.listFiles(); - if (files != null) { - for (File file : files) { - if (file.isDirectory()) { - removeDir(file); - } else { - file.delete(); - } - } - } - - dir.delete(); + @BeforeClass + public static void createDataFolder() { + log.info("创建测试文件夹..."); + FileUtil.createDir(FileUtil.TEST_PATH); } - /** - * 创建临时文件生成目录 - */ - @BeforeClass - public static void createTmpDir() { - File dir = new File("test_gen_files"); - if (!dir.exists()) { - dir.mkdir(); - } else { - removeDir(dir); - dir.mkdir(); - } + @AfterClass + public static void clearDataFolder() { + log.info("清除测试文件夹..."); + FileUtil.removeDir(FileUtil.TEST_PATH); } /** @@ -75,7 +58,6 @@ public void testCreateTransaction() throws IOException, FileException { */ @Test public void testChangeStatus() throws IOException, FileException { - // TODO 将Mock类改成实现类 var manager = new TransactionManagerImpl("test_gen_files/test_change.log"); var committedTransaction = manager.createTransactionContext(TransactionIsolation.READ_COMMITTED); // 事务初始状态 @@ -101,7 +83,6 @@ public void testChangeStatus() throws IOException, FileException { */ @Test public void testTransactionPersistence() throws IOException, FileException { - // TODO 将Mock类改成实现类 var manager = new TransactionManagerImpl("test_gen_files/test_persistence.log"); // 事务创建,事务状态记录数改变 var transaction1 = manager.createTransactionContext(TransactionIsolation.READ_UNCOMMITTED); @@ -156,7 +137,6 @@ public void testTransactionRecovery() throws IOException, FileException { */ @Test public void testAddLock() throws IOException, FileException { - // TODO 将Mock类改成实现类 var manager = new TransactionManagerImpl("test_gen_files/test_add_lock.log"); var transaction1 = manager.createTransactionContext(TransactionIsolation.READ_UNCOMMITTED); var transaction2 = manager.createTransactionContext(TransactionIsolation.READ_UNCOMMITTED);