diff --git a/.gitignore b/.gitignore deleted file mode 100644 index fe93c2a..0000000 --- a/.gitignore +++ /dev/null @@ -1,37 +0,0 @@ -testFile -test_gen_files -xid.log -metadata.db - -# IntelliJ IDEA -.idea -*.iws -*.iml -*.ipr -build/ -.gradle - -*.srctrl* -# Compiled class file -*.class - -# Log file -*.log - -# BlueJ files -*.ctxt - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 336a154..0000000 --- a/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: java -jdk: oraclejdk11 -dist: trusty -group: edge - -script: - - ./gradlew build --scan -s diff --git a/README.md b/README.md index 6774050..f46897d 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,19 @@ # RumBase Java -| master | dev | -| ------ | --- | -| [![Build Status](https://www.travis-ci.com/kaaass/rumbase_java.svg?token=7d6V7UKwzfD6augATNKx&branch=master)](https://www.travis-ci.com/kaaass/rumbase_java) | [![Build Status](https://www.travis-ci.com/kaaass/rumbase_java.svg?token=7d6V7UKwzfD6augATNKx&branch=dev)](https://www.travis-ci.com/kaaass/rumbase_java) | - -Java构建的SQL关系型数据库。 +Java构建的高性能SQL关系型数据库。 本项目为吉林大学2018级数据库系统课程&系统软件综合实践(荣誉课)课程设计。 -## 构建 - -1. 在 Release 页面下载源码或 clone 项目 -2. 在项目目录执行 `./gradlew build` - ## 分工 | **模块** | **内容** | **负责人** | **包** | | ----------------------- | -------------------- | ---------- | ------------ | -| Server Module | 服务器、会话管理 | @KAAAsS | server | | Query Parse Module | SQL 语句解析 | @KAAAsS | parse | -| Query Execution Module | 查询执行、优化 | @KveinAxel | query | -| Table Management Module | 系统内数据库、表管理 | @KveinAxel | table | -| Indexing Module | 索引结构,使用 B+ 树 | @DoctorWei1314 | index | +| Query Execution Module | 查询执行、优化 | | query | +| Table Management Module | 系统内数据库、表管理 | | table | +| Indexing Module | 索引结构,使用 B+ 树 | | index | | Record Module | 记录管理,实现 MVCC | @KAAAsS | record | -| Transaction Module | 实现事务的管理与 2PL | @criki | transaction | -| Data Item Module | 数据项管理 | @kaito | dataitem | -| Recovery Log Module | 日志与恢复管理 | @kaito | recovery | -| Page Caching Module | 缓冲与页管理 | @XuanLaoYee | page | \ No newline at end of file +| Transaction Module | 实现事务的管理与 2PL | | transaction | +| Data Item Module | 数据项管理 | | dataitem | +| Recovery Log Module | 日志与恢复管理 | | recovery | +| Page Caching Module | 缓冲与页管理 | | page | \ No newline at end of file diff --git a/build.gradle b/build.gradle index 15a5525..47e84f2 100644 --- a/build.gradle +++ b/build.gradle @@ -2,10 +2,6 @@ plugins { id 'java' } -tasks.withType(JavaCompile) { - options.encoding = 'UTF-8' -} - group 'net.kaaass' version '1.0-SNAPSHOT' @@ -14,33 +10,5 @@ repositories { } dependencies { - // java-binary-block-parser - compile 'com.igormaznitsa:jbbp:2.0.2' - // Lombok - compileOnly 'org.projectlombok:lombok:1.18.16' - annotationProcessor 'org.projectlombok:lombok:1.18.16' - testCompileOnly 'org.projectlombok:lombok:1.18.16' - testAnnotationProcessor 'org.projectlombok:lombok:1.18.16' - // Slf4j - compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.30' - compile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.7.30' - // JSQLParser - compile 'com.github.jsqlparser:jsqlparser:4.0' - // JUnit testCompile group: 'junit', name: 'junit', version: '4.12' } - -// Agree --scan ToS -if (hasProperty('buildScan')) { - buildScan { - termsOfServiceUrl = 'https://gradle.com/terms-of-service' - termsOfServiceAgree = 'yes' - } -} - -test { - testLogging { - events "passed", "skipped", "failed" - exceptionFormat "full" - } -} diff --git a/src/main/java/net/kaaass/rumbase/Main.java b/src/main/java/net/kaaass/rumbase/Main.java deleted file mode 100644 index 25d9bc6..0000000 --- a/src/main/java/net/kaaass/rumbase/Main.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.kaaass.rumbase; - -import lombok.extern.slf4j.Slf4j; -import net.kaaass.rumbase.server.Server; - -/** - * 入口类 - * - * @author kaaass - */ -@Slf4j -public class Main { - - public static void main(String[] args) { - 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/IItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java deleted file mode 100644 index 70c6b17..0000000 --- a/src/main/java/net/kaaass/rumbase/dataitem/IItemStorage.java +++ /dev/null @@ -1,84 +0,0 @@ -package net.kaaass.rumbase.dataitem; - -import net.kaaass.rumbase.dataitem.exception.PageCorruptedException; -import net.kaaass.rumbase.dataitem.exception.UUIDException; -import net.kaaass.rumbase.transaction.TransactionContext; - -import java.util.List; - -/** - * 数据项管理接口 - * - * @author kaito - */ -public interface IItemStorage { - /** - * 插入数据项 - * - * @param item 数据项 - * @return 返回数据项的UUID - */ - long insertItem(TransactionContext txContext, byte[] item); - - /** - * 插入一个有UUID的数据项,唯一使用的地方是日志恢复时使用 - *

- * 如果数据项已经存在,就将数据更新在已存在的数据项所在空间上; - * 如果数据项不存在,则以此UUID插入数据项 - *

- * - * @param item 数据项 - * @param uuid 编号 - */ - void insertItemWithUuid(TransactionContext txContext, byte[] item, long uuid); - - /** - * 通过UUID查询数据项 - * - * @param uuid 编号 - * @return 数据项 - * @throws UUIDException UUID找不到的异常 - */ - byte[] queryItemByUuid(long uuid) throws UUIDException; - - - /** - * 列出页中所有的记录 - * - * @param pageId 页号 - * @return list的一堆数据项 - */ - List listItemByPageId(int pageId); - - /** - * 根据UUID更新数据项 - * - * @param uuid 编号 - * @param item 数据项 - * @throws UUIDException 没有找到对应UUID的异常 - */ - void updateItemByUuid(TransactionContext txContext, long uuid, byte[] item) throws UUIDException, PageCorruptedException; - - /** - * 获得数据项存储的元数据(可以用于头) - * - * @return 元数据 - */ - byte[] getMetadata(); - - /** - * 设置数据项存储的元数据(可以用于头) - * - * @param metadata 头信息 - */ - void setMetadata(TransactionContext txContext, byte[] metadata) throws PageCorruptedException; - - /** - * 清理多余的数据项,空间清理时使用。 - * - * @param uuids 数据项UUID的编号列表 - */ - void removeItems(List uuids); -} - - diff --git a/src/main/java/net/kaaass/rumbase/dataitem/ItemManager.java b/src/main/java/net/kaaass/rumbase/dataitem/ItemManager.java deleted file mode 100644 index 609fff6..0000000 --- a/src/main/java/net/kaaass/rumbase/dataitem/ItemManager.java +++ /dev/null @@ -1,59 +0,0 @@ -package net.kaaass.rumbase.dataitem; - - -import net.kaaass.rumbase.page.exception.FileException; -import net.kaaass.rumbase.page.exception.PageException; -import net.kaaass.rumbase.transaction.TransactionContext; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -/** - * 数据项管理类 - * - * @author kaito - */ - -public class ItemManager { - - static Map maps = new HashMap<>(); - - /** - * 通过文件名解析得到数据项管理器 - * - * @param fileName 文件名 - * @return 数据项管理器,用于管理数据项 - */ - public static IItemStorage fromFile(String fileName) throws FileException, IOException, PageException { - if (maps.containsKey(fileName)) { - return maps.get(fileName); - } else { - IItemStorage iItemStorage = ItemStorage.ofFile(fileName); - maps.put(fileName, iItemStorage); - return iItemStorage; - } - } - - /** - * 新建一个数据库,并且将上层提供的头信息写入。 - * - * @param fileName 文件名 - * @param metadata 上层提供的表头信息 - * @param txContext 对应的事务名 - * @return 数据项管理器 - * @throws FileException 想新建的文件已经存在的异常 - */ - public static IItemStorage createFile(TransactionContext txContext, String fileName, byte[] metadata) throws FileException, IOException, PageException { - // 如果文件已经存在,那么就抛出文件已存在异常 - if (maps.containsKey(fileName)) { - throw new FileException(1); - } else { - // 若文件不存在,则创建文件。 - IItemStorage iItemStorage = ItemStorage.ofNewFile(txContext, fileName, metadata); - maps.put(fileName, iItemStorage); - return iItemStorage; - } - - } -} diff --git a/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java deleted file mode 100644 index 7e054bb..0000000 --- a/src/main/java/net/kaaass/rumbase/dataitem/ItemStorage.java +++ /dev/null @@ -1,689 +0,0 @@ -package net.kaaass.rumbase.dataitem; - -import com.igormaznitsa.jbbp.JBBPParser; -import com.igormaznitsa.jbbp.io.JBBPOut; -import com.igormaznitsa.jbbp.mapper.Bin; -import lombok.extern.slf4j.Slf4j; -import net.kaaass.rumbase.dataitem.exception.PageCorruptedException; -import net.kaaass.rumbase.dataitem.exception.UUIDException; -import net.kaaass.rumbase.page.Page; -import net.kaaass.rumbase.page.PageManager; -import net.kaaass.rumbase.page.PageStorage; -import net.kaaass.rumbase.page.exception.FileException; -import net.kaaass.rumbase.page.exception.PageException; -import net.kaaass.rumbase.recovery.IRecoveryStorage; -import net.kaaass.rumbase.transaction.TransactionContext; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.Random; - -/** - * 数据项管理器的具体实现 - * - *

- * 每个表的头信息都是一致的,为 - * |头信息标志位:1 2 3 4(共4字节)|当前可用的第一个空闲页(4字节)|是否写入表头信息(1字节),写入为123|头信息所对应的UUID(8字节) - *

- * 同时每个页都有相应的页头,页头格式为: - * |页头标志位 2 3 4 5(共4字节)|lsn来记录日志相关内容(8字节)|页剩余空间大小(4字节)|页内数据项个数n(4字节)|每个数据项标志(n*8字节)| - *

- * 数据项标志为 |uuid后面的随机数(4字节)|在页内偏移offset(4字节)| - *

- * 每个数据项的内容为|标志位,表示有没有拉链等特殊情况(1字节)|数据长度m(4字节)|数据内容(m字节)| - * TODO : |(若有拉链的话,则记录下一个uuid位置)8字节| - *

- * - * @author kaito - */ -@Slf4j -public class ItemStorage implements IItemStorage { - - private String fileName; - /** - * 当前第一个空闲的页,用于插入时作为起始页来进行操作。 - */ - private int tempFreePage; - /** - * 表信息头对应的UUID - */ - private long headerUuid; - /** - * 内部维护一个对应该文件的页管理器 - */ - private PageStorage pageStorage; - /** - * 维护一个日志管理器 - */ - private IRecoveryStorage recoveryStorage; - - - public ItemStorage(String fileName, int tempFreePage, long headerUuid, PageStorage pageStorage) { - this.fileName = fileName; - this.tempFreePage = tempFreePage; - this.headerUuid = headerUuid; - this.pageStorage = pageStorage; - } - - /** - * 判断有没有头部标志 - * - *

- * 获取表头的前四个字节数据,若是1234则表示是表头,解析后面的数据,否则就认为该表没有被初始化 - *

- * - * @param header 第一页的Page对象 - * @return 是否是表的第一页 - */ - private static boolean checkTableHeader(Page header) { - var data = header.getData(); - byte[] flag = new byte[4]; - try { - data.read(flag); - } catch (IOException e) { - throw new PageCorruptedException(1, e); - } - return flag[0] == 1 && flag[1] == 2 && flag[2] == 3 && flag[3] == 4; - } - - /** - * 打开相应的文件并读取头信息,如果没有对应的头信息就进行初始化 - * - * @param fileName 文件名 - * @return 解析或新建得到的数据项管理器对象 - */ - public static IItemStorage ofFile(String fileName) throws FileException, PageException { - var pageStorage = PageManager.fromFile(fileName); - var header = pageStorage.get(0); - header.pin(); - 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); - } - } finally { - header.unpin(); - } - } - - /** - * 创建新的表,初始化相应数据,并且保存头信息。 - * - * @param fileName 文件名 - * @param metadata 表头信息 - * @return 数据项管理器 - */ - public static IItemStorage ofNewFile(TransactionContext txContext, String fileName, byte[] metadata) throws IOException, FileException, PageException { - var pageStorage = ItemStorage.ofFile(fileName); - pageStorage.setMetadata(txContext, metadata); - return pageStorage; - } - - /** - * 根据uuid获取后面的随机位置 - */ - private static int getRndByUuid(long uuid) { - return (int) (uuid & 0xFFFFFFFF); - } - - /** - * 根据uuid获取page - */ - private Page getPage(long uuid) { - var pageId = uuid >> 32; - Page page = pageStorage.get(pageId); - page.pin(); - return page; - } - - /** - * 根据pageId获取Page - */ - private Page getPage(int pageId) { - Page page = pageStorage.get(pageId); - page.pin(); - return page; - } - - /** - * 释放page的操作 - * - * @param page - */ - private void releasePage(Page page) { - page.unpin(); - } - - /** - * 解析表头数据 - * - * @return 解析得到的表头对象 - */ - private static TableHeader parseHeader(Page page) throws PageCorruptedException { - try { - return JBBPParser.prepare("int headerFlag;int tempFreePage;byte hasHeaderInfo;long headerUuid;"). - parse(page.getData()).mapTo(new TableHeader()); - } catch (IOException e) { - throw new PageCorruptedException(1, e); - } - } - - /** - * 通过偏移量解析得到数据 - * - * @param page 页 - * @param item 一个数据项记录 - * @return 解析得到的数据 - */ - private static byte[] parseData(Page page, Item item) throws PageCorruptedException { - int offset = item.offset; - var data = page.getData(); - try { - data.skip(offset); - var content = JBBPParser.prepare("byte type;int size;byte[size] data;").parse(data).mapTo(new ItemContent()); - if (content.type != NORMAL_DATA) { - throw new PageCorruptedException(2); - } - return content.data; - } catch (IOException e) { - throw new PageCorruptedException(2, e); - } - } - - /** - * 检查一个页头标志位是否存在,表示其是否已经被初始化。若初始化则标志位为2345 - * - * @param page 页 - * @return 该页是否已经被初始化 - */ - private boolean checkPageHeader(Page page) { - byte[] pageFlag = new byte[4]; - try { - var n = page.getData().read(pageFlag); - } catch (IOException e) { - throw new PageCorruptedException(1, e); - } - return pageFlag[0] == 2 && pageFlag[1] == 3 && pageFlag[2] == 4 && pageFlag[3] == 5; - } - - private Optional getPageHeader(Page page) { - try { - if (checkPageHeader(page)) { - // 如果页头信息正确,就解析得到页头信息的对象。 - var data = page.getData(); - var pageHeader = JBBPParser.prepare("int pageFlag;long lsn;int leftSpace;int recordNumber;" + - "item [recordNumber]{int uuid;int offset;}").parse(data); - var p = pageHeader.mapTo(new PageHeader()); - return Optional.of(p); - } - } catch (IOException e) { - throw new PageCorruptedException(1, e); - } - // 否则返回空,交由上层处理。 - return Optional.empty(); - } - - private PageHeader initPage(Page page) { - final byte[] bytes; - try { - bytes = JBBPOut.BeginBin(). - Byte(2, 3, 4, 5). // 页头标志位 - Long(0). // 日志记录位置,以后若有日志记录点则使用 - Int(4072). // 剩余空间大小 - Int(0). // 记录数目 - End().toByteArray(); - page.patchData(0, bytes); - } catch (IOException | PageException e) { - throw new PageCorruptedException(1, e); - } - return new PageHeader(0, 0, 4072, 0); - } - - /** - * 修改当前第一个可用页 - */ - private void addTempFreePage() { - this.tempFreePage += 1; - var page = pageStorage.get(0); - page.pin(); - byte[] tempFreePage; - try { - tempFreePage = JBBPOut.BeginBin(). - Int(this.tempFreePage) - .End().toByteArray(); - page.patchData(4, tempFreePage); - } catch (Exception e) { - throw new PageCorruptedException(1, e); - } finally { - page.unpin(); - } - } - - @Override - public synchronized long insertItem(TransactionContext txContext, byte[] item) { - var page = getPage(this.tempFreePage); - try { - var pageHeaderOp = getPageHeader(page); - if (pageHeaderOp.isEmpty()) { - // 如果获取的页没有页头信息,则进行初始化。 - pageHeaderOp = Optional.of(initPage(page)); - } - var pageHeader = pageHeaderOp.get(); - if (pageHeader.leftSpace - Math.min(item.length, MAX_RECORD_SIZE) <= MIN_LEFT_SPACE) { - // 如果剩余空间过小的话,就切换到下一个页进行,同时修改表头信息.并且,若数据过大则使用拉链,所以取512和数据大小较小的 - addTempFreePage(); - return insertItem(txContext, item); - } else { - // 剩余空间足够,则插入 - int rnd = Math.abs(new Random().nextInt()); - long s = this.tempFreePage; - long uuid = ((s << 32) + (long) (rnd)); - // 保证uuid不重复 - while (checkUuidExist(uuid)) { - rnd = Math.abs(new Random().nextInt()); - uuid = ((s << 32) + (long) (rnd)); - } - insertToPage(page, pageHeader, txContext, item, rnd); - return uuid; - } - } catch (PageCorruptedException e) { - throw e; - } catch (Exception e) { - throw new PageCorruptedException(3); - } finally { - releasePage(page); - } - } - - /** - * 将数据插入到页内对应位置,并修改页头信息 - */ - private void insertToPage(Page page, PageHeader pageHeader, TransactionContext txContext, byte[] item, int rnd) { - if (item.length < MAX_RECORD_SIZE) { - int offset = 0; - if (pageHeader.recordNumber == 0) { - // 如果页没有元素的话 - offset = 4095 - item.length - DATA_EXTRA_SIZE; - } else { - // 如果页内有插入的数据,则读取其offset并推算自己的offset - offset = pageHeader.item[pageHeader.recordNumber - 1].offset - item.length - DATA_EXTRA_SIZE; - } - try { - //修改数据项头信息 - var i = JBBPOut.BeginBin(). - Int(rnd). - Int(offset). - End().toByteArray(); - page.patchData(ITEM_OFFSET + pageHeader.recordNumber * ITEM_SIZE, i); - //修改数据信息 - var data = JBBPOut.BeginBin(). - Byte(NORMAL_DATA). - Int(item.length). - Byte(item).End().toByteArray(); - page.patchData(offset, data); - } catch (IOException | PageException e) { - throw new PageCorruptedException(2, e); - } - try { - //修改页头信息 - var headerInfo = JBBPOut.BeginBin(). - Int(pageHeader.leftSpace - item.length - DATA_EXTRA_SIZE - ITEM_SIZE). - Int(pageHeader.recordNumber + 1). - End().toByteArray(); - page.patchData(LEFT_SPACE_OFFSET, headerInfo); - } catch (IOException | PageException e) { - throw new PageCorruptedException(1, e); - } - } - } - - @Override - public synchronized void insertItemWithUuid(TransactionContext txContext, byte[] item, long uuid) { - if (!checkUuidExist(uuid)) { - // 若不存在,则要恢复 - var page = getPage(uuid); - try { - var pageHeaderOp = getPageHeader(page); - if (pageHeaderOp.isEmpty()) { - // 如果获取的页没有页头信息,则进行初始化。 - pageHeaderOp = Optional.of(initPage(page)); - } - int rnd = getRndByUuid(uuid); - insertToPage(page, pageHeaderOp.get(), txContext, item, rnd); - } catch (Exception e) { - throw new PageCorruptedException(3); - } finally { - releasePage(page); - } - } - // 若存在则不需要恢复,直接返回 - } - - /** - * 检查uuid是否存在,若Uuid的页号超过当前可用页,则直接返回False - * - * @param uuid - * @return - */ - private boolean checkUuidExist(long uuid) { - var pageId = uuid >> 32; - if (pageId > this.tempFreePage || pageId < 0) { - return false; - } - var page = getPage(uuid); - int id = getRndByUuid(uuid); - try { - var pageHeader = getPageHeader(page); - if (pageHeader.isEmpty()) { - return false; - } else { - for (var item : pageHeader.get().item) { - if (id == item.uuid) { - return true; - } - } - } - return false; - } catch (Exception e) { - throw new PageCorruptedException(2); - } finally { - releasePage(page); - } - } - - @Override - public byte[] queryItemByUuid(long uuid) throws UUIDException { - if (checkUuidExist(uuid)) { - var page = getPage(uuid); - try { - var header = getPageHeader(page); - if (header.isEmpty()) { - throw new UUIDException(2); - } else { - // 遍历所有的item读取数据 - var items = header.get().item; - int id = getRndByUuid(uuid); - for (var item : items) { - if (item.uuid == id) { - var s = parseData(page, item); - return s; - } - } - } - return new byte[0]; - } catch (Exception e) { - throw new UUIDException(2); - } finally { - releasePage(page); - } - } else { - throw new UUIDException(2); - } - } - - - @Override - public List listItemByPageId(int pageId) { - var page = getPage(pageId); - try { - List bytes = new ArrayList<>(); - var pageHeaderOp = getPageHeader(page); - if (pageHeaderOp.isPresent()) { - var pageHeader = pageHeaderOp.get(); - for (var item : pageHeader.item) { - var data = parseData(page, item); - bytes.add(data); - } - } - return bytes; - } catch (Exception e) { - throw new PageCorruptedException(2); - } finally { - releasePage(page); - } - } - - @Override - public void updateItemByUuid(TransactionContext txContext, long uuid, byte[] item) throws UUIDException, PageCorruptedException { - var page = getPage(uuid); - try { - if (checkUuidExist(uuid)) { - var pageHeader = getPageHeader(page); - var items = pageHeader.get().item; - try { - for (var i : items) { - if (i.uuid == getRndByUuid(uuid)) { - var offset = i.offset; - var bytes = JBBPOut.BeginBin(). - Byte(NORMAL_DATA). - Int(item.length) - .Byte(item) - .End().toByteArray(); - page.patchData(offset, bytes); - return; - } - } - } catch (PageException | IOException e) { - throw new PageCorruptedException(2, e); - } - } else { - throw new UUIDException(2); - } - } finally { - releasePage(page); - } - } - - @Override - public byte[] getMetadata() { - var page = getPage(0); - var header = parseHeader(page); - if (checkTableHeader(page) && header.hasHeaderInfo == HAS_HEADER) { - // 若表头已经被初始化并且有标志位的话,就说明有表头信息,进行获取. - byte[] h; - try { - h = queryItemByUuid(header.headerUuid); - } catch (UUIDException e) { - // 若UUID不存在,肯定是页头的问题,因为控制过程都是ItemStorage操作的 - throw new PageCorruptedException(1, e); - } finally { - releasePage(page); - } - return h; - } else { - // 默认Metadata为空 - releasePage(page); - return new byte[0]; - } - } - - @Override - public void setMetadata(TransactionContext txContext, byte[] metadata) throws PageCorruptedException { - var page = getPage(0); - try { - var headerUuid = insertItem(txContext, metadata); - var bytes = JBBPOut.BeginBin(). - Byte(HAS_HEADER). - Long(headerUuid).End().toByteArray(); - page.patchData(HEADER_OFFSET, bytes); - } catch (Exception e) { - throw new PageCorruptedException(1, e); - } finally { - releasePage(page); - } - } - - @Override - public void removeItems(List uuids) { - - } - - /** - * - */ - final static byte NORMAL_DATA = 121; - /** - * 头部标志的偏移 - */ - final static int HEADER_OFFSET = 8; - - /** - * 表头判断是否有表头数据 - */ - final static byte HAS_HEADER = 123; - /** - * 数据项记录的大小 - */ - final static int ITEM_SIZE = 8; - - /** - * 数据项记录的起始偏移 - */ - final static int ITEM_OFFSET = 20; - /** - * 记录数据项标志和数据项大小额外占用的空间 - */ - final static int DATA_EXTRA_SIZE = 5; - /** - * 页内空闲空间的页内偏移 - */ - final static int LEFT_SPACE_OFFSET = 12; - /** - * 页的大小 - */ - final static int PAGE_SIZE = 4096; - /** - * 单个数据项的最大值,超过的话使用拉链 - */ - final static int MAX_RECORD_SIZE = 512; - /** - * 每个页保留的大小 - */ - final static int MIN_LEFT_SPACE = 409; - - /** - * 表头 - */ - public static class TableHeader { - /** - * 是否是表头的标志 - */ - @Bin - int headerFlag; - /** - * 第一个可使用的空闲页编号 - */ - @Bin - int tempFreePage; - /** - * 是否有表头信息 - */ - @Bin - byte hasHeaderInfo; - /** - * 表头信息对应的UUID - */ - @Bin - long headerUuid; - - public Object newInstance(Class klazz) { - return klazz == TableHeader.class ? new TableHeader() : null; - } - } - - /** - * 每个数据项对应的相关信息 - */ - public static class Item { - /** - * 数据项编号 - */ - @Bin - public int uuid; - /** - * 页内偏移 - */ - @Bin - public int offset; - - public Object newInstance(Class klazz) { - return klazz == Item.class ? new Item() : null; - } - } - - /** - * 页头 - */ - public static class PageHeader { - /** - * 页头标志 - */ - @Bin - public int pageFlag; - - /** - * 日志记录编号 - */ - @Bin - long lsn; - /** - * 剩余空间大小 - */ - @Bin - int leftSpace; - /** - * 页内记录总数 - */ - @Bin - int recordNumber; - /** - * 页内记录的相关信息 - */ - @Bin - Item[] item; - - public PageHeader() { - } - - public PageHeader(int pageFlag, long lsn, int leftSpace, int recordNumber) { - this.pageFlag = pageFlag; - this.lsn = lsn; - this.leftSpace = leftSpace; - this.recordNumber = recordNumber; - } - - public Object newInstance(Class klazz) { - return klazz == PageHeader.class ? new PageHeader() : null; - } - } - - public static class ItemContent { - @Bin - byte type; - @Bin - int size; - @Bin - byte[] data; - - public Object newInstance(Class klazz) { - return klazz == ItemContent.class ? new ItemContent() : null; - } - } -} diff --git a/src/main/java/net/kaaass/rumbase/dataitem/exception/PageCorruptedException.java b/src/main/java/net/kaaass/rumbase/dataitem/exception/PageCorruptedException.java deleted file mode 100644 index 11255fd..0000000 --- a/src/main/java/net/kaaass/rumbase/dataitem/exception/PageCorruptedException.java +++ /dev/null @@ -1,27 +0,0 @@ -package net.kaaass.rumbase.dataitem.exception; - -import net.kaaass.rumbase.exception.RumbaseRuntimeException; - -import java.util.HashMap; -import java.util.Map; - -/** - * 对数据库进行解析时出现的异常错误 - * - * @author kaito - */ -public class PageCorruptedException extends RumbaseRuntimeException { - public static final Map REASONS = new HashMap<>() {{ - put(1, "没有相应表头信息或表头信息损坏"); - put(2, "数据项信息损坏"); - put(3, "数据插入异常"); - }}; - - public PageCorruptedException(int subID) { - super(7002, subID, REASONS.get(subID)); - } - - public PageCorruptedException(int subID, Throwable e) { - super(7002, subID, REASONS.get(subID), e); - } -} diff --git a/src/main/java/net/kaaass/rumbase/dataitem/exception/UUIDException.java b/src/main/java/net/kaaass/rumbase/dataitem/exception/UUIDException.java deleted file mode 100644 index e551ae1..0000000 --- a/src/main/java/net/kaaass/rumbase/dataitem/exception/UUIDException.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.kaaass.rumbase.dataitem.exception; - -import net.kaaass.rumbase.exception.RumbaseException; - -import java.util.HashMap; -import java.util.Map; - -/** - * 关于Uuid的相关错误 - * - * @author kaito - */ -public class UUIDException extends RumbaseException { - - public static final Map REASONS = new HashMap<>() {{ - put(1, "要插入的UUID已存在"); - put(2, "要查找的UUID不存在"); - }}; - - public UUIDException(int subID) { - super(7001, subID, REASONS.get(subID)); - } -} diff --git a/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java b/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java deleted file mode 100644 index 19e6fd5..0000000 --- a/src/main/java/net/kaaass/rumbase/dataitem/mock/MockItemStorage.java +++ /dev/null @@ -1,156 +0,0 @@ -package net.kaaass.rumbase.dataitem.mock; - -import lombok.Data; -import net.kaaass.rumbase.dataitem.IItemStorage; -import net.kaaass.rumbase.dataitem.exception.UUIDException; -import net.kaaass.rumbase.transaction.TransactionContext; - -import java.util.*; - -/** - * 数据项管理的Mock,进行数据项的增删改查 - * - * @author kaito - */ -@Data -public class MockItemStorage implements IItemStorage { - - private String fileName; - /** - * 当前第一个空闲的页,用于插入时作为起始页来进行操作。 - */ - private int tempFreePage; - /** - * 表信息头对应的UUID - */ - private long headerUuid; - - - /** - * 模拟的数据信息 - */ - private Map maps; - /** - * 模拟的文件头信息 - */ - private byte[] meta; - - /** - * 模拟的构造函数 - * - * @param fileName 文件名 - * @param tempFreePage 当前第一个空闲页号 - * @param headerUuid 头信息对应UUID - */ - public MockItemStorage(String fileName, int tempFreePage, long headerUuid) { - this.fileName = fileName; - this.tempFreePage = tempFreePage; - this.headerUuid = headerUuid; - maps = new HashMap<>(); - meta = new byte[1024]; - } - - public Map getMap() { - return maps; - } - - /** - * 通过已存在的文件名解析得到数据项管理器 - * - * @param fileName 文件名 - * @return 数据项管理器 - */ - - public static IItemStorage ofFile(String fileName) { - // TODO: 实际通过文件名建立数据项管理器,还需要获取到文件头信息来解析得到可以插入的起始页 - return new MockItemStorage(fileName, 0, 0); - } - - /** - * 新建数据库,并写入表头 - * - * @param fileName 文件名 - * @param tableHeader 表头信息 - * @return 返回数据项管理器 - */ - public static IItemStorage ofNewFile(TransactionContext txContext, String fileName, byte[] tableHeader) { - // TODO: 因为是新建的文件,所以需要给文件头写入头信息数据。 - return new MockItemStorage(fileName, 0, 0); - } - - - @Override - public long insertItem(TransactionContext txContext, byte[] item) { - Random ran = new Random(); - long r = ran.nextLong(); - maps.put(r, item); - return r; - } - - @Override - public void insertItemWithUuid(TransactionContext txContext, byte[] item, long uuid) { - maps.put(uuid, item); - } - - @Override - public byte[] queryItemByUuid(long uuid) throws UUIDException { - if (maps.containsKey(uuid)) { - return maps.get(uuid); - } else { - throw new UUIDException(2); - } - } - - @Override - public List listItemByPageId(int pageId) { - return new ArrayList<>(maps.values()); - } - - @Override - public void updateItemByUuid(TransactionContext txContext, long uuid, byte[] item) throws UUIDException { - if (maps.containsKey(uuid)) { - maps.put(uuid, item); - } else { - throw new UUIDException(2); - } - } - - @Override - public byte[] getMetadata() { - return meta; - } - - @Override - public void setMetadata(TransactionContext txContext, byte[] metadata) { - this.meta = metadata; - } - - - @Override - public void removeItems(List uuids) { - System.out.println("已经清除文件对应uuid的信息"); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - MockItemStorage that = (MockItemStorage) o; - return tempFreePage == that.tempFreePage && - headerUuid == that.headerUuid && - Objects.equals(fileName, that.fileName) && - Objects.equals(maps, that.maps) && - Arrays.equals(meta, that.meta); - } - - @Override - public int hashCode() { - int result = Objects.hash(fileName, tempFreePage, headerUuid, maps); - result = 31 * result + Arrays.hashCode(meta); - return result; - } -} diff --git a/src/main/java/net/kaaass/rumbase/exception/RumbaseException.java b/src/main/java/net/kaaass/rumbase/exception/RumbaseException.java deleted file mode 100644 index 4f6a659..0000000 --- a/src/main/java/net/kaaass/rumbase/exception/RumbaseException.java +++ /dev/null @@ -1,63 +0,0 @@ -package net.kaaass.rumbase.exception; - -/** - * 错误基类 - *

- * 错误分为主错误号、子错误号。 - * 主错误号应该体现错误的类型,由子类构造器直接赋值。主错误号由模块号确定十进制千位,其余位由模块编码。 - * 子错误号体现错误的细节、逻辑。在具体抛出错误的时候赋值。 - *

- * 主错误号模块分配: - * - * - * - * - * - * - * - * - * - * - * - * - * - *
功能起始主错误号
SQL 语句解析parse1000
查询执行、优化query2000
系统内数据库、表管理table3000
索引结构,使用 B+ 树index4000
记录管理,实现 MVCCrecord5000
实现事务的管理与 2PLtransaction6000
数据项管理dataitem7000
日志与恢复管理recovery8000
缓冲与页管理page9000
- *

- * 如对于 {@link net.kaaass.rumbase.record.exception.RecordNotFoundException},主错误号 - * 是5001,而子错误号不同表示不同发生原因。如物理记录不存在,或记录对事务不可见等等。 - * - * @author kaaass - */ -public class RumbaseException extends Exception { - - private int mainId; - - private int subId; - - /** - * 构造Rumbase异常 - * - * @param mainId 主错误号 - * @param subId 子错误号 - * @param reason 错误原因 - */ - public RumbaseException(int mainId, int subId, String reason) { - super(String.format("E%d-%d: %s", mainId, subId, reason)); - this.mainId = mainId; - this.subId = subId; - } - - /** - * 构造Rumbase异常 - * - * @param mainId 主错误号 - * @param subId 子错误号 - * @param reason 错误原因 - * @param cause 源错误 - */ - public RumbaseException(int mainId, int subId, String reason, Throwable cause) { - super(String.format("E%d-%d: %s", mainId, subId, reason), cause); - this.mainId = mainId; - this.subId = subId; - } -} diff --git a/src/main/java/net/kaaass/rumbase/exception/RumbaseRuntimeException.java b/src/main/java/net/kaaass/rumbase/exception/RumbaseRuntimeException.java deleted file mode 100644 index c719220..0000000 --- a/src/main/java/net/kaaass/rumbase/exception/RumbaseRuntimeException.java +++ /dev/null @@ -1,41 +0,0 @@ -package net.kaaass.rumbase.exception; -/** - * 运行时错误基类 - *

- * 详细的错误规范参考 {@link net.kaaass.rumbase.exception.RumbaseException} - * - * @author kaaass - */ -public class RumbaseRuntimeException extends RuntimeException { - - private int mainId; - - private int subId; - - /** - * 构造Rumbase运行时异常 - * - * @param mainId 主错误号 - * @param subId 子错误号 - * @param reason 错误原因 - */ - public RumbaseRuntimeException(int mainId, int subId, String reason) { - super(String.format("E%d-%d: %s", mainId, subId, reason)); - this.mainId = mainId; - this.subId = subId; - } - - /** - * 构造Rumbase运行时异常 - * - * @param mainId 主错误号 - * @param subId 子错误号 - * @param reason 错误原因 - * @param cause 源错误 - */ - public RumbaseRuntimeException(int mainId, int subId, String reason, Throwable cause) { - super(String.format("E%d-%d: %s", mainId, subId, reason), cause); - this.mainId = mainId; - this.subId = subId; - } -} diff --git a/src/main/java/net/kaaass/rumbase/index/Index.java b/src/main/java/net/kaaass/rumbase/index/Index.java deleted file mode 100644 index aba3871..0000000 --- a/src/main/java/net/kaaass/rumbase/index/Index.java +++ /dev/null @@ -1,140 +0,0 @@ -package net.kaaass.rumbase.index; - -import net.kaaass.rumbase.index.btree.BPlusTreeIndex; -import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; -import net.kaaass.rumbase.index.exception.IndexNotFoundException; -import net.kaaass.rumbase.index.mock.MockBtreeIndex; -import net.kaaass.rumbase.page.Page; -import net.kaaass.rumbase.page.PageManager; -import net.kaaass.rumbase.page.PageStorage; -import net.kaaass.rumbase.page.exception.FileException; - -import javax.swing.*; -import java.io.File; -import java.io.IOException; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -/** - * 索引 - * - * @author DoctorWei1314 - */ - -public interface Index extends Iterable { - /** - * 通过文件名拿到索引,如果不存在,则抛出异常 - * - * @param indexFileName - * @return - * @throws IndexNotFoundException - */ - static Index getIndex(String indexFileName) throws IndexNotFoundException { - if (BPlusTreeIndex.B_PLUS_TREE_INDEX_MAP.get(indexFileName) != null) { - return BPlusTreeIndex.B_PLUS_TREE_INDEX_MAP.get(indexFileName); - } else { - BPlusTreeIndex bPlusTreeIndex = new BPlusTreeIndex(indexFileName); - if (!bPlusTreeIndex.isIndexedFile()) { - throw new IndexNotFoundException(1); - } - BPlusTreeIndex.B_PLUS_TREE_INDEX_MAP.put(indexFileName, bPlusTreeIndex); - return bPlusTreeIndex; - } - } - - /** - * 查看索引文件是否存在 - * - * @param indexFileName - * @return - */ - static boolean exists(String indexFileName) { - return new File(indexFileName).exists(); - } - - /** - * 创建一个空的索引 - * - * @param indexFileName - * @return - * @throws IndexAlreadyExistException - */ - static Index createEmptyIndex(String indexFileName) throws IndexAlreadyExistException { - BPlusTreeIndex bPlusTreeIndex = new BPlusTreeIndex(indexFileName); - if (bPlusTreeIndex.isIndexedFile()) { - throw new IndexAlreadyExistException(1); - } - bPlusTreeIndex.initPage(); - BPlusTreeIndex.B_PLUS_TREE_INDEX_MAP.put(indexFileName, bPlusTreeIndex); - return bPlusTreeIndex; - } - - /** - * 对索引节点的uuid值进行批量替换 - * - * @param uuidMap UUID替换表,键为旧UUID,值为替换的目标UUID - */ - void replace(Map uuidMap); - - /** - * 向索引中加入键值对“数据Hash-UUID” - * - * @param dataHash 数据Hash - * @param uuid 对应记录UUID - */ - void insert(long dataHash, long uuid); - - /** - * 查询所有数据Hash对应的UUID - * - * @param dataHash 数据Hash - * @return 返回所有对应的UUID,若不存在则为空 - */ - List query(long dataHash); - - /** - * 查找第一个键为dataHash的键值对 - *

- * 如 dataHash = 4,当前键值有: - *

-     * 3 3 [4 4] 5 5 7 7
-     *      ↑迭代器指向
-     * 
-     *
-     * @param dataHash 数据Hash
-     * @return 指向该键值对的迭代器
-     */
-    Iterator findFirst(long dataHash);
-
-    /**
-     * 查找键为dataHash的上界
-     * 

- * 如 dataHash = 4,当前键值有: - *

-     * 3 3 [4 4] 5 5 7 7
-     *           ↑迭代器指向
-     * 
-     *
-     * @param dataHash 数据Hash
-     * @return 指向该键值对的迭代器
-     */
-    Iterator findUpperbound(long dataHash);
-
-    /**
-     * 返回第一个键值对的迭代器
-     *
-     * @return 指向该键值对的迭代器
-     */
-    Iterator findFirst();
-
-    /**
-     * 返回遍历索引的迭代器
-     *
-     * @return 第一个键值对的迭代器
-     */
-    @Override
-    default Iterator iterator() {
-        return findFirst();
-    }
-}
diff --git a/src/main/java/net/kaaass/rumbase/index/Pair.java b/src/main/java/net/kaaass/rumbase/index/Pair.java
deleted file mode 100644
index e361483..0000000
--- a/src/main/java/net/kaaass/rumbase/index/Pair.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package net.kaaass.rumbase.index;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-
-/**
- * 用于保存索引中的key-uuid对,上层模块可以根据key的值判断是否决定停止迭代,以获得想要的范围数据
- * @author 无索魏
- */
-@Data
-@AllArgsConstructor
-public class Pair {
-    private long key;
-    private long uuid;
-}
diff --git a/src/main/java/net/kaaass/rumbase/index/btree/BPlusTreeIndex.java b/src/main/java/net/kaaass/rumbase/index/btree/BPlusTreeIndex.java
deleted file mode 100644
index 9a45793..0000000
--- a/src/main/java/net/kaaass/rumbase/index/btree/BPlusTreeIndex.java
+++ /dev/null
@@ -1,1196 +0,0 @@
-package net.kaaass.rumbase.index.btree;
-
-import lombok.extern.slf4j.Slf4j;
-import net.kaaass.rumbase.index.Index;
-import net.kaaass.rumbase.index.Pair;
-import net.kaaass.rumbase.index.exception.ItemInNextPageException;
-import net.kaaass.rumbase.index.exception.PageFullException;
-import net.kaaass.rumbase.index.exception.PageTypeException;
-import net.kaaass.rumbase.page.Page;
-import net.kaaass.rumbase.page.PageManager;
-import net.kaaass.rumbase.page.PageStorage;
-import net.kaaass.rumbase.page.exception.FileException;
-import net.kaaass.rumbase.page.exception.PageException;
-
-import javax.management.loading.MLet;
-import java.nio.file.attribute.UserDefinedFileAttributeView;
-import java.util.*;
-import java.util.concurrent.locks.ReadWriteLock;
-
-/**
- * @author 无索魏
- */
-@Slf4j
-public class BPlusTreeIndex implements Index {
-//    Page root;
-    PageStorage pageStorage;
-
-    private enum PageType {  //页类型
-        INTERNAL,
-        //树枝节点
-        LEAF,
-        //树叶节点
-        META;
-        //元信息节点
-    }
-
-    /**
-     * 内存中已经加载的的BPlusTreeIndex
-     */
-
-    public static Map B_PLUS_TREE_INDEX_MAP = new HashMap<>();
-    public static int MAX_PAGE_ITEM = (4096 - 24)/16;
-    public static int PAGE_BEGIN_POSTION = 24;
-    public static int PAGE_MID_POSTION = PAGE_BEGIN_POSTION + 16 * (BPlusTreeIndex.MAX_PAGE_ITEM)/2 ;
-    private static final int rootNum = 4;
-
-    private Map RW_LOCKS = new HashMap<>();
-
-    public BPlusTreeIndex(String indexName) {
-        try {
-            pageStorage = PageManager.fromFile(indexName);
-        } catch (FileException e) {
-            e.printStackTrace();
-        }
-    }
-
-
-    synchronized public void initPage() {
-        initRootAsLeaf();
-        Page metaPage = this.pageStorage.get(0);
-        //pin
-        metaPage.pin();
-        setPageType(metaPage,PageType.META);
-        byte[] bs = ByteUtil.long2Bytes(5);
-        byte[] indexFlag = ByteUtil.long2Bytes(Long.MAX_VALUE);//作为索引文件的标志
-        try {
-            metaPage.patchData(4,bs);
-            metaPage.patchData(12,indexFlag);
-        } catch (PageException e) {
-            e.printStackTrace();
-        }finally {
-            //flush
-            try {
-                metaPage.flush();
-            } catch (FileException e) {
-                e.printStackTrace();
-            }
-            //unpin
-            metaPage.unpin();
-        }
-    }
-
-    public boolean isIndexedFile() {
-        return Long.MAX_VALUE == ByteUtil.bytes2Long(ByteUtil.subByte(this.pageStorage.get(0).getDataBytes(),12,8));
-    }
-
-    @Override
-    public void replace(Map uuidMap) {
-        //TODO
-    }
-
-    @Override
-    synchronized public void insert(long dataHash, long uuid) {
-        Stack pageStack = new Stack<>();
-        Page currentPage = this.pageStorage.get(rootNum);
-        //pin
-        currentPage.pin();
-        while (getPageType(currentPage) != PageType.LEAF) {
-            long nextPageNum = 0;
-
-            try {
-                nextPageNum = queryFirstInternalItem(currentPage,dataHash);
-            } catch (ItemInNextPageException e) {
-                //unpin
-                currentPage.unpin();
-                currentPage = this.pageStorage.get(e.getNextPageNum());
-                //pin
-                currentPage.pin();
-                continue;
-            }
-
-            pageStack.add(nextPageNum);
-            //unpin
-            currentPage.unpin();
-            currentPage = this.pageStorage.get(nextPageNum);
-            //pin
-            currentPage.pin();
-        }
-        boolean isInsert = false;
-        while (!isInsert) {
-
-            try {
-                insertLeafItem(currentPage, dataHash, uuid);
-                isInsert = true;
-                //flush
-                try {
-                    currentPage.flush();
-                } catch (FileException e) {
-                    e.printStackTrace();
-                }
-                //unpin
-                currentPage.unpin();
-            } catch (ItemInNextPageException e) {
-                //unpin
-                currentPage.unpin();
-                currentPage = this.pageStorage.get(e.getNextPageNum());
-                //pin
-                currentPage.pin();
-            } catch (PageFullException e) {
-                long splitPageNum = 0;
-                if (pageStack.size() != 0) {
-                     splitPageNum = pageStack.pop();
-                }
-                long rawPageNum = this.getRawPageNum();
-                Page rawPage = this.pageStorage.get(rawPageNum);
-                //pin
-                rawPage.pin();
-                long newKey = insertFullLeaf(currentPage, rawPage, rawPageNum, dataHash, uuid);
-                //flush
-                try {
-                    currentPage.flush();
-                } catch (FileException eee) {
-                    eee.printStackTrace();
-                }
-                //unpin
-                currentPage.unpin();
-                boolean isInsertInternal = false, stackNeed = true;
-                Page parent = null;
-                long parentNum = 0;
-                while (!isInsertInternal) {
-                    if (stackNeed) {
-                        if (pageStack.size() > 0) {
-                            parentNum = pageStack.pop();
-                            parent = this.pageStorage.get(parentNum);
-                            //pin
-                            parent.pin();
-                        } else {
-                            Page root = this.pageStorage.get(rootNum);
-                            //pin
-                            root.pin();
-                            if (getPageType(root) == PageType.LEAF) {
-                                long rawPageNum0 = this.getRawPageNum();
-                                Page rawPage0 = this.pageStorage.get(rawPageNum0);
-                                //pin
-                                rawPage0.pin();
-
-                                try {
-                                    rawPage0.writeData(root.getDataBytes());
-                                } catch (PageException pageException) {
-                                    //flush
-                                    try {
-                                        rawPage.flush();
-                                        rawPage0.flush();
-                                    } catch (FileException fileException) {
-                                        fileException.printStackTrace();
-                                    }
-                                    //unpin
-                                    rawPage.unpin();
-                                    rawPage0.unpin();
-                                    root.unpin();
-                                    pageException.printStackTrace();
-                                }
-
-                                //unpin
-                                rawPage.unpin();
-                                rawPage0.unpin();
-                                root.unpin();
-                                initRootAsInternal(newKey, rawPageNum0, rawPageNum);
-                            } else {
-
-                                try {
-                                    insertInternalItem(root, getMaxKey(rawPage), splitPageNum, rawPageNum, newKey);
-                                    //flesh
-                                    try {
-                                        rawPage.flush();
-                                        root.flush();
-                                    } catch (FileException fileException) {
-                                        fileException.printStackTrace();
-                                    }
-                                    //unpin
-                                    rawPage.unpin();
-                                    root.unpin();
-                                } catch (PageFullException pageFullException) {
-                                    long rawPageNum0 = this.getRawPageNum();
-                                    Page rawPage0 = this.pageStorage.get(rawPageNum0);
-                                    long rawPageNum1 = this.getRawPageNum();
-                                    Page rawPage1 = this.pageStorage.get(rawPageNum1);
-                                    try {
-                                        rawPage0.writeData(root.getDataBytes());
-                                    } catch (PageException pageException) {
-                                        //unpin
-                                        root.unpin();
-                                        rawPage0.unpin();
-                                        rawPage1.unpin();
-                                        rawPage.unpin();
-                                        pageException.printStackTrace();
-                                    }
-
-                                    newKey = insertFullInternal(rawPage0, rawPage1, rawPageNum1, getMaxKey(rawPage), splitPageNum, rawPageNum, newKey);
-                                    //flush
-                                    try {
-                                        rawPage0.flush();
-                                        rawPage1.flush();
-                                        rawPage.flush();
-                                    } catch (FileException fileException) {
-                                        fileException.printStackTrace();
-                                    }
-                                    //unpin
-                                    rawPage0.unpin();
-                                    rawPage1.unpin();
-                                    rawPage.unpin();
-                                    root.unpin();
-                                    initRootAsInternal(newKey, rawPageNum0, rawPageNum1);
-                                } catch (ItemInNextPageException itemInNextPageException) {
-                                    //unpin
-                                    rawPage.unpin();
-                                    root.unpin();
-                                    itemInNextPageException.printStackTrace();
-                                }
-
-                            }
-                            isInsertInternal = true;
-                            isInsert = true;
-                            continue;
-                        }
-                    } else {
-                        stackNeed = true;
-                    }
-
-                    try {
-                        insertInternalItem(parent, getMaxKey(rawPage), splitPageNum, rawPageNum, newKey);
-                        isInsertInternal = true;
-                        isInsert = true;
-                        //unpin
-                        parent.unpin();
-                        rawPage.unpin();
-                    } catch (PageFullException ee) {
-                        long rawPageNum0 = this.getRawPageNum();
-                        Page rawPage0 = this.pageStorage.get(rawPageNum0);
-                        //pin
-                        rawPage0.pin();
-                        newKey = insertFullInternal(parent, rawPage0, rawPageNum0, getMaxKey(rawPage), splitPageNum, rawPageNum, newKey);
-                        rawPageNum = rawPageNum0;
-                        //flush
-                        try {
-                            rawPage.flush();
-                            parent.flush();
-                            rawPage0.flush();
-                        } catch (FileException fileException) {
-                            fileException.printStackTrace();
-                        }
-                        //unpin
-                        rawPage.unpin();
-                        parent.unpin();
-                        rawPage = rawPage0;
-                        splitPageNum = parentNum;
-                    }  catch (ItemInNextPageException ee) {
-                        //unpin
-                        parent.unpin();
-                        parent = this.pageStorage.get(ee.getNextPageNum());
-                        parent.pin();
-                        stackNeed = false;
-                    }
-
-                }
-            }
-
-        }
-    }
-
-    @Override
-    synchronized public List query(long keyHash) {
-        Page currentPage = this.pageStorage.get(rootNum);
-        //pin
-        currentPage.pin();
-        long nextPageNum = 0;
-        while (getPageType(currentPage) != PageType.LEAF) {
-            try {
-                nextPageNum = queryFirstInternalItem(currentPage, keyHash);
-            } catch (ItemInNextPageException e) {
-                //unpin
-                currentPage.unpin();
-                currentPage = this.pageStorage.get(e.getNextPageNum());
-                //pin
-                currentPage.pin();
-                continue;
-            }
-            //unpin
-            currentPage.unpin();
-            currentPage = this.pageStorage.get(nextPageNum);
-            //pin
-            currentPage.pin();
-        }
-        int pos = 0;
-        while (true) {
-            try {
-                pos = queryKeyPos(currentPage, keyHash);
-                break;
-            } catch (ItemInNextPageException e) {
-                var nextPageNum0 =  getPageNextPage(currentPage);
-                //unpin
-                currentPage.unpin();
-                currentPage = this.pageStorage.get(nextPageNum0);
-                //pin
-                currentPage.pin();
-            }
-        }
-        List res = new LinkedList<>();
-        long val = 0;
-        while (true) {
-            if (pos >= getPageItemNum(currentPage)) {
-                pos = 0;
-                var nextPageNum0 =  getPageNextPage(currentPage);
-                //unpin
-                currentPage.unpin();
-                currentPage = this.pageStorage.get(nextPageNum0);
-                //pin
-                currentPage.pin();
-            }
-            long key = getKeyByPosition(currentPage, pos);
-            if (key == keyHash) {
-                val = getValByPosition(currentPage, pos);
-                res.add(val);
-            } else {
-                break;
-            }
-            pos ++;
-        }
-        //unpin
-        currentPage.unpin();
-        return res;
-    }
-
-    @Override
-    synchronized public Iterator findFirst(long dataHash) {
-        Page currentPage = this.pageStorage.get(rootNum);
-        //pin
-        currentPage.pin();
-        long nextPageNum = 0;
-        while (getPageType(currentPage) != PageType.LEAF) {
-            try {
-                nextPageNum = queryFirstInternalItem(currentPage, dataHash);
-            } catch (ItemInNextPageException e) {
-                //unpin
-                currentPage.unpin();
-                currentPage = this.pageStorage.get(e.getNextPageNum());
-                //pin
-                currentPage.pin();
-                continue;
-            }
-            //unpin
-            currentPage.unpin();
-            currentPage = this.pageStorage.get(nextPageNum);
-            //pin
-            currentPage.pin();
-        }
-        int position = 0;
-        while (true) {
-            try {
-                position = queryKeyPos(currentPage, dataHash);
-                break;
-            } catch (ItemInNextPageException e) {
-                //unpin
-                currentPage.unpin();
-                currentPage = this.pageStorage.get(e.getNextPageNum());
-                //pin
-                currentPage.pin();
-                continue;
-            }
-        }
-        Iterator res= new BPlusTreeIterator(this,currentPage, position);
-        currentPage.unpin();
-        return res;
-    }
-
-    @Override
-    synchronized public Iterator findUpperbound(long dataHash) {
-        Page currentPage = this.pageStorage.get(rootNum);
-        //pin
-        currentPage.pin();
-        long nextPageNum = 0;
-        while (getPageType(currentPage) != PageType.LEAF) {
-            try {
-                nextPageNum = queryUpperboundInternal(currentPage, dataHash);
-            } catch (ItemInNextPageException e) {
-                //unpin
-                currentPage.unpin();
-                currentPage = this.pageStorage.get(e.getNextPageNum());
-                //pin
-                currentPage.pin();
-                continue;
-            }
-            //unpin
-            currentPage.unpin();
-            currentPage = this.pageStorage.get(nextPageNum);
-            //pin
-            currentPage.pin();
-        }
-        int position = 0;
-        while (true) {
-            try {
-                position = queryUpperboundKeyPos(currentPage, dataHash);
-                break;
-            } catch (ItemInNextPageException e) {
-                //unpin
-                currentPage.unpin();
-                currentPage = this.pageStorage.get(e.getNextPageNum());
-                //pin
-                currentPage.pin();
-            }
-        }
-        Iterator res= new BPlusTreeIterator(this,currentPage, position);
-        currentPage.unpin();
-        return res;
-    }
-
-    @Override
-    synchronized public Iterator findFirst() {
-        Page currentPage = this.pageStorage.get(rootNum);
-        //pin
-        currentPage.pin();
-        long nextPageNum = 0;
-        while (getPageType(currentPage) != PageType.LEAF) {
-            nextPageNum = getMinChild(currentPage);
-            //unpin
-            currentPage.unpin();
-            currentPage = this.pageStorage.get(nextPageNum);
-            //pin
-            currentPage.pin();
-        }
-        Iterator res= new BPlusTreeIterator(this,currentPage, 0);
-        currentPage.unpin();
-        return res;
-    }
-
-    /**
-     * 用于Internal节点找到最小的儿子,服务于findFirst()
-     * @param page 儿子的页号
-     * @return
-     */
-    private long getMinChild(Page page) {
-        return ByteUtil.bytes2Long(ByteUtil.subByte(page.getDataBytes(),BPlusTreeIndex.PAGE_BEGIN_POSTION + 8,8));
-    }
-
-    /**
-     * LEAF节点的指定key的最前面的位置,服务于findFirst(dataHash)
-     * @return key的位置
-     */
-    private int queryKeyPos(Page page,  long key) throws ItemInNextPageException {
-        if ( key > getMaxKey(page) ) {
-            throw new ItemInNextPageException(1, getPageNextPage(page));
-        }
-        int itemNum = getPageItemNum(page);
-        int i = 0,j = itemNum;
-        int temp = (i + j)/2;
-        while (i < j) {
-            if (getKeyByPosition(page, temp) > key){
-                j = temp;
-            }else if (getKeyByPosition(page, temp) < key){
-                i = temp + 1;
-            }else {
-                break;
-            }
-            temp = (i + j ) / 2;
-        }
-        while (temp > 0 && getKeyByPosition(page, temp-1) >= key){
-            temp--;
-        }
-       return temp;
-    }
-
-    /**
-     * LEAF节点的指定大于key的最前面的位置,服务于findUpperbound(dataHash)
-     * @param page
-     * @param key
-     * @return
-     */
-    private int queryUpperboundKeyPos(Page page, long key) throws ItemInNextPageException {
-        if ( key >= getMaxKey(page) ) {
-            throw new ItemInNextPageException(1, getPageNextPage(page));
-        }
-        int itemNum = getPageItemNum(page);
-        int i = 0,j = itemNum;
-        int temp = (i + j)/2;
-        while (i < j) {
-            if (getKeyByPosition(page, temp) > key){
-                j = temp;
-            }else if (getKeyByPosition(page, temp) < key){
-                i = temp + 1;
-            }else {
-                break;
-            }
-            temp = (i + j ) / 2;
-        }
-        while (temp < itemNum - 1){
-            if (getKeyByPosition(page, temp) > key) {
-                break;
-            }
-            temp++;
-        }
-        return temp;
-    }
-
-    /**
-     * 获取一个新页,并元页总页数自动加一
-     * @return 新页的页号
-     * @throws PageTypeException
-     */
-    private long getRawPageNum() {
-        Page page = this.pageStorage.get(0);
-        //pin
-        page.pin();
-        if (getPageType(page) != PageType.META) {
-            try {
-                throw new PageTypeException(2);
-            } catch (PageTypeException e) {
-                //unpin
-                page.unpin();
-                e.printStackTrace();
-                throw new RuntimeException();
-            }
-        }
-        long res = ByteUtil.bytes2Long(ByteUtil.subByte(page.getDataBytes(),4,8));
-        byte[] bs = ByteUtil.long2Bytes(res + 1);
-        try {
-            page.patchData(4,bs);
-        } catch (PageException e) {
-            e.printStackTrace();
-        } finally {
-          //unpin
-          page.unpin();
-        }
-        return res;
-    }
-
-    /**
-     * 将根,从LEAF节点变为INTERNAL节点
-     * @param minKey 通过minKey初始化根节点
-     * @param minPageNum 小于minKey的页的页号
-     * @param maxPageNum 大于minKey的页的页号
-     */
-    private void initRootAsInternal(long minKey, long minPageNum, long maxPageNum) {
-        //pin
-        Page page = this.pageStorage.get(rootNum);
-        page.pin();
-        setPageType(page, PageType.INTERNAL);
-        setPageItemNum(page, 2);
-        setMaxKey(page, Long.MAX_VALUE);
-        byte[] inserted;
-        try {
-            inserted = ByteUtil.byteMerger(ByteUtil.long2Bytes(minKey), ByteUtil.long2Bytes(minPageNum));
-            page.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION,inserted);
-            inserted = ByteUtil.byteMerger(ByteUtil.long2Bytes(Long.MAX_VALUE), ByteUtil.long2Bytes(maxPageNum));
-            page.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + 16,inserted);
-        } catch (PageException e) {
-            e.printStackTrace();
-        } finally {
-            //flush
-            try {
-                page.flush();
-            } catch (FileException e) {
-                e.printStackTrace();
-            }
-            //unpin
-            page.unpin();
-        }
-    }
-
-    /**
-     * 将一个页初始化为根,且为LEAF节点
-     */
-    private void initRootAsLeaf() {
-        //pin
-        Page page = this.pageStorage.get(rootNum);
-        page.pin();
-        setPageType(page, PageType.LEAF);
-        setPageItemNum(page, 0);
-        setMaxKey(page, Long.MAX_VALUE);
-        setPageNextPage(page, 0);
-        //flush
-        try {
-            page.flush();
-        } catch (FileException e) {
-            e.printStackTrace();
-        }
-        //unpin
-        page.unpin();
-    }
-
-    /**
-     *将internal节点的一个key(如果存在重复的key,指第一个)指向的页面替换成新的子页,同时在该条目前插入新的key.主要服务于于分裂操作
-     * 如果满了或要插入的值
-     * 
-     * oldKey - oldPageNum
-     * >>>
-     * newKey - oldPageNum
-     * oldKey - replacePageNum
-     * 
-     * @param page
-     * @param oldKey 待替换的key
-     * @param replacePageNum 替换的新子页号
-     * @param newKey 新插入的key
-     * @param oldPageNum 待替换的页号
-     * @return
-     */
-    private void insertInternalItem(Page page, long oldKey, long oldPageNum, long replacePageNum, long newKey) throws PageFullException, ItemInNextPageException {
-        if ( oldKey > getMaxKey(page) ) {
-            throw new ItemInNextPageException(1, getPageNextPage(page));
-        }
-        int itemNum = getPageItemNum(page);
-        if ( itemNum >= BPlusTreeIndex.MAX_PAGE_ITEM ) {
-            throw new PageFullException(1);
-        }
-        int i = 0,j = itemNum;
-        int temp = (i + j)/2;
-        while (i < j) {
-            if (getKeyByPosition(page, temp) > oldKey){
-                j = temp;
-            }else if (getKeyByPosition(page, temp) < oldKey){
-                i = temp + 1;
-            }else {
-                break;
-            }
-            temp = (i + j ) / 2;
-        }
-        int low = temp, high = temp + 1;
-        boolean isFind = false;
-        while (getKeyByPosition(page, low) == oldKey && low >= 0){
-            if(getValByPosition(page, low) == oldPageNum) {
-                temp = low;
-                isFind = true;
-                break;
-            }
-            low--;
-        }
-        while (getKeyByPosition(page, high) == oldKey && !isFind && high <= (BPlusTreeIndex.MAX_PAGE_ITEM - 1)) {
-            if(getValByPosition(page, high) == oldPageNum) {
-                temp = high;
-                isFind = true;
-                break;
-            }
-            high++;
-        }
-        if (!isFind) {
-            throw new ItemInNextPageException(1,getPageNextPage(page));
-        }
-
-        try {
-            byte[] bytes = ByteUtil.long2Bytes(replacePageNum);
-            page.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + temp * 16 + 8, bytes);
-            byte[] bs = new byte[16];
-            for (int k = itemNum; k > temp; k--) {
-                System.arraycopy(page.getDataBytes(), BPlusTreeIndex.PAGE_BEGIN_POSTION + (k - 1) * 16 , bs, 0, 16);
-                page.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + k * 16 ,bs);
-            }
-            byte[] inserted = ByteUtil.byteMerger(ByteUtil.long2Bytes(newKey), ByteUtil.long2Bytes(oldPageNum));
-            page.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + temp * 16,inserted);
-        } catch (PageException e) {
-            e.printStackTrace();
-        }
-        setPageItemNum(page, itemNum + 1);
-    }
-
-    /**
-     *将一个满的internal节点的一个key(如果存在重复的key,指第一个)指向的页面替换成新的子页,同时在该条目前插入新的key.主要服务于于分裂操作
-     * 
-     * oldKey - oldPageNum
-     * >>>
-     * newKey - oldPageNum
-     * oldKey - replacePageNum
-     * 
-     * @param page
-     * @param newPage
-     * @param newPageNum 新页的页号
-     * @param oldKey 带替换的key
-     * @param oldPageNum 待替换的页号
-     * @param replacePageNum 替换的新子页号
-     * @param newKey 新插入的key
-     * @return 为分裂后新的key
-     */
-    private long insertFullInternal(Page page,  Page newPage, long newPageNum, long oldKey, long oldPageNum, long replacePageNum, long newKey) {
-        if ( oldKey > getMaxKey(page)) {
-            try {
-                throw new ItemInNextPageException(1, getPageNextPage(page));
-            } catch (ItemInNextPageException e) {
-                e.printStackTrace();
-            }
-        }
-        setPageType(newPage, PageType.INTERNAL);
-        setMaxKey(newPage, getMaxKey(page));
-        setPageNextPage(newPage, getPageNextPage(page));
-        setPageNextPage(page, newPageNum);
-        int i = 0,j = BPlusTreeIndex.MAX_PAGE_ITEM;
-        int temp = (i + j)/2;
-        while (i < j) {
-            if (getKeyByPosition(page, temp) > oldKey){
-                j = temp;
-            }else if (getKeyByPosition(page, temp) < oldKey){
-                i = temp + 1;
-            }else {
-                break;
-            }
-            temp = (i + j ) / 2;
-        }
-        int low = temp, high = temp + 1;
-        boolean isFind = false;
-        while (getKeyByPosition(page, low) == oldKey && low >= 0){
-            if(getValByPosition(page, low) == oldPageNum) {
-                temp = low;
-                isFind = true;
-                break;
-            }
-            low--;
-        }
-        while (getKeyByPosition(page, high) == oldKey && !isFind && high <= (BPlusTreeIndex.MAX_PAGE_ITEM - 1)) {
-            if(getValByPosition(page, high) == oldPageNum) {
-                temp = high;
-                isFind = true;
-                break;
-            }
-            high++;
-        }
-        if (!isFind) {
-            try {
-                throw new ItemInNextPageException(1, getPageNextPage(page));
-            } catch (ItemInNextPageException e) {
-                e.printStackTrace();
-            }
-        }
-        //先对半分
-        byte[] bs = new byte[16];
-        try {
-            for (int k = 0; k < BPlusTreeIndex.MAX_PAGE_ITEM/2; k++) {
-                System.arraycopy(page.getDataBytes(), BPlusTreeIndex.PAGE_MID_POSTION + k * 16, bs, 0, 16);
-                newPage.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + k * 16,bs);
-            }
-        }
-        catch (PageException e) {
-            e.printStackTrace();
-        }
-        //在根据temp的取值情况分别处理
-        if (temp < (BPlusTreeIndex.MAX_PAGE_ITEM)/2) {
-            try {
-                for (int k = BPlusTreeIndex.MAX_PAGE_ITEM/2; k > temp; k--) {
-                    System.arraycopy(page.getDataBytes(), BPlusTreeIndex.PAGE_BEGIN_POSTION + (k - 1) * 16, bs, 0, 16);
-                    page.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + k * 16,bs);
-                }
-                page.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + (temp + 1) * 16 + 8,ByteUtil.long2Bytes(replacePageNum));
-                byte[] inserted = ByteUtil.byteMerger(ByteUtil.long2Bytes(newKey), ByteUtil.long2Bytes(oldPageNum));
-                page.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + temp * 16,inserted);
-            } catch (PageException e) {
-                e.printStackTrace();
-            }
-            setPageItemNum(page, BPlusTreeIndex.MAX_PAGE_ITEM/2 + 1);
-            setPageItemNum(newPage,BPlusTreeIndex.MAX_PAGE_ITEM/2);
-            long newKey0 = getKeyByPosition(page, BPlusTreeIndex.MAX_PAGE_ITEM/2);
-            setMaxKey(page, newKey0);
-            return newKey0;
-        } else {
-            temp = temp - BPlusTreeIndex.MAX_PAGE_ITEM/2;
-            try {
-                for (int k = BPlusTreeIndex.MAX_PAGE_ITEM/2; k > temp; k--) {
-                    System.arraycopy(newPage.getDataBytes(), BPlusTreeIndex.PAGE_BEGIN_POSTION + (k - 1) * 16, bs, 0, 16);
-                    newPage.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + k * 16,bs);
-                }
-                newPage.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + (temp + 1) * 16 + 8,ByteUtil.long2Bytes(replacePageNum));
-                byte[] inserted = ByteUtil.byteMerger(ByteUtil.long2Bytes(newKey), ByteUtil.long2Bytes(oldPageNum));
-                newPage.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + temp * 16,inserted);
-            } catch (PageException e) {
-                e.printStackTrace();
-            }
-            setPageItemNum(page, BPlusTreeIndex.MAX_PAGE_ITEM/2);
-            setPageItemNum(newPage,BPlusTreeIndex.MAX_PAGE_ITEM/2 + 1);
-            long newKey0 = getKeyByPosition(page, BPlusTreeIndex.MAX_PAGE_ITEM/2 - 1);
-            setMaxKey(page, newKey0);
-            return newKey0;
-        }
-    }
-
-    /**
-     * 在internal节点中找到第一个keyHash有关的下一个节点,如果不满maxKey检验,则表明搜索的条目不再此页,抛出异常
-     * @param page
-     * @param keyHash
-     * @return 相应儿子节点页号
-     */
-    private long queryFirstInternalItem(Page page,  long keyHash) throws ItemInNextPageException {
-        if ( keyHash > getMaxKey(page) ) {
-            throw  new ItemInNextPageException(1, getPageNextPage(page));
-        }
-        int itemNum = getPageItemNum(page);
-        int i = 0,j = itemNum;
-        int temp = (i + j)/2;
-//        try {
-            while (i < j ) {
-                if (getKeyByPosition(page, temp) > keyHash){
-                    j = temp;
-                }else if (getKeyByPosition(page, temp) < keyHash){
-                    i = temp + 1;
-                }else {
-                    break;
-                }
-                temp = (i + j ) / 2;
-            }
-//        }catch (ArrayIndexOutOfBoundsException e) {
-//            System.out.println("werwe");
-//        }
-        while (temp >= 1 && getKeyByPosition(page, temp-1) >= keyHash){
-            temp--;
-        }
-        return getValByPosition(page, temp);
-    }
-
-    /**
-     * 在internal节点中找到大于keyHash有关的下一个节点,如果不满maxKey检验,则表明搜索的条目不再此页,抛出异常
-     * @param page
-     * @param keyHash
-     * @return 相应儿子节点页号
-     */
-    private long queryUpperboundInternal(Page page,  long keyHash) throws ItemInNextPageException {
-        if ( keyHash > getMaxKey(page) ) {
-            throw  new ItemInNextPageException(1, getPageNextPage(page));
-        }
-        int itemNum = getPageItemNum(page);
-        int i = 0,j = itemNum;
-        int temp = (i + j)/2;
-        while (i < j ) {
-            if (getKeyByPosition(page, temp) > keyHash){
-                j = temp;
-            }else if (getKeyByPosition(page, temp) < keyHash){
-                i = temp + 1;
-            }else {
-                break;
-            }
-            temp = (i + j ) / 2;
-        }
-        while (temp < itemNum && getKeyByPosition(page, temp) <= keyHash){
-            temp++;
-        }
-        return getValByPosition(page, temp);
-    }
-
-    /**
-     * 对树叶节点插入item,相应会抛出页满,条目不在相应页的异常
-     * @param page
-     * @param keyHash
-     * @param uuid
-     * @return
-     */
-    private void insertLeafItem(Page page, long keyHash, long uuid) throws ItemInNextPageException, PageFullException {
-        if ( keyHash > getMaxKey(page)) {
-            throw new ItemInNextPageException(1, getPageNextPage(page));
-        }
-        int itemNum = getPageItemNum(page);
-        if ( itemNum >= BPlusTreeIndex.MAX_PAGE_ITEM ) {
-            throw new PageFullException(1);
-        }
-        int i = 0,j = itemNum;
-        int temp = (i + j)/2;
-        while (i < j ) {
-            long cmp = getKeyByPosition(page, temp);
-//            long cmp0 = getKeyByPosition(page, temp - 1);
-//            long cmp1 = getKeyByPosition(page, temp - 2);
-            if (cmp > keyHash){
-                j = temp;
-            }else if (cmp < keyHash){
-                i = temp + 1;
-            }else {
-                break;
-            }
-            temp = (i + j ) / 2;
-        }
-        try {
-            byte[] bs = new byte[16];
-            for (int k = itemNum; k > temp; k--) {
-                System.arraycopy(page.getDataBytes(), BPlusTreeIndex.PAGE_BEGIN_POSTION + (k - 1) * 16, bs, 0, 16);
-                page.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + k * 16,bs);
-            }
-            byte[] inserted = ByteUtil.byteMerger(ByteUtil.long2Bytes(keyHash), ByteUtil.long2Bytes(uuid));
-            page.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + temp * 16,inserted);
-        } catch (PageException e) {
-            e.printStackTrace();
-        }
-        setPageItemNum(page, itemNum + 1);
-    }
-
-    /**
-     *对一个已经满了的叶插入item
-     * @param page 待分裂已满的页
-     * @param newPage 一个未用过的新的页,用于分裂
-     * @param newPageNum 新页的页号
-     * @param keyHash 分裂时顺便插入的条目的键
-     * @param uuid 分裂时顺便插入的条目的值
-     * @return 为分裂后新的key
-     */
-    private long insertFullLeaf(Page page, Page newPage, long newPageNum, long keyHash, long uuid) {
-        if ( keyHash > getMaxKey(page)) {
-            try {
-                throw new ItemInNextPageException(1, getPageNextPage(page));
-            } catch (ItemInNextPageException e) {
-                e.printStackTrace();
-            }
-        }
-        setPageType(newPage, PageType.LEAF);
-//        setPageItemNum(newPage,(BPlusTreeIndex.MAX_PAGE_ITEM + 1)/2);
-        setMaxKey(newPage, getMaxKey(page));
-        setPageNextPage(newPage, getPageNextPage(page));
-        setPageNextPage(page, newPageNum);
-        int i = 0,j = BPlusTreeIndex.MAX_PAGE_ITEM;
-        int temp = (i + j)/2;
-        while (i < j) {
-            if (getKeyByPosition(page, temp) > keyHash){
-                j = temp;
-            }else if (getKeyByPosition(page, temp) < keyHash){
-                i = temp + 1;
-            }else {
-                break;
-            }
-            temp = (i + j ) / 2;
-        }
-        if (temp < (BPlusTreeIndex.MAX_PAGE_ITEM)/2) {
-            byte[] bs = new byte[16];
-            try {
-                for (int k = 0; k < BPlusTreeIndex.MAX_PAGE_ITEM/2; k++) {
-                    System.arraycopy(page.getDataBytes(), BPlusTreeIndex.PAGE_MID_POSTION + k * 16, bs, 0, 16);
-                    newPage.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + k * 16, bs);
-                }
-            }
-            catch (PageException e) {
-                e.printStackTrace();
-            }
-            try {
-                for (int k = BPlusTreeIndex.MAX_PAGE_ITEM/2; k > temp; k--) {
-                    System.arraycopy(page.getDataBytes(), BPlusTreeIndex.PAGE_BEGIN_POSTION + (k - 1) * 16, bs, 0, 16);
-                    page.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + k * 16,bs);
-                }
-                byte[] inserted = ByteUtil.byteMerger(ByteUtil.long2Bytes(keyHash), ByteUtil.long2Bytes(uuid));
-                page.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + temp * 16,inserted);
-            } catch (PageException e) {
-                e.printStackTrace();
-            }
-            setPageItemNum(newPage,BPlusTreeIndex.MAX_PAGE_ITEM/2);
-            setPageItemNum(page, BPlusTreeIndex.MAX_PAGE_ITEM/2 + 1);
-            long newKey = ByteUtil.bytes2Long(ByteUtil.subByte(page.getDataBytes(), BPlusTreeIndex.PAGE_MID_POSTION,8));
-            setMaxKey(page, newKey);
-            return newKey;
-        } else {
-            byte[] bs = new byte[16];
-            try {
-                boolean isInsert = false;
-                for (int k = 0; k < BPlusTreeIndex.MAX_PAGE_ITEM/2; k++) {
-                    System.arraycopy(page.getDataBytes(), BPlusTreeIndex.PAGE_MID_POSTION + k * 16, bs, 0, 16);
-                    if (keyHash < ByteUtil.bytes2Long(ByteUtil.subByte(bs, 0, 8)) && !isInsert) {
-                        byte[] inserted = ByteUtil.byteMerger(ByteUtil.long2Bytes(keyHash), ByteUtil.long2Bytes(uuid));
-                        newPage.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + k * 16,inserted);
-                        isInsert = true;
-                    }
-                    if (isInsert) {
-                        newPage.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + ( k + 1 ) * 16,bs);
-                    } else {
-                        newPage.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + k * 16,bs);
-                    }
-                }
-                if (!isInsert) {
-                    byte[] inserted = ByteUtil.byteMerger(ByteUtil.long2Bytes(keyHash), ByteUtil.long2Bytes(uuid));
-                    newPage.patchData(BPlusTreeIndex.PAGE_BEGIN_POSTION + BPlusTreeIndex.MAX_PAGE_ITEM/2 * 16,inserted);
-                }
-            }
-            catch (PageException e) {
-                e.printStackTrace();
-            }
-            setPageItemNum(newPage,BPlusTreeIndex.MAX_PAGE_ITEM/2 + 1);
-            setPageItemNum(page, BPlusTreeIndex.MAX_PAGE_ITEM/2);
-            long newKey = ByteUtil.bytes2Long(ByteUtil.subByte(page.getDataBytes(),BPlusTreeIndex.PAGE_MID_POSTION - 16,8));
-            setMaxKey(page, newKey);
-            return newKey;
-        }
-    }
-
-    /**
-     * 通过位置获得key
-     * @param page
-     * @param position
-     * @return
-     */
-    private long getKeyByPosition(Page page, int position) {
-        int pos = BPlusTreeIndex.PAGE_BEGIN_POSTION + 16*position;
-        return ByteUtil.bytes2Long(ByteUtil.subByte(page.getDataBytes(),pos,8));
-    }
-
-    private long getValByPosition(Page page, int position) {
-        int pos = BPlusTreeIndex.PAGE_BEGIN_POSTION + 16*position + 8;
-        return ByteUtil.bytes2Long(ByteUtil.subByte(page.getDataBytes(),pos,8));
-    }
-
-    /**
-     * 设置页的最大key字段
-     * @param page
-     * @param maxKey
-     */
-    private void setMaxKey(Page page, long maxKey) {
-        byte[] bs = ByteUtil.long2Bytes(maxKey);
-        try {
-            page.patchData(16,bs);
-        } catch (PageException e) {
-            e.printStackTrace();
-        }
-    }
-
-    /**
-     * 读取页的最大key字段
-     * @param page
-     * @return
-     */
-    private long getMaxKey(Page page) {
-        return ByteUtil.bytes2Long(ByteUtil.subByte(page.getDataBytes(),16,8));
-    }
-
-    /**
-     * 设置某页的项目数量
-     * @param page
-     * @param itemNum
-     */
-    private void setPageItemNum(Page page, int itemNum) {
-        byte[] bs = ByteUtil.int2Bytes(itemNum);
-        try {
-            page.patchData(4,bs);
-        } catch (PageException e) {
-            e.printStackTrace();
-        }
-    }
-
-    /**
-     * 获得某页的项目数量
-     * @param page
-     * @return
-     */
-    private int getPageItemNum(Page page) {
-        return ByteUtil.bytes2Int(ByteUtil.subByte(page.getDataBytes(),4,4));
-    }
-
-    /**
-     * 设置某页的下一页的页码
-     * @param page
-     * @param pageNum
-     */
-    private void setPageNextPage(Page page, long pageNum) {
-        byte[] bs = ByteUtil.long2Bytes(pageNum);
-        try {
-            page.patchData(8,bs);
-        } catch (PageException e) {
-            e.printStackTrace();
-        }
-    }
-
-    /**
-     *
-     * @param page
-     * @return 返回下一页的页码
-     */
-    private long getPageNextPage(Page page) {
-        return ByteUtil.bytes2Long(ByteUtil.subByte(page.getDataBytes(),8,8));
-    }
-
-    /**
-     *
-     * @param page 页
-     * @param pageType 设置页的类型
-     */
-    private void setPageType(Page page, PageType pageType) {
-        int temp = pageType.ordinal();
-        byte[] bs = ByteUtil.int2Bytes(temp);
-        try {
-            page.patchData(0,bs);
-        } catch (PageException e) {
-            e.printStackTrace();
-        }
-    }
-
-    /**
-     *
-     * @param page  页
-     * @return 页的类型,如果不存在对应页类型,则抛出异常
-     */
-    public PageType getPageType(Page page) {
-        int typeNum = ByteUtil.bytes2Int(ByteUtil.subByte(page.getDataBytes(),0,4));
-        if (typeNum == PageType.INTERNAL.ordinal()) {
-            return  PageType.INTERNAL;
-        } else if (typeNum == PageType.LEAF.ordinal()) {
-            return  PageType.LEAF;
-        } else if (typeNum == PageType.META.ordinal()) {
-            return PageType.META;
-        }
-        try {
-            throw new PageTypeException(1);
-        } catch (PageTypeException e) {
-            e.printStackTrace();
-        }
-        return null;
-    }
-
-    private class BPlusTreeIterator implements Iterator {
-        BPlusTreeIndex bPlusTreeIndex;
-        Page currentPage;
-        int currentPosition;
-        int currentPageItemNum;
-        boolean isEnd = false;
-
-        public BPlusTreeIterator(BPlusTreeIndex bPlusTreeIndex, Page currentPage, int currentPosition) {
-            this.bPlusTreeIndex = bPlusTreeIndex;
-            this.currentPage = currentPage;
-            //pin 双重pin 传进来之前已经pin过次此来
-            currentPage.pin();
-            this.currentPosition = currentPosition;
-            this.currentPageItemNum = getPageItemNum(currentPage);
-        }
-
-        @Override
-        public boolean hasNext() {
-            synchronized (bPlusTreeIndex) {
-                if (currentPageItemNum > currentPosition) {
-                    return true;
-                } else {
-                    if (!isEnd && getPageNextPage(currentPage) != 0) {
-                        return true;
-                    } else{
-                        return false;
-                    }
-                }
-            }
-        }
-
-        @Override
-        public Pair next() {
-            synchronized (bPlusTreeIndex) {
-                if ( currentPageItemNum > currentPosition ) {
-                    Pair res = new Pair(getKeyByPosition(currentPage,currentPosition), getValByPosition(currentPage,currentPosition));
-                    currentPosition++;
-                    return res;
-                }
-                else {
-                    long nextPageNum = getPageNextPage(currentPage);
-                    if (nextPageNum == 0) {
-                        if (isEnd) {
-                            isEnd = true;
-                            //unpin
-                            currentPage.unpin();
-                        }
-                        return null;
-                    } else {
-                        log.debug("nextPage, num = {}", nextPageNum);
-                        //unpin
-                        currentPage.unpin();
-                        currentPage = this.bPlusTreeIndex.pageStorage.get(nextPageNum);
-                        //pin
-                        currentPage.pin();
-                        currentPageItemNum = getPageItemNum(currentPage);
-                        currentPosition = 0;
-                        Pair res = new Pair(getKeyByPosition(currentPage,currentPosition), getValByPosition(currentPage,currentPosition));
-                        currentPosition++;
-                        return res;
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/src/main/java/net/kaaass/rumbase/index/btree/ByteUtil.java b/src/main/java/net/kaaass/rumbase/index/btree/ByteUtil.java
deleted file mode 100644
index 057b474..0000000
--- a/src/main/java/net/kaaass/rumbase/index/btree/ByteUtil.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package net.kaaass.rumbase.index.btree;
-
-/**
- *下面为byte[]与其他类型有关的转化关系代码内容
- *
- * @author 无索魏
- */
-
-public class ByteUtil {
-
-    /**
-     * 合并byte[]数组 (不改变原数组)
-     * @param byte_1
-     * @param byte_2
-     * @return 合并后的数组
-     */
-    public static byte[] byteMerger(byte[] byte_1, byte[] byte_2){
-        byte[] byte_3 = new byte[byte_1.length+byte_2.length];
-        System.arraycopy(byte_1, 0, byte_3, 0, byte_1.length);
-        System.arraycopy(byte_2, 0, byte_3, byte_1.length, byte_2.length);
-        return byte_3;
-    }
-
-    /**
-     * 截取byte数组   不改变原数组
-     * @param b 原数组
-     * @param off 偏差值(索引)
-     * @param length 长度
-     * @return 截取后的数组
-     */
-    public static byte[] subByte(byte[] b,int off,int length){
-        byte[] b1 = new byte[length];
-        System.arraycopy(b, off, b1, 0, length);
-        return b1;
-    }
-
-    /**
-     * Long 转 byte[]
-     * @return
-     */
-    public static byte[] long2Bytes(long num) {
-        byte[] byteNum = new byte[8];
-        for (int ix = 0; ix < 8; ++ix) {
-            int offset = 64 - (ix + 1) * 8;
-            byteNum[ix] = (byte) ((num >> offset) & 0xff);
-        }
-        return byteNum;
-    }
-
-    /**
-     * byte[] 转 Long
-     * @return
-     */
-    public static long bytes2Long(byte[] byteNum) {
-        long num = 0;
-        for (int ix = 0; ix < 8; ++ix) {
-            num <<= 8;
-            num |= (byteNum[ix] & 0xff);
-        }
-        return num;
-    }
-
-    /**
-     * byte 转 Int
-     * @param byteNum
-     * @return
-     */
-    public static int bytes2Int(byte[] byteNum) {
-        int num = 0;
-        for (int ix = 0; ix < 4; ++ix) {
-            num <<= 8;
-            num |= (byteNum[ix] & 0xff);
-        }
-        return num;
-    }
-
-    /**
-     * Int 转 byte[]
-     * @param num
-     * @return
-     */
-    public static byte[] int2Bytes(int num) {
-        byte[] byteNum = new byte[4];
-        for (int ix = 0; ix < 4; ++ix) {
-            int offset = 32 - (ix + 1) * 8;
-            byteNum[ix] = (byte) ((num >> offset) & 0xff);
-        }
-        return byteNum;
-    }
-}
diff --git a/src/main/java/net/kaaass/rumbase/index/exception/IndexAlreadyExistException.java b/src/main/java/net/kaaass/rumbase/index/exception/IndexAlreadyExistException.java
deleted file mode 100644
index 1c9a4c3..0000000
--- a/src/main/java/net/kaaass/rumbase/index/exception/IndexAlreadyExistException.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package net.kaaass.rumbase.index.exception;
-
-import net.kaaass.rumbase.exception.RumbaseException;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * 当根据文件名创建一个新的空索引时,如果相应的文件名已经存在了索引,则不能创建新的空索引,并抛出此异常
- * @author 无索魏
- */
-public class IndexAlreadyExistException extends RumbaseException {
-
-    public static final Map REASONS = new HashMap<>() {{
-        put(1, "索引已经存在");
-    }};
-
-    /**
-     * 构造Rumbase异常
-     *
-     * @param mainId 主错误号
-     * @param subId  子错误号
-     * @param reason 错误原因
-     */
-    private IndexAlreadyExistException(int mainId, int subId, String reason) {
-        super(mainId, subId, reason);
-    }
-
-    /**
-     * 索引不存在
-     *
-     * @param subId 子错误号
-     */
-    public IndexAlreadyExistException(int subId) {
-        super(9002, subId, REASONS.get(subId));
-    }
-}
diff --git a/src/main/java/net/kaaass/rumbase/index/exception/IndexNotFoundException.java b/src/main/java/net/kaaass/rumbase/index/exception/IndexNotFoundException.java
deleted file mode 100644
index e7cdf60..0000000
--- a/src/main/java/net/kaaass/rumbase/index/exception/IndexNotFoundException.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package net.kaaass.rumbase.index.exception;
-
-import net.kaaass.rumbase.exception.RumbaseException;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * 当加载一个索引时,如果索引实现不存在相应的持久化信息,则无法加载,并抛出此异常
- * @author 无索魏
- */
-public class IndexNotFoundException extends RumbaseException {
-    /**
-     * 构造Rumbase异常
-     *
-     * @param mainId 主错误号
-     * @param subId  子错误号
-     * @param reason 错误原因
-     */
-    public IndexNotFoundException(int mainId, int subId, String reason) {
-        super(mainId, subId, reason);
-    }
-
-    public static final Map REASONS = new HashMap<>() {{
-        put(1, "索引不存在");
-    }};
-
-    /**
-     * 索引不存在
-     *
-     * @param subId 子错误号
-     */
-    public IndexNotFoundException(int subId) {
-        super(9001, subId, REASONS.get(subId));
-    }
-}
diff --git a/src/main/java/net/kaaass/rumbase/index/exception/ItemInNextPageException.java b/src/main/java/net/kaaass/rumbase/index/exception/ItemInNextPageException.java
deleted file mode 100644
index cfa392f..0000000
--- a/src/main/java/net/kaaass/rumbase/index/exception/ItemInNextPageException.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package net.kaaass.rumbase.index.exception;
-
-import lombok.Getter;
-import net.kaaass.rumbase.exception.RumbaseException;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * 要找的条目不在本页,而下一页
- * @author 无索魏
- */
-public class ItemInNextPageException extends RumbaseException {
-
-    @Getter
-    private long nextPageNum;
-
-    /**
-     * 构造Rumbase异常
-     *
-     * @param mainId 主错误号
-     * @param subId  子错误号
-     * @param reason 错误原因
-     */
-    public ItemInNextPageException(int mainId, int subId, String reason) {
-        super(mainId, subId, reason);
-    }
-
-    public static final Map REASONS = new HashMap<>() {{
-        put(1, "页类型不存在");
-    }};
-
-    /**
-     * 条目不在本页
-     *
-     * @param subId 子错误号
-     */
-    public ItemInNextPageException(int subId, long nextPageNum) {
-        super(9004, subId, REASONS.get(subId));
-        this.nextPageNum = nextPageNum;
-    }
-}
diff --git a/src/main/java/net/kaaass/rumbase/index/exception/PageFullException.java b/src/main/java/net/kaaass/rumbase/index/exception/PageFullException.java
deleted file mode 100644
index e26f94a..0000000
--- a/src/main/java/net/kaaass/rumbase/index/exception/PageFullException.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package net.kaaass.rumbase.index.exception;
-
-import net.kaaass.rumbase.exception.RumbaseException;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * 页已经满了,无法进行原先的插入操作
- * @author 无索魏
- */
-public class PageFullException extends RumbaseException {
-    /**
-     * 构造Rumbase异常
-     *
-     * @param mainId 主错误号
-     * @param subId  子错误号
-     * @param reason 错误原因
-     */
-    public PageFullException(int mainId, int subId, String reason) {
-        super(mainId, subId, reason);
-    }
-
-    public static final Map REASONS = new HashMap<>() {{
-        put(1, "页已满,无法插入");
-    }};
-
-    /**
-     * 索引不存在
-     *
-     * @param subId 子错误号
-     */
-    public PageFullException(int subId) {
-        super(9005, subId, REASONS.get(subId));
-    }
-}
diff --git a/src/main/java/net/kaaass/rumbase/index/exception/PageTypeException.java b/src/main/java/net/kaaass/rumbase/index/exception/PageTypeException.java
deleted file mode 100644
index d0942db..0000000
--- a/src/main/java/net/kaaass/rumbase/index/exception/PageTypeException.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package net.kaaass.rumbase.index.exception;
-
-import net.kaaass.rumbase.exception.RumbaseException;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- *
- * @author 无索魏
- */
-public class PageTypeException extends RumbaseException {
-    /**
-     * 构造Rumbase异常
-     *
-     * @param mainId 主错误号
-     * @param subId  子错误号
-     * @param reason 错误原因
-     */
-    public PageTypeException(int mainId, int subId, String reason) {
-        super(mainId, subId, reason);
-    }
-
-    public static final Map REASONS = new HashMap<>() {{
-        put(1, "页类型不存在");
-        put(2, "非MEAT页不能读取文件总页数");
-    }};
-
-    /**
-     * 索引不存在
-     *
-     * @param subId 子错误号
-     */
-    public PageTypeException(int subId) {
-        super(9003, subId, REASONS.get(subId));
-    }
-}
diff --git a/src/main/java/net/kaaass/rumbase/index/mock/MockBtreeIndex.java b/src/main/java/net/kaaass/rumbase/index/mock/MockBtreeIndex.java
deleted file mode 100644
index a37d75f..0000000
--- a/src/main/java/net/kaaass/rumbase/index/mock/MockBtreeIndex.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package net.kaaass.rumbase.index.mock;
-
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-import net.kaaass.rumbase.index.Index;
-import net.kaaass.rumbase.index.Pair;
-
-import java.util.*;
-
-/**
- * @author 无索魏
- */
-@RequiredArgsConstructor
-public class MockBtreeIndex implements Index {
-    /**
-     * 内存中创建的MockBtreeIndex
-     */
-    public static Map MOCK_BTREE_INDEX_MAP = new HashMap<>();
-
-    @Getter
-    private HashMap> hashMap = new HashMap<>();
-
-    @Override
-    public void replace(Map uuidMap) {
-        var values = hashMap.values();
-        for (List value : values) {
-            for (Long old : value) {
-                if (uuidMap.containsKey(old)) {
-                    value.remove(old);
-                    value.add(uuidMap.get(old));
-                }
-            }
-        }
-    }
-
-    @Override
-    public void insert(long dataHash, long uuid) {
-        hashMap.computeIfAbsent(dataHash, k -> new ArrayList<>()).add(uuid);
-    }
-
-    @Override
-    public List query(long dataHash) {
-        return hashMap.get(dataHash) == null ? new LinkedList<>() : hashMap.get(dataHash);
-    }
-
-    @Override
-    public Iterator findFirst(long keyHash) {
-        return new MockIterator(this, keyHash, true);
-    }
-
-    @Override
-    public Iterator findUpperbound(long keyHash) {
-        return new MockIterator(this, keyHash, false);
-    }
-
-    @Override
-    public Iterator findFirst() {
-        return new MockIterator(this);
-    }
-}
diff --git a/src/main/java/net/kaaass/rumbase/index/mock/MockIterator.java b/src/main/java/net/kaaass/rumbase/index/mock/MockIterator.java
deleted file mode 100644
index 239114a..0000000
--- a/src/main/java/net/kaaass/rumbase/index/mock/MockIterator.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package net.kaaass.rumbase.index.mock;
-
-import net.kaaass.rumbase.index.Pair;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author 无索魏
- */
-public class MockIterator implements Iterator {
-    private Iterator>> indexIterator;
-    private Iterator tempIterator;
-    private long tempKey;
-    private boolean state = true;
-
-    public MockIterator(MockBtreeIndex mockBtreeIndex) {
-        indexIterator = mockBtreeIndex.getHashMap().entrySet().iterator();
-        if (!indexIterator.hasNext()) {
-            state = false;
-            return;
-        }
-        var f = indexIterator.next();
-        tempIterator = f.getValue().iterator();
-        tempKey = f.getKey();
-    }
-
-    public MockIterator(MockBtreeIndex mockBtreeIndex, long keyHash, boolean isWith) {
-        indexIterator = mockBtreeIndex.getHashMap().entrySet().iterator();
-        if (isWith == true) {
-            do {
-                var v = indexIterator.next();
-                if (v == null) {
-                    state = false;
-                    break;
-                }
-                tempIterator = v.getValue().iterator();
-                tempKey = v.getKey();
-            } while (tempKey < keyHash);
-        } else {
-            do {
-                var v = indexIterator.next();
-                if (v == null) {
-                    state = false;
-                    break;
-                }
-                tempIterator = v.getValue().iterator();
-                tempKey = v.getKey();
-            } while (tempKey <= keyHash);
-        }
-    }
-
-    @Override
-    public boolean hasNext() {
-        return indexIterator.hasNext() || (tempIterator != null && tempIterator.hasNext());
-    }
-
-
-    @Override
-    public Pair next() {
-        if (state == false) {
-            return null;
-        }
-        Pair res = new Pair(tempKey, tempIterator.next());
-        if (!tempIterator.hasNext()) {
-            if (!indexIterator.hasNext()) {
-                state = false;
-                return res;
-            }
-            var v = indexIterator.next();
-            tempIterator = v.getValue().iterator();
-            tempKey = v.getKey();
-        }
-        return res;
-    }
-}
diff --git a/src/main/java/net/kaaass/rumbase/page/Page.java b/src/main/java/net/kaaass/rumbase/page/Page.java
deleted file mode 100644
index 77b13b3..0000000
--- a/src/main/java/net/kaaass/rumbase/page/Page.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package net.kaaass.rumbase.page;
-
-import net.kaaass.rumbase.page.exception.FileException;
-import net.kaaass.rumbase.page.exception.PageException;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-
-/**
- * 单页管理
- * 

- * Page对象通过PageCache获得。获得的对象【不可以长期保存】(如保存在对象中作为对象的字段)。 - * 使用页面需要注意使用pin,以防止Page对象被提前回收。 - *

- *     var page = pageCache.get(1);
- *     page.pin();
- *     // ...
- *     page.getData();
- *     // ...
- *     // 如果不pin,则此处page对象可能因为被淘汰失效
- *     page.patchData(2, patch);
- *     page.unpin();
- * 
- * 如果操作有错误风险(有可能发生不造成停机的错误),必须加上try-catch-finally
- * 
- *     var page = pageCache.get(1);
- *     page.pin();
- *     try {
- *         page.getData();
- *         // ...
- *         page.patchData(2, patch);
- *     } catch (Exception e) {
- *         // ...
- *     } finally {
- *         page.unpin(); // 重要:防止内存泄漏,必须在finally释放
- *     }
- * 
- * 若操作数量为1,不复用Page对象的情形,可以忽略。
- * 
- *     pageCache.get(1).getData();
- * 
- *
- * @author XuanLaoYee
- */
-public interface Page {
-
-    /**
-     * (性能原因,建议使用getData)获得页内数据
-     *
-     * @return 字节数组,通常为4K
-     */
-    byte[] getDataBytes();
-
-    /**
-     * 获得页内数据的字节流
-     * 

- * 目前使用default方法实现,留作将来优化性能用 - * - * @return 字节流 - */ - default InputStream getData() { - return new ByteArrayInputStream(getDataBytes()); - } - - /** - * 将字节数据写入页 - * - * @param data 待写入字节数据 - * @throws PageException 若写入的数据超出页的范围则抛出异常 - */ - default void writeData(byte[] data) throws PageException { - patchData(0, data); - } - - /** - * 在页指定位置写入数据 - * - * @param offset 页内偏移值,以字节为单位 - * @param data 待写入数据 - * @throws PageException 若写入的数据超出页的范围则抛出异常 - */ - void patchData(int offset, byte[] data) throws PageException; - - void flush() throws FileException; - - /** - * 将页固定在内存中 - *

- * 操作规约:必须在系列操作之前使用pin,以防止页被回收 - */ - void pin(); - - /** - * 将页从内存中取消固定 - *

- * 操作规约:必须在系列操作之后使用unpin,以防止内存泄露 - */ - void unpin(); -} diff --git a/src/main/java/net/kaaass/rumbase/page/PageManager.java b/src/main/java/net/kaaass/rumbase/page/PageManager.java deleted file mode 100644 index ba4e166..0000000 --- a/src/main/java/net/kaaass/rumbase/page/PageManager.java +++ /dev/null @@ -1,41 +0,0 @@ -package net.kaaass.rumbase.page; - -import net.kaaass.rumbase.page.exception.FileException; -import net.kaaass.rumbase.page.mock.MockPageStorage; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * @author XuanLaoYee - */ -public class PageManager { - public static int PAGE_SIZE = 1024 * 4; // 页面大小是4KB - public static long FILE_HEAD_SIZE = 5; // 文件头留5页 - public static int BUFFER_SIZE = 1000; //缓冲大小,单位是页,页的大小不可以超过524287 - public static int BYTE_BUFFER_SIZE = 1024 * 4 * BUFFER_SIZE; - - /** - * 取数据库文件生成文件管理的对象 - * - * @param filepath 每个表文件路径 - * @return - * @throws FileException 若文件不存在则创建,创建过程中出现错误会抛出错误 - */ - public static PageStorage fromFile(String filepath) throws FileException { - PageStorage storage = new RumPageStorage(filepath); - storages.add(storage); - return storage; - } - /** - * 取数据库文件生成文件管理的对象 - */ - public static void flush(){ - for(PageStorage storage : storages){ - storage.flush(); - } - } - public static List storages = new ArrayList<>(); -} diff --git a/src/main/java/net/kaaass/rumbase/page/PageStorage.java b/src/main/java/net/kaaass/rumbase/page/PageStorage.java deleted file mode 100644 index 5d67685..0000000 --- a/src/main/java/net/kaaass/rumbase/page/PageStorage.java +++ /dev/null @@ -1,22 +0,0 @@ -package net.kaaass.rumbase.page; - -/** - * 用于管理一系列连续页的存储对象,隐藏任何关于存储的物理细节 - * - * @author XuanLaoYee - */ -public interface PageStorage { - - /** - * 获取该页存储中的某一页 - * - * @param pageId 页号 - * @return 该页页对象 - */ - Page get(long pageId); - - /** - * 将页存储中的所有脏页写回文件 - */ - void flush(); -} diff --git a/src/main/java/net/kaaass/rumbase/page/Replacer.java b/src/main/java/net/kaaass/rumbase/page/Replacer.java deleted file mode 100644 index 283fc4c..0000000 --- a/src/main/java/net/kaaass/rumbase/page/Replacer.java +++ /dev/null @@ -1,130 +0,0 @@ -package net.kaaass.rumbase.page; - -import net.kaaass.rumbase.page.exception.BufferException; - -import java.util.HashMap; -import java.util.Map; - -public class Replacer { - private static Replacer instance = null; - private Replacer() { - this.head = null; - this.tail = null; - this.table = new HashMap<>(); - } - - public static Replacer getInstance() { - if (instance == null) { - synchronized (Replacer.class) { - if (instance == null) { - instance = new Replacer(); - } - } - } - return instance; - } - - public void insert(RumPage value) { - synchronized (this) { - if (!this.table.containsKey(value)) {//如果页没在内存中 - Node tmp = new Node(value, null); - if(head==null){ - this.head = tmp; - this.tail = tmp; - }else{ - this.tail.next = tmp; - this.tail = this.tail.next; - this.table.put(value, this.tail); - } - ++size; - } else { - Node hitNode = this.table.get(value); - hit(hitNode); - } - } - } - - /** - * 从链表中取出受害者页,若链表为空则返回null - * @return 返回受害者页面 - * @throws BufferException 若链表中所有的页均被钉住,则抛出异常 - */ - public RumPage victim() throws BufferException { - synchronized (this) { - if (size == 0) { - return null; - } - Node tmp = head; - while (tmp != null && tmp.pinned()){ - tmp = tmp.next; - } - if(tmp == null){ - throw new BufferException(2); - } - Node pre = head;//找tmp上一个节点 - if(pre!=tmp){ - while(pre.next != tmp){ - pre = pre.next; - } - } - if(tmp == head){ - head = head.next; - size--; - return tmp.getData(); - }else{ - pre.next = tmp.next; - size--; - return tmp.getData(); - } - } - } - - public int size() { - return size; - } - - /** - * 将命中的页移至链表尾 - * - * @param p 命中的节点 - */ - private void hit(Node p) { - Node tmp = head; - while (tmp.next != null) { - if (tmp.next == p) { - break; - } else { - tmp = tmp.next; - } - } - if (p.next != null) { - tmp.next = p.next; - this.tail.next = p; - this.tail = this.tail.next; - } - } - - private int size; - Node tail; - Node head; - Map table; - -} - -class Node { - private final RumPage data; - Node next = null; - - public Node(RumPage data, Node p) { - this.data = data; - this.next = p; - } - - public boolean pinned(){ - return data.pinned(); - } - - public RumPage getData(){ - return data; - } -} diff --git a/src/main/java/net/kaaass/rumbase/page/RumBuffer.java b/src/main/java/net/kaaass/rumbase/page/RumBuffer.java deleted file mode 100644 index 5f1b909..0000000 --- a/src/main/java/net/kaaass/rumbase/page/RumBuffer.java +++ /dev/null @@ -1,132 +0,0 @@ -package net.kaaass.rumbase.page; - -import net.kaaass.rumbase.page.exception.BufferException; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.locks.ReentrantLock; - -/** - * 内存管理 - *

- * 使用单例模式,使用byte数组开辟连续空间,内存的大小不得超过BYTE_BUFFER_SIZE,RumBuffer在操作时直接将整块内存锁住 - *

- * @author XuanLaoYee - */ -public class RumBuffer { - private static RumBuffer instance = null; - private int size = 0; - private ReentrantLock lock = null; - private final byte[] byteBuffer = new byte[PageManager.BYTE_BUFFER_SIZE]; - private List freePage = null; - - private RumBuffer(){ - this.lock = new ReentrantLock(); - this.size = PageManager.BUFFER_SIZE; - this.freePage = new ArrayList<>(); - for(int i=0;i - * 页持有的是整个缓冲区的指针和偏移。页在patchData时本身并不加锁,如果防止冲突需要在上层加锁。 - *

- * @author XuanLaoYee - */ -public class RumPage implements Page { - public RumPage(byte[] data, long pageId, String filepath, int offset) { - this.data = data; - this.pageId = pageId; - this.dirty = false; - this.filepath = filepath; - this.offset = offset;//在内存中的偏移,指的是以页为单位的偏移 - } - - /** - * 得到的是数据的副本,而非缓冲区的指针。 - * @return clone后的数据 - */ - @Override - public byte[] getDataBytes() { - synchronized (this) { - byte[] tmp = new byte[PageManager.PAGE_SIZE]; - System.arraycopy(this.data, this.offset * PageManager.PAGE_SIZE, tmp, 0, tmp.length); - return tmp; - } - } - - /** - * - * @param offset 页内偏移值,以字节为单位 ,该过程不加锁 - * @param data 待写入数据 - * @throws PageException 回写数据偏移与大小之和超过规定,则抛出异常 - */ - @Override - public void patchData(int offset, byte[] data) throws PageException { - if (offset + data.length > PageManager.PAGE_SIZE) { - throw new PageException(1); - } - synchronized (this) { - this.dirty = true; - } - //直接往缓冲内写入 - System.arraycopy(data, 0, this.data, this.offset * PageManager.PAGE_SIZE + offset, data.length); - } - - /** - * 还未实现double write - * @throws FileException - */ - @Override - public void flush() throws FileException { - File file = new File(this.filepath); - synchronized (this) { - try { - RandomAccessFile out = new RandomAccessFile(file, "rw"); - try { - out.seek((PageManager.FILE_HEAD_SIZE + this.pageId) * (long)PageManager.PAGE_SIZE); - } catch (Exception e) { - throw new FileException(4); - } - try { - byte[] data = new byte[PageManager.PAGE_SIZE]; - System.arraycopy(this.data,this.offset*PageManager.PAGE_SIZE,data,0,data.length); - out.write(data); - } catch (Exception e) { - throw new FileException(2); - } - out.close(); - } catch (FileException e) { - throw e; - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - @Override - public void pin() { - synchronized (this) { - pinned++; - } - } - - @Override - public void unpin() { - synchronized (this) { - pinned--; - } - } - - @Override - public boolean equals(Object obj) { - return this == obj; - } - - @Override - public int hashCode() { - return super.hashCode(); - } - - public boolean pinned() { - return pinned > 0; - } - - public boolean dirty() { - return dirty; - } - - public Long pageId(){ - return this.pageId; - } - - private final byte[] data; - private final long pageId; - boolean dirty; - int pinned = 0; - String filepath; - int offset; -} diff --git a/src/main/java/net/kaaass/rumbase/page/RumPageStorage.java b/src/main/java/net/kaaass/rumbase/page/RumPageStorage.java deleted file mode 100644 index d94dc23..0000000 --- a/src/main/java/net/kaaass/rumbase/page/RumPageStorage.java +++ /dev/null @@ -1,101 +0,0 @@ -package net.kaaass.rumbase.page; - -import net.kaaass.rumbase.page.exception.BufferException; -import net.kaaass.rumbase.page.exception.FileException; - -import java.io.*; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -/** - * @author 11158 - */ -public class RumPageStorage implements PageStorage { - public RumPageStorage(String filepath) throws FileException { - this.filepath = filepath; - pageMap = new HashMap<>(); - } - - @Override - public Page get(long pageId) { - File file = new File(filepath); - //文件不存在时创建新文件 - if (!file.exists()) { - try { - file.createNewFile(); - FileOutputStream out = new FileOutputStream(file); - out.write(new byte[PageManager.PAGE_SIZE * 10]); - } catch (IOException e) { - e.printStackTrace(); - } - } - //文件会预留5页作为文件头 - try { - FileInputStream in = new FileInputStream(file); - byte[] data = new byte[PageManager.PAGE_SIZE]; - try { - //当文件存储容量不够时追加 - while (in.available() < (pageId + 1 + PageManager.FILE_HEAD_SIZE) * PageManager.PAGE_SIZE) { - FileWriter fw = new FileWriter(file, true); - char[] blank = new char[PageManager.PAGE_SIZE * (in.available() / PageManager.PAGE_SIZE)]; - Arrays.fill(blank, (char)0); - fw.write(blank); - fw.close(); - } - in.skip((pageId + PageManager.FILE_HEAD_SIZE) * PageManager.PAGE_SIZE); - int readNumber = in.read(data); - if (readNumber < PageManager.PAGE_SIZE) { - throw new FileException(4); - } - } catch (Exception e) { - throw new FileException(4); - } - - Long tmpId = pageId; - if (pageMap.containsKey(tmpId)) { - return pageMap.get(tmpId); - } - int offset = -1; - while (offset < 0) { - synchronized (RumBuffer.getInstance()) {//并非区间锁,而是将整个内存全部锁住 - try { - offset = RumBuffer.getInstance().getFreeOffset(); - RumBuffer.getInstance().put(offset, data); - } catch (BufferException e) { - //下面的这个换出算法没有考虑到在此过程中其他进程再次pin()的情况 - RumPage p = Replacer.getInstance().victim(); - if (p.dirty()) { - p.flush(); - } - RumBuffer.getInstance().free(p.offset); - this.pageMap.remove(p.pageId()); - } - } - } - RumPage page = new RumPage(RumBuffer.getInstance().buffer(), pageId, this.filepath, offset); - Replacer.getInstance().insert(page); - pageMap.put(tmpId, page); - return page; - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - @Override - public void flush() { - Set> entrySet = this.pageMap.entrySet(); - for (Map.Entry entry : entrySet) { - try { - entry.getValue().flush(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - private final Map pageMap; - private final String filepath; -} diff --git a/src/main/java/net/kaaass/rumbase/page/exception/BufferException.java b/src/main/java/net/kaaass/rumbase/page/exception/BufferException.java deleted file mode 100644 index 8d14de2..0000000 --- a/src/main/java/net/kaaass/rumbase/page/exception/BufferException.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.kaaass.rumbase.page.exception; - -import net.kaaass.rumbase.exception.RumbaseException; - -import java.util.HashMap; -import java.util.Map; - -/** - * E9003 缓冲异常 - *

- * E9003-1 内存不足无法换入 - * E9003-2 内存中所有页均被钉住无法换出 - * E9003-3 占用非空内存位置 - * - * @author XuanLaoYee - */ -public class BufferException extends RumbaseException { - public static final Map REASONS = new HashMap() {{ - put(1, "内存不足无法换入"); - put(2, "内存中所有页均被钉住无法换出"); - put(3, "占用非空内存位置"); - }}; - - /** - * 文件异常 - * - * @param subId 子错误号 - */ - public BufferException(int subId) { - super(9003, subId, REASONS.get(subId)); - } -} diff --git a/src/main/java/net/kaaass/rumbase/page/exception/FileException.java b/src/main/java/net/kaaass/rumbase/page/exception/FileException.java deleted file mode 100644 index 8358beb..0000000 --- a/src/main/java/net/kaaass/rumbase/page/exception/FileException.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.kaaass.rumbase.page.exception; - -import net.kaaass.rumbase.exception.RumbaseException; - -import java.util.HashMap; -import java.util.Map; - -/** - * E9001 文件异常 - *

- * E9001-1 创建文件失败 - * E9001-2 写入文件失败 - * E9001-3 文件打开失败 - * E9001-4 游标越界 - * - * @author XuanLaoYee - */ -public class FileException extends RumbaseException { - public static final Map REASONS = new HashMap() {{ - put(1, "创建文件失败"); - put(2, "写入文件失败"); - put(3, "文件打开失败"); - put(4, "offset越界"); - }}; - - /** - * 文件异常 - * - * @param subId 子错误号 - */ - public FileException(int subId) { - super(9001, subId, REASONS.get(subId)); - } -} diff --git a/src/main/java/net/kaaass/rumbase/page/exception/PageException.java b/src/main/java/net/kaaass/rumbase/page/exception/PageException.java deleted file mode 100644 index 356e5b4..0000000 --- a/src/main/java/net/kaaass/rumbase/page/exception/PageException.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.kaaass.rumbase.page.exception; - -import net.kaaass.rumbase.exception.RumbaseException; - -import java.util.HashMap; -import java.util.Map; - -/** - * E9002 文件异常 - *

- * E9002-1 回写数据偏移与大小之和超过规定 - * - * @author XuanLaoYee - */ -public class PageException extends RumbaseException { - public static final Map REASONS = new HashMap() {{ - put(1, "回写数据偏移与大小之和超过规定"); - }}; - - /** - * 页操作异常 - * - * @param subId 主错误号 - */ - public PageException(int subId) { - super(9002, subId, REASONS.get(subId)); - } -} diff --git a/src/main/java/net/kaaass/rumbase/page/mock/MockBuffer.java b/src/main/java/net/kaaass/rumbase/page/mock/MockBuffer.java deleted file mode 100644 index a536bc3..0000000 --- a/src/main/java/net/kaaass/rumbase/page/mock/MockBuffer.java +++ /dev/null @@ -1,74 +0,0 @@ -package net.kaaass.rumbase.page.mock; - -import net.kaaass.rumbase.page.PageManager; -import net.kaaass.rumbase.page.exception.BufferException; - -import java.util.concurrent.locks.ReentrantLock; - -/** - * - */ -public class MockBuffer { - private static MockBuffer instance = null; - private int size = 0; - - private MockBuffer() { - this.lock = new ReentrantLock(); - size = PageManager.BUFFER_SIZE; - } - - public static MockBuffer getInstance() { - if (instance == null) { - synchronized (MockBuffer.class) { - if (instance == null) { - instance = new MockBuffer(); - } - } - } - return instance; - } - - private final byte[] byteBuffer = new byte[PageManager.BYTE_BUFFER_SIZE]; - - public void put(int offset, byte[] bytes) throws BufferException { - if (this.size <= 0) { - throw new BufferException(1); - } - lock.lock(); - try { - System.arraycopy(bytes, 0, this.byteBuffer, offset, bytes.length); - this.size--; - } catch (Exception e) { - e.printStackTrace(); - } finally { - lock.unlock(); - } - } - - public byte[] get(int offset) { - lock.lock(); - try { - byte[] temp = new byte[PageManager.PAGE_SIZE]; - System.arraycopy(this.byteBuffer, offset, temp, offset, PageManager.PAGE_SIZE); - return temp; - } catch (Exception e) { - e.printStackTrace(); - } finally { - lock.unlock(); - } - return null; - } - - public void free(int offset) { - lock.lock(); - try { - System.arraycopy(this.byteBuffer, offset, new byte[PageManager.PAGE_SIZE], 0, PageManager.PAGE_SIZE); - } catch (Exception e) { - e.printStackTrace(); - } finally { - lock.unlock(); - } - } - - private ReentrantLock lock = null; -} diff --git a/src/main/java/net/kaaass/rumbase/page/mock/MockPage.java b/src/main/java/net/kaaass/rumbase/page/mock/MockPage.java deleted file mode 100644 index e96a8c2..0000000 --- a/src/main/java/net/kaaass/rumbase/page/mock/MockPage.java +++ /dev/null @@ -1,54 +0,0 @@ -package net.kaaass.rumbase.page.mock; - -import net.kaaass.rumbase.page.Page; -import net.kaaass.rumbase.page.PageManager; -import net.kaaass.rumbase.page.exception.FileException; -import net.kaaass.rumbase.page.exception.PageException; - -public class MockPage implements Page { - private byte[] data; - long pageId; - boolean dirty; - int pinned = 0; - String filepath; - - MockPage(byte[] data, long pageId, String filepath) { - this.data = data; - this.pageId = pageId; - this.dirty = false; - this.filepath = filepath; - } - - @Override - public byte[] getDataBytes() { - synchronized (this) { - return data; - } - } - - @Override - public void patchData(int offset, byte[] data) throws PageException { - if (offset + data.length > PageManager.PAGE_SIZE) { - throw new PageException(1); - } - System.arraycopy(data, 0, this.data, offset, data.length); - } - - @Override - public void flush() throws FileException { - } - - @Override - public void pin() { - synchronized (this) { - pinned++; - } - } - - @Override - public void unpin() { - synchronized (this) { - pinned--; - } - } -} diff --git a/src/main/java/net/kaaass/rumbase/page/mock/MockPageStorage.java b/src/main/java/net/kaaass/rumbase/page/mock/MockPageStorage.java deleted file mode 100644 index d995199..0000000 --- a/src/main/java/net/kaaass/rumbase/page/mock/MockPageStorage.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.kaaass.rumbase.page.mock; - -import net.kaaass.rumbase.page.Page; -import net.kaaass.rumbase.page.PageManager; -import net.kaaass.rumbase.page.PageStorage; -import net.kaaass.rumbase.page.exception.FileException; - -import java.util.HashMap; -import java.util.Map; - -/** - * @author XuanLaoYee - */ -public class MockPageStorage implements PageStorage { - - - public MockPageStorage(String filepath) throws FileException { - this.filepath = filepath; - pageMap = new HashMap<>(); - this.fakeFile = new byte[1024 * 4 * 10000]; - for (int i = 0; i < 10000; i++) { - for (int j = 0; j < 1024 * 4; j++) { - this.fakeFile[1024 * 4 * i + j] = (byte) i; - } - } - } - - @Override - public Page get(long pageId) { - //文件会预留5页作为文件头 - try { - byte[] data = new byte[PageManager.PAGE_SIZE]; - System.arraycopy(fakeFile, (int) (pageId + PageManager.FILE_HEAD_SIZE) * PageManager.PAGE_SIZE, data, 0, data.length); - Integer tmpId = (int) pageId; - if (pageMap.containsKey(tmpId)) { - return pageMap.get(tmpId); - } - Page page = new MockPage(data, pageId, this.filepath); - pageMap.put(tmpId, page); - return page; - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - @Override - public void flush() { - } - - private Map pageMap; - - private String filepath; - private byte[] fakeFile; -} diff --git a/src/main/java/net/kaaass/rumbase/parse/ColumnIdentifier.java b/src/main/java/net/kaaass/rumbase/parse/ColumnIdentifier.java deleted file mode 100644 index 5cc462c..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/ColumnIdentifier.java +++ /dev/null @@ -1,18 +0,0 @@ -package net.kaaass.rumbase.parse; - -import lombok.AllArgsConstructor; -import lombok.Data; - -/** - * 操作、标志字段的标识符 - * - * @author kaaass - */ -@Data -@AllArgsConstructor -public class ColumnIdentifier { - - private String tableName; - - private String fieldName; -} diff --git a/src/main/java/net/kaaass/rumbase/parse/ConditionExpression.java b/src/main/java/net/kaaass/rumbase/parse/ConditionExpression.java deleted file mode 100644 index 5aa10b7..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/ConditionExpression.java +++ /dev/null @@ -1,435 +0,0 @@ -package net.kaaass.rumbase.parse; - -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import net.kaaass.rumbase.parse.exception.EvaluationException; -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; -import net.sf.jsqlparser.expression.operators.conditional.OrExpression; -import net.sf.jsqlparser.expression.operators.relational.*; -import net.sf.jsqlparser.schema.Column; -import net.sf.jsqlparser.util.deparser.ExpressionDeParser; - -import java.util.*; - -/** - * 条件表达式操作相关 - * - * @author kaaass - */ -@RequiredArgsConstructor -public class ConditionExpression { - - public static double PRECISION = 0.00001; - - private final Expression expression; - - @NonNull - private final String defaultTableName; - - private Map paramColumn = null; - - /** - * 根据参数列表求值 - * - * @param paramMap 参数列表,其中参数必须是原生类型的装箱对象,如Integer、String - */ - public boolean evaluate(Map paramMap) { - if (expression == null) { - return true; - } - updateParam(); - var parser = new DeParser(paramMap); - expression.accept(parser); - var result = parser.getResult(); - if (result instanceof Double) { - return Math.abs((Double) result) > PRECISION; - } else if (result instanceof Long) { - return ((Long) result) != 0; - } else if (result instanceof Boolean) { - return (boolean) result; - } else if (result instanceof String) { - return !"".equals(result); - } - throw new EvaluationException(1); - } - - /** - * 获得表达式求值需要的参数 - */ - public List getParams() { - if (expression == null) { - return List.of(); - } - updateParam(); - return List.copyOf(paramColumn.values()); - } - - private void updateParam() { - if (paramColumn == null) { - paramColumn = new HashMap<>(); - expression.accept(new ExpressionVisitorAdapter() { - - @Override - public void visit(Column column) { - paramColumn.put(column, ParserUtil.mapColumn(column, defaultTableName)); - } - }); - } - } - - @Override - public String toString() { - return "ConditionExpression{" + - "expression=" + expression + - ", defaultTableName='" + defaultTableName + '\'' + - '}'; - } - - /** - * 实现表达式执行的具体访问者 - */ - @RequiredArgsConstructor - class DeParser extends ExpressionDeParser { - - /* - * 类型:数字暂时都转为Double、Boolean、String - */ - Stack stack = new Stack<>(); - - @NonNull - Map params; - - /** - * 获得表达式求值结果 - */ - public Object getResult() { - if (stack.size() != 1) { - throw new EvaluationException(2); - } - return stack.get(0); - } - - @Override - public void visit(Addition addition) { - super.visit(addition); - // + - var b = stack.pop(); - var a = stack.pop(); - assert a instanceof Double; - assert b instanceof Double; - stack.push((double) a + (double) b); - } - - @Override - public void visit(Division division) { - super.visit(division); - // / - var b = stack.pop(); - var a = stack.pop(); - assert a instanceof Double; - assert b instanceof Double; - stack.push((double) a / (double) b); - } - - @Override - public void visit(Multiplication multiplication) { - super.visit(multiplication); - // * - var b = stack.pop(); - var a = stack.pop(); - assert a instanceof Double; - assert b instanceof Double; - stack.push((double) a * (double) b); - } - - @Override - public void visit(Subtraction subtraction) { - super.visit(subtraction); - // - - var b = stack.pop(); - var a = stack.pop(); - assert a instanceof Double; - assert b instanceof Double; - stack.push((double) a - (double) b); - } - - @Override - public void visit(SignedExpression signedExpression) { - super.visit(signedExpression); - // - var a = stack.pop(); - assert a instanceof Double; - if (signedExpression.getSign() == '+') { - stack.push(a); - } else if (signedExpression.getSign() == '-') { - stack.push(-(double) a); - } else if (signedExpression.getSign() == '~') { - stack.push((double) (~(long) a)); - } - } - - @Override - public void visit(AndExpression andExpression) { - super.visit(andExpression); - // and - var b = stack.pop(); - var a = stack.pop(); - assert a instanceof Boolean; - assert b instanceof Boolean; - stack.push((boolean) a && (boolean) b); - } - - @Override - public void visit(NotExpression notExpr) { - super.visit(notExpr); - // ! - var a = stack.pop(); - assert a instanceof Boolean; - stack.push(!(boolean) a); - } - - @Override - public void visit(OrExpression orExpression) { - super.visit(orExpression); - // or - var b = stack.pop(); - var a = stack.pop(); - assert a instanceof Boolean; - assert b instanceof Boolean; - stack.push((boolean) a || (boolean) b); - } - - @Override - public void visit(Between between) { - super.visit(between); - // between - var c = stack.pop(); - var b = stack.pop(); - var a = stack.pop(); - Comparator cmp = Comparator.naturalOrder(); - stack.push(cmp.compare(b, a) <= 0 && cmp.compare(a, c) < 0); - } - - @Override - public void visit(GreaterThan greaterThan) { - super.visit(greaterThan); - // > - var b = stack.pop(); - var a = stack.pop(); - Comparator cmp = Comparator.naturalOrder(); - stack.push(cmp.compare(a, b) > 0); - } - - @Override - public void visit(GreaterThanEquals greaterThanEquals) { - super.visit(greaterThanEquals); - // >= - var b = stack.pop(); - var a = stack.pop(); - if (a instanceof Double && b instanceof Double) { - stack.push((double) a - (double) b > -PRECISION); - } else { - Comparator cmp = Comparator.naturalOrder(); - stack.push(cmp.compare(a, b) >= 0); - } - } - - @Override - public void visit(MinorThan minorThan) { - super.visit(minorThan); - // < - var b = stack.pop(); - var a = stack.pop(); - Comparator cmp = Comparator.naturalOrder(); - stack.push(cmp.compare(a, b) < 0); - } - - @Override - public void visit(MinorThanEquals minorThanEquals) { - super.visit(minorThanEquals); - // <= - var b = stack.pop(); - var a = stack.pop(); - if (a instanceof Double && b instanceof Double) { - stack.push((double) a - (double) b < PRECISION); - } else { - Comparator cmp = Comparator.naturalOrder(); - stack.push(cmp.compare(a, b) <= 0); - } - } - - @Override - public void visit(EqualsTo equalsTo) { - super.visit(equalsTo); - // = - var b = stack.pop(); - var a = stack.pop(); - if (a instanceof Double && b instanceof Double) { - stack.push(Math.abs((double) a - (double) b) < PRECISION); - } else { - stack.push(a.equals(b)); - } - } - - @Override - public void visit(NotEqualsTo notEqualsTo) { - super.visit(notEqualsTo); - // != - var b = stack.pop(); - var a = stack.pop(); - if (a instanceof Double && b instanceof Double) { - stack.push(Math.abs((double) a - (double) b) >= PRECISION); - } else { - stack.push(!a.equals(b)); - } - } - - @Override - public void visit(IntegerDivision division) { - super.visit(division); - // // - var b = stack.pop(); - var a = stack.pop(); - assert a instanceof Double; - assert b instanceof Double; - stack.push((double) ((long) a / (long) b)); - } - - @Override - public void visit(BitwiseRightShift expr) { - super.visit(expr); - // >> - var b = stack.pop(); - var a = stack.pop(); - assert a instanceof Double; - assert b instanceof Double; - stack.push((double) ((long) a >> (long) b)); - } - - @Override - public void visit(BitwiseLeftShift expr) { - super.visit(expr); - // << - var b = stack.pop(); - var a = stack.pop(); - assert a instanceof Double; - assert b instanceof Double; - stack.push((double) ((long) a << (long) b)); - } - - @Override - public void visit(BitwiseAnd bitwiseAnd) { - super.visit(bitwiseAnd); - // & - var b = stack.pop(); - var a = stack.pop(); - assert a instanceof Double; - assert b instanceof Double; - stack.push((double) ((long) a & (long) b)); - } - - @Override - public void visit(BitwiseOr bitwiseOr) { - super.visit(bitwiseOr); - // | - var b = stack.pop(); - var a = stack.pop(); - assert a instanceof Double; - assert b instanceof Double; - stack.push((double) ((long) a | (long) b)); - } - - @Override - public void visit(BitwiseXor bitwiseXor) { - super.visit(bitwiseXor); - // ^ - var b = stack.pop(); - var a = stack.pop(); - assert a instanceof Double; - assert b instanceof Double; - stack.push((double) ((long) a ^ (long) b)); - } - - @Override - public void visit(Modulo modulo) { - super.visit(modulo); - // % - var b = stack.pop(); - var a = stack.pop(); - assert a instanceof Double; - assert b instanceof Double; - stack.push((double) ((long) a % (long) b)); - } - - @Override - public void visit(DoubleValue doubleValue) { - super.visit(doubleValue); - // - stack.push(doubleValue.getValue()); - } - - @Override - public void visit(HexValue hexValue) { - super.visit(hexValue); - // - stack.push(Integer.valueOf(hexValue.getValue(), 16).doubleValue()); - } - - @Override - public void visit(LongValue longValue) { - super.visit(longValue); - // - stack.push((double) longValue.getValue()); - } - - @Override - public void visit(NullValue nullValue) { - super.visit(nullValue); - // - stack.push(null); - } - - @Override - public void visit(StringValue stringValue) { - super.visit(stringValue); - // - stack.push(stringValue.getValue()); - } - - @Override - public void visit(Column tableColumn) { - super.visit(tableColumn); - // - var key = paramColumn.get(tableColumn); - var value = params.get(key); - if (value instanceof Number) { - value = ((Number) value).doubleValue(); - } - stack.push(value); - } - - @Override - public void visit(IsNullExpression isNullExpression) { - super.visit(isNullExpression); - // - stack.push(stack.pop() == null); - } - - @Override - public void visit(IsBooleanExpression isBooleanExpression) { - super.visit(isBooleanExpression); - // - stack.push(stack.pop() instanceof Boolean); - } - - @Override - public void visit(Concat concat) { - super.visit(concat); - // - stack.push(stack.pop().toString() + stack.pop().toString()); - } - } -} diff --git a/src/main/java/net/kaaass/rumbase/parse/ISqlStatement.java b/src/main/java/net/kaaass/rumbase/parse/ISqlStatement.java deleted file mode 100644 index 5d58b37..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/ISqlStatement.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.kaaass.rumbase.parse; - -/** - * 标志用接口,用于标志SQL语句 - * - * @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 deleted file mode 100644 index 833849f..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/ISqlStatementVisitor.java +++ /dev/null @@ -1,37 +0,0 @@ -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 deleted file mode 100644 index 62e803e..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/SqlParser.java +++ /dev/null @@ -1,82 +0,0 @@ -package net.kaaass.rumbase.parse; - -import net.kaaass.rumbase.parse.exception.SqlSyntaxException; -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; - -import java.util.ArrayList; -import java.util.List; - -/** - * 解析任意给定的SQL语句 - * - * @author kaaass - */ -public class SqlParser { - - 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()); - add(new DeleteStatementParser()); - add(new CreateTableStatementParser()); - add(new CreateIndexStatementParser()); - }}; - - /** - * 将语句解析为SQL语法树 - */ - public static ISqlStatement parseStatement(String sql) throws SqlSyntaxException { - // 尝试字符串解析器解析 - for (var parser : STRING_STATEMENT_PARSERS) { - if (parser.checkStatement(sql)) { - return parser.parse(sql); - } - } - // 尝试 JSqlParser 解析 - Statement stmt; - try { - stmt = CCJSqlParserUtil.parse(sql); - } catch (JSQLParserException e) { - throw new SqlSyntaxException(1, e); - } - for (var parser : JSQLP_STATEMENT_PARSERS) { - if (parser.checkStatement(stmt)) { - return parser.parse(stmt); - } - } - throw new SqlSyntaxException(2); - } - - /** - * 语句解析器的通用接口 - */ - public interface StatementParser { - - /** - * 将输入解析为SQL语法树 - */ - ISqlStatement parse(T input) throws SqlSyntaxException; - - /** - * 检查语句可否被当前解析器解析 - */ - boolean checkStatement(T input); - } -} diff --git a/src/main/java/net/kaaass/rumbase/parse/exception/EvaluationException.java b/src/main/java/net/kaaass/rumbase/parse/exception/EvaluationException.java deleted file mode 100644 index 8ae0093..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/exception/EvaluationException.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.kaaass.rumbase.parse.exception; - -import net.kaaass.rumbase.exception.RumbaseRuntimeException; - -import java.util.HashMap; -import java.util.Map; - -/** - * E1002 表达式运算错误 - *

- * E1002-1 运算结果类型错误 - * E1002-2 运算过程错误,可能存在不支持的表达式 - * - * @author kaaass - */ -public class EvaluationException extends RumbaseRuntimeException { - - public static final Map REASONS = new HashMap<>() {{ - put(1, "运算结果类型错误"); - put(2, "运算过程错误,可能存在不支持的表达式"); - }}; - - public EvaluationException(int subId) { - super(5001, subId, REASONS.get(subId)); - } - - public EvaluationException(int subId, Throwable e) { - super(5001, subId, REASONS.get(subId), e); - } -} diff --git a/src/main/java/net/kaaass/rumbase/parse/exception/SqlSyntaxException.java b/src/main/java/net/kaaass/rumbase/parse/exception/SqlSyntaxException.java deleted file mode 100644 index cc87add..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/exception/SqlSyntaxException.java +++ /dev/null @@ -1,36 +0,0 @@ -package net.kaaass.rumbase.parse.exception; - -import net.kaaass.rumbase.exception.RumbaseException; - -import java.util.HashMap; -import java.util.Map; - -/** - * E1001 记录不存在异常 - *

- * E1001-1 SQL语句语法错误 - * E1001-2 不支持的SQL语句 - * E1001-3 语句生成错误,请检查服务器日志 - * - * @author kaaass - */ -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 deleted file mode 100644 index 341be90..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/parser/CommandStatementParser.java +++ /dev/null @@ -1,47 +0,0 @@ -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/JsqlpStatementParser.java b/src/main/java/net/kaaass/rumbase/parse/parser/JsqlpStatementParser.java deleted file mode 100644 index 27793cd..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/parser/JsqlpStatementParser.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.kaaass.rumbase.parse.parser; - -import net.kaaass.rumbase.parse.SqlParser; -import net.sf.jsqlparser.statement.Statement; - -/** - * 适配JSqlParser库的解析器 - * - * @author kaaass - */ -public interface JsqlpStatementParser extends SqlParser.StatementParser { -} 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 deleted file mode 100644 index 0a373ef..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/parser/command/ExecStatementParser.java +++ /dev/null @@ -1,22 +0,0 @@ -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/jsqlp/CreateIndexStatementParser.java b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/CreateIndexStatementParser.java deleted file mode 100644 index 1245ab4..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/CreateIndexStatementParser.java +++ /dev/null @@ -1,36 +0,0 @@ -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; - -import java.util.stream.Collectors; - -/** - * 将建索引语句解释为对应语法树 - * - * @author kaaass - */ -public class CreateIndexStatementParser implements JsqlpStatementParser { - @Override - public ISqlStatement parse(Statement input) { - var stmt = (CreateIndex) input; - // 解析索引名 - var indexName = stmt.getIndex().getName(); - // 解析表名 - var tableName = stmt.getTable().getName(); - // 解析字段 - var columns = stmt.getIndex().getColumnsNames().stream() - .map(name -> new ColumnIdentifier(tableName, name)) - .collect(Collectors.toList()); - return new CreateIndexStatement(indexName, tableName, columns); - } - - @Override - public boolean checkStatement(Statement input) { - return input instanceof CreateIndex; - } -} diff --git a/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/CreateTableStatementParser.java b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/CreateTableStatementParser.java deleted file mode 100644 index 7b3cbcb..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/CreateTableStatementParser.java +++ /dev/null @@ -1,60 +0,0 @@ -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; -import net.sf.jsqlparser.statement.create.table.CreateTable; - -import java.util.List; -import java.util.stream.Collectors; - -/** - * 将建表语句解释为对应语法树 - * - * @author kaaass - */ -public class CreateTableStatementParser implements JsqlpStatementParser { - @Override - 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()), - def.getColumnName(), - def.getColumnSpecs() != null - && checkNotNull(def.getColumnSpecs()) - )) - .collect(Collectors.toList()); - return new CreateTableStatement(tableName, columnDefs); - } - - private boolean checkNotNull(List specs) { - var a = specs.indexOf("not"); - if (a < 0) { - a = specs.indexOf("NOT"); - } - var b = specs.indexOf("null"); - if (b < 0) { - b = specs.indexOf("NULL"); - } - return a >= 0 && b > a; - } - - public static CreateTableStatement.ColumnType mapColType(ColDataType type) { - return new CreateTableStatement.ColumnType(type.getDataType(), type.getArgumentsStringList()); - } - - @Override - public boolean checkStatement(Statement input) { - return input instanceof CreateTable; - } -} diff --git a/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/DeleteStatementParser.java b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/DeleteStatementParser.java deleted file mode 100644 index 328579c..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/DeleteStatementParser.java +++ /dev/null @@ -1,34 +0,0 @@ -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; - -/** - * 将删除语句解释为对应语法树 - * - * @author kaaass - */ -public class DeleteStatementParser implements JsqlpStatementParser { - @Override - public ISqlStatement parse(Statement input) { - Delete stmt = (Delete) input; - // 解析表名 - var tableName = stmt.getTable().getName(); - // 解析where - ConditionExpression where = null; - if (stmt.getWhere() != null) { - where = new ConditionExpression(stmt.getWhere(), tableName); - } - // 拼接结果 - return new DeleteStatement(tableName, where); - } - - @Override - public boolean checkStatement(Statement input) { - return input instanceof Delete; - } -} diff --git a/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/InsertStatementParser.java b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/InsertStatementParser.java deleted file mode 100644 index 65c12b4..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/InsertStatementParser.java +++ /dev/null @@ -1,53 +0,0 @@ -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; -import net.sf.jsqlparser.statement.Statement; -import net.sf.jsqlparser.statement.insert.Insert; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * 将插入语句解释为对应语法树 - * - * @author kaaass - */ -public class InsertStatementParser implements JsqlpStatementParser { - @Override - public ISqlStatement parse(Statement input) { - var stmt = (Insert) input; - // 解析表名 - var tableName = stmt.getTable().getName(); - // 解析列 - List columns = null; - var parsedColumn = stmt.getColumns(); - if (parsedColumn != null) { - columns = ParserUtil.mapColumnList(parsedColumn, tableName); - } - // 解析插入的数据 - var values = new ArrayList(); - stmt.getItemsList().accept(new ItemsListVisitorAdapter() { - - @Override - public void visit(ExpressionList expressionList) { - expressionList.getExpressions().stream() - .map(Objects::toString) - .map(s -> "NULL".equals(s) ? null : s) - .forEach(values::add); - } - }); - // 拼接结果 - return new InsertStatement(tableName, columns, values); - } - - @Override - public boolean checkStatement(Statement stmt) { - return stmt instanceof Insert; - } -} diff --git a/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/ParserUtil.java b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/ParserUtil.java deleted file mode 100644 index 5ee4447..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/ParserUtil.java +++ /dev/null @@ -1,45 +0,0 @@ -package net.kaaass.rumbase.parse.parser.jsqlp; - -import net.kaaass.rumbase.parse.ColumnIdentifier; -import net.sf.jsqlparser.schema.Column; - -import java.util.List; -import java.util.stream.Collectors; - -/** - * 解析相关的工具函数 - * - * @author kaaass - */ -public class ParserUtil { - - /** - * 映射字段 - * - * @param column 字段 - * @param defaultTableName 若不存在表,默认填充的表字段 - * @return 语法树字段 - */ - public static ColumnIdentifier mapColumn(Column column, String defaultTableName) { - return new ColumnIdentifier( - column.getTable() == null ? defaultTableName : column.getTable().getName(), - column.getColumnName() - ); - } - - /** - * 映射字段列表 - * - * @param columnList 字段列表 - * @param defaultTableName 若不存在表,默认填充的表字段 - * @return 语法树字段列表 - */ - public static List mapColumnList(List columnList, String defaultTableName) { - return columnList.stream() - .map(column -> new ColumnIdentifier( - column.getTable() == null ? defaultTableName : column.getTable().getName(), - column.getColumnName() - )) - .collect(Collectors.toList()); - } -} diff --git a/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/SelectStatementParser.java b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/SelectStatementParser.java deleted file mode 100644 index e9e4569..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/SelectStatementParser.java +++ /dev/null @@ -1,127 +0,0 @@ -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; -import net.sf.jsqlparser.schema.Table; -import net.sf.jsqlparser.statement.Statement; -import net.sf.jsqlparser.statement.select.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -/** - * 将选择语句解释为对应语法树 - * - * @author kaaass - */ -@Slf4j -public class SelectStatementParser implements JsqlpStatementParser { - @Override - public ISqlStatement parse(Statement input) throws SqlSyntaxException { - final PlainSelect[] selectStmtArr = {null}; - ((Select) input).getSelectBody().accept(new SelectVisitorAdapter() { - @Override - public void visit(PlainSelect plainSelect) { - selectStmtArr[0] = plainSelect; - } - }); - PlainSelect stmt = selectStmtArr[0]; - // 解析distinct - var distinct = stmt.getDistinct() != null; - // 解析表名 - if (stmt.getFromItem() == null) { - throw new SqlSyntaxException(1, "选择的目标表不能为空"); - } - var tableName = getTableFromItem(stmt.getFromItem()); - // 解析列 - List columns = new ArrayList<>(); - var columnVisitor = new ExpressionVisitorAdapter() { - - @Override - public void visit(Column column) { - columns.add(ParserUtil.mapColumn(column, tableName)); - } - }; - stmt.getSelectItems().forEach(selectItem -> selectItem.accept(new SelectItemVisitorAdapter() { - - @Override - public void visit(AllColumns column) { - columns.clear(); - } - - @Override - public void visit(SelectExpressionItem item) { - item.getExpression().accept(columnVisitor); - } - })); - // 解析join - 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(), tableName); - } - // 解析orderBy - ColumnIdentifier[] columnIdentifiers = new ColumnIdentifier[1]; - var orderVisitor = new ExpressionVisitorAdapter() { - - @Override - public void visit(Column column) { - columnIdentifiers[0] = ParserUtil.mapColumn(column, tableName); - } - }; - 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); - } - - private String getTableFromItem(FromItem fi) { - final String[] tableNames = new String[1]; - fi.accept(new FromItemVisitorAdapter() { - - @Override - public void visit(Table table) { - tableNames[0] = table.getName(); - } - }); - return tableNames[0]; - } - - @Override - public boolean checkStatement(Statement input) { - return input instanceof Select; - } -} diff --git a/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/UpdateStatementParser.java b/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/UpdateStatementParser.java deleted file mode 100644 index 110bb7e..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/parser/jsqlp/UpdateStatementParser.java +++ /dev/null @@ -1,48 +0,0 @@ -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; - -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -/** - * 将更新语句解释为对应语法树 - * - * @author kaaass - */ -public class UpdateStatementParser implements JsqlpStatementParser { - @Override - public ISqlStatement parse(Statement input) { - Update stmt = (Update) input; - // 解析表名 - var tableName = stmt.getTable().getName(); - // 解析列 - List columns = null; - var parsedColumn = stmt.getColumns(); - if (parsedColumn != null) { - columns = ParserUtil.mapColumnList(parsedColumn, tableName); - } - // 解析插入的数据 - var values = stmt.getExpressions().stream() - .map(Objects::toString) - .collect(Collectors.toList()); - // 解析where - ConditionExpression where = null; - if (stmt.getWhere() != null) { - where = new ConditionExpression(stmt.getWhere(), tableName); - } - return new UpdateStatement(tableName, columns, values, where); - } - - @Override - public boolean checkStatement(Statement input) { - return input instanceof 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 deleted file mode 100644 index 2f001d4..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/CommitStatement.java +++ /dev/null @@ -1,16 +0,0 @@ -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 deleted file mode 100644 index 92a1527..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/CreateIndexStatement.java +++ /dev/null @@ -1,39 +0,0 @@ -package net.kaaass.rumbase.parse.stmt; - -import lombok.AllArgsConstructor; -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; - -/** - * SQL语法树:创建索引语句 - * - * @author kaaass - */ -@Data -@AllArgsConstructor -public class CreateIndexStatement implements ISqlStatement { - - /** - * 待创建的索引名称 - */ - private String indexName; - - /** - * 索引的目标表名称 - */ - private String tableName; - - /** - * 索引的目标列 - */ - 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 deleted file mode 100644 index 6c1b75c..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/CreateTableStatement.java +++ /dev/null @@ -1,74 +0,0 @@ -package net.kaaass.rumbase.parse.stmt; - -import lombok.AllArgsConstructor; -import lombok.Data; -import net.kaaass.rumbase.parse.ISqlStatement; -import net.kaaass.rumbase.parse.ISqlStatementVisitor; - -import java.util.List; - -/** - * SQL语法树:建表语句 - * - * @author kaaass - */ -@Data -@AllArgsConstructor -public class CreateTableStatement implements ISqlStatement { - - /** - * 创建表的表名 - */ - private String tableName; - - /** - * 创建表中的列定义 - */ - private List columnDefinitions; - - @Override - public T accept(ISqlStatementVisitor visitor) { - return visitor.visit(this); - } - - /** - * SQL语法树:列定义 - */ - @Data - @AllArgsConstructor - public static class ColumnDefinition { - - /** - * 字段类型 - */ - private ColumnType columnType; - - /** - * 字段名称 - */ - private String columnName; - - /** - * 字段值非空 - */ - private boolean notNull; - } - - /** - * SQL语法树:字段类型 - */ - @Data - @AllArgsConstructor - public static class ColumnType { - - /** - * 字段的SQL类型名,全小写 - */ - private String typeName; - - /** - * 字段参数,如varchar(255)则为['255'] - */ - private List arguments; - } -} diff --git a/src/main/java/net/kaaass/rumbase/parse/stmt/DeleteStatement.java b/src/main/java/net/kaaass/rumbase/parse/stmt/DeleteStatement.java deleted file mode 100644 index 3f92fd2..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/DeleteStatement.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.kaaass.rumbase.parse.stmt; - -import lombok.AllArgsConstructor; -import lombok.Data; -import net.kaaass.rumbase.parse.ConditionExpression; -import net.kaaass.rumbase.parse.ISqlStatement; -import net.kaaass.rumbase.parse.ISqlStatementVisitor; - -/** - * SQL语法树:删除语句 - * - * @author kaaass - */ -@Data -@AllArgsConstructor -public class DeleteStatement implements ISqlStatement { - - /** - * 删除的目标表名 - */ - private String tableName; - - /** - * 删除的筛选条件,为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 deleted file mode 100644 index 43ec55b..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/ExecStatement.java +++ /dev/null @@ -1,23 +0,0 @@ -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 deleted file mode 100644 index c9f399a..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/ExitStatement.java +++ /dev/null @@ -1,16 +0,0 @@ -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 deleted file mode 100644 index 4506312..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/FlushStatement.java +++ /dev/null @@ -1,16 +0,0 @@ -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 deleted file mode 100644 index 1efce70..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/InsertStatement.java +++ /dev/null @@ -1,39 +0,0 @@ -package net.kaaass.rumbase.parse.stmt; - -import lombok.AllArgsConstructor; -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; - -/** - * SQL语法树:插入语句 - * - * @author kaaass - */ -@Data -@AllArgsConstructor -public class InsertStatement implements ISqlStatement { - - /** - * 插入行的目标表名 - */ - private String tableName; - - /** - * 插入数据对应的列,若为null则说明值为完整元组 - */ - private List columns; - - /** - * 插入的数据,以字符串表示 - */ - 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 deleted file mode 100644 index fb6cf4d..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/RollbackStatement.java +++ /dev/null @@ -1,16 +0,0 @@ -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 deleted file mode 100644 index 8625b9a..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/SelectStatement.java +++ /dev/null @@ -1,100 +0,0 @@ -package net.kaaass.rumbase.parse.stmt; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.RequiredArgsConstructor; -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; - -/** - * SQL语法树:选择语句 - * - * @author kaaass - */ -@Data -@AllArgsConstructor -public class SelectStatement implements ISqlStatement { - - /** - * 选择的结果行是否不允许重复 - */ - private boolean distinct; - - /** - * 选择的字段,如果为null则代表选择全部字段,即“*” - */ - private List selectColumns; - - /** - * 选择的源表,其他表以Join的方式表示 - */ - private String fromTable; - - /** - * 需要Join的表,按顺序从fromTable开始连接,为null代表不join - * 如:a join b on cond1 join c on cond2, d - * 则fromTable为a,joins有3项[b, c, d] - */ - private List joins; - - /** - * 选择时用于过滤的条件,为null代表不进行过滤 - */ - private ConditionExpression where; - - /** - * 选择后结果排序的规则,为null代表不排序 - */ - private List orderBys; - - @Override - public T accept(ISqlStatementVisitor visitor) { - return visitor.visit(this); - } - - /** - * SQL语法树:Join表 - */ - @Data - @RequiredArgsConstructor - public static class JoinTable { - - private final String tableName; - - private final ConditionExpression joinOn; - - /* - * Join方式 - */ - - private boolean outer = false; - private boolean right = false; - private boolean left = false; - private boolean natural = false; - private boolean full = false; - private boolean inner = false; - private boolean simple = false; - } - - /** - * SQL语法树:排序方式 - */ - @Data - @AllArgsConstructor - public static class OrderBy { - - /** - * 排序依据的列 - */ - private ColumnIdentifier column; - - /** - * 是否升序 - */ - private boolean ascending; - } -} diff --git a/src/main/java/net/kaaass/rumbase/parse/stmt/ShutdownStatement.java b/src/main/java/net/kaaass/rumbase/parse/stmt/ShutdownStatement.java deleted file mode 100644 index 1f3d052..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/ShutdownStatement.java +++ /dev/null @@ -1,16 +0,0 @@ -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 deleted file mode 100644 index 6d90030..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/StartTransactionStatement.java +++ /dev/null @@ -1,16 +0,0 @@ -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 deleted file mode 100644 index 97f00b2..0000000 --- a/src/main/java/net/kaaass/rumbase/parse/stmt/UpdateStatement.java +++ /dev/null @@ -1,45 +0,0 @@ -package net.kaaass.rumbase.parse.stmt; - -import lombok.AllArgsConstructor; -import lombok.Data; -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; - -/** - * SQL语法树:更新语句 - * - * @author kaaass - */ -@Data -@AllArgsConstructor -public class UpdateStatement implements ISqlStatement { - - /** - * 更新的目标表名 - */ - private String tableName; - - /** - * 要更新的列,与值对应 - */ - private List columns; - - /** - * 更新的目标值 - */ - private List values; - - /** - * 更新行的条件 - */ - private ConditionExpression where; - - @Override - public T accept(ISqlStatementVisitor visitor) { - return visitor.visit(this); - } -} diff --git a/src/main/java/net/kaaass/rumbase/query/AbstractJoinExecutor.java b/src/main/java/net/kaaass/rumbase/query/AbstractJoinExecutor.java deleted file mode 100644 index 68979aa..0000000 --- a/src/main/java/net/kaaass/rumbase/query/AbstractJoinExecutor.java +++ /dev/null @@ -1,39 +0,0 @@ -package net.kaaass.rumbase.query; - -import lombok.Getter; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import net.kaaass.rumbase.parse.ColumnIdentifier; - -import net.kaaass.rumbase.parse.stmt.SelectStatement; -import net.kaaass.rumbase.table.TableManager; -import net.kaaass.rumbase.transaction.TransactionContext; - -import java.util.List; - -/** - * - * @author @KveinAxel - */ -@RequiredArgsConstructor -public abstract class AbstractJoinExecutor implements Executable{ - - @NonNull - protected final String fromTable; - - @NonNull - protected final List joins; - - @NonNull - protected final TableManager manager; - - @NonNull - protected final TransactionContext context; - - @Getter - protected List resultIdr; - - @Getter - protected List> resultRows; - -} diff --git a/src/main/java/net/kaaass/rumbase/query/ConditionExecutor.java b/src/main/java/net/kaaass/rumbase/query/ConditionExecutor.java deleted file mode 100644 index 2e66305..0000000 --- a/src/main/java/net/kaaass/rumbase/query/ConditionExecutor.java +++ /dev/null @@ -1,60 +0,0 @@ -package net.kaaass.rumbase.query; - -import lombok.*; -import net.kaaass.rumbase.parse.ColumnIdentifier; -import net.kaaass.rumbase.parse.ConditionExpression; - -import java.util.*; - -/** - * @author @KveinAxel - */ -@RequiredArgsConstructor -public class ConditionExecutor implements Executable { - - @NonNull - private final List idrs; - - @NonNull - private final List> tableData; - - @NonNull - private final ConditionExpression expression; - - @Getter - private final List> result = new ArrayList<>(); - - @Override - public void execute() { - - var params = expression.getParams(); - var len = params.size(); - var paramMap = new HashMap(len); - boolean ok; - for (var row: tableData) { - paramMap.clear(); - ok = true; - for (var param: params) { - for (int i = 0; i < idrs.size(); i++) { - var idr = idrs.get(i); - if (idr.getTableName().equals(param.getTableName()) && idr.getFieldName().equals(param.getFieldName())) { - var val = row.get(i); - if (val == null) { - ok = false; - } else { - paramMap.put(idr, val); - } - break; - } - } - if (!ok) { - break; - } - } - if (ok && expression.evaluate(paramMap)) { - result.add(row); - } - } - - } -} diff --git a/src/main/java/net/kaaass/rumbase/query/CreateIndexExecutor.java b/src/main/java/net/kaaass/rumbase/query/CreateIndexExecutor.java deleted file mode 100644 index bd507ca..0000000 --- a/src/main/java/net/kaaass/rumbase/query/CreateIndexExecutor.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.kaaass.rumbase.query; - -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; -import net.kaaass.rumbase.parse.stmt.CreateIndexStatement; -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; - -/** - * - * - * @author @KveinAxel - */ -@RequiredArgsConstructor -public class CreateIndexExecutor implements Executable{ - - @NonNull - private final CreateIndexStatement statement; - - @NonNull - private final TableManager manager; - - @NonNull - private final TransactionContext context; - - @Override - public void execute() throws TableExistenceException, IndexAlreadyExistException { - var table = manager.getTable(statement.getTableName()); - BaseField field = null; - - boolean ok; - for (var tableField: table.getFields()) { - ok = false; - for (var column: statement.getColumns()) { - if (tableField.getName().equals(column.getFieldName())) { - field = tableField; - field.setIndexName(statement.getIndexName()); - ok = true; - break; - } - } - if (ok) { - break; - } - } - - 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 deleted file mode 100644 index 3560e27..0000000 --- a/src/main/java/net/kaaass/rumbase/query/CreateTableExecutor.java +++ /dev/null @@ -1,64 +0,0 @@ -package net.kaaass.rumbase.query; - -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -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.TableManager; -import net.kaaass.rumbase.table.exception.TableConflictException; -import net.kaaass.rumbase.table.exception.TableExistenceException; -import net.kaaass.rumbase.table.field.*; -import net.kaaass.rumbase.transaction.TransactionContext; - -import java.util.ArrayList; -import java.util.Locale; - -/** - * @author @KveinAxel - */ -@RequiredArgsConstructor -public class CreateTableExecutor implements Executable { - - @NonNull - private final CreateTableStatement statement; - - @NonNull - private final TableManager manager; - - @NonNull - private final TransactionContext context; - - @Override - public void execute() throws TableExistenceException, TableConflictException, ArgumentException, RecordNotFoundException { - var tableName = statement.getTableName(); - var baseFields = new ArrayList(); - boolean nullable; - for (var def : statement.getColumnDefinitions()) { - nullable = !def.isNotNull(); - var fieldName = def.getColumnName(); - var fieldType = FieldType.valueOf(def.getColumnType().getTypeName().toUpperCase(Locale.ROOT)); - - try { - switch (fieldType) { - case INT: - baseFields.add(new IntField(fieldName, nullable, null)); - break; - case FLOAT: - baseFields.add(new FloatField(fieldName, nullable, null)); - break; - case VARCHAR: - baseFields.add(new VarcharField(fieldName, Integer.parseInt(def.getColumnType().getArguments().get(0)), nullable, null)); - break; - default: - throw new TableConflictException(1); - } - } catch (NumberFormatException | IndexOutOfBoundsException e) { - throw new ArgumentException(1); - } - - } - - manager.createTable(context, tableName, baseFields, "data/table/" + tableName + ".db"); - } -} diff --git a/src/main/java/net/kaaass/rumbase/query/DeleteExecutor.java b/src/main/java/net/kaaass/rumbase/query/DeleteExecutor.java deleted file mode 100644 index 16befdf..0000000 --- a/src/main/java/net/kaaass/rumbase/query/DeleteExecutor.java +++ /dev/null @@ -1,76 +0,0 @@ -package net.kaaass.rumbase.query; - -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; -import net.kaaass.rumbase.parse.ColumnIdentifier; -import net.kaaass.rumbase.parse.stmt.DeleteStatement; -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.TransactionContext; - -import java.util.ArrayList; -import java.util.List; - -/** - * - * - * @author @KveinAxel - */ -@RequiredArgsConstructor -public class DeleteExecutor implements Executable{ - - @NonNull - private final DeleteStatement statement; - - @NonNull - private final TableManager manager; - - @NonNull - private final TransactionContext context; - - @Override - public void execute() throws TableExistenceException, ArgumentException, IndexAlreadyExistException, TableConflictException, RecordNotFoundException { - var table = manager.getTable(statement.getTableName()); - var idrs = new ArrayList(); - table.getFields().forEach(f -> idrs.add(new ColumnIdentifier(table.getTableName(), f.getName()))); - idrs.add(new ColumnIdentifier("__reserved__", "id")); - - var field = table.getFirstIndexedField(); - if (field == null) { - throw new ArgumentException(2); - } - - List> rows = new ArrayList<>(); - var iter = table.searchAll(field.getName()); - while(iter.hasNext()) { - var uuid = iter.next().getUuid(); - List> finalRows = rows; - table.read(context, uuid).ifPresent(row -> { - row.add(uuid); - finalRows.add(row); - }); - } - - var where = statement.getWhere(); - if (where != null) { - - var conditionExe = new ConditionExecutor(idrs, rows, where); - conditionExe.execute(); - rows = conditionExe.getResult(); - - } - - for (var row: rows) { - try { - table.delete(context, (long) row.get(row.size() - 1)); - } catch (ClassCastException e) { - throw new RuntimeException(e); - } - } - - } -} diff --git a/src/main/java/net/kaaass/rumbase/query/Executable.java b/src/main/java/net/kaaass/rumbase/query/Executable.java deleted file mode 100644 index e017f1f..0000000 --- a/src/main/java/net/kaaass/rumbase/query/Executable.java +++ /dev/null @@ -1,26 +0,0 @@ -package net.kaaass.rumbase.query; - -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; - -/** - * 执行接口,实现该接口可以接受Statement语句并执行 - * - * @author @KveinAxel - */ -public interface Executable { - - /** - * 执行器的执行接口 - * - * @throws IndexAlreadyExistException 索引已存在 - * @throws TableConflictException 表模块冲突 - * @throws ArgumentException sql参数异常 - * @throws RecordNotFoundException 记录未找到 - * @throws TableExistenceException 表存在性异常 - */ - void execute() throws TableExistenceException, IndexAlreadyExistException, TableConflictException, ArgumentException, RecordNotFoundException; -} diff --git a/src/main/java/net/kaaass/rumbase/query/InnerJoinExecutor.java b/src/main/java/net/kaaass/rumbase/query/InnerJoinExecutor.java deleted file mode 100644 index 35008d9..0000000 --- a/src/main/java/net/kaaass/rumbase/query/InnerJoinExecutor.java +++ /dev/null @@ -1,121 +0,0 @@ -package net.kaaass.rumbase.query; - -import lombok.NonNull; -import net.kaaass.rumbase.parse.ColumnIdentifier; -import net.kaaass.rumbase.parse.stmt.SelectStatement; -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.TransactionContext; - -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * - * - * @author @KveinAxel - */ -public class InnerJoinExecutor extends AbstractJoinExecutor{ - - - public InnerJoinExecutor(@NonNull String fromTable, @NonNull List joins, TableManager manager, TransactionContext context) { - super(fromTable, joins, manager, context); - } - - @Override - public void execute() throws TableExistenceException, TableConflictException, ArgumentException, RecordNotFoundException { - var table = manager.getTable(fromTable); - var rows = table.readAll(context); - - var idrs = new ArrayList(); - table - .getFields() - .forEach( - f -> idrs.add(new ColumnIdentifier(table.getTableName(), f.getName())) - ); - - - for (var join: joins) { - var joinTable = manager.getTable(join.getTableName()); - var joinRows = joinTable.readAll(context); - var intermediateRows = new ArrayList>(); - var joinIdrs = new ArrayList(); - - joinTable - .getFields() - .forEach( - f -> joinIdrs.add(new ColumnIdentifier(joinTable.getTableName(), f.getName())) - ); - - var len = idrs.size(); - var joinLen = joinIdrs.size(); - var paramMap = new HashMap(idrs.size()); - var params = join.getJoinOn().getParams(); - boolean ok; - - for (var row: rows) { - for (var joinRow: joinRows) { - paramMap.clear(); - ok = true; - - for (var param: params) { - - for (int i = 0; i < len; i++) { - var idr = idrs.get(i); - if (idr.getTableName().equals(param.getTableName()) && idr.getFieldName().equals(param.getFieldName())) { - var val = row.get(i); - if (val == null) { - ok = false; - } else { - paramMap.put(idr, val); - ok = true; - } - break; - } - } - if (!ok) { - break; - } - for (int i = 0; i < joinLen; i++) { - var idr = joinIdrs.get(i); - if (idr.getTableName().equals(param.getTableName()) && idr.getFieldName().equals(param.getFieldName())) { - var val = joinRow.get(i); - if (val == null) { - ok = false; - } else { - paramMap.put(idr, val); - ok = true; - } - break; - } - } - if (!ok) { - break; - } - } - if (ok && join.getJoinOn().evaluate(paramMap)) { - intermediateRows.add( - Stream - .of(row, joinRow) - .flatMap(Collection::stream) - .collect(Collectors.toList()) - ); - - } - - - } - } - - rows = intermediateRows; - idrs.addAll(joinIdrs); - } - - resultIdr = idrs; - resultRows = rows; - } -} diff --git a/src/main/java/net/kaaass/rumbase/query/InsertExecutor.java b/src/main/java/net/kaaass/rumbase/query/InsertExecutor.java deleted file mode 100644 index c760397..0000000 --- a/src/main/java/net/kaaass/rumbase/query/InsertExecutor.java +++ /dev/null @@ -1,67 +0,0 @@ -package net.kaaass.rumbase.query; - -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; -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.transaction.TransactionContext; - -import java.util.ArrayList; - -/** - * - * - * @author @KveinAxel - */ -@RequiredArgsConstructor -public class InsertExecutor implements Executable{ - - @NonNull - private final InsertStatement statement; - - @NonNull - private final TableManager manager; - - @NonNull - private final TransactionContext context; - - @Override - public void execute() throws TableExistenceException, TableConflictException, ArgumentException { - 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 (int j = 0; j < len; j++) { - var insertField = columns.get(j); - ok = false; - for (BaseField f : table.getFields()) { - if (f.getName().equals(insertField.getFieldName())) { - - insertArray.add(statement.getValues().get(j)); - ok = true; - } - } - if (!ok) { - throw new TableConflictException(1); - } - } - - table.insert(context, insertArray); - - } -} diff --git a/src/main/java/net/kaaass/rumbase/query/ProjectExecutor.java b/src/main/java/net/kaaass/rumbase/query/ProjectExecutor.java deleted file mode 100644 index b836a32..0000000 --- a/src/main/java/net/kaaass/rumbase/query/ProjectExecutor.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.kaaass.rumbase.query; - -import lombok.Getter; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; -import net.kaaass.rumbase.parse.ColumnIdentifier; -import net.kaaass.rumbase.query.exception.ArgumentException; -import net.kaaass.rumbase.table.exception.TableConflictException; -import net.kaaass.rumbase.table.exception.TableExistenceException; - -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author @KveinAxel - */ -@RequiredArgsConstructor -public class ProjectExecutor implements Executable{ - - @NonNull - private final List idrs; - - @NonNull - private final List selectedColumns; - - @NonNull - private final List> data; - - @NonNull - @Getter - private final List> projectedResult = new ArrayList<>(); - - @Override - public void execute() throws TableExistenceException, IndexAlreadyExistException, TableConflictException, ArgumentException { - var newColumnsLen = selectedColumns.size(); - var indexList = new ArrayList(); - for (int i = 0; i < newColumnsLen; i++) { - var col = selectedColumns.get(i); - int finalI = i; - idrs.forEach(idr -> { - if (idr.getTableName().equals(col.getTableName()) && idr.getFieldName().equals(col.getFieldName())) { - indexList.add(finalI); - } - }); - } - - data.forEach(row -> { - var newRow = new ArrayList<>(); - indexList.forEach(index -> newRow.add(row.get(index))); - projectedResult.add(newRow); - }); - } -} diff --git a/src/main/java/net/kaaass/rumbase/query/SelectExecutor.java b/src/main/java/net/kaaass/rumbase/query/SelectExecutor.java deleted file mode 100644 index 3a49f16..0000000 --- a/src/main/java/net/kaaass/rumbase/query/SelectExecutor.java +++ /dev/null @@ -1,98 +0,0 @@ -package net.kaaass.rumbase.query; - -import lombok.Getter; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; -import net.kaaass.rumbase.parse.ColumnIdentifier; -import net.kaaass.rumbase.parse.stmt.SelectStatement; -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.TransactionContext; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; - -/** - * - * @author @KveinAxel - */ -@RequiredArgsConstructor -public class SelectExecutor implements Executable{ - - @NonNull - private final SelectStatement statement; - - @NonNull - private final TableManager manager; - - @NonNull - private final TransactionContext context; - - @Getter - private List resultTable; - - @Getter - private List> resultData; - - @Override - public void execute() throws TableConflictException, ArgumentException, TableExistenceException, IndexAlreadyExistException, RecordNotFoundException { - - - // 连接 - var joins = statement.getJoins(); - if (joins == null) { - joins = new ArrayList<>(); - } - var joinExe = new InnerJoinExecutor(statement.getFromTable(), joins, manager, context); - joinExe.execute(); - resultData = joinExe.resultRows; - resultTable = joinExe.resultIdr; - - // 选择 - var where = statement.getWhere(); - if (where != null) { - var conditionExe = new ConditionExecutor(resultTable, resultData, where); - conditionExe.execute(); - resultData = conditionExe.getResult(); - } - - // 排序 - var orderBys = statement.getOrderBys(); - if (orderBys != null) { - var sortExe = new SortExecutor(resultTable, resultData, orderBys, manager); - sortExe.execute(); - resultData = sortExe.getData(); - } - - // 投影 - var selectCols = statement.getSelectColumns(); - if (selectCols != null && !selectCols.isEmpty()) { - var projectExe = new ProjectExecutor(resultTable, selectCols, resultData); - projectExe.execute(); - resultData = projectExe.getProjectedResult(); - resultTable = selectCols; - } - - // 去重 - // FIXME: 2021/1/16 存储过大 - if (statement.isDistinct()) { - var len = resultData.size(); - var hashSet = new HashSet>(len); - var resultList = new ArrayList>(len); - - for (var item: resultData) { - if (hashSet.add(item)) { - resultList.add(item); - } - } - - resultData = resultList; - } - - } -} diff --git a/src/main/java/net/kaaass/rumbase/query/SortExecutor.java b/src/main/java/net/kaaass/rumbase/query/SortExecutor.java deleted file mode 100644 index bc86b2f..0000000 --- a/src/main/java/net/kaaass/rumbase/query/SortExecutor.java +++ /dev/null @@ -1,85 +0,0 @@ -package net.kaaass.rumbase.query; - -import lombok.Getter; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; -import net.kaaass.rumbase.parse.ColumnIdentifier; -import net.kaaass.rumbase.parse.stmt.SelectStatement; -import net.kaaass.rumbase.query.exception.ArgumentException; -import net.kaaass.rumbase.table.TableManager; -import net.kaaass.rumbase.table.exception.TableConflictException; -import net.kaaass.rumbase.table.exception.TableExistenceException; - -import java.util.List; -import java.util.stream.Collectors; - -/** - * - * @author @KveinAxel - */ -@RequiredArgsConstructor -public class SortExecutor implements Executable { - - @NonNull - private final List idrs; - - @Getter - @NonNull - private List> data; - - @NonNull - private final List orderBys; - - @NonNull - private final TableManager manager; - - - @Override - public void execute() throws TableExistenceException, IndexAlreadyExistException, TableConflictException, ArgumentException { - var len = idrs.size(); - for (var orderBy : orderBys) { - - int index = -1; - ColumnIdentifier orderIdr = null; - for (int i = 0; i < len; i++) { - var column = orderBy.getColumn(); - var idr = idrs.get(i); - if (idr.getTableName().equals(column.getTableName()) && idr.getFieldName().equals(column.getFieldName())) { - index = i; - orderIdr = idr; - break; - } - } - - if (index == -1) { - throw new ArgumentException(1); - } - - var table = manager.getTable(orderIdr.getTableName()); - var field = table - .getField(orderBy.getColumn().getFieldName()) - .orElseThrow(() -> new ArgumentException(1)); - - final int finalIndex = index; - if (orderBy.isAscending()) { - data = data.stream().sorted((list1, list2) -> { - try { - return field.compare(list1.get(finalIndex), list2.get(finalIndex)); - } catch (TableConflictException e) { - throw new RuntimeException(e); - } - }).collect(Collectors.toList()); - } else { - data = data.stream().sorted((list1, list2) -> { - try { - return field.compare(list2.get(finalIndex), list1.get(finalIndex)); - } catch (TableConflictException e) { - throw new RuntimeException(e); - } - }).collect(Collectors.toList()); - } - - } - } -} diff --git a/src/main/java/net/kaaass/rumbase/query/UpdateExecutor.java b/src/main/java/net/kaaass/rumbase/query/UpdateExecutor.java deleted file mode 100644 index 018eeb1..0000000 --- a/src/main/java/net/kaaass/rumbase/query/UpdateExecutor.java +++ /dev/null @@ -1,93 +0,0 @@ -package net.kaaass.rumbase.query; - -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import net.kaaass.rumbase.index.exception.IndexAlreadyExistException; -import net.kaaass.rumbase.parse.ColumnIdentifier; -import net.kaaass.rumbase.parse.stmt.UpdateStatement; -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.TransactionContext; - -import java.util.ArrayList; -import java.util.List; - -/** - * - * - * @author @KveinAxel - */ -@RequiredArgsConstructor -public class UpdateExecutor implements Executable{ - - @NonNull - private final UpdateStatement statement; - - @NonNull - private final TableManager manager; - - @NonNull - private final TransactionContext context; - - @Override - public void execute() throws TableExistenceException, ArgumentException, IndexAlreadyExistException, TableConflictException, RecordNotFoundException { - var table = manager.getTable(statement.getTableName()); - var idrs = new ArrayList(); - table.getFields().forEach(f -> idrs.add(new ColumnIdentifier(table.getTableName(), f.getName()))); - idrs.add(new ColumnIdentifier("__reserved__", "id")); - - var indexedField = table.getFirstIndexedField(); - if (indexedField == null) { - throw new ArgumentException(2); - } - - List> rows = new ArrayList<>(); - var iter = table.searchAll(indexedField.getName()); - while(iter.hasNext()) { - var uuid = iter.next().getUuid(); - List> finalRows = rows; - table.read(context, uuid).ifPresent(row -> { - row.add(uuid); - finalRows.add(row); - }); - } - - var where = statement.getWhere(); - if (where != null) { - var conditionExe = new ConditionExecutor(idrs, rows, where); - conditionExe.execute(); - rows = conditionExe.getResult(); - } - - var uuids = new ArrayList(); - - for (var row : rows) { - uuids.add((long) row.remove(row.size() - 1)); - } - - var fields = table.getFields(); - var len = fields.size(); - var rowLen = rows.size(); - var updateFieldLen = statement.getColumns().size(); - - for (int i = 0; i < len; i++) { - for (int j = 0; j < updateFieldLen; j++) { - var field = fields.get(i); - if (field.getName().equals(statement.getColumns().get(j).getFieldName())) { - for (var list : rows) { - var val = fields.get(i).strToValue(statement.getValues().get(j)); - list.set(i, val); - } - } - } - } - - for (int i = 0; i < rowLen; i++) { - table.updateObjs(context, uuids.get(i), rows.get(i)); - } - - } -} diff --git a/src/main/java/net/kaaass/rumbase/query/exception/ArgumentException.java b/src/main/java/net/kaaass/rumbase/query/exception/ArgumentException.java deleted file mode 100644 index e748c7e..0000000 --- a/src/main/java/net/kaaass/rumbase/query/exception/ArgumentException.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.kaaass.rumbase.query.exception; - -import net.kaaass.rumbase.exception.RumbaseException; - -import java.util.HashMap; -import java.util.Map; - -/** - * E2001 参数异常 - *

- * E2001-1 列参数异常 - *

- * E2001-2 请求不包含索引列 - * - * @author @KveinAxel - */ -public class ArgumentException extends RumbaseException { - public static final Map REASONS = new HashMap<>(){{ - put(1, "列参数异常"); - put(2, "请求不包含索引列"); - }}; - - /** - * 类型不匹配异常 - * - * @param subId 子错误号 - */ - public ArgumentException(int subId) { - super(2001, subId, REASONS.get(subId)); - } -} diff --git a/src/main/java/net/kaaass/rumbase/record/IRecordStorage.java b/src/main/java/net/kaaass/rumbase/record/IRecordStorage.java deleted file mode 100644 index abe0919..0000000 --- a/src/main/java/net/kaaass/rumbase/record/IRecordStorage.java +++ /dev/null @@ -1,69 +0,0 @@ -package net.kaaass.rumbase.record; - -import net.kaaass.rumbase.record.exception.RecordNotFoundException; -import net.kaaass.rumbase.transaction.TransactionContext; - -import java.util.Optional; - -/** - * 记录存储接口,提供由记录ID存取数据的容器 - * - * @author kaaass - */ -public interface IRecordStorage { - - /** - * 向存储中加入一串记录数据字节 - * - * @param txContext 事务上下文 - * @param rawData 字节数据 - * @return 记录ID - */ - long insert(TransactionContext txContext, byte[] rawData); - - /** - * 由记录ID查询记录数据 - * - * @param txContext 事务上下文 - * @param recordId 记录ID - * @return 记录数据字节 - * @throws RecordNotFoundException 若记录不存在、不可见,抛出错误 - */ - default byte[] query(TransactionContext txContext, long recordId) throws RecordNotFoundException { - var result = queryOptional(txContext, recordId); - return result.orElseThrow(() -> new RecordNotFoundException(2)); - } - - /** - * 由记录ID查询记录数据,并忽略由事务造成的记录不可见。若物理记录不存在,将抛出运行时错误 - * - * @param txContext 事务上下文 - * @param recordId 记录ID - * @return 记录数据字节,若记录不可见则返回Optional.empty() - */ - Optional queryOptional(TransactionContext txContext, long recordId) throws RecordNotFoundException; - - /** - * 由记录ID删除记录数据 - * - * @param txContext 事务上下文 - * @param recordId 记录ID - */ - void delete(TransactionContext txContext, long recordId) throws RecordNotFoundException; - - /** - * 获得记录存储的元信息(与单个记录无关) - * - * @return 元信息数据 - */ - byte[] getMetadata(TransactionContext txContext); - - /** - * 更新记录存储的元信息 - * - * @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 deleted file mode 100644 index 6f3ebc7..0000000 --- a/src/main/java/net/kaaass/rumbase/record/MvccRecordStorage.java +++ /dev/null @@ -1,279 +0,0 @@ -package net.kaaass.rumbase.record; - -import lombok.Getter; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import net.kaaass.rumbase.dataitem.IItemStorage; -import net.kaaass.rumbase.dataitem.exception.UUIDException; -import net.kaaass.rumbase.record.exception.NeedRollbackException; -import net.kaaass.rumbase.record.exception.RecordNotFoundException; -import net.kaaass.rumbase.record.exception.StorageCorruptedException; -import net.kaaass.rumbase.transaction.TransactionContext; -import net.kaaass.rumbase.transaction.TransactionIsolation; -import net.kaaass.rumbase.transaction.TransactionStatus; -import net.kaaass.rumbase.transaction.exception.DeadlockException; -import net.kaaass.rumbase.transaction.exception.StatusException; - -import java.util.Optional; - -/** - * 实现MVCC并且通过transaction模块实现2PL的记录存储 - * - * @author kaaass - */ -@Slf4j -@RequiredArgsConstructor -public class MvccRecordStorage implements IRecordStorage { - - @NonNull - private final IItemStorage storage; - - @NonNull - @Getter - private final String identifiedName; - - /** - * 元数据缓存。仅在第一条metadata可见时有效 - */ - private byte[] metadataCache = null; - - @Override - public long insert(TransactionContext txContext, byte[] rawData) { - var data = new byte[rawData.length + 8]; - // 拼接data - writeXmin(data, txContext.getXid()); - writeXmax(data, 0); - writePayload(data, rawData); - // 不用检查版本跳跃的原因是,插入本身不用;更新操作必定先删除,而删除检查 - // 插入记录 - return storage.insertItem(txContext, data); - } - - @Override - public Optional queryOptional(TransactionContext txContext, long recordId) throws RecordNotFoundException { - // 串行化事务则申请读锁 - if (txContext.getIsolation() == TransactionIsolation.SERIALIZABLE) { - try { - txContext.sharedLock(recordId, this.identifiedName); - } catch (DeadlockException e) { - throw new NeedRollbackException(2, e); - } catch (StatusException e) { - throw new RecordNotFoundException(3, e); - } - } - // 读取数据 - byte[] data; - try { - data = storage.queryItemByUuid(recordId); - } catch (UUIDException e) { - throw new RecordNotFoundException(1, e); - } - // 检查可见性 - if (isVisible(txContext, data)) { - return Optional.of(readPayload(data)); - } else { - return Optional.empty(); - } - } - - @Override - public void delete(TransactionContext txContext, long recordId) throws RecordNotFoundException { - // 读取数据 - byte[] data; - try { - data = storage.queryItemByUuid(recordId); - } catch (UUIDException e) { - throw new RecordNotFoundException(1, e); - } - // 判断可见性,若不可见直接返回 - if (!isVisible(txContext, data)) { - throw new RecordNotFoundException(2); - } - // 申请互斥锁 - try { - txContext.exclusiveLock(recordId, this.identifiedName); - } catch (DeadlockException e) { - throw new NeedRollbackException(2, e); - } catch (StatusException e) { - throw new RecordNotFoundException(3, e); - } - var xid = txContext.getXid(); - if (xid == 0) { - xid = -1; - } - // 是否已经被删除 - var xmax = readXmax(data); - if (xmax == xid) { - throw new RecordNotFoundException(2); - } - // 版本跳跃检查 - if (isVersionSkip(txContext, data)) { - log.info("事务 {} 操作记录 {} 发生版本跳跃", txContext.getXid(), recordId); - throw new NeedRollbackException(1); - } - // 更新记录 - writeXmax(data, xid); - try { - storage.updateItemByUuid(txContext, recordId, data); - } catch (UUIDException e) { - throw new RecordNotFoundException(1, e); - } - } - - /** - * 判断可见性 - */ - private boolean isVisible(TransactionContext txContext, byte[] data) { - var isolation = txContext.getIsolation(); - var xid = txContext.getXid(); - var xmin = readXmin(data); - var xmax = readXmax(data); - if (isolation == TransactionIsolation.READ_UNCOMMITTED) { - // 读未提交:没被删除 - return xmax == 0; - } else if (isolation == TransactionIsolation.READ_COMMITTED) { - // 读已提交 - // 事务自身创建,且未被删除 - if (xmin == xid && xmax == 0) { - return true; - } - // 记录已提交 - if (statusOf(xmin, txContext) == TransactionStatus.COMMITTED) { - // 未被删除 - if (xmax == 0) { - return true; - } - // 被自身删除则不可见 - if (xmax == xid) { - return false; - } - // 被删除但是删除事务未提交 - return statusOf(xmax, txContext) != TransactionStatus.COMMITTED; - } - return false; - } else if (isolation == TransactionIsolation.REPEATABLE_READ) { - // 可重复读 - // 事务自身创建,且未被删除 - if (xmin == xid && xmax == 0) { - return true; - } - // 记录被可见事务提交 - if (xmin < xid && !txContext.getSnapshot().contains(xmin) - && statusOf(xmin, txContext) == TransactionStatus.COMMITTED) { - // 未被删除 - if (xmax == 0) { - return true; - } - // 被自身删除则不可见 - if (xmax == xid) { - return false; - } - // 被删除但是删除事务未提交 - return xmax > xid || txContext.getSnapshot().contains(xmax) - || statusOf(xmax, txContext) != TransactionStatus.COMMITTED; - } - } else if (isolation == TransactionIsolation.SERIALIZABLE) { - // 可串行化:没被删除,依靠2PL保证事务性 - return xmax == 0; - } - return false; - } - - /** - * 判断版本跳跃 - */ - private boolean isVersionSkip(TransactionContext txContext, byte[] data) { - var isolation = txContext.getIsolation(); - if (isolation != TransactionIsolation.REPEATABLE_READ) { - // 只有可重复读需要检测版本跳跃 - // 序列化隔离度因为严格2PL,根本不出现版本跳跃 - return false; - } - var xmax = readXmax(data); - // 事务已经提交且对当前事务不可见 - return statusOf(xmax, txContext) == TransactionStatus.COMMITTED - && (xmax > txContext.getXid() || txContext.getSnapshot().contains(xmax)); - } - - @Override - public byte[] getMetadata(TransactionContext txContext) { - // TODO 申请全表锁,用this锁代替 - synchronized (this) { - if (this.metadataCache != null) { - return this.metadataCache; - } - // 读入记录数据 - var uuids = storage.getMetadata(); - for (int st = 0; st < uuids.length; st += 8) { - var uuid = MvccUtil.readLong(uuids, st); - Optional result; - try { - result = queryOptional(txContext, uuid); - } catch (RecordNotFoundException e) { - throw new StorageCorruptedException(1, e); - } - if (result.isPresent()) { - // 如果是第一个,更新cache - if (st == 0) { - this.metadataCache = result.get(); - } - return result.get(); - } - } - } - return new byte[0]; - } - - @Override - public void setMetadata(TransactionContext txContext, byte[] metadata) { - // TODO 申请全表锁,用this锁代替 - // 主要逻辑:为了保证事务性,使用UUID数组,结合可见性选择对应的记录。倒序记录便于存储。 - synchronized (this) { - // 创建一条记录 - var newId = insert(txContext, metadata); - // 保存记录至下层 metadata - var oldMetadata = storage.getMetadata(); - var newMetadata = new byte[oldMetadata.length + 8]; - System.arraycopy(oldMetadata, 0, newMetadata, 8, oldMetadata.length); - MvccUtil.writeLong(newMetadata, 0, newId); - storage.setMetadata(txContext, newMetadata); - // 缓存取消 - this.metadataCache = null; - } - } - - private static TransactionStatus statusOf(int xid, TransactionContext txContext) { - if (xid == 0 || xid == -1) { - return TransactionStatus.COMMITTED; - } - return txContext.getManager().getContext(xid).getStatus(); - } - - private static void writeXmin(byte[] data, int xmin) { - MvccUtil.writeInt(data, 0, xmin); - } - - private static void writeXmax(byte[] data, int xmax) { - MvccUtil.writeInt(data, 4, xmax); - } - - private static void writePayload(byte[] data, byte[] payload) { - System.arraycopy(payload, 0, data, 8, payload.length); - } - - private static int readXmin(byte[] data) { - return MvccUtil.readInt(data, 0); - } - - private static int readXmax(byte[] data) { - return MvccUtil.readInt(data, 4); - } - - private static byte[] readPayload(byte[] data) { - var result = new byte[data.length - 8]; - System.arraycopy(data, 8, result, 0, result.length); - return result; - } -} diff --git a/src/main/java/net/kaaass/rumbase/record/MvccUtil.java b/src/main/java/net/kaaass/rumbase/record/MvccUtil.java deleted file mode 100644 index e31b454..0000000 --- a/src/main/java/net/kaaass/rumbase/record/MvccUtil.java +++ /dev/null @@ -1,81 +0,0 @@ -package net.kaaass.rumbase.record; - -/** - * MVCC常用操作函数库 - * - * @author kaaass - */ -public class MvccUtil { - - /** - * 将整数以大端序写入字节数组 - * - * @param data 目的字节数组 - * @param offset 偏移 - * @param value 写入值 - */ - public static void writeInt(byte[] data, int offset, int value) { - assert data.length >= 4; - data[offset] = (byte) (value >> (8 * 3)); - data[offset + 1] = (byte) ((value >> (8 * 2)) & 0xff); - data[offset + 2] = (byte) ((value >> 8) & 0xff); - data[offset + 3] = (byte) (value & 0xff); - } - - /** - * 从字节数组读入大端序整数 - * - * @param data 源字节数组 - * @param offset 偏移 - * @return 读入的整数 - */ - public static int readInt(byte[] data, int offset) { - assert data.length >= 4; - int result = 0; - result |= (data[offset] & 0xff) << (8 * 3); - result |= (data[offset + 1] & 0xff) << (8 * 2); - result |= (data[offset + 2] & 0xff) << 8; - result |= data[offset + 3] & 0xff; - return result; - } - - /** - * 将长整数以大端序写入字节数组 - * - * @param data 目的字节数组 - * @param offset 偏移 - * @param value 写入值 - */ - public static void writeLong(byte[] data, int offset, long value) { - assert data.length >= 8; - data[offset] = (byte) (value >> (8 * 7)); - data[offset + 1] = (byte) ((value >> (8 * 6)) & 0xff); - data[offset + 2] = (byte) ((value >> (8 * 5)) & 0xff); - data[offset + 3] = (byte) ((value >> (8 * 4)) & 0xff); - data[offset + 4] = (byte) ((value >> (8 * 3)) & 0xff); - data[offset + 5] = (byte) ((value >> (8 * 2)) & 0xff); - data[offset + 6] = (byte) ((value >> 8) & 0xff); - data[offset + 7] = (byte) (value & 0xff); - } - - /** - * 从字节数组读入大端序长整数 - * - * @param data 源字节数组 - * @param offset 偏移 - * @return 读入的整数 - */ - public static long readLong(byte[] data, int offset) { - assert data.length >= 8; - long result = 0; - result |= (long) (data[offset] & 0xff) << (8 * 7); - result |= (long) (data[offset + 1] & 0xff) << (8 * 6); - result |= (long) (data[offset + 2] & 0xff) << (8 * 5); - result |= (long) (data[offset + 3] & 0xff) << (8 * 4); - result |= (long) (data[offset + 4] & 0xff) << (8 * 3); - result |= (long) (data[offset + 5] & 0xff) << (8 * 2); - result |= (long) (data[offset + 6] & 0xff) << 8; - result |= (long) data[offset + 7] & 0xff; - return result; - } -} diff --git a/src/main/java/net/kaaass/rumbase/record/RecordManager.java b/src/main/java/net/kaaass/rumbase/record/RecordManager.java deleted file mode 100644 index e7a26bb..0000000 --- a/src/main/java/net/kaaass/rumbase/record/RecordManager.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.kaaass.rumbase.record; - -import lombok.SneakyThrows; -import net.kaaass.rumbase.dataitem.ItemManager; - -import java.io.File; -import java.nio.file.Paths; - -/** - * 记录管理类 - * - * @author kaaass - */ -public class RecordManager { - - - /** - * 从文件获取记录存储对象 - * - * @param filepath 记录文件 - * @return 记录存储对象 - */ - @SneakyThrows - public static IRecordStorage fromFile(String filepath) { - var itemStorage = ItemManager.fromFile(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/exception/NeedRollbackException.java b/src/main/java/net/kaaass/rumbase/record/exception/NeedRollbackException.java deleted file mode 100644 index d13bc60..0000000 --- a/src/main/java/net/kaaass/rumbase/record/exception/NeedRollbackException.java +++ /dev/null @@ -1,40 +0,0 @@ -package net.kaaass.rumbase.record.exception; - -import net.kaaass.rumbase.exception.RumbaseRuntimeException; - -import java.util.HashMap; -import java.util.Map; - -/** - * E5003 需要自动回滚异常 - *

- * E5003-1 发生版本跳跃,需要自动回滚事务 - * E5003-2 发生死锁,需要回滚当前事务 - * - * @author kaaass - */ -public class NeedRollbackException extends RumbaseRuntimeException { - - public static final Map REASONS = new HashMap<>() {{ - put(1, "发生版本跳跃,需要自动回滚事务"); - put(2, "发生死锁,需要回滚当前事务"); - }}; - - /** - * 需要自动回滚异常 - * - * @param subId 子错误号 - */ - public NeedRollbackException(int subId) { - super(5003, subId, REASONS.get(subId)); - } - - /** - * 需要自动回滚异常 - * - * @param subId 子错误号 - */ - public NeedRollbackException(int subId, Throwable cause) { - super(5003, subId, REASONS.get(subId), cause); - } -} diff --git a/src/main/java/net/kaaass/rumbase/record/exception/RecordNotFoundException.java b/src/main/java/net/kaaass/rumbase/record/exception/RecordNotFoundException.java deleted file mode 100644 index 0c8644b..0000000 --- a/src/main/java/net/kaaass/rumbase/record/exception/RecordNotFoundException.java +++ /dev/null @@ -1,42 +0,0 @@ -package net.kaaass.rumbase.record.exception; - -import net.kaaass.rumbase.exception.RumbaseException; - -import java.util.HashMap; -import java.util.Map; - -/** - * E5001 记录不存在异常 - *

- * E5001-1 物理记录不存在 - * E5001-2 由于事务性,记录不可见 - * E5001-3 事务未处于活动状态,不可访问记录 - * - * @author kaaass - */ -public class RecordNotFoundException extends RumbaseException { - - public static final Map REASONS = new HashMap<>() {{ - put(1, "物理记录不存在"); - put(2, "由于事务隔离或已经被删除,记录不可见"); - put(3, "事务未处于活动状态,不可访问记录"); - }}; - - /** - * 记录不存在异常 - * - * @param subId 子错误号 - */ - public RecordNotFoundException(int subId) { - super(5001, subId, REASONS.get(subId)); - } - - /** - * 记录不存在异常 - * - * @param subId 子错误号 - */ - public RecordNotFoundException(int subId, Throwable cause) { - super(5001, subId, REASONS.get(subId), cause); - } -} diff --git a/src/main/java/net/kaaass/rumbase/record/exception/StorageCorruptedException.java b/src/main/java/net/kaaass/rumbase/record/exception/StorageCorruptedException.java deleted file mode 100644 index b7305f1..0000000 --- a/src/main/java/net/kaaass/rumbase/record/exception/StorageCorruptedException.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.kaaass.rumbase.record.exception; - -import net.kaaass.rumbase.exception.RumbaseException; -import net.kaaass.rumbase.exception.RumbaseRuntimeException; - -import java.util.HashMap; -import java.util.Map; - -/** - * E5002 存储数据错误异常 - *

- * E5002-1 存储数据元信息不存在,存储数据可能损坏 - * - * @author kaaass - */ -public class StorageCorruptedException extends RumbaseRuntimeException { - - public static final Map REASONS = new HashMap<>() {{ - put(1, "存储数据元信息不存在"); - }}; - - /** - * 记录不存在异常 - * - * @param subId 子错误号 - */ - public StorageCorruptedException(int subId) { - super(5002, subId, REASONS.get(subId)); - } - - public StorageCorruptedException(int subId, Throwable cause) { - super(5002, subId, REASONS.get(subId), cause); - } -} diff --git a/src/main/java/net/kaaass/rumbase/record/mock/MockRecordStorage.java b/src/main/java/net/kaaass/rumbase/record/mock/MockRecordStorage.java deleted file mode 100644 index 031fb21..0000000 --- a/src/main/java/net/kaaass/rumbase/record/mock/MockRecordStorage.java +++ /dev/null @@ -1,91 +0,0 @@ -package net.kaaass.rumbase.record.mock; - - -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import net.kaaass.rumbase.record.IRecordStorage; -import net.kaaass.rumbase.record.exception.RecordNotFoundException; -import net.kaaass.rumbase.transaction.TransactionContext; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; - -/** - * Mock记录存储,仅用于测试 - * - * @author kaaass - */ -@Deprecated -@RequiredArgsConstructor -public class MockRecordStorage implements IRecordStorage { - - /** - * 内存中创建的Mock存储 - */ - private static final Map MOCK_STORAGES = new HashMap<>(); - - - @Getter - private final String mockId; - - private final Map memoryStorage = new HashMap<>(); - - private byte[] metadata = new byte[0]; - - @Override - public long insert(TransactionContext txContext, byte[] rawData) { - var uuid = UUID.randomUUID().getLeastSignificantBits(); - this.memoryStorage.put(uuid, rawData); - return uuid; - } - - @Override - public byte[] query(TransactionContext txContext, long recordId) throws RecordNotFoundException { - if (!this.memoryStorage.containsKey(recordId)) { - throw new RecordNotFoundException(1); - } - return this.memoryStorage.get(recordId); - } - - @Override - public Optional queryOptional(TransactionContext txContext, long recordId) { - try { - return Optional.ofNullable(query(txContext, recordId)); - } catch (RecordNotFoundException e) { - return Optional.empty(); - } - } - - @Override - public void delete(TransactionContext txContext, long recordId) { - this.memoryStorage.remove(recordId); - } - - @Override - public byte[] getMetadata(TransactionContext txContext) { - return this.metadata; - } - - @Override - 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)) { - return MOCK_STORAGES.get(mockId); - } - var result = new MockRecordStorage(mockId); - MOCK_STORAGES.put(mockId, result); - return result; - } - -} diff --git a/src/main/java/net/kaaass/rumbase/recovery/IRecoveryStorage.java b/src/main/java/net/kaaass/rumbase/recovery/IRecoveryStorage.java deleted file mode 100644 index 0684071..0000000 --- a/src/main/java/net/kaaass/rumbase/recovery/IRecoveryStorage.java +++ /dev/null @@ -1,63 +0,0 @@ -package net.kaaass.rumbase.recovery; - -import java.util.List; - -/** - * 日志管理的接口,用来进行日志的写入和恢复 - * - * @author kaito - */ -public interface IRecoveryStorage { - /** - * 记录事务开始 - * - * @param xid 事务编号 - * @param snapshots 快照集合 - */ - void begin(int xid, List snapshots); - - /** - * 记录事务失败回滚 - * - * @param xid - */ - void rollback(int xid); - - /** - * 记录事务完成 - * - * @param xid - */ - void commit(int xid); - - /** - * 插入数据项的日志记录 - * - * @param xid 日志编号 - * @param uuid 数据项的对应编号 - * @param item 插入的数据内容 - */ - void insert(int xid, long uuid, byte[] item); - - /** - * 更新数据项的日志记录 - * - * @param xid - * @param uuid - * @param item - */ - void update(int xid, long uuid, byte[] item); - - /** - * 更新数据项的日志头 - * - * @param xid - * @param metaUUID 头信息的UUID - */ - void updateMeta(int xid, long metaUUID); - - /** - * 模拟打印日志资料 - */ - List getContent(); -} diff --git a/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java b/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java deleted file mode 100644 index 4fbc18a..0000000 --- a/src/main/java/net/kaaass/rumbase/recovery/RecoveryManager.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.kaaass.rumbase.recovery; - -import net.kaaass.rumbase.recovery.mock.MockRecoveryStorage; - -/** - * 日志恢复的管理器,用来对每个数据库文件进行恢复 - * - * @author kaito - */ -public class RecoveryManager { - /** - * 对某个数据库文件进行恢复,并且返回对应的日志管理器 - * - * @param fileName 文件名 - * @return 数据库日志管理器 - */ - public static IRecoveryStorage recovery(String fileName) { - // TODO:对数据进行恢复 - return new MockRecoveryStorage(); - } -} diff --git a/src/main/java/net/kaaass/rumbase/recovery/mock/MockRecoveryStorage.java b/src/main/java/net/kaaass/rumbase/recovery/mock/MockRecoveryStorage.java deleted file mode 100644 index fa8c4e9..0000000 --- a/src/main/java/net/kaaass/rumbase/recovery/mock/MockRecoveryStorage.java +++ /dev/null @@ -1,73 +0,0 @@ -package net.kaaass.rumbase.recovery.mock; - -import net.kaaass.rumbase.recovery.IRecoveryStorage; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - - -public class MockRecoveryStorage implements IRecoveryStorage { - - public MockRecoveryStorage() { - bytes = new ArrayList<>(); - } - - /** - * 模拟日志记录 - */ - public List bytes; - - @Override - public void begin(int xid, List snapshots) { - String beginStr = "begin " + xid; - bytes.add(beginStr.getBytes()); - String snapStr = "snap " + snapshots.toString(); - bytes.add(snapStr.getBytes()); - } - - @Override - public void rollback(int xid) { - String backStr = "abort " + xid; - bytes.add(backStr.getBytes()); - } - - @Override - public void commit(int xid) { - String commitStr = "commit " + xid; - bytes.add(commitStr.getBytes()); - } - - @Override - public void insert(int xid, long uuid, byte[] item) { - String insertStr = "insert " + xid + " " + uuid + " "; - // 对控制语句、数据两部分进行合并得到最终日志记录 - byte[] first = insertStr.getBytes(); - byte[] result = Arrays.copyOf(first, first.length + item.length); - System.arraycopy(item, 0, result, first.length, item.length); - bytes.add(result); - } - - @Override - public void update(int xid, long uuid, byte[] item) { - String updateStr = "update " + xid + " " + uuid + " "; - // 对控制语句、数据两部分进行合并得到最终日志记录 - byte[] first = updateStr.getBytes(); - byte[] result = Arrays.copyOf(first, first.length + item.length); - System.arraycopy(item, 0, result, first.length, item.length); - bytes.add(result); - } - - @Override - public void updateMeta(int xid, long metaUUID) { - String updateMetaStr = "meta " + xid + " " + metaUUID; - bytes.add(updateMetaStr.getBytes()); - } - - @Override - public List getContent() { - return bytes; - } - - -} diff --git a/src/main/java/net/kaaass/rumbase/server/Server.java b/src/main/java/net/kaaass/rumbase/server/Server.java deleted file mode 100644 index d3783d9..0000000 --- a/src/main/java/net/kaaass/rumbase/server/Server.java +++ /dev/null @@ -1,139 +0,0 @@ -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 deleted file mode 100644 index 5db2376..0000000 --- a/src/main/java/net/kaaass/rumbase/server/Session.java +++ /dev/null @@ -1,494 +0,0 @@ -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 net.kaaass.rumbase.transaction.exception.StatusException; - -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); - } catch (StatusException ignored) { - } - } - // 删除活跃会话 - 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; - try { - if (rollback) { - currentContext.rollback(); - } else { - currentContext.commit(); - } - } catch (StatusException e) { - log.warn("自动提交事务失败,会话 {} ", sessionId, e); - say(e); - } - 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; - } - // 提交事务 - try { - currentContext.commit(); - } catch (StatusException e) { - say(e); - return false; - } - say("成功提交事务" + currentContext.getXid() + "\n"); - currentContext = null; - return false; - } - - @Override - public Boolean visit(RollbackStatement statement) { - if (currentContext == null) { - say("当前会话内无事务\n"); - return false; - } - // 回滚事务 - try { - currentContext.rollback(); - } catch (StatusException e) { - say(e); - return false; - } - 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 deleted file mode 100644 index c31dd18..0000000 --- a/src/main/java/net/kaaass/rumbase/table/Table.java +++ /dev/null @@ -1,574 +0,0 @@ -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.*; -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; -import net.kaaass.rumbase.record.exception.RecordNotFoundException; -import net.kaaass.rumbase.table.field.BaseField; -import net.kaaass.rumbase.table.exception.TableExistenceException; -import net.kaaass.rumbase.table.exception.TableConflictException; -import net.kaaass.rumbase.transaction.TransactionContext; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.*; - -/** - * 表结构 - *

- * 验证数据是否满足表约束 - *

- * 提供行数据解析服务 - * - * @author @KveinAxel - */ -@RequiredArgsConstructor -public class Table { - - /** - * 表名 - */ - @NonNull - @Getter - String tableName; - - /** - * 表所在文件的记录接口 - */ - @Getter - @NonNull - IRecordStorage recordStorage; - - /** - * 表的状态,可能的状态有: - *

- * 正常 - *

- *

- * 被删除 - *

- */ - @Getter - TableStatus status = TableStatus.NORMAL; - - /** - * 下一张表的uuid - */ - @Setter - @Getter - long next; - - /** - * 表结构拥有的字段 - */ - @Getter - @Setter - List fields = new ArrayList<>(); - - @Getter - private final String path; - - /** - * 直接通过表名、字段创建表 - *

- * 不检测是否与已存在表冲突,这个留给表管理器处检测 - *

- * - * @param tableName 表名 - * @param fields 表的字段结构 - */ - public Table(@NonNull String tableName, @NonNull List fields) { - 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; - this.path = tableName; - } - - /** - * 直接通过表名、字段创建表 - *

- * 不检测是否与已存在表冲突,这个留给表管理器处检测 - *

- * - * @param tableName 表名 - * @param fields 表的字段结构 - */ - public Table(@NonNull String tableName, @NonNull List fields, String path) { - this.recordStorage = RecordManager.fromFile(path); - this.tableName = tableName; - this.fields = fields; - this.next = -1; - this.path = path; - } - - - - /** - * 将当前表结构信息持久化到外存中 - */ - public void persist(TransactionContext context) { - - var byteOutStream = new ByteArrayOutputStream(); - var out = new JBBPBitOutputStream(byteOutStream); - - try { - out.writeString(tableName, JBBPByteOrder.BIG_ENDIAN); - out.writeString(status.toString().toUpperCase(Locale.ROOT), JBBPByteOrder.BIG_ENDIAN); - out.writeLong(next, JBBPByteOrder.BIG_ENDIAN); - out.writeInt(fields.size(), JBBPByteOrder.BIG_ENDIAN); - for (var f: fields) { - f.persist(byteOutStream); - } - } catch (IOException e) { - e.printStackTrace(); - } - - recordStorage.setMetadata(context, byteOutStream.toByteArray()); - } - - public static Table load(IRecordStorage recordStorage) { - - var context = TransactionContext.empty(); - var meta = recordStorage.getMetadata(context); - var stream = new ByteArrayInputStream(meta); - var in = new JBBPBitInputStream(stream); - try { - var name = in.readString(JBBPByteOrder.BIG_ENDIAN); - var status = in.readString(JBBPByteOrder.BIG_ENDIAN); - var next = in.readLong(JBBPByteOrder.BIG_ENDIAN); - var fieldNum = in.readInt(JBBPByteOrder.BIG_ENDIAN); - var fieldList = new ArrayList(); - var table = new Table(name, fieldList, recordStorage.getIdentifiedName().substring(4)); - for (int i = 0; i < fieldNum; i++) { - var f = BaseField.load(stream, table); - fieldList.add(f); - } - table.next = next; - table.status = TableStatus.valueOf(status); - return table; - } catch (IOException | IndexNotFoundException e) { - throw new RuntimeException(e); - } - } - - /** - * 删除元组 - * - * @param context 事务context - * @param uuid 元组的uuid - */ - public void delete(TransactionContext context, long uuid) throws RecordNotFoundException { - recordStorage.delete(context, uuid); - } - - /** - * 更新元组 - * - * @param context 事务context - * @param uuid 元组的uuid - * @param entry 新的行的字符串值列表 - */ - public void update(TransactionContext context, long uuid, List entry) throws TableConflictException, TableExistenceException, RecordNotFoundException { - - if(!checkStringEntry(entry)) { - throw new TableConflictException(3); - } - - var raw = stringEntryToBytes(entry); - - recordStorage.delete(context, uuid); - var newUuid = recordStorage.insert(context, raw); - - var l = entry.size(); - for (int i = 0; i < l; i++) { - var field = fields.get(i); - if (field.indexed()) { - field.insertIndex(entry.get(i), newUuid); - } - } - } - - - /** - * 更新元组 - * - * @param context 事务context - * @param uuid 元组的uuid - * @param entry 新的行的值列表 - */ - public void updateObjs(TransactionContext context, long uuid, List entry) throws TableConflictException, TableExistenceException, RecordNotFoundException { - - var raw = entryToBytes(entry); - - recordStorage.delete(context, uuid); - var newUuid = recordStorage.insert(context, raw); - - var l = entry.size(); - for (int i = 0; i < l; i++) { - var field = fields.get(i); - if (field.indexed()) { - field.insertIndex(entry.get(i), newUuid); - } - } - } - - - - - /** - * 检查一个entry是否满足当前表的约束 - * - * @param entry 待检查entry - * @return 满足情况 - */ - public boolean checkEntry(List entry) { - if (fields.size() != entry.size()) { - return false; - } - - var len = fields.size(); - - for (int i = 0; i < len; i++) { - if (!fields.get(i).checkObject(entry.get(i))) { - return false; - } - } - - return true; - } - - - /** - * 检查一个entry是否满足当前表的约束 - * - * @param entry 待检查entry - * @return 满足情况 - */ - public boolean checkStringEntry(List entry) { - if (fields.size() != entry.size()) { - return false; - } - - var len = fields.size(); - - for (int i = 0; i < len; i++) { - if (!fields.get(i).checkStr(entry.get(i))) { - return false; - } - } - - return true; - } - - /** - * 获取一个元组内容 - * - * @param context 事务context - * @param uuid 元组的uuid - * @return 元组 - * @throws TableExistenceException 要查询的表不存在 - * @throws TableConflictException 查询到的entry和当前表冲突 - */ - public Optional> read(TransactionContext context, long uuid) throws TableExistenceException, TableConflictException, RecordNotFoundException { - - var bytes = recordStorage - .queryOptional(context, uuid); - - if (bytes.isPresent()) { - try { - return Optional.of(parseEntry(bytes.get())); - } catch (IOException e) { - // 查询到的entry和当前表冲突 - throw new TableConflictException(3); - } - } else { - return Optional.empty(); - } - - } - - /** - * 读取表所有记录 - * - * @param context 事务context - * @return 所有记录 - */ - public List> readAll(TransactionContext context) throws TableExistenceException, TableConflictException, ArgumentException, RecordNotFoundException { - var field = getFirstIndexedField(); - if (field == null) { - throw new ArgumentException(2); - } - - var rows = new ArrayList>(); - var iter = searchAll(field.getName()); - while(iter.hasNext()) { - var uuid = iter.next().getUuid(); - read(context, uuid).ifPresent(rows::add); - } - return rows; - } - - /** - * 向表插入元组 - * - * @param context 事务context - * @param entry 新的元组 - * @throws TableConflictException 插入的元组不满足表约束 - */ - public void insert(TransactionContext context, List entry) throws TableConflictException, TableExistenceException, ArgumentException { - - var bytes = stringEntryToBytes(entry); - - var uuid = recordStorage.insert(context, bytes); - - var l = entry.size(); - boolean ok = false; - for (int i = 0; i < l; i++) { - var field = fields.get(i); - if (field.indexed()) { - field.insertIndex(entry.get(i), uuid); - ok = true; - } - } - - if (!ok) { - throw new ArgumentException(2); - } - } - - /** - * @param fieldName 字段名 - * @param fieldValue 字段值 - * @return 查询到的uuid列表 - * @throws TableExistenceException 要查询的表不存在 - */ - public List search(String fieldName, String fieldValue) throws TableExistenceException, TableConflictException { - BaseField field = null; - - for (var f: fields) { - if (f.getName().equals(fieldName)) { - field = f; - } - } - - if (field == null) { - throw new TableExistenceException(2); - } - - return field.queryIndex(fieldValue); - } - - /** - * @param fieldName 字段名 - * @param fieldValue 字段值 - * @return 查询到的uuid列表 - * @throws TableExistenceException 要查询的表不存在 - */ - public List search(String fieldName, Object fieldValue) throws TableExistenceException, TableConflictException { - BaseField field = null; - - for (var f: fields) { - if (f.getName().equals(fieldName)) { - field = f; - } - } - - if (field == null) { - throw new TableExistenceException(2); - } - - return field.queryIndex(fieldValue); - } - - - - /** - * 以指定的索引查询全部记录 - *

- * 返回第一个记录的迭代器,以(字段值, 记录uuid)的方式返回 - *

- * 返回的uuid不保证可见 - * - * @param fieldName 字段名 - * @return (字段值, 记录uuid)形式的第一个迭代器 - * @throws TableExistenceException 字段不存在(2), 索引不存在(6) - */ - public Iterator searchAll(String fieldName) throws TableExistenceException { - BaseField field = null; - - for (var f: fields) { - if (f.getName().equals(fieldName)) { - field = f; - } - } - - if (field == null) { - throw new TableExistenceException(2); - } - - return field.queryFirst(); - } - - - /** - * 查询第一个满足字段值的迭代器 - *

- * 返回第一个记录的迭代器,以(字段值, 记录uuid)的方式返回 - *

- * 返回的uuid不保证可见 - * - * @param fieldName 字段名 - * @param key 字段值 - * @return (字段值, 记录uuid)形式的第一个迭代器 - * @throws TableExistenceException 字段不存在(2), 索引不存在(6) - * @throws TableConflictException 字段类型不匹配 - */ - public Iterator searchFirst(String fieldName, String key) throws TableExistenceException, TableConflictException { - BaseField field = null; - - for (var f: fields) { - if (f.getName().equals(fieldName)) { - field = f; - } - } - - if (field == null) { - throw new TableExistenceException(2); - } - - return field.queryFirstMeet(key); - } - - /** - * 查询第一个满足值且与查询键不相等的迭代器 - *

- * 返回第一个记录的迭代器,以(字段值, 记录uuid)的方式返回 - *

- * 返回的uuid不保证可见 - * - * @param fieldName 字段名 - * @return (字段值, 记录uuid)形式的第一个迭代器 - * @throws TableExistenceException 字段不存在(2), 索引不存在(6) - */ - public Iterator searchFirstNotEqual(String fieldName, String key) throws TableExistenceException, TableConflictException { - BaseField field = null; - - for (var f: fields) { - if (f.getName().equals(fieldName)) { - field = f; - } - } - - if (field == null) { - throw new TableExistenceException(2); - } - - return field.queryFirstMeetNotEqual(key); - } - - /** - * 将entry转换成字节数组 - * - * @param entry 元组 - * @return 字节数组 - */ - public byte[] stringEntryToBytes(List entry) throws TableConflictException { - var stream = new ByteArrayOutputStream(); - - if (!checkStringEntry(entry)) { - throw new TableConflictException(3); - } - - var len = fields.size(); - - for (int i = 0; i < len; i++) { - fields.get(i).serialize(stream, entry.get(i)); - } - - return stream.toByteArray(); - } - - - /** - * 将entry转换成字节数组 - * - * @param entry 元组 - * @return 字节数组 - */ - public byte[] entryToBytes(List entry) throws TableConflictException { - var stream = new ByteArrayOutputStream(); - - if (!checkEntry(entry)) { - throw new TableConflictException(3); - } - - var len = fields.size(); - - for (int i = 0; i < len; i++) { - fields.get(i).serialize(stream, entry.get(i)); - } - - return stream.toByteArray(); - } - - - - /** - * 将字节数组转换成entry - * - * @param raw 字节数组 - * @return 元组 - */ - public List parseEntry(byte[] raw) throws TableConflictException, IOException { - var stream = new ByteArrayInputStream(raw); - var list = new ArrayList<>(); - - for (var field : fields) { - list.add(field.deserialize(stream)); - } - - if (stream.available() == 0) { - return list; - } else { - throw new TableConflictException(2); - } - } - - /** - * 返回第一个建立了索引的列 - * - * @return 列 - */ - public BaseField getFirstIndexedField() { - for (var f: fields) { - if (f.indexed()) { - return f; - } - } - return null; - } - - - public Optional getField(String fieldName) { - for (var f : fields) { - if (f.getName().equals(fieldName)) { - return Optional.of(f); - } - } - - return Optional.empty(); - } -} \ No newline at end of file diff --git a/src/main/java/net/kaaass/rumbase/table/TableManager.java b/src/main/java/net/kaaass/rumbase/table/TableManager.java deleted file mode 100644 index 5695809..0000000 --- a/src/main/java/net/kaaass/rumbase/table/TableManager.java +++ /dev/null @@ -1,219 +0,0 @@ -package net.kaaass.rumbase.table; - -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 net.kaaass.rumbase.transaction.exception.StatusException; - -import java.io.File; -import java.util.*; - -/** - * 表管理器 - *

- * ITableManager用于管理表结构, 已经为上层模块提供更加高级和抽象的接口. - *

- * ITableManager会依赖index模块进行索引, 依赖record模块进行表单数据查找. - *

- * - * @author @KveinAxel - */ - -public class TableManager { - - static { - var dataDir = new File("data/"); - if (!dataDir.exists() && !dataDir.isDirectory()) { - dataDir.mkdirs(); - } - } - - private final IRecordStorage metaRecord = RecordManager.fromFile("data/metadata.db"); - - /** - * 对所有的表结构的缓存 - *

- * 如果不在这里,说明就没有这张表 - *

- * 同样地,创建表、删除表需要维护这个结构 - */ - private final Map tableCache = new HashMap<>(); - - @Getter - private final List recordPaths = new ArrayList<>(); - - - /** - * 提交一个事务 - * - * @param context 事务context - */ - public void commit(TransactionContext context) throws StatusException { - context.commit(); - } - - /** - * 终止一个事务 - * - * @param context 事务context - */ - public void abort(TransactionContext context) throws StatusException { - context.rollback(); - } - - public TableManager() throws TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException, IndexAlreadyExistException { - load(); - } - - public void load() throws TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException, IndexAlreadyExistException { - var context = TransactionContext.empty(); - 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(); - } - - metaTable = new Table("metadata", fields, "data/metadata.db"); - - for (var f: fields) { - f.setParentTable(metaTable); - } - - keyField.createIndex("data/"); - - metaTable.persist(context); - tableCache.put("metadata", metaTable); - } - 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); - } - } - - - } - - /** - * 显示所有的表名 - * - * @return 表名的列表 - */ - public List showTables() { - List list = new ArrayList<>(); - - tableCache.forEach((k, v) -> list.add(k)); - - return list; - } - - /** - * 创建一个表 - * - * @param context 事务context - * @param tableName 表名 - * @param baseFields 表的字段 - * @throws TableExistenceException 该表已存在 - */ - public void createTable( - TransactionContext context, - String tableName, - List baseFields, - String path - ) 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) { - f.setParentTable(table); - } - - table.persist(context); - - var metaTable = tableCache.get("metadata"); - - var uuids = metaTable.search("key", "table_num"); - - 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; - } - } - - 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); - } - - public Table getTable(String tableName) throws TableExistenceException { - var table = tableCache.get(tableName); - - if (table == null) { - throw new TableExistenceException(1); - } else { - return table; - } - } - -} diff --git a/src/main/java/net/kaaass/rumbase/table/TableStatus.java b/src/main/java/net/kaaass/rumbase/table/TableStatus.java deleted file mode 100644 index cdf5441..0000000 --- a/src/main/java/net/kaaass/rumbase/table/TableStatus.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.kaaass.rumbase.table; - -/** - * 表状态的枚举 - * - * @author @KveinAxel - */ -public enum TableStatus { - /** - * 正常状态 - */ - NORMAL, - /** - * 表已经被删除(待定) - */ - DELETED, -} \ No newline at end of file diff --git a/src/main/java/net/kaaass/rumbase/table/exception/TableConflictException.java b/src/main/java/net/kaaass/rumbase/table/exception/TableConflictException.java deleted file mode 100644 index 5688d83..0000000 --- a/src/main/java/net/kaaass/rumbase/table/exception/TableConflictException.java +++ /dev/null @@ -1,33 +0,0 @@ -package net.kaaass.rumbase.table.exception; - -import net.kaaass.rumbase.exception.RumbaseException; - -import java.util.HashMap; -import java.util.Map; - -/** - * E3002 类型不匹配异常 - *

- * E3002-1 字段类型不匹配 - *

- * E3002-2 Entry类型不匹配 - *

- * E3002-3 字段不满足约束 - * @author @KveinAxel - */ -public class TableConflictException extends RumbaseException { - public static final Map REASONS = new HashMap<>(){{ - put(1, "字段类型不匹配"); - put(2, "Entry不匹配"); - put(3, "字段不满足约束"); - }}; - - /** - * 类型不匹配异常 - * - * @param subId 子错误号 - */ - public TableConflictException(int subId) { - super(3002, subId, REASONS.get(subId)); - } -} diff --git a/src/main/java/net/kaaass/rumbase/table/exception/TableExistenceException.java b/src/main/java/net/kaaass/rumbase/table/exception/TableExistenceException.java deleted file mode 100644 index 1dcaced..0000000 --- a/src/main/java/net/kaaass/rumbase/table/exception/TableExistenceException.java +++ /dev/null @@ -1,44 +0,0 @@ -package net.kaaass.rumbase.table.exception; - -import net.kaaass.rumbase.exception.RumbaseException; - -import java.util.HashMap; -import java.util.Map; - -/** - * E3001 关系不存在异常 - *

- * E3001-1 关系不存在 - *

- * E3001-2 字段不存在 - *

- * E3001-3 视图不存在 - *

- * E3001-4 元组不存在 - *

- * E3001-5 关系已存在 - *

- * E3001-6 索引不存在 - * - * - * @author @KveinAxel - */ -public class TableExistenceException extends RumbaseException { - public static final Map REASONS = new HashMap<>(){{ - put(1, "关系不存在"); - put(2, "字段不存在"); - put(3, "视图不存在"); - put(4, "元组不存在"); - put(5, "关系已存在"); - put(6, "索引不存在"); - }}; - - /** - * 关系不存在异常 - * - * @param subId 子错误号 - */ - public TableExistenceException(int subId) { - super(3001, subId, REASONS.get(subId)); - } -} diff --git a/src/main/java/net/kaaass/rumbase/table/field/BaseField.java b/src/main/java/net/kaaass/rumbase/table/field/BaseField.java deleted file mode 100644 index a0264ed..0000000 --- a/src/main/java/net/kaaass/rumbase/table/field/BaseField.java +++ /dev/null @@ -1,360 +0,0 @@ -package net.kaaass.rumbase.table.field; - -import com.igormaznitsa.jbbp.io.JBBPBitInputStream; -import com.igormaznitsa.jbbp.io.JBBPByteOrder; -import lombok.*; -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; -import java.util.Iterator; -import java.util.List; - - -/** - * 字段结构 - *

- * 提供字段解析服务 - *

- * 提供字段的索引处理 - * - * @author @KveinAxel - */ -@RequiredArgsConstructor -public abstract class BaseField{ - - /** - * 字段名 - */ - @Getter - @NonNull - protected final String name; - - /** - * 字段类型 - */ - @Getter - @NonNull - private final FieldType type; - - /** - * 字段是否可空 - */ - @Getter - private final boolean nullable; - - /** - * 索引 - *

- * 如果未建立索引则为空 - */ - protected Index index = null; - - /** - * 索引名 - */ - @Getter - @Setter - protected String indexName; - - /** - * 当前列所属的表 - */ - @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; - } - - /** - * 向输出流中写入当前字段格式信息 - *

- * 格式为: - *

- * 列名 - *

- * 列类型 - *

- * 是否可空 - *

- * 是否建立索引 - *

- * 索引名(如果建立索引) - *

- * 列参数(可选) - *

- * - * @param stream 输出流 - */ - public abstract void persist(OutputStream stream); - - /** - * 从输入流中读入当前字段格式信息,并构造、返回当前字段 - * - * @param stream 输入流 - * @return 字段 - */ - public static BaseField load(InputStream stream, Table table) throws IndexNotFoundException { - var in = new JBBPBitInputStream(stream); - - try { - var name = in.readString(JBBPByteOrder.BIG_ENDIAN); - var type = FieldType.valueOf(in.readString(JBBPByteOrder.BIG_ENDIAN)); - var flag = in.readByte(); - var nullable = (flag & 1) == 1; - var indexed = (flag & 2) == 2; - String indexName = null; - if (indexed) { - indexName = in.readString(JBBPByteOrder.BIG_ENDIAN); - } - - 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) { - throw new RuntimeException(e); - } - } - - /** - * 判断字符串是否能够转成符合当前字段约束的值 - * @param valStr 待检查字符串 - * @return 满足情况 - */ - public abstract boolean checkStr(String valStr); - - /** - * 将字符串转成哈希 - * @param str 待转换字符串 - * @throws TableConflictException 字段类型不匹配 - * @return 哈希 - */ - public abstract long strToHash(String str) throws TableConflictException; - - - /** - * 将值对象转成哈希 - * @param val 值对象 - * @throws TableConflictException 字段类型不匹配 - * @return 哈希 - */ - public abstract long toHash(Object val) throws TableConflictException; - - /** - * 从输入流中反序列化出一个满足当前字段约束的值对象 - * @param inputStream 输入流 - * @throws TableConflictException 输入流中读出对象与字段类型不匹配 - * @return 值对象 - */ - public abstract Object deserialize(InputStream inputStream) throws TableConflictException; - - /** - * 从输入流中反序列化一个满足当前类型的对象,并判断是否满足约束 - * @param inputStream 输入流 - * @return 满足情况 - */ - public abstract boolean checkInputStream(InputStream inputStream); - - /** - * 将值对象序列化到输出流中 - *

- * 先序列化一位isNull,1 -> null ; 0 -> 非null - *

- * 如果非null则继续序列化他的值 - * - * @param outputStream 输出流 - * @param strVal 值对象 - * @throws TableConflictException 类型不匹配 - */ - public abstract void serialize(OutputStream outputStream, String strVal) throws TableConflictException; - - - /** - * 将值对象序列化到输出流中 - *

- * 序列化方法同上 - * - * @param outputStream 输出流 - * @param val 值对象 - * @throws TableConflictException 类型不匹配 - */ - public abstract void serialize(OutputStream outputStream, Object val) throws TableConflictException; - - - - /** - * 创建索引 - * - * @throws IndexAlreadyExistException 索引已存在 - */ - public void createIndex() throws IndexAlreadyExistException { - var delimiter = "$"; - - 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 值对象 - * @param uuid uuid - * @throws TableConflictException 字段类型不匹配 - * @throws TableExistenceException 索引不存在 - */ - public abstract void insertIndex(String value, long uuid) throws TableConflictException, TableExistenceException; - - - /** - * 向索引插入一个键值对 - * @param value 值对象 - * @param uuid uuid - * @throws TableConflictException 字段类型不匹配 - * @throws TableExistenceException 索引不存在 - */ - public abstract void insertIndex(Object value, long uuid) throws TableConflictException, TableExistenceException; - - - - /** - * 通过当前字段的索引树查询记录 - * - * @param key 字段值 - * @throws TableConflictException 字段类型不匹配 - * @throws TableExistenceException 索引不存在 - * @return 记录的uuid - */ - public abstract List queryIndex(String key) throws TableExistenceException, TableConflictException; - - /** - * 通过当前字段的索引树查询记录 - * - * @param key 字段值 - * @throws TableConflictException 字段类型不匹配 - * @throws TableExistenceException 索引不存在 - * @return 记录的uuid - */ - public abstract List queryIndex(Object key) throws TableExistenceException, TableConflictException; - - /** - * 查询当前索引的第一个迭代器 - * - * @throws TableExistenceException 索引不存在 - * @return 迭代器 - */ - public abstract Iterator queryFirst() throws TableExistenceException; - - /** - * 查询第一个满足字段值的迭代器 - * - * @param key 查询键 - * @throws TableExistenceException 索引不存在 - * @throws TableConflictException 字段类型不匹配 - * @return 迭代器 - */ - public abstract Iterator queryFirstMeet(String key) throws TableExistenceException, TableConflictException; - - /** - * 查询第一个满足值且与查询键不相等的迭代器 - * - * @param key 查询键 - * @throws TableExistenceException 索引不存在 - * @throws TableConflictException 字段类型不匹配 - * @return 迭代器 - */ - public abstract Iterator queryFirstMeetNotEqual(String key) throws TableExistenceException, TableConflictException; - - /** - * 是否建立索引 - * @return true -> 已建立索引; false -> 未建立索引 - */ - public boolean indexed() { - return index != null; - } - - /** - * 将str转成值 - * - * @param str 字符串 - * @return 值 - * @throws TableConflictException 字段类型不匹配 - */ - public abstract Object strToValue(String str) throws TableConflictException; - - /** - * 检测值是否满足约束 - * - * @param val 值 - * @return true -> 满足约束; false -> 不满足约束 - */ - public abstract boolean checkObject(Object val); - - /** - * 比较两个字段大小 - * @param a 第一个字段 - * @param b 第二个字段 - * @return 比较结果 - * @throws TableConflictException 字段类型不匹配 - */ - public abstract int compare(Object a, Object b) throws TableConflictException; -} \ No newline at end of file diff --git a/src/main/java/net/kaaass/rumbase/table/field/FieldType.java b/src/main/java/net/kaaass/rumbase/table/field/FieldType.java deleted file mode 100644 index b150126..0000000 --- a/src/main/java/net/kaaass/rumbase/table/field/FieldType.java +++ /dev/null @@ -1,36 +0,0 @@ -package net.kaaass.rumbase.table.field; - -/** - * 字段的类型枚举 - * - * @author @KveinAxel - */ -public enum FieldType { - /** - * 4字节整型 - */ - INT, - /** - * 4字节浮点类型 - */ - FLOAT, - /** - * 带最大长度的可变长字符串 - */ - VARCHAR; - - @Override - public String toString() { - switch (this) { - case INT: - return "int"; - case FLOAT: - return "float"; - case VARCHAR: - return "varchar"; - default: - return ""; - } - } - -} diff --git a/src/main/java/net/kaaass/rumbase/table/field/FloatField.java b/src/main/java/net/kaaass/rumbase/table/field/FloatField.java deleted file mode 100644 index a8c09b5..0000000 --- a/src/main/java/net/kaaass/rumbase/table/field/FloatField.java +++ /dev/null @@ -1,311 +0,0 @@ -package net.kaaass.rumbase.table.field; - -import com.igormaznitsa.jbbp.io.JBBPBitInputStream; -import com.igormaznitsa.jbbp.io.JBBPBitOutputStream; -import com.igormaznitsa.jbbp.io.JBBPByteOrder; -import lombok.NonNull; -import net.kaaass.rumbase.index.Pair; -import net.kaaass.rumbase.table.Table; -import net.kaaass.rumbase.table.exception.TableConflictException; -import net.kaaass.rumbase.table.exception.TableExistenceException; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; - - -/** - * 单浮点数类型的字段 - * - * @author @KveinAxel - */ -public class FloatField extends BaseField { - - public FloatField(@NonNull String name, boolean nullable, Table parentTable) { - super(name, FieldType.FLOAT, nullable, parentTable); - } - - - @Override - public void persist(OutputStream stream) { - var out = new JBBPBitOutputStream(stream); - - try { - out.writeString(getName(), JBBPByteOrder.BIG_ENDIAN); - out.writeString(getType().toString().toUpperCase(Locale.ROOT), JBBPByteOrder.BIG_ENDIAN); - var flags = new byte[]{0}; - flags[0] |= isNullable() ? 1 : 0; - if (indexed()) { - flags[0] |= 2; - out.writeBytes(flags, 1, JBBPByteOrder.BIG_ENDIAN); - out.writeString(indexName, JBBPByteOrder.BIG_ENDIAN); - } else { - out.writeBytes(flags, 1, JBBPByteOrder.BIG_ENDIAN); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - @Override - public boolean checkStr(String valStr) { - if (valStr == null || valStr.isBlank()) { - return isNullable(); - } - try { - return checkVal(Float.parseFloat(valStr)); - } catch (NumberFormatException e) { - return false; - } - } - - /** - * 字段约束(待定) - * - * @param val 值 - * @return 是否满足约束 - */ - boolean checkVal(float val) { - return true; - } - - @Override - public long strToHash(String str) throws TableConflictException { - - // 空值的哈希固定为0 - if (str == null || str.isBlank()) { - return 0; - } - - try { - var val = Float.parseFloat(str); - if (checkVal(val)) { - return toHash(val); - } else { - throw new TableConflictException(3); - } - } catch (NumberFormatException e) { - throw new TableConflictException(1); - } - } - - @Override - public long toHash(Object val) throws TableConflictException { - - // 空值的哈希固定为0 - if (val == null) { - return 0; - } - - try { - var f = (float) val; - return toHash(f); - } catch (ClassCastException e) { - throw new TableConflictException(1); - } - } - - /** - * 将float转成hash - * - * @param f float - * @return hash - */ - long toHash(float f) { - return (long) (f * 1000); - } - - @Override - public Object deserialize(InputStream inputStream) throws TableConflictException { - - var stream = new JBBPBitInputStream(inputStream); - - try { - var flag = stream.readByte(); - var isNull = (flag & 1) == 1; - if (isNull) { - if (isNullable()) { - return null; - } else { - throw new TableConflictException(3); - } - } - - var val = stream.readFloat(JBBPByteOrder.BIG_ENDIAN); - if (checkVal(val)) { - return val; - } else { - throw new TableConflictException(3); - } - - } catch (IOException e) { - throw new TableConflictException(1); - } - - } - - @Override - public boolean checkInputStream(InputStream inputStream) { - - var stream = new JBBPBitInputStream(inputStream); - - try { - var flag = stream.readByte(); - var isNull = (flag & 1) == 1; - if (isNull) { - return isNullable(); - } - - return checkVal(stream.readFloat(JBBPByteOrder.BIG_ENDIAN)); - } catch (IOException e) { - return false; - } - } - - @Override - public void serialize(OutputStream outputStream, String strVal) throws TableConflictException { - - var stream = new JBBPBitOutputStream(outputStream); - - try { - if (strVal == null || strVal.isBlank()) { - stream.writeBytes(new byte[]{1}, 1, JBBPByteOrder.BIG_ENDIAN); - } else { - stream.writeBytes(new byte[]{0}, 1, JBBPByteOrder.BIG_ENDIAN); - var val = Float.parseFloat(strVal); - if (checkVal(val)) { - stream.writeFloat(val, JBBPByteOrder.BIG_ENDIAN); - } else { - throw new TableConflictException(3); - } - } - - } catch (IOException e) { - throw new RuntimeException(e); - } catch (NumberFormatException e) { - throw new TableConflictException(1); - } - } - - @Override - public void serialize(OutputStream outputStream, Object objVal) throws TableConflictException { - var stream = new JBBPBitOutputStream(outputStream); - - try { - if (objVal == null) { - stream.writeBytes(new byte[]{1}, 1, JBBPByteOrder.BIG_ENDIAN); - } else { - stream.writeBytes(new byte[]{0}, 1, JBBPByteOrder.BIG_ENDIAN); - var val = (float) objVal; - if (checkVal(val)) { - stream.writeFloat(val, JBBPByteOrder.BIG_ENDIAN); - } else { - throw new TableConflictException(3); - } - } - - } catch (IOException e) { - throw new RuntimeException(e); - } catch (NumberFormatException e) { - throw new TableConflictException(1); - } - } - - @Override - public void insertIndex(String value, long uuid) throws TableConflictException, TableExistenceException { - if (index == null) { - throw new TableExistenceException(6); - } - index.insert(strToHash(value), uuid); - } - - @Override - public void insertIndex(Object value, long uuid) throws TableConflictException, TableExistenceException { - if (index == null) { - throw new TableExistenceException(6); - } - index.insert(toHash(value), uuid); - } - - @Override - public List queryIndex(String value) throws TableExistenceException, TableConflictException { - if (index == null) { - throw new TableExistenceException(6); - } - - return index.query(strToHash(value)); - } - - @Override - public List queryIndex(Object key) throws TableExistenceException, TableConflictException { - if (index == null) { - throw new TableExistenceException(6); - } - - try { - return index.query(toHash(key)); - } catch (ClassCastException e) { - throw new TableConflictException(1); - } - } - - @Override - public Iterator queryFirst() throws TableExistenceException { - if (index == null) { - throw new TableExistenceException(6); - } - - return index.findFirst(); - } - - @Override - public Iterator queryFirstMeet(String key) throws TableExistenceException, TableConflictException { - if (index == null) { - throw new TableExistenceException(6); - } - - return index.findFirst(strToHash(key)); - } - - @Override - public Iterator queryFirstMeetNotEqual(String key) throws TableExistenceException, TableConflictException { - if (index == null) { - throw new TableExistenceException(6); - } - - return index.findUpperbound(strToHash(key)); - } - - @Override - public Object strToValue(String str) throws TableConflictException { - - try { - return Float.parseFloat(str); - } catch (NumberFormatException e) { - throw new TableConflictException(1); - } - } - - @Override - public boolean checkObject(Object val) { - try { - var res = (float) val; - return true; - } catch (NumberFormatException e) { - return false; - } - } - - @Override - public int compare(Object a, Object b) throws TableConflictException { - try { - return Float.compare((float) a, (float) b); - } catch (ClassCastException 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 deleted file mode 100644 index da204e6..0000000 --- a/src/main/java/net/kaaass/rumbase/table/field/IntField.java +++ /dev/null @@ -1,309 +0,0 @@ -package net.kaaass.rumbase.table.field; - -import com.igormaznitsa.jbbp.io.JBBPBitInputStream; -import com.igormaznitsa.jbbp.io.JBBPBitOutputStream; -import com.igormaznitsa.jbbp.io.JBBPByteOrder; -import lombok.NonNull; -import net.kaaass.rumbase.index.Pair; -import net.kaaass.rumbase.table.Table; -import net.kaaass.rumbase.table.exception.TableConflictException; -import net.kaaass.rumbase.table.exception.TableExistenceException; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; - -/** - * 整型类型的字段 - * - * @author @KveinAxel - */ -public class IntField extends BaseField { - - public IntField(@NonNull String name, boolean nullable, Table parentTable) { - super(name, FieldType.INT, nullable, parentTable); - } - - @Override - public void persist(OutputStream stream) { - var out = new JBBPBitOutputStream(stream); - - try { - out.writeString(getName(), JBBPByteOrder.BIG_ENDIAN); - out.writeString(getType().toString().toUpperCase(Locale.ROOT), JBBPByteOrder.BIG_ENDIAN); - var flags = new byte[]{0}; - flags[0] |= isNullable() ? 1 : 0; - if (indexed()) { - flags[0] |= 2; - out.writeBytes(flags, 1, JBBPByteOrder.BIG_ENDIAN); - out.writeString(indexName, JBBPByteOrder.BIG_ENDIAN); - } else { - out.writeBytes(flags, 1, JBBPByteOrder.BIG_ENDIAN); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - @Override - public boolean checkStr(String valStr) { - if (valStr == null || valStr.isBlank()) { - return isNullable(); - } - try { - var val = Integer.parseInt(valStr); - return checkVal(val); - } catch (NumberFormatException e) { - return false; - } - } - - /** - * 字段约束(待定) - * - * @param val 值 - * @return 是否满足约束 - */ - boolean checkVal(int val) { - return true; - } - - @Override - public long strToHash(String str) throws TableConflictException { - - // 空值的哈希固定为0 - if (str == null || str.isBlank()) { - return 0; - } - - try { - var val = Integer.parseInt(str); - - if (!checkVal(val)) { - throw new TableConflictException(3); - } - return toHash(val); - } catch (NumberFormatException e) { - throw new TableConflictException(1); - } - } - - @Override - public long toHash(Object val) throws TableConflictException { - - // 空值的哈希固定为0 - if (val == null) { - return 0; - } - - try { - var i = (int) val; - return toHash(i); - } catch (ClassCastException e) { - throw new TableConflictException(1); - } - } - - /** - * 将int转成hash - * - * @param val int值 - * @return hash - */ - long toHash(int val) { - return val; - } - - @Override - public Object deserialize(InputStream inputStream) throws TableConflictException { - - var stream = new JBBPBitInputStream(inputStream); - - try { - var flag = stream.readByte(); - var isNull = (flag & 1) == 1; - if (isNull) { - if (isNullable()) { - return null; - } else { - throw new TableConflictException(3); - } - } - - var val = stream.readInt(JBBPByteOrder.BIG_ENDIAN); - if (checkVal(val)) { - return val; - } else { - throw new TableConflictException(3); - } - } catch (IOException e) { - throw new TableConflictException(1); - } - } - - @Override - public boolean checkInputStream(InputStream inputStream) { - - var stream = new JBBPBitInputStream(inputStream); - - try { - var flag = stream.readByte(); - var isNull = (flag & 1) == 1; - if (isNull) { - return isNullable(); - } - - return checkVal(stream.readInt(JBBPByteOrder.BIG_ENDIAN)); - } catch (IOException e) { - return false; - } - } - - @Override - public void serialize(OutputStream outputStream, String strVal) throws TableConflictException { - - var stream = new JBBPBitOutputStream(outputStream); - - try { - if (strVal == null || strVal.isBlank()) { - stream.writeBytes(new byte[]{1}, 1, JBBPByteOrder.BIG_ENDIAN); - } else { - stream.writeBytes(new byte[]{0}, 1, JBBPByteOrder.BIG_ENDIAN); - var val = Integer.parseInt(strVal); - if (checkVal(val)) { - stream.writeInt(val, JBBPByteOrder.BIG_ENDIAN); - } else { - throw new TableConflictException(3); - } - } - - - } catch (IOException e) { - throw new RuntimeException(e); - } catch (NumberFormatException e) { - throw new TableConflictException(1); - } - } - - @Override - public void serialize(OutputStream outputStream, Object objVal) throws TableConflictException { - var stream = new JBBPBitOutputStream(outputStream); - - try { - if (objVal == null) { - stream.writeBytes(new byte[]{1}, 1, JBBPByteOrder.BIG_ENDIAN); - } else { - stream.writeBytes(new byte[]{0}, 1, JBBPByteOrder.BIG_ENDIAN); - var val = (int) objVal; - if (checkVal(val)) { - stream.writeInt(val, JBBPByteOrder.BIG_ENDIAN); - } else { - throw new TableConflictException(3); - } - } - - } catch (IOException e) { - throw new RuntimeException(e); - } catch (NumberFormatException e) { - throw new TableConflictException(1); - } - } - - @Override - public void insertIndex(String value, long uuid) throws TableExistenceException, TableConflictException { - if (index == null) { - throw new TableExistenceException(6); - } - index.insert(strToHash(value), uuid); - } - - @Override - public void insertIndex(Object value, long uuid) throws TableConflictException, TableExistenceException { - if (index == null) { - throw new TableExistenceException(6); - } - index.insert(toHash(value), uuid); - } - - @Override - public List queryIndex(String value) throws TableExistenceException, TableConflictException { - if (index == null) { - throw new TableExistenceException(6); - } - - return index.query(strToHash(value)); - } - - @Override - public List queryIndex(Object key) throws TableExistenceException, TableConflictException { - if (index == null) { - throw new TableExistenceException(6); - } - - try { - return index.query(toHash(key)); - } catch (ClassCastException e) { - throw new TableConflictException(1); - } - } - - @Override - public Iterator queryFirst() throws TableExistenceException { - if (index == null) { - throw new TableExistenceException(6); - } - - return index.findFirst(); - } - - @Override - public Iterator queryFirstMeet(String key) throws TableExistenceException, TableConflictException { - if (index == null) { - throw new TableExistenceException(6); - } - - return index.findFirst(strToHash(key)); - } - - @Override - public Iterator queryFirstMeetNotEqual(String key) throws TableExistenceException, TableConflictException { - if (index == null) { - throw new TableExistenceException(6); - } - - return index.findUpperbound(strToHash(key)); - } - - @Override - public Object strToValue(String str) throws TableConflictException { - try { - return Integer.parseInt(str); - } catch (NumberFormatException e) { - throw new TableConflictException(1); - } - } - - @Override - public boolean checkObject(Object val) { - try { - var res = (int) val; - return true; - } catch (ClassCastException e) { - return false; - } - } - - @Override - public int compare(Object a, Object b) throws TableConflictException { - try { - return Integer.compare((int) a, (int) b); - } catch (ClassCastException 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 deleted file mode 100644 index 24d57c4..0000000 --- a/src/main/java/net/kaaass/rumbase/table/field/VarcharField.java +++ /dev/null @@ -1,292 +0,0 @@ -package net.kaaass.rumbase.table.field; - -import com.igormaznitsa.jbbp.io.JBBPBitInputStream; -import com.igormaznitsa.jbbp.io.JBBPBitOutputStream; -import com.igormaznitsa.jbbp.io.JBBPByteOrder; -import lombok.Getter; -import lombok.NonNull; -import net.kaaass.rumbase.index.Pair; -import net.kaaass.rumbase.table.Table; -import net.kaaass.rumbase.table.exception.TableConflictException; -import net.kaaass.rumbase.table.exception.TableExistenceException; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; - - -/** - * 可变长字符串类型的字段 - * - * @author @KveinAxel - */ -public class VarcharField extends BaseField { - - /** - * 字符串长度的限制 - */ - @Getter - private final int limit; - - private static final String DELIMIT = "'"; - - public VarcharField(@NonNull String name, int limit, boolean nullable, Table parentTable) { - super(name, FieldType.VARCHAR, nullable, parentTable); - this.limit = limit; - } - - @Override - public void persist(OutputStream stream) { - var out = new JBBPBitOutputStream(stream); - - try { - out.writeString(getName(), JBBPByteOrder.BIG_ENDIAN); - out.writeString(getType().toString().toUpperCase(Locale.ROOT), JBBPByteOrder.BIG_ENDIAN); - var flags = new byte[]{0}; - flags[0] |= isNullable() ? 1 : 0; - if (indexed()) { - flags[0] |= 2; - out.writeBytes(flags, 1, JBBPByteOrder.BIG_ENDIAN); - out.writeString(indexName, JBBPByteOrder.BIG_ENDIAN); - } else { - out.writeBytes(flags, 1, JBBPByteOrder.BIG_ENDIAN); - } - out.writeInt(limit, JBBPByteOrder.BIG_ENDIAN); - } catch (IOException e) { - e.printStackTrace(); - } - } - - @Override - public boolean checkStr(String valStr) { - if (valStr == null || valStr.isBlank()) { - return isNullable(); - } - return valStr.startsWith(DELIMIT) && valStr.endsWith(DELIMIT) && valStr.length() <= this.limit + 2 * DELIMIT.length(); - } - - @Override - public long strToHash(String str) { - - // 空值的哈希固定为0 - if (str == null || str.isBlank()) { - return 0; - } - - if (str.startsWith(DELIMIT) && str.endsWith(DELIMIT)) { - var substr = str.substring(1, str.length() - 1); - return substr.hashCode(); - } - - return str.hashCode(); - } - - @Override - public long toHash(Object val) throws TableConflictException { - - // 空值的哈希固定为0 - if (val == null) { - return 0; - } - - try { - var str = (String) val; - return strToHash(str); - } catch (ClassCastException e) { - throw new TableConflictException(1); - } - } - - @Override - public Object deserialize(InputStream inputStream) throws TableConflictException { - - var stream = new JBBPBitInputStream(inputStream); - - try { - var flag = stream.readByte(); - var isNull = (flag & 1) == 1; - if (isNull) { - if (isNullable()) { - return null; - } else { - throw new TableConflictException(3); - } - } - - return stream.readString(JBBPByteOrder.BIG_ENDIAN); - } catch (IOException e) { - throw new TableConflictException(1); - } - } - - @Override - public boolean checkInputStream(InputStream inputStream) { - - var stream = new JBBPBitInputStream(inputStream); - - try { - var flag = stream.readByte(); - var isNull = (flag & 1) == 1; - if (isNull) { - return isNullable(); - } - - stream.readString(JBBPByteOrder.BIG_ENDIAN); - return true; - } catch (IOException e) { - return false; - } - } - - @Override - public void serialize(OutputStream outputStream, String strVal) throws TableConflictException { - - var stream = new JBBPBitOutputStream(outputStream); - - if (!checkStr(strVal)) { - throw new TableConflictException(3); - } - - try { - if (strVal == null || strVal.isBlank()) { - stream.writeBytes(new byte[]{1}, 1, JBBPByteOrder.BIG_ENDIAN); - } else { - if (strVal.startsWith(DELIMIT) && strVal.endsWith(DELIMIT)) { - var substr = strVal.substring(1, strVal.length() - 1); - if (substr.isBlank()) { - stream.writeBytes(new byte[]{1}, 1, JBBPByteOrder.BIG_ENDIAN); - } else { - stream.writeBytes(new byte[]{0}, 1, JBBPByteOrder.BIG_ENDIAN); - stream.writeString(substr, JBBPByteOrder.BIG_ENDIAN); - } - } else { - throw new TableConflictException(1); - } - } - - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @Override - public void serialize(OutputStream outputStream, Object val) throws TableConflictException { - - var stream = new JBBPBitOutputStream(outputStream); - - if (!checkObject(val)) { - throw new TableConflictException(3); - } - - try { - if (val == null) { - stream.writeBytes(new byte[]{1}, 1, JBBPByteOrder.BIG_ENDIAN); - } else { - stream.writeBytes(new byte[]{0}, 1, JBBPByteOrder.BIG_ENDIAN); - stream.writeString((String) val, JBBPByteOrder.BIG_ENDIAN); - } - - } catch (IOException e) { - throw new RuntimeException(e); - } catch (ClassCastException e){ - throw new TableConflictException(1); - } - } - - @Override - public void insertIndex(String value, long uuid) throws TableExistenceException { - if (index == null) { - throw new TableExistenceException(6); - } - index.insert(strToHash(value), uuid); - } - - @Override - public void insertIndex(Object value, long uuid) throws TableConflictException, TableExistenceException { - if (index == null) { - throw new TableExistenceException(6); - } - index.insert(toHash(value), uuid); - } - - @Override - public List queryIndex(String value) throws TableExistenceException { - if (index == null) { - throw new TableExistenceException(6); - } - - return index.query(strToHash(value)); - } - - @Override - public List queryIndex(Object key) throws TableExistenceException, TableConflictException { - if (index == null) { - throw new TableExistenceException(6); - } - - try { - return index.query(toHash(key)); - } catch (ClassCastException e) { - throw new TableConflictException(1); - } - } - - @Override - public Iterator queryFirst() throws TableExistenceException { - if (index == null) { - throw new TableExistenceException(6); - } - - return index.findFirst(); - } - - @Override - public Iterator queryFirstMeet(String key) throws TableExistenceException { - if (index == null) { - throw new TableExistenceException(6); - } - - return index.findFirst(strToHash(key)); - } - - @Override - public Iterator queryFirstMeetNotEqual(String key) throws TableExistenceException { - if (index == null) { - throw new TableExistenceException(6); - } - - return index.findUpperbound(strToHash(key)); - } - - @Override - public Object strToValue(String str) { - if (str.startsWith(DELIMIT) && str.endsWith(DELIMIT)) { - return str.substring(1, str.length() - 1); - } else { - return str; - } - } - - @Override - public boolean checkObject(Object val) { - try { - var res = (String) val; - return true; - } catch (ClassCastException e) { - return false; - } - } - - @Override - public int compare(Object a, Object b) throws TableConflictException { - try { - return ((String) a).compareTo((String) b); - } catch (ClassCastException e) { - throw new TableConflictException(1); - } - } - -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/TransactionContext.java b/src/main/java/net/kaaass/rumbase/transaction/TransactionContext.java deleted file mode 100644 index bd8ec79..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/TransactionContext.java +++ /dev/null @@ -1,94 +0,0 @@ -package net.kaaass.rumbase.transaction; - -import net.kaaass.rumbase.transaction.exception.DeadlockException; -import net.kaaass.rumbase.transaction.exception.StatusException; - -import java.util.List; - -/** - * 事务上下文 - *

- * 存储事务状态,对事务进行操作 - * - * @author criki - */ -public interface TransactionContext { - - - /** - * 返回空事务上下文。空事务或超级事务XID为0,不受事务限制,也不具备ACID性质。 - * - * @return 空事务上下文 - */ - static TransactionContext empty() { - return new TransactionContextImpl(); - } - - /** - * 获取当前事务快照信息 - * - * @return 事务快照 - */ - List getSnapshot(); - - /** - * 获取事务隔离度 - * - * @return 事务隔离度 - */ - TransactionIsolation getIsolation(); - - /** - * 获取事务状态 - * - * @return 事务状态 - */ - TransactionStatus getStatus(); - - /** - * 获取事务管理器 - * - * @return 事务管理器 - */ - TransactionManager getManager(); - - /** - * 获取事务id - * - * @return 事务id - */ - int getXid(); - - /** - * 事务开始 - */ - void start() throws StatusException; - - /** - * 事务提交 - */ - void commit() throws StatusException; - - /** - * 事务撤销 - */ - void rollback() throws StatusException; - - /** - * 对记录加共享锁 - * - * @param uuid 记录id - * @param tableName 表字段 - * @throws DeadlockException 发生死锁异常 - */ - void sharedLock(long uuid, String tableName) throws DeadlockException, StatusException; - - /** - * 对记录加排他锁 - * - * @param uuid 记录id - * @param tableName 表字段 - * @throws DeadlockException 发生死锁异常 - */ - void exclusiveLock(long uuid, String tableName) throws DeadlockException, StatusException; -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/TransactionContextImpl.java b/src/main/java/net/kaaass/rumbase/transaction/TransactionContextImpl.java deleted file mode 100644 index 643f127..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/TransactionContextImpl.java +++ /dev/null @@ -1,238 +0,0 @@ -package net.kaaass.rumbase.transaction; - -import lombok.Getter; -import lombok.Setter; -import net.kaaass.rumbase.transaction.exception.DeadlockException; -import net.kaaass.rumbase.transaction.exception.StatusException; -import net.kaaass.rumbase.transaction.lock.LockTable; -import net.kaaass.rumbase.transaction.lock.LockTableImpl; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -/** - * 事务上下文的实现 - * - * @author criki - */ -public class TransactionContextImpl implements TransactionContext { - - /** - * 事务Id - */ - @Getter - private final int xid; - /** - * 事务隔离度 - */ - @Getter - private final TransactionIsolation isolation; - /** - * 存储创建它的管理器 - */ - @Getter - private final TransactionManager manager; - /** - * 事务快照 - */ - @Getter - private final List snapshot; - /** - * 状态互斥锁 - */ - private final Lock statusLock = new ReentrantLock(); - /** - * 事务状态 - */ - @Getter - @Setter - private TransactionStatus status; - - /** - * 事务上下文 - */ - public TransactionContextImpl() { - this.xid = 0; - this.status = TransactionStatus.COMMITTED; - this.isolation = TransactionIsolation.READ_UNCOMMITTED; - this.manager = null; - this.snapshot = new ArrayList<>(); - } - - /** - * 事务上下文 - * - * @param xid 事务id - * @param isolation 事务隔离度 - * @param manager 创建事务的管理器 - */ - public TransactionContextImpl(int xid, TransactionIsolation isolation, TransactionManager manager) { - this.xid = xid; - this.status = TransactionStatus.PREPARING; - this.isolation = isolation; - this.manager = manager; - this.snapshot = new ArrayList<>(); - } - - /** - * 事务上下文 - * - * @param xid 事务id - * @param isolation 事务隔离度 - * @param manager 创建事务的管理器 - * @param status 事务状态 - */ - public TransactionContextImpl(int xid, TransactionIsolation isolation, TransactionManager manager, TransactionStatus status) { - this.xid = xid; - this.isolation = isolation; - this.manager = manager; - this.status = status; - this.snapshot = new ArrayList<>(); - } - - /** - * 事务上下文 - * - * @param xid 事务id - * @param isolation 事务隔离度 - * @param manager 创建事务的管理器 - * @param snapshot 事务状态 - */ - public TransactionContextImpl(int xid, TransactionIsolation isolation, TransactionManager manager, List snapshot) { - this.xid = xid; - this.isolation = isolation; - this.manager = manager; - this.status = TransactionStatus.PREPARING; - this.snapshot = snapshot; - } - - /** - * 事务上下文 - * - * @param xid 事务id - * @param isolation 事务隔离度 - * @param manager 创建事务的管理器 - * @param snapshot 事务快照 - * @param status 事务状态 - */ - public TransactionContextImpl(int xid, TransactionIsolation isolation, TransactionManager manager, List snapshot, TransactionStatus status) { - this.xid = xid; - this.isolation = isolation; - this.manager = manager; - this.snapshot = snapshot; - this.status = status; - } - - /** - * 开始事务 - */ - @Override - public void start() throws StatusException { - statusLock.lock(); - try { - if (this.xid != 0 && !this.status.equals(TransactionStatus.PREPARING)) { - throw new StatusException(1); - } - this.status = TransactionStatus.ACTIVE; - if (manager != null) { - manager.changeTransactionStatus(xid, TransactionStatus.ACTIVE); - } - } finally { - statusLock.unlock(); - } - } - - /** - * 提交事务 - */ - @Override - public void commit() throws StatusException { - statusLock.lock(); - try { - if (this.xid != 0 && !this.status.equals(TransactionStatus.ACTIVE)) { - throw new StatusException(1); - } - // 修改状态 - this.status = TransactionStatus.COMMITTED; - if (manager != null) { - manager.changeTransactionStatus(xid, TransactionStatus.COMMITTED); - } - - // 释放锁 - LockTable lockTable = LockTableImpl.getInstance(); - lockTable.release(xid); - } finally { - statusLock.unlock(); - } - } - - /** - * 中止事务 - */ - @Override - public void rollback() throws StatusException { - statusLock.lock(); - try { - if (this.xid != 0 && !this.status.equals(TransactionStatus.ACTIVE)) { - throw new StatusException(1); - } - - // 修改状态 - this.status = TransactionStatus.ABORTED; - if (manager != null) { - manager.changeTransactionStatus(xid, TransactionStatus.ABORTED); - } - - // 释放锁 - LockTable lockTable = LockTableImpl.getInstance(); - lockTable.release(xid); - } finally { - statusLock.unlock(); - } - } - - /** - * 加共享锁 - * - * @param uuid 记录id - * @param tableName 表字段 - */ - @Override - public void sharedLock(long uuid, String tableName) throws DeadlockException, StatusException { - statusLock.lock(); - try { - if (this.xid != 0 && !this.status.equals(TransactionStatus.ACTIVE)) { - throw new StatusException(1); - } - - LockTable lockTable = LockTableImpl.getInstance(); - lockTable.addSharedLock(xid, uuid, tableName); - } finally { - statusLock.unlock(); - } - - } - - /** - * 加排他锁 - * - * @param uuid 记录id - * @param tableName 表字段 - */ - @Override - public void exclusiveLock(long uuid, String tableName) throws DeadlockException, StatusException { - statusLock.lock(); - try { - if (this.xid != 0 && !this.status.equals(TransactionStatus.ACTIVE)) { - throw new StatusException(1); - } - LockTable lockTable = LockTableImpl.getInstance(); - lockTable.addExclusiveLock(xid, uuid, tableName); - } finally { - statusLock.unlock(); - } - } - -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/TransactionIsolation.java b/src/main/java/net/kaaass/rumbase/transaction/TransactionIsolation.java deleted file mode 100644 index d4d077f..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/TransactionIsolation.java +++ /dev/null @@ -1,52 +0,0 @@ -package net.kaaass.rumbase.transaction; - -import lombok.Getter; - -/** - * 事务隔离度 - * - * @author criki - */ -public enum TransactionIsolation { - /** - * 读未提交 - */ - READ_UNCOMMITTED(0), - /** - * 读已提交 - */ - READ_COMMITTED(1), - /** - * 重复读 - */ - REPEATABLE_READ(2), - /** - * 串行化 - */ - SERIALIZABLE(3); - - /** - * 事务隔离度Id - */ - @Getter - private final int isolationId; - - /** - * 事务隔离度 - * - * @param isolationId 事务隔离度Id - */ - TransactionIsolation(int isolationId) { - this.isolationId = isolationId; - } - - public static TransactionIsolation getStatusById(byte id) { - for (TransactionIsolation value : values()) { - if (id == value.isolationId) { - return value; - } - } - - return null; - } -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/TransactionManager.java b/src/main/java/net/kaaass/rumbase/transaction/TransactionManager.java deleted file mode 100644 index ced9f1d..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/TransactionManager.java +++ /dev/null @@ -1,36 +0,0 @@ -package net.kaaass.rumbase.transaction; - -/** - * 事务管理器 - *

- * 管理事务的状态 - * - * @author criki - */ -public interface TransactionManager { - - /** - * 创建新事务 - * - * @param isolation 事务隔离度 - * @return 创建的事物对象 - */ - TransactionContext createTransactionContext(TransactionIsolation isolation); - - /** - * 根据事务id获取事务上下文 - * - * @param xid 事务id - * @return 事务id为xid的事务上下文 - */ - TransactionContext getContext(int xid); - - /** - * 改变事务日志中的事务状态 - * - * @param xid 事务id - * @param status 新事务状态 - */ - void changeTransactionStatus(int xid, TransactionStatus status); - -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/TransactionManagerImpl.java b/src/main/java/net/kaaass/rumbase/transaction/TransactionManagerImpl.java deleted file mode 100644 index e2d7a6e..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/TransactionManagerImpl.java +++ /dev/null @@ -1,235 +0,0 @@ -package net.kaaass.rumbase.transaction; - -import com.igormaznitsa.jbbp.io.JBBPBitInputStream; -import com.igormaznitsa.jbbp.io.JBBPByteOrder; -import com.igormaznitsa.jbbp.io.JBBPOut; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import net.kaaass.rumbase.page.Page; -import net.kaaass.rumbase.page.PageManager; -import net.kaaass.rumbase.page.PageStorage; -import net.kaaass.rumbase.page.exception.FileException; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -/** - * 事务管理器的实现 - * - * @author criki - */ -@Slf4j -public class TransactionManagerImpl implements TransactionManager { - - /** - * 每页最大事务状态数 - */ - private static final int TX_NUM_PER_PAGE = 2048; - /** - * 事务状态持久化文件名 - */ - private final String LOG_FILE_NAME; - /** - * 事务ID计数器 - */ - @Getter - private final AtomicInteger SIZE; - /** - * 事务数量日志写入锁 - */ - private final Lock sizeWriteLock = new ReentrantLock(); - /** - * 事务状态日志 - */ - private final PageStorage storage; - - /** - * 事务缓存 - *

- * TODO 实现事务缓存调度 - */ - private final Map txCache = new HashMap<>(); - - /** - * 事务管理器 - */ - public TransactionManagerImpl() throws IOException, FileException { - this("data/xid.log"); - } - - /** - * 事务管理器 - * - * @param logFile 事务日志文件 - */ - public TransactionManagerImpl(String logFile) throws FileException, IOException { - this.LOG_FILE_NAME = logFile; - - if (new File(LOG_FILE_NAME).exists()) { - // 初始化storage - this.storage = PageManager.fromFile(LOG_FILE_NAME); - // 从日志文件里获取事务数量 - JBBPBitInputStream stream = new JBBPBitInputStream(storage.get(0).getData()); - int size = stream.readInt(JBBPByteOrder.BIG_ENDIAN); - log.info("Initial size : {}", size); - // 初始化SIZE - this.SIZE = new AtomicInteger(size); - } else { - // 初始化storage - this.storage = PageManager.fromFile(LOG_FILE_NAME); - // 初始化SIZE - this.SIZE = new AtomicInteger(0); - } - - } - - /** - * 创建新事务 - * - * @param isolation 事务隔离度 - * @return 事务对象 - */ - @Override - public TransactionContext createTransactionContext(TransactionIsolation isolation) { - // 获取最新事务id - int xid = SIZE.incrementAndGet(); - - // 生成快照 - List snapshot = new ArrayList<>(); - - synchronized (txCache) { - for (TransactionContext context : txCache.values()) { - if (context.getStatus() == TransactionStatus.ACTIVE) { - snapshot.add(context.getXid()); - } - } - } - - // 创建对象 - TransactionContext context = new TransactionContextImpl(xid, isolation, this, snapshot); - // 加入缓存 - txCache.put(xid, context); - - // 进行持久化 - Page page = storage.get(0); - page.pin(); - sizeWriteLock.lock(); - try { - // 转换数据 - byte[] bytes = JBBPOut.BeginBin() - .Int(SIZE.get()) - .End().toByteArray(); - // 写入数据 - page.writeData(bytes); - // 刷新数据 - page.flush(); - - // 写入日志中的事务隔离度 - writeTransactionIsolation(xid, isolation); - // 更新日志中的事务状态 - changeTransactionStatus(xid, TransactionStatus.PREPARING); - } catch (Exception e) { - e.printStackTrace(); - } finally { - sizeWriteLock.unlock(); - page.unpin(); - } - - - return context; - } - - /** - * 改变日志中的事务隔离度 - * - * @param xid 事务id - * @param isolation 事务隔离度 - */ - private void writeTransactionIsolation(int xid, TransactionIsolation isolation) { - int pageId = xid / TX_NUM_PER_PAGE + 1; - int offset = xid % TX_NUM_PER_PAGE * 2 + 1; - - log.info("Xid : {}", xid); - log.info("Page id : {}", pageId); - log.info("offset : {}", offset); - Page page = storage.get(pageId); - page.pin(); - try { - byte[] data = new byte[1]; - data[0] = (byte) isolation.getIsolationId(); - page.patchData(offset, data); - page.flush(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - page.unpin(); - } - } - - /** - * 改变日志中的事务状态 - * - * @param xid 事务id - * @param status 新事务状态 - */ - @Override - public void changeTransactionStatus(int xid, TransactionStatus status) { - int pageId = xid / TX_NUM_PER_PAGE + 1; - int offset = xid % TX_NUM_PER_PAGE * 2; - - Page page = storage.get(pageId); - page.pin(); - try { - byte[] data = new byte[1]; - data[0] = status.getStatusId(); - page.patchData(offset, data); - page.flush(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - page.unpin(); - } - - var context = txCache.get(xid); - if (context instanceof TransactionContextImpl) { - ((TransactionContextImpl) context).setStatus(status); - } - } - - /** - * 根据事务id获取事务上下文 - * - * @param xid 事务id - * @return 事务id为xid的事务上下文 - */ - @Override - public TransactionContext getContext(int xid) { - if (txCache.containsKey(xid)) { - return txCache.get(xid); - } - - int pageId = xid / TX_NUM_PER_PAGE + 1; - int statusOffset = xid % TX_NUM_PER_PAGE * 2; - int isolationOffset = xid % TX_NUM_PER_PAGE * 2 + 1; - - Page page = storage.get(pageId); - page.pin(); - byte[] bytes = page.getDataBytes(); - byte statusId = bytes[statusOffset]; - byte isolationId = bytes[isolationOffset]; - - TransactionStatus status = TransactionStatus.getStatusById(statusId); - TransactionIsolation isolation = TransactionIsolation.getStatusById(isolationId); - - page.unpin(); - - return new TransactionContextImpl(xid, isolation, this, status); - } -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/TransactionStatus.java b/src/main/java/net/kaaass/rumbase/transaction/TransactionStatus.java deleted file mode 100644 index 5ecae72..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/TransactionStatus.java +++ /dev/null @@ -1,52 +0,0 @@ -package net.kaaass.rumbase.transaction; - -import lombok.Getter; - -/** - * 事务状态 - * - * @author criki - */ -public enum TransactionStatus { - /** - * 未开始 - */ - PREPARING(0), - /** - * 正在进行 - */ - ACTIVE(1), - /** - * 已提交 - */ - COMMITTED(2), - /** - * 被撤销 - */ - ABORTED(3); - - /** - * 事务状态Id - */ - @Getter - private final byte statusId; - - /** - * 事务状态 - * - * @param statusId 事务状态Id - */ - TransactionStatus(int statusId) { - this.statusId = (byte) statusId; - } - - public static TransactionStatus getStatusById(byte id) { - for (TransactionStatus value : values()) { - if (id == value.statusId) { - return value; - } - } - - return null; - } -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/exception/DeadlockException.java b/src/main/java/net/kaaass/rumbase/transaction/exception/DeadlockException.java deleted file mode 100644 index aa158b8..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/exception/DeadlockException.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.kaaass.rumbase.transaction.exception; - - -import net.kaaass.rumbase.exception.RumbaseException; - -import java.util.HashMap; -import java.util.Map; - -/** - * E6001 死锁异常 - *

- * E6001-1 发生死锁 - * - * @author criki - */ -public class DeadlockException extends RumbaseException { - - public static final Map REASONS = new HashMap<>() {{ - put(1, "发生死锁"); - }}; - - /** - * 死锁异常 - * - * @param subId 子错误号 - */ - public DeadlockException(int subId) { - super(6001, subId, REASONS.get(subId)); - } -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/exception/StatusException.java b/src/main/java/net/kaaass/rumbase/transaction/exception/StatusException.java deleted file mode 100644 index 6801f39..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/exception/StatusException.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.kaaass.rumbase.transaction.exception; - - -import net.kaaass.rumbase.exception.RumbaseException; - -import java.util.HashMap; -import java.util.Map; - -/** - * E6002 事务状态异常 - *

- * E6002-1 事务状态异常 - * - * @author criki - */ -public class StatusException extends RumbaseException { - - public static final Map REASONS = new HashMap<>() {{ - put(1, "事务状态异常"); - }}; - - /** - * 事务状态异常 - * - * @param subId 子错误号 - */ - public StatusException(int subId) { - super(6001, subId, REASONS.get(subId)); - } - -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/lock/DataItemId.java b/src/main/java/net/kaaass/rumbase/transaction/lock/DataItemId.java deleted file mode 100644 index 966590f..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/lock/DataItemId.java +++ /dev/null @@ -1,59 +0,0 @@ -package net.kaaass.rumbase.transaction.lock; - -import lombok.Getter; - -/** - * 数据项标识符 - *

- * 用于唯一指定一个数据项 - * - * @author criki - */ -public class DataItemId { - /** - * 数据项所在表 - */ - @Getter - private final String tableName; - - /** - * 数据项表内id - */ - @Getter - private final long uuid; - - public DataItemId(String tableName, long uuid) { - this.tableName = tableName; - this.uuid = uuid; - } - - @Override - public String toString() { - return "(" + tableName + ", " + uuid + ")"; - } - - @Override - public int hashCode() { - return tableName.hashCode() * 37 + Long.valueOf(uuid).hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - - if (this == obj) { - return true; - } - - if (!(obj instanceof DataItemId)) { - return false; - } - - DataItemId id = (DataItemId) obj; - - return this.tableName.equals(id.tableName) - && this.uuid == id.uuid; - } -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/lock/Graph.java b/src/main/java/net/kaaass/rumbase/transaction/lock/Graph.java deleted file mode 100644 index 43d1075..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/lock/Graph.java +++ /dev/null @@ -1,104 +0,0 @@ -package net.kaaass.rumbase.transaction.lock; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * 有向图数据结构 - *

- * 用于死锁检测 - * - * @author criki - */ -public class Graph { - - /** - * 深搜访问数组 - */ - private final Map visited = new HashMap<>(); - /** - * 等待图邻接表 - */ - public Map> waitGraph = new HashMap<>(); - - /** - * 添加边 - * - * @param from 源点 - * @param to 终点 - */ - public void addEdge(int from, int to) { - if (waitGraph.containsKey(from)) { - waitGraph.get(from).add(to); - } else { - List edges = new ArrayList<>(); - edges.add(to); - waitGraph.put(from, edges); - } - - if (!waitGraph.containsKey(to)) { - List edges = new ArrayList<>(); - waitGraph.put(to, edges); - } - } - - /** - * 判断是否存在环路 - * - * @return - * - * - *
true存在环路
false不存在环路
- */ - public boolean hasLoop() { - // 初始化访问数组 - visited.clear(); - for (Integer vertex : waitGraph.keySet()) { - visited.put(vertex, 0); - } - - for (Map.Entry v : visited.entrySet()) { - if (v.getValue() == 0) { - if (dfs(v.getKey())) { - // 有环 - return true; - } - } - } - - return false; - } - - /** - * 从u点开始深度优先搜索 - * - * @param u 源点 - * @return 是否存在环路 - */ - private boolean dfs(int u) { - // 标识正在访问 - visited.put(u, -1); - - List edges = waitGraph.get(u); - for (Integer v : edges) { - int visitedV = visited.get(v); - if (visitedV < 0) { - return true; - } else if (visitedV == 0 && dfs(v)) { - return true; - } - } - - visited.put(u, 1); - return false; - } - - @Override - public String toString() { - return "Graph{" + - "waitGraph=" + waitGraph + - '}'; - } -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/lock/LockMode.java b/src/main/java/net/kaaass/rumbase/transaction/lock/LockMode.java deleted file mode 100644 index 6cb9609..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/lock/LockMode.java +++ /dev/null @@ -1,19 +0,0 @@ -package net.kaaass.rumbase.transaction.lock; - -/** - * 锁模式 - *

- * 用于锁表中标识锁类型 - * - * @author criki - */ -public enum LockMode { - /** - * 共享锁 - */ - SHARED, - /** - * 排他锁 - */ - EXCLUSIVE -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/lock/LockTable.java b/src/main/java/net/kaaass/rumbase/transaction/lock/LockTable.java deleted file mode 100644 index 23b46ea..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/lock/LockTable.java +++ /dev/null @@ -1,41 +0,0 @@ -package net.kaaass.rumbase.transaction.lock; - -import net.kaaass.rumbase.transaction.exception.DeadlockException; - -/** - * 锁表 - *

- * 记录锁的信息 - * - * @author criki - */ -public interface LockTable { - /** - * 添加共享锁 - * - * @param xid 事务id - * @param uuid 记录id - * @param tableName 表名 - * @throws DeadlockException 发生死锁异常 - */ - void addSharedLock(int xid, long uuid, String tableName) throws DeadlockException; - - /** - * 添加排他锁 - * - * @param xid 事务id - * @param uuid 记录id - * @param tableName 表名 - * @throws DeadlockException 发生死锁异常 - */ - void addExclusiveLock(int xid, long uuid, String tableName) throws DeadlockException; - - /** - * 释放事务的锁 - * - * @param xid 事务id - */ - void release(int xid); - - -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/lock/LockTableImpl.java b/src/main/java/net/kaaass/rumbase/transaction/lock/LockTableImpl.java deleted file mode 100644 index ee354ee..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/lock/LockTableImpl.java +++ /dev/null @@ -1,294 +0,0 @@ -package net.kaaass.rumbase.transaction.lock; - -import lombok.extern.slf4j.Slf4j; -import net.kaaass.rumbase.transaction.exception.DeadlockException; - -import java.util.*; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.stream.Collectors; - -/** - * 锁表的实现 - * - * @author criki - */ -@Slf4j -public class LockTableImpl implements LockTable { - - /** - * 单例 - */ - private static LockTable instance; - /** - * 锁表 - */ - private final Map lockTable = new HashMap<>(); - /** - * 锁表互斥锁 - */ - private final Lock lock = new ReentrantLock(); - - private LockTableImpl() { - - } - - /** - * 获取实例方法 - * - * @return 单例 - */ - public static LockTable getInstance() { - if (instance == null) { - instance = new LockTableImpl(); - } - return instance; - } - - /** - * 添加锁的模板函数 - * - * @param xid 事务id - * @param id 数据项id - * @param mode 锁类型 - */ - private void addLockTemplate(int xid, DataItemId id, LockMode mode) throws DeadlockException { - TxList list; - - // 获取id的等待队列 - lock.lock(); - try { - if (lockTable.containsKey(id)) { - list = lockTable.get(id); - } else { - list = new TxList(); - lockTable.put(id, list); - } - } finally { - lock.unlock(); - } - - // 判断是否需要手动释放互斥锁 - boolean canUnlock = true; - list.mutexLock.lock(); - try { - // 判断是否能加锁 - boolean canGrant = list.canGrant(mode); - log.info("{} can grant {} lock : {}", xid, mode, canGrant); - // TODO 并发度差,最好改成读写锁 - synchronized (this) { - // 虚加锁 - list.weakInsert(xid, id, mode, canGrant); - // 检测死锁 - if (deadlockCheck()) { - log.info("deadlock"); - list.pop(); - throw new DeadlockException(1); - } - } - - // 可以加锁 - // 对于互斥锁,如果发生等待,在等待处即已释放,此处无需释放 - canUnlock = canGrant; - - // TODO 并发度差,最好改成读写锁 - synchronized (list) { - // 移除虚锁 - list.pop(); - // 正式加锁 - list.insert(xid, id, mode, canGrant); - } - } finally { - if (canUnlock) { - list.mutexLock.unlock(); - } - } - - } - - /** - * 添加共享锁 - * - * @param xid 事务id - * @param uuid 记录id - * @param tableName 表名 - */ - @Override - public void addSharedLock(int xid, long uuid, String tableName) throws DeadlockException { - log.info("{} add shared lock on ({}, {})", xid, tableName, uuid); - addLockTemplate(xid, new DataItemId(tableName, uuid), LockMode.SHARED); - } - - /** - * 添加排他锁 - * - * @param xid 事务id - * @param uuid 记录id - * @param tableName 表名 - */ - @Override - public void addExclusiveLock(int xid, long uuid, String tableName) throws DeadlockException { - log.info("{} add exclusive lock on ({}, {})", xid, tableName, uuid); - addLockTemplate(xid, new DataItemId(tableName, uuid), LockMode.EXCLUSIVE); - } - - /** - * 释放事务的锁 - * - * @param xid 事务id - */ - @Override - public void release(int xid) { - lock.lock(); - try { - Set dataItemSet = new HashSet<>(); - List sharedLocks = TxList.sharedLocks.get(xid); - List exclusiveLocks = TxList.exclusiveLocks.get(xid); - log.info("{}'s sharedLocks: {}", xid, sharedLocks); - log.info("{}'s exclusiveLocks: {}", xid, exclusiveLocks); - if (sharedLocks != null) { - dataItemSet.addAll(sharedLocks); - } - if (exclusiveLocks != null) { - - dataItemSet.addAll(exclusiveLocks); - } - - for (DataItemId id : dataItemSet) { - release(xid, id); - } - } finally { - lock.unlock(); - } - } - - /** - * 释放事务xid持有的数据项id的锁 - * - * @param xid 事务id - * @param id 数据项id - */ - private void release(int xid, DataItemId id) { - TxList waitList; - - // 获取id的等待队列 - lock.lock(); - try { - waitList = lockTable.get(id); - } finally { - lock.unlock(); - } - - // 从等待队列中移除xid - waitList.mutexLock.lock(); - try { - // 查找等待队列中事务id为xid的项 - List lockList = waitList.locks.stream().filter(lock -> lock.xid == xid).collect(Collectors.toList()); - - List txSharedLocks = TxList.sharedLocks.get(xid); - List txExclusiveLocks = TxList.exclusiveLocks.get(xid); - for (TxItem lock : lockList) { - // 从事务持锁列表中移除该数据项 - if (lock.mode.equals(LockMode.SHARED)) { - txSharedLocks.remove(id); - } else { - txExclusiveLocks.remove(id); - } - - // 中止锁申请 - lock.abort(); - - // 从数据项等待队列中移除该事务锁 - waitList.locks.remove(lock); - } - - // 数据项等待队列空,从锁表中移除 - if (waitList.locks.isEmpty()) { - lockTable.remove(id); - return; - } - - } finally { - waitList.mutexLock.unlock(); - } - - boolean firstTx = true; - // 等待队列非空,从等待队列中唤醒下一个事务 - for (TxItem tx : waitList.locks) { - if (tx.granted) { - // 有事务持有该数据项的锁,暂不分配新锁 - break; - } - - // 给第一个事务加锁 - if (firstTx) { - tx.grant(); - firstTx = false; - } - // 给非第一个事务且申请共享锁的事务加锁 - else if (tx.mode.equals(LockMode.SHARED)) { - tx.grant(); - continue; - } - - // 如果该事务是排他锁,则不给之后的事务加锁 - if (tx.mode.equals(LockMode.EXCLUSIVE)) { - break; - } - } - } - - /** - * 检查是否存在死锁 - * - * @return - * - * - *
true 存在死锁
false 不存在死锁
- */ - private boolean deadlockCheck() { - Graph graph = new Graph(); - - // 建图 - - // 遍历每一个等待队列 - var lockTableView = Collections.unmodifiableMap(lockTable); - log.debug("Lock table: {}", lockTableView); - for (TxList list : lockTableView.values()) { - List waitingTxs = new ArrayList<>(list.locks); - log.debug("locks: {}", list.locks); - // 对等待队列中建立等待关系 - for (int i = 0; i < waitingTxs.size() - 1; i++) { - TxItem frontItem = waitingTxs.get(i); - // 共享锁 - if (frontItem.mode.equals(LockMode.SHARED)) { - // 找到后面第一个排他锁 - for (int j = i + 1; j < waitingTxs.size(); j++) { - TxItem backItem = waitingTxs.get(j); - // 邻近的共享锁不构成等待关系 - if (backItem.mode.equals(LockMode.SHARED)) { - continue; - } - - log.debug("[CREATING GRAPH] add edge : {} -> {}", backItem.xid, frontItem.xid); - - // backItem等待frontItem - graph.addEdge(backItem.xid, frontItem.xid); - } - } - // 排他锁 - else { - // 邻近的后面的锁等待该锁 - TxItem backItem = waitingTxs.get(i + 1); - // backItem等待frontItem - log.debug("[CREATING GRAPH] add edge : {} -> {}", backItem.xid, frontItem.xid); - graph.addEdge(backItem.xid, frontItem.xid); - } - } - } - - log.debug("create graph successful: {}", graph); - // 图成环,则有死锁 - return graph.hasLoop(); - } -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/lock/LockTableManager.java b/src/main/java/net/kaaass/rumbase/transaction/lock/LockTableManager.java deleted file mode 100644 index 6b37c95..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/lock/LockTableManager.java +++ /dev/null @@ -1,38 +0,0 @@ -package net.kaaass.rumbase.transaction.lock; - -import net.kaaass.rumbase.transaction.mock.MockLockTable; - -import java.util.HashMap; -import java.util.Map; - -/** - * 锁表管理器 - *

- * 管理锁表 - * - * @author criki - */ -@Deprecated -public class LockTableManager { - /** - * 表名与锁表的映射 - */ - private final Map lockTables; - - /** - * 锁表管理器 - */ - public LockTableManager() { - this.lockTables = new HashMap<>(); - } - - public LockTable getTable(String tableName) { - if (lockTables.containsKey(tableName)) { - return lockTables.get(tableName); - } else { - LockTable table = new MockLockTable(); - lockTables.put(tableName, table); - return table; - } - } -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/lock/TxItem.java b/src/main/java/net/kaaass/rumbase/transaction/lock/TxItem.java deleted file mode 100644 index 2db6513..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/lock/TxItem.java +++ /dev/null @@ -1,105 +0,0 @@ -package net.kaaass.rumbase.transaction.lock; - -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -/** - * 事务项 - *

- * 锁表中记录事务加锁信息的单元 - * - * @author criki - */ -public class TxItem { - /** - * 判断是否被分配锁 - */ - public boolean granted; - - /** - * 事务id - */ - public int xid; - - /** - * 加锁类型 - */ - public LockMode mode; - - /** - * 事务项的互斥锁 - */ - public Lock lock = new ReentrantLock(); - - /** - * 分配锁条件量 - */ - public Condition grantLock = lock.newCondition(); - - /** - * 事务项 - * - * @param granted 是否已分配锁 - * @param xid 事务id - * @param mode 锁类型 - */ - public TxItem(boolean granted, int xid, LockMode mode) { - this.granted = granted; - this.xid = xid; - this.mode = mode; - } - - /** - * 请求分配锁 - */ - public void waitForGrant() { - lock.lock(); - try { - // 等待分配锁 - while (!this.granted) { - grantLock.await(); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } finally { - lock.unlock(); - } - } - - /** - * 分配锁 - */ - public void grant() { - lock.lock(); - try { - // 分配到锁 - granted = true; - // 唤醒线程 - grantLock.signal(); - } finally { - lock.unlock(); - } - } - - /** - * 中止请求 - */ - public void abort() { - lock.lock(); - try { - grantLock.signal(); - } finally { - lock.unlock(); - } - } - - @Override - public String toString() { - return "TxItem{" + - "granted=" + granted + - ", xid=" + xid + - ", mode=" + mode + - '}'; - } -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/lock/TxList.java b/src/main/java/net/kaaass/rumbase/transaction/lock/TxList.java deleted file mode 100644 index a264c62..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/lock/TxList.java +++ /dev/null @@ -1,141 +0,0 @@ -package net.kaaass.rumbase.transaction.lock; - -import lombok.extern.slf4j.Slf4j; - -import java.util.*; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -/** - * 事务项列表 - *

- * 锁表中一个数据项的事务等待列表 - * - * @author criki - */ -@Slf4j -public class TxList { - - /** - * 记录事务持有的共享锁 - */ - public static Map> sharedLocks = new HashMap<>(); - - /** - * 记录事务持有的排他锁 - */ - public static Map> exclusiveLocks = new HashMap<>(); - - /** - * 一个数据项上的事务请求列表 - */ - public Deque locks = new ArrayDeque<>(); - - /** - * 事务列表的互斥锁 - */ - public Lock mutexLock = new ReentrantLock(); - - /** - * 判断当前等待列表是否支持分配mode类型的锁 - * - * @param mode 待分配锁类型 - * @return 是否可以分配 - */ - public boolean canGrant(LockMode mode) { - // 等待队列为空,可以分配任何锁 - if (locks.isEmpty()) { - return true; - } - - // 非空队列中,不可申请排他锁 - if (mode.equals(LockMode.EXCLUSIVE)) { - return false; - } - - // 当前锁类型为共享锁,且等待队列非空 - - // 获取队尾事务项 - TxItem item = locks.getLast(); - - // 当且仅当队尾事务项锁类型是共享锁 - // 且已得到锁时,才可申请共享锁 - return item.mode.equals(LockMode.SHARED) && item.granted; - } - - /** - * 向等待列表插入一个事务项 - * - * @param xid 事务id - * @param id 数据项id - * @param mode 申请锁类型 - * @param granted 是否已分配锁 - */ - public void insert(int xid, DataItemId id, LockMode mode, boolean granted) { - - log.info("{} getting {} lock on {}, it's {}", xid, mode, id, granted); - - // 创建事务项 - TxItem item = new TxItem(granted, xid, mode); - // 加入等待队列 - locks.add(item); - - // 未分配锁时,令其等待 - if (!granted) { - // 先将互斥锁解开,放行后面对等待队列的操作 - mutexLock.unlock(); - // 等待 - item.waitForGrant(); - } - - - // 记录事务获得到的数据项锁 - List lockList; - if (mode.equals(LockMode.SHARED)) { - if (sharedLocks.containsKey(xid)) { - lockList = sharedLocks.get(xid); - } else { - lockList = new ArrayList<>(); - sharedLocks.put(xid, lockList); - } - } else { - if (exclusiveLocks.containsKey(xid)) { - lockList = exclusiveLocks.get(xid); - } else { - lockList = new ArrayList<>(); - exclusiveLocks.put(xid, lockList); - } - } - - lockList.add(id); - } - - /** - * 弹出最后一个事务项 - */ - public void pop() { - locks.pollLast(); - } - - /** - * 向等待列表插入一个事务项,用于判断死锁 - * - * @param xid 事务id - * @param id 数据项id - * @param mode 申请锁类型 - * @param granted 是否已分配锁 - */ - public void weakInsert(int xid, DataItemId id, LockMode mode, boolean granted) { - // 创建事务项 - TxItem item = new TxItem(granted, xid, mode); - // 加入等待队列 - locks.add(item); - } - - @Override - public String toString() { - return "TxList{" + - "locks=" + locks + - '}'; - } -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/mock/MockLockTable.java b/src/main/java/net/kaaass/rumbase/transaction/mock/MockLockTable.java deleted file mode 100644 index af01bd6..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/mock/MockLockTable.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.kaaass.rumbase.transaction.mock; - -import net.kaaass.rumbase.transaction.lock.LockTable; - -/** - * Mock锁表 - * - * @author criki - */ - -@Deprecated -public class MockLockTable implements LockTable { - - - @Override - public void addSharedLock(int xid, long uuid, String tableName) { - - } - - @Override - public void addExclusiveLock(int xid, long uuid, String tableName) { - - } - - @Override - public void release(int xid) { - - } -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/mock/MockTransactionContext.java b/src/main/java/net/kaaass/rumbase/transaction/mock/MockTransactionContext.java deleted file mode 100644 index 8df3a6a..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/mock/MockTransactionContext.java +++ /dev/null @@ -1,120 +0,0 @@ -package net.kaaass.rumbase.transaction.mock; - -import lombok.Getter; -import net.kaaass.rumbase.transaction.TransactionContext; -import net.kaaass.rumbase.transaction.TransactionIsolation; -import net.kaaass.rumbase.transaction.TransactionManager; -import net.kaaass.rumbase.transaction.TransactionStatus; - -import java.util.ArrayList; -import java.util.List; - -/** - * Mock事务上下文 - * - * @author criki - */ -@Deprecated -public class MockTransactionContext implements TransactionContext { - - /** - * 事务Id - */ - @Getter - private final int xid; - - /** - * 事务隔离度 - */ - @Getter - private final TransactionIsolation isolation; - - /** - * 存储创建它的管理器 - */ - @Getter - private final TransactionManager manager; - /** - * 事务快照 - */ - @Getter - private final List snapshot; - /** - * 事务状态 - */ - @Getter - private TransactionStatus status; - - - public MockTransactionContext() { - this.xid = 0; - this.status = TransactionStatus.COMMITTED; - this.isolation = TransactionIsolation.READ_UNCOMMITTED; - this.manager = null; - this.snapshot = new ArrayList<>(); - } - - /** - * 事务上下文 - * - * @param isolation 事务隔离度 - * @param manager 创建事务的管理器 - */ - public MockTransactionContext(int xid, TransactionIsolation isolation, TransactionManager manager) { - this.xid = xid; - this.status = TransactionStatus.PREPARING; - this.isolation = isolation; - this.manager = manager; - this.snapshot = new ArrayList<>(); - } - - /** - * 用于恢复的事务上下文构造函数 - * - * @param xid 事务id - * @param isolation 事务隔离度 - * @param manager 创建事务的管理器 - * @param status 事务状态 - */ - public MockTransactionContext(int xid, TransactionIsolation isolation, TransactionManager manager, TransactionStatus status) { - this.xid = xid; - this.isolation = isolation; - this.manager = manager; - this.status = status; - this.snapshot = new ArrayList<>(); - } - - @Override - public void start() { - this.status = TransactionStatus.ACTIVE; - if (manager != null) { - manager.changeTransactionStatus(xid, TransactionStatus.ACTIVE); - } - } - - @Override - public void commit() { - this.status = TransactionStatus.COMMITTED; - if (manager != null) { - manager.changeTransactionStatus(xid, TransactionStatus.COMMITTED); - } - } - - @Override - public void rollback() { - this.status = TransactionStatus.ABORTED; - if (manager != null) { - manager.changeTransactionStatus(xid, TransactionStatus.ABORTED); - } - } - - @Override - public void sharedLock(long uuid, String tableName) { - - } - - @Override - public void exclusiveLock(long uuid, String tableName) { - - } -} diff --git a/src/main/java/net/kaaass/rumbase/transaction/mock/MockTransactionManager.java b/src/main/java/net/kaaass/rumbase/transaction/mock/MockTransactionManager.java deleted file mode 100644 index a298efb..0000000 --- a/src/main/java/net/kaaass/rumbase/transaction/mock/MockTransactionManager.java +++ /dev/null @@ -1,97 +0,0 @@ -package net.kaaass.rumbase.transaction.mock; - -import net.kaaass.rumbase.transaction.TransactionContext; -import net.kaaass.rumbase.transaction.TransactionIsolation; -import net.kaaass.rumbase.transaction.TransactionManager; -import net.kaaass.rumbase.transaction.TransactionStatus; - -import javax.transaction.xa.Xid; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Mock事务管理器 - * - * @author criki - */ -@Deprecated -public class MockTransactionManager implements TransactionManager { - - /** - * 事务状态持久化文件名 - */ - private static final String LOG_FILE_NAME = "xid.log"; - - /** - * Mock事务数量存储 - */ - public static int TransactionSize; - - /** - * Mock事务状态持久化日志 - */ - public static Map XidLog; - - static { - XidLog = new HashMap<>(); - } - - /** - * 事务ID计数器 - */ - private final AtomicInteger SIZE; - - /** - * Mock事务管理器 - */ - public MockTransactionManager() { - this.SIZE = new AtomicInteger(0); - } - - /** - * 创建新事务 - * - * @param isolation 事务隔离度 - * @return 事务对象 - */ - @Override - public TransactionContext createTransactionContext(TransactionIsolation isolation) { - //获取最新事务id - int xid = SIZE.incrementAndGet(); - //更新日志中的SIZE - TransactionSize = SIZE.get(); - //更新日志中的事务状态 - changeTransactionStatus(xid, TransactionStatus.PREPARING); - - return new MockTransactionContext(xid, isolation, this); - } - - /** - * 根据事务id获取事务上下文 - * - * @param xid 事务id - * @return 事务id为xid的事务上下文 - */ - @Override - public TransactionContext getContext(int xid) { - TransactionStatus status = TransactionStatus.getStatusById(XidLog.get(xid)); - - // 此处为了mock,事务隔离度均为TransactionIsolation.READ_UNCOMMITTED - - return new MockTransactionContext(xid, TransactionIsolation.READ_UNCOMMITTED, this, status); - } - - /** - * 改变日志中的事务状态 - * - * @param xid 事务id - * @param status 新事务状态 - */ - @Override - public void changeTransactionStatus(int xid, TransactionStatus status) { - XidLog.put(xid, status.getStatusId()); - } - - -} diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties deleted file mode 100644 index 97db8c7..0000000 --- a/src/main/resources/log4j.properties +++ /dev/null @@ -1,5 +0,0 @@ -log4j.rootLogger=debug, console -log4j.appender.console=org.apache.log4j.ConsoleAppender -log4j.appender.console.Target=System.out -log4j.appender.console.layout=org.apache.log4j.EnhancedPatternLayout -log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1.}:%L - %m%n \ No newline at end of file diff --git a/src/test/java/net/kaaass/rumbase/FileUtil.java b/src/test/java/net/kaaass/rumbase/FileUtil.java deleted file mode 100644 index 16a2be5..0000000 --- a/src/test/java/net/kaaass/rumbase/FileUtil.java +++ /dev/null @@ -1,55 +0,0 @@ -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/JBBPDemo.java b/src/test/java/net/kaaass/rumbase/JBBPDemo.java deleted file mode 100644 index 83a5289..0000000 --- a/src/test/java/net/kaaass/rumbase/JBBPDemo.java +++ /dev/null @@ -1,84 +0,0 @@ -package net.kaaass.rumbase; - -import com.igormaznitsa.jbbp.JBBPParser; -import com.igormaznitsa.jbbp.io.JBBPBitInputStream; -import com.igormaznitsa.jbbp.io.JBBPByteOrder; -import com.igormaznitsa.jbbp.io.JBBPOut; -import com.igormaznitsa.jbbp.model.JBBPFieldArrayByte; -import com.igormaznitsa.jbbp.model.JBBPFieldShort; -import lombok.extern.slf4j.Slf4j; -import org.junit.Test; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.Arrays; - -/** - * JBBP库的使用示例 - */ -@Slf4j -public class JBBPDemo { - - /** - * 解析字节流 - */ - @Test - public void parseFromStream() throws IOException { - // 首次解析 - var parser = JBBPParser.prepare( - "ushort shortVal;" + - "int intVal;" + - "byte[4] bytes;" - ); - var stream = new ByteArrayInputStream( - new byte[]{0, 12, - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, - 'a', 'b', 'c', 'd', - 66, 0, 12}); - var result = parser.parse(stream); - Arrays.stream(result.getArray()).forEach(field -> - log.info("解析字段: {}", field.getFieldPath())); - log.info("bytes = {}", - result - .findFieldForNameAndType("bytes", JBBPFieldArrayByte.class) - .getArray()); - // 再次解析 - parser = JBBPParser.prepare( - "byte byteVal;" + - "short shortVal;" - ); - result = parser.parse(stream); - log.info("shortVal = {}", - result - .findFieldForNameAndType("shortVal", JBBPFieldShort.class) - .getAsInt()); - // - stream.close(); - } - - /** - * 不编写脚本进行解析 - */ - @Test - public void parseWithoutScript() throws IOException { - var data = new byte[]{1, 2, 0, 4, 0, 4, 5, 'c', 'h', -28, -72, -83}; - var stream = new JBBPBitInputStream(new ByteArrayInputStream(data)); - // 解析过程就是读入一个个字段 - log.info("读入short {}", stream.readUnsignedShort(JBBPByteOrder.LITTLE_ENDIAN)); - log.info("读入数组 {}", stream.readShortArray(2, JBBPByteOrder.BIG_ENDIAN)); - log.info("读入字符串 {}", stream.readString(JBBPByteOrder.BIG_ENDIAN)); - } - - /** - * 把数据写到字符串数组 - */ - @Test - public void writeToBinary() throws IOException { - var result = JBBPOut.BeginBin(). - Bit(1, 0, 0, 1, 1, 1). // 0b111001 - Short(233). - String("汉字"). - End().toByteArray(); - log.info("{}", result); - } -} diff --git a/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java b/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java deleted file mode 100644 index cd6f433..0000000 --- a/src/test/java/net/kaaass/rumbase/dataitem/IItemStorageTest.java +++ /dev/null @@ -1,268 +0,0 @@ -package net.kaaass.rumbase.dataitem; - -import junit.framework.TestCase; -import lombok.extern.slf4j.Slf4j; -import net.kaaass.rumbase.FileUtil; -import net.kaaass.rumbase.dataitem.exception.PageCorruptedException; -import net.kaaass.rumbase.dataitem.exception.UUIDException; -import net.kaaass.rumbase.page.exception.FileException; -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; -import java.util.Comparator; -import java.util.List; -import java.util.Random; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.fail; - -/** - * 对数据项管理部分进行测试 - * - * @author kaito - * @see net.kaaass.rumbase.dataitem.IItemStorage - */ - -@Slf4j -public class IItemStorageTest { - - @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); - // 如果表中没有对应的文件,那么就抛出错误 -// String failFileName = "error.db"; -// try { -// IItemStorage iItemStorage1 = ItemManager.fromFile(failFileName); -// } catch (FileException f) { -// log.error("Exception Error :", f); -// } - } - - /** - * 测试能否新建文件并得到数据项管理器 - */ - @Test - public void testCreateFile() throws IOException, FileException, PageException { - TransactionContext txContext = TransactionContext.empty(); - String fileName = PATH + "testCreateFile.db"; - byte[] metadata = new byte[1024]; - // 第一次执行的时候,表中没有数据,不会报错 - var iItemStorage = ItemManager.createFile(txContext, fileName, metadata); - - try { - iItemStorage = ItemManager.createFile(txContext, fileName, metadata); - fail("should get exception"); - } catch (Exception e) { - log.error("Exception Error :", e); - } - } - - /** - * 进行插入的测试 - */ - @Test - public void testInsert() throws FileException, IOException, PageException, UUIDException, PageCorruptedException { - String fileName = PATH + "testInsert.db"; - IItemStorage iItemStorage = ItemManager.fromFile(fileName); - byte[] bytes = new byte[]{1, 2, 3, 4}; - TransactionContext txContext = TransactionContext.empty(); - long uuid = iItemStorage.insertItem(txContext, bytes); - - long uuid2 = iItemStorage.insertItem(txContext, bytes); - - long uuid3 = iItemStorage.insertItem(txContext, bytes); - - assertArrayEquals(bytes, iItemStorage.queryItemByUuid(uuid)); - } - - /** - * 对插入一个已分配UUID的测试 - */ - @Test - public void testInsertWithUUID() throws FileException, IOException, PageException { - String fileName = PATH + "testInsertWithUUID.db"; - IItemStorage iItemStorage = ItemManager.fromFile(fileName); - byte[] bytes = new byte[]{1, 2, 3, 4}; - long s = 1; - int rnd = Math.abs(new Random().nextInt()); - long uuid = (s << 32) + rnd; - TransactionContext txContext = TransactionContext.empty(); - // 第一次插入,表中没有该UUID,可以正常执行 - iItemStorage.insertItemWithUuid(txContext, bytes, uuid); - try { - assertArrayEquals(bytes, iItemStorage.queryItemByUuid(uuid)); - } catch (UUIDException | PageCorruptedException e) { - e.printStackTrace(); - } - - // 第二次插入 - iItemStorage.insertItemWithUuid(txContext, bytes, uuid); - - } - - /** - * 对插入大量数据进行测试 - */ - @Test - public void testManyInsert() throws FileException, IOException, PageException, UUIDException, PageCorruptedException { - String fileName = PATH + "testInsertMany.db"; - IItemStorage iItemStorage = ItemManager.fromFile(fileName); - byte[] bytes = new byte[]{1, 2, 3, 4}; - TransactionContext txContext = TransactionContext.empty(); - for (int i = 0; i < 1000; i++) { - long uuid = iItemStorage.insertItem(txContext, bytes); - long uuid2 = iItemStorage.insertItem(txContext, bytes); - long uuid3 = iItemStorage.insertItem(txContext, bytes); - // 查询可以正常执行 - var item = iItemStorage.queryItemByUuid(uuid); - assertArrayEquals(bytes, item); - var item3 = iItemStorage.queryItemByUuid(uuid3); - assertArrayEquals(bytes, item3); - } - } - - /** - * 获取整个页的数据项进行测试 - */ - @Test - public void testQueryByPageID() throws FileException, IOException, PageException, PageCorruptedException { - String fileName = PATH + "testQueryByPageID.db"; - IItemStorage iItemStorage = ItemManager.fromFile(fileName); - byte[] bytes = new byte[]{1, 2, 3, 4}; - TransactionContext txContext = TransactionContext.empty(); - long uuid = iItemStorage.insertItem(txContext, bytes); - - byte[] bytes1 = new byte[]{2, 3, 4, 5}; - long uuid1 = iItemStorage.insertItem(txContext, bytes1); - - Comparator comparator = (o1, o2) -> { - int length = Math.min(o1.length, o2.length); - for (int i = 0; i < length; i++) { - if (o2[i] > o1[i]) { - return -1; - } else if (o2[i] < o1[i]) { - return 1; - } - } - - return Integer.compare(o1.length, o2.length); - }; - - List bs = new ArrayList<>(); - bs.add(bytes); - bs.add(bytes1); - bs.sort(comparator); - // 获取pageID对应的数据项,在这里Mock是获取所有list中的数据 - var result = iItemStorage.listItemByPageId(1); - result.sort(comparator); - for (int i = 0; i < bs.size(); i++) { - assertArrayEquals(bs.get(i), result.get(i)); - } - } - - - static class Insert implements Runnable { - IItemStorage iItemStorage; - TransactionContext txContext; - - public Insert(IItemStorage iItemStorage, TransactionContext txContext) { - this.iItemStorage = iItemStorage; - this.txContext = txContext; - } - - @Override - public void run() { - var bytes = new byte[]{1, 2, 3, 4}; - try { - for (int i = 0; i < 100; i++) { - long uuid = iItemStorage.insertItem(txContext, bytes); - assertArrayEquals(bytes, iItemStorage.queryItemByUuid(uuid)); - } - } catch (Exception e) { - e.printStackTrace(); - fail("Exception caught"); - } - } - } - - /** - * 测试并发下插入是否有问题 - */ - @Test - public void testSynInsert() throws IOException, FileException, PageException { - String fileName = PATH + "testInsert.db"; - IItemStorage iItemStorage = ItemManager.fromFile(fileName); - byte[] bytes = new byte[]{1, 2, 3, 4}; - TransactionContext txContext = TransactionContext.empty(); - new Thread(new Insert(iItemStorage, txContext)).start(); - new Thread(new Insert(iItemStorage, txContext)).start(); - new Thread(new Insert(iItemStorage, txContext)).start(); - new Thread(new Insert(iItemStorage, txContext)).start(); - } - - - /** - * 对更新进行测试 - */ - @Test - public void testUpdate() throws FileException, IOException, PageException, UUIDException, PageCorruptedException { - String fileName = PATH + "testUpdate.db"; - TransactionContext txContext = TransactionContext.empty(); - IItemStorage iItemStorage = ItemManager.fromFile(fileName); - byte[] bytes = new byte[]{1, 2, 3, 4}; - long uuid = iItemStorage.insertItem(txContext, bytes); - // 正常情况下进行修改 - byte[] result = new byte[]{2, 3, 4, 5}; - iItemStorage.updateItemByUuid(txContext, uuid, result); - byte[] bs = iItemStorage.queryItemByUuid(uuid); - assertArrayEquals(bs, result); - // 修改一个不存在的UUID - long s = 1; - if (s == uuid) { - s += 1; - } - try { - iItemStorage.updateItemByUuid(txContext, s, result); - fail("Should get exception"); - } catch (UUIDException e) { - e.printStackTrace(); - } - } - - /** - * 测试修改和获取表头信息 - */ - @Test - public void testMeta() throws FileException, IOException, PageException, UUIDException, PageCorruptedException { - String fileName = PATH + "testMeta.db"; - IItemStorage iItemStorage = ItemManager.fromFile(fileName); - byte[] result = new byte[]{1, 2, 3, 4}; - TransactionContext txContext = TransactionContext.empty(); - iItemStorage.setMetadata(txContext, result); - byte[] bs = iItemStorage.getMetadata(); - assertArrayEquals(result, bs); - } - -} diff --git a/src/test/java/net/kaaass/rumbase/index/BTreeTest.java b/src/test/java/net/kaaass/rumbase/index/BTreeTest.java deleted file mode 100644 index 6e8be60..0000000 --- a/src/test/java/net/kaaass/rumbase/index/BTreeTest.java +++ /dev/null @@ -1,207 +0,0 @@ -package net.kaaass.rumbase.index; - -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; -import java.util.Random; - -/** - * 对B+树进行测试 - * - * @author DoctorWei1314 - * @see net.kaaass.rumbase.index.BTreeTest - */ -@Slf4j -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 { - new File(fileDir + "BtreetestInsert$id").deleteOnExit(); - testIndex = Index.createEmptyIndex(fileDir + "BtreetestInsert$id"); - } catch (IndexAlreadyExistException e) { - log.error("Exception Error :", e); - } - - for (int i = 4000; i >= 0; i--) { - - assert testIndex != null; - testIndex.insert(i, new Random().nextLong()); - - testIndex.insert(i, new Random().nextLong()); - } - - // 测试数据是否符合预期 - int cnt = 0; - for (var pair : testIndex) { - Assert.assertEquals(cnt / 2, - pair.getKey()); - // log.debug("{}", pair); - cnt++; - } - } - - /** - * 测试不按顺寻key插入的情况 - */ - @Test - public void testInsertRandomKey() { - Index testIndex = null; - try { - new File(fileDir + "testInsertRandomKey$id").deleteOnExit(); - testIndex = Index.createEmptyIndex(fileDir + "testInsertRandomKey$id"); - } catch (IndexAlreadyExistException e) { - log.error("Exception Error :", e); - } - - for (int i = 4000; i >= 0; i--) { - - assert testIndex != null; - testIndex.insert(i, new Random().nextLong()); - - testIndex.insert(4000 - i, new Random().nextLong()); - } - - // 测试数据是否符合预期 - int cnt = 0; - for (var pair : testIndex) { - Assert.assertEquals(cnt / 2, - pair.getKey()); - // log.debug("{}", pair); - cnt++; - } - } - - /** - * 测试索引的查询功能 - */ - @Test - public void testQuery() { - Index testIndex = null; - - try { - new File(fileDir + "BtreetestQuery$id").deleteOnExit(); - testIndex = Index.createEmptyIndex(fileDir + "BtreetestQuery$id"); - } catch (IndexAlreadyExistException e) { - log.error("Exception Error :", e); - } - - // 倒序添加若干随机数据 - for (int i = 2000; i > 0; i--) { - var rand = new Random().nextLong(); - - assert testIndex != null; - testIndex.insert(i, rand); - - testIndex.insert(i, new Random().nextLong()); - } - - // 打印当前索引情况 - for (var pair : testIndex) { - log.debug("{}", pair); - } - - // 测试 findFirst 方法 - // keyHash在内的迭代器 1122->334455 - Iterator it1 = testIndex.findFirst(3); - 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); - 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); - System.out.println(results); -// assertTrue(results.contains(standardRand.get(2))); -// assertTrue(results.contains(standardRand.get(2 + 1))); - } - - /** - * 测试multiKey索引的查询功能 - */ - @Test - public void testMultiKeyQuery() { - Index testIndex = null; - - try { - new File(fileDir + "testMultiKeyQuery$id").deleteOnExit(); - testIndex = Index.createEmptyIndex(fileDir + "testMultiKeyQuery$id"); - } catch (IndexAlreadyExistException e) { - log.error("Exception Error :", e); - } - - // 倒序添加若干随机数据 - for (int i = 30; i > 0; i--) { - assert testIndex != null; - for (int j = 0; j < 50; j++) { - testIndex.insert(i, new Random().nextLong()); - testIndex.insert(i, new Random().nextLong()); - } - } - - int y = 0; - // 打印当前索引情况 - for (var pair : testIndex) { - log.debug("{}{}", y % 100, pair); - y++; - } - - // 测试 query 方法 - var results = testIndex.query(4); - System.out.println(results); - - // 测试 findFirst 方法 - // keyHash在内的迭代器 1122->334455 - Iterator it1 = testIndex.findFirst(3); - 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); - 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()); - } - -// assertTrue(results.contains(standardRand.get(2))); -// assertTrue(results.contains(standardRand.get(2 + 1))); - } -} diff --git a/src/test/java/net/kaaass/rumbase/index/ConcurrentIndexTest.java b/src/test/java/net/kaaass/rumbase/index/ConcurrentIndexTest.java deleted file mode 100644 index db7d77f..0000000 --- a/src/test/java/net/kaaass/rumbase/index/ConcurrentIndexTest.java +++ /dev/null @@ -1,134 +0,0 @@ -package net.kaaass.rumbase.index; - -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 { - 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 { - new File(fileDir + "test$id").deleteOnExit(); - testIndex = Index.createEmptyIndex(fileDir + "test$id"); - } catch (IndexAlreadyExistException e) { - log.error("Exception Error :", e); - } - - Index finalTestIndex = testIndex; - Thread thread = new Thread(() -> { - for (int i = 4000; i >= 0; i--) { - - assert finalTestIndex != null; - - finalTestIndex.insert(i, new Random().nextLong()); - } - }); - - thread.start(); - - for (int i = 4000; i >= 0; i--) { - - assert testIndex != null; - testIndex.insert(i, new Random().nextLong()); - } - - try { - thread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - // 测试数据是否符合预期 - int cnt = 0; - for (var pair : testIndex) { - Assert.assertEquals(cnt / 2, - pair.getKey()); - //log.debug("{}", pair); - cnt++; - } - } - - /** - * 测试索引的更复杂的并发功能 - */ - @Test - public void testComplex() { - Index testIndex = null; - try { - new File(fileDir + "ConcurrenttestComplex$id").deleteOnExit(); - testIndex = Index.createEmptyIndex(fileDir + "ConcurrenttestComplex$id"); - } catch (IndexAlreadyExistException e) { - log.error("Exception Error :", e); - } - - Index finalTestIndex = testIndex; - Thread thread1 = new Thread(() -> { - for (int i = 4000; i >= 0; i--) { - - assert finalTestIndex != null; - - finalTestIndex.insert(i, new Random().nextLong()); - } - }); - - thread1.start(); - - Thread thread2 = new Thread(() -> { - for (int i = 0; i <= 4000; i++) { - - assert finalTestIndex != null; - - finalTestIndex.insert(i, new Random().nextLong()); - } - }); - - thread2.start(); - - for (int i = 4000; i >= 0; i--) { - - assert testIndex != null; - testIndex.insert(i, new Random().nextLong()); - } - - try { - thread1.join(); - thread2.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - // 测试数据是否符合预期 - int cnt = 0; - for (var pair : testIndex) { - 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 deleted file mode 100644 index 425401f..0000000 --- a/src/test/java/net/kaaass/rumbase/index/IndexTest.java +++ /dev/null @@ -1,129 +0,0 @@ -package net.kaaass.rumbase.index; - -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; -import java.util.Iterator; -import java.util.List; -import java.util.Random; - -/** - * 对索引部分进行测试 - * - * @author DoctorWei1314 - * @see net.kaaass.rumbase.index.Index - */ -@Slf4j -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(); - try { - new File(fileDir + "testInsert$id").deleteOnExit(); - testIndex = Index.createEmptyIndex(fileDir + "testInsert$id"); - } catch (IndexAlreadyExistException e) { - log.error("Exception Error :", e); - } - - for (int i = 0; i < 50; i++) { - var rand = new Random().nextLong(); - - standardRand.add(rand); - assert testIndex != null; - testIndex.insert(i, rand); - } - - // 测试数据是否符合预期 - int cnt = 0; - for (var pair : testIndex) { - Assert.assertEquals(standardRand.get(cnt).longValue(), - pair.getUuid()); - cnt++; - } - } - - /** - * 测试索引的查询功能 - */ - @Test - public void testQuery() { - Index testIndex = null; - var standardRand = new ArrayList(); - - try { - new File(fileDir + "testQuery$id").deleteOnExit(); - testIndex = Index.createEmptyIndex(fileDir + "testQuery$id"); - } catch (IndexAlreadyExistException e) { - log.error("Exception Error :", e); - } - - // 倒序添加若干随机数据 - for (int i = 5; i > 0; i--) { - var rand = new Random().nextLong(); - - standardRand.add(rand); - assert testIndex != null; - testIndex.insert(i, rand); - - standardRand.add(rand = new Random().nextLong()); - testIndex.insert(i, rand); - } - - // 打印当前索引情况 - for (var pair : testIndex) { - log.debug("{}", pair); - } - - // 测试 findFirst 方法 - // keyHash在内的迭代器 1122->334455 - Iterator it1 = testIndex.findFirst(3); - Assert.assertTrue(it1.hasNext()); - var expected = List.of( - standardRand.get(2 * 2), - standardRand.get(2 * 2 + 1) - ); - Assert.assertTrue(expected.contains(it1.next().getUuid())); - Assert.assertTrue(expected.contains(it1.next().getUuid())); - - // 测试 findUpperbound 方法 - // 不包括keyHash在内的迭代器 112233->4455 - Iterator it2 = testIndex.findUpperbound(3); - Assert.assertTrue(it2.hasNext()); - expected = List.of( - standardRand.get(2), - standardRand.get(2 + 1) - ); - Assert.assertTrue(expected.contains(it2.next().getUuid())); - Assert.assertTrue(expected.contains(it2.next().getUuid())); - - // 测试 query 方法 - var results = testIndex.query(4); - 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 deleted file mode 100644 index 6a3d08a..0000000 --- a/src/test/java/net/kaaass/rumbase/page/PageStorageTest.java +++ /dev/null @@ -1,213 +0,0 @@ -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; -import java.io.IOException; -import java.util.Arrays; - -import static org.junit.Assert.assertArrayEquals; - -/** - * 文件管理测试 - * - * @author XuanLaoYee - * @see net.kaaass.rumbase.page.PageStorage - */ -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 { - rps = PageManager.fromFile(filePath); - } catch (Exception e) { - e.printStackTrace(); - } - assert rps != null; - for (int i = 0; i < 10; i++) { - Page p = rps.get(i); - p.pin(); - } - Page p0 = rps.get(0); - Page p1 = rps.get(1); - p0.unpin(); - p1.unpin(); - Page p10 = rps.get(10); - p10.pin(); - Page p11 = rps.get(11); - p11.pin(); - - File file = new File(filePath); - try { - FileInputStream in = new FileInputStream(file); - byte[] dataFromFile = new byte[PageManager.PAGE_SIZE]; - byte[] dataFromPage = new byte[PageManager.PAGE_SIZE]; - in.skip((11 + PageManager.FILE_HEAD_SIZE) * PageManager.PAGE_SIZE); - int readNumber = in.read(dataFromFile); - p11.getData().read(dataFromPage); - Assert.assertEquals(readNumber, PageManager.PAGE_SIZE); - assertArrayEquals(dataFromPage, dataFromFile); - } catch (Exception e) { - throw e; - } finally { - p10.unpin(); - p11.unpin(); - } - } - - @Test - public void testWriteToFile() throws FileException, PageException { - PageStorage storage = PageManager.fromFile(filePath); - int[] testPage = new int[]{1, 3, 5, 7, 10, 11}; - // 测试每一页是否能正常读写 - for (var pageId: testPage) { - // 准备标志数据 - byte[] data = new byte[PageManager.PAGE_SIZE]; - Arrays.fill(data, (byte) (0xF0 | pageId)); - // 获取页 - var page = storage.get(pageId); - page.pin(); - // 写入页 - try { - // 写数据 - page.patchData(0, data); - page.flush(); - } finally { - page.unpin(); - } - // 检查页数据 - var tempStorage = PageManager.fromFile(filePath); - var pageData = tempStorage.get(pageId).getDataBytes(); - assertArrayEquals(data, pageData); - } - } - - @Test - public void testFlush() throws PageException { - PageStorage rps = null; - try { - rps = PageManager.fromFile(filePath); - } catch (Exception e) { - e.printStackTrace(); - } - assert rps != null; - Page p0 = rps.get(0); - Page p3 = rps.get(3); - Page p4 = rps.get(4); - p0.pin(); - p3.pin(); - p4.pin(); - byte[] data0 = new byte[PageManager.PAGE_SIZE]; - byte[] data3 = new byte[PageManager.PAGE_SIZE]; - byte[] data4 = new byte[PageManager.PAGE_SIZE]; - byte[] dataFromFile0 = new byte[PageManager.PAGE_SIZE]; - byte[] dataFromFile3 = new byte[PageManager.PAGE_SIZE]; - byte[] dataFromFile4 = new byte[PageManager.PAGE_SIZE]; - for (int i = 0; i < PageManager.PAGE_SIZE; i++) { - data0[i] = (byte) 0xf0; - data3[i] = (byte) 0xf3; - data4[i] = (byte) 0xf4; - } - // 打印下之前的数据,检查之前写入是否正确 - try { - p0.writeData(data0); - p3.writeData(data3); - p4.writeData(data4); - rps.flush(); - } catch (Exception e) { - throw e; - } finally { - p0.unpin(); - p3.unpin(); - p4.unpin(); - } - File file = new File(filePath); - try { - FileInputStream in = new FileInputStream(file); - in.skip((PageManager.FILE_HEAD_SIZE) * PageManager.PAGE_SIZE); - in.read(dataFromFile0); - in.close(); - in = new FileInputStream(file); - in.skip((3 + PageManager.FILE_HEAD_SIZE) * PageManager.PAGE_SIZE); - in.read(dataFromFile3); - in.close(); - in = new FileInputStream(file); - in.skip((4 + PageManager.FILE_HEAD_SIZE) * PageManager.PAGE_SIZE); - in.read(dataFromFile4); - in.close(); - } catch (Exception e) { - e.printStackTrace(); - } - try { - p0.getData().read(data0); - p3.getData().read(data3); - p4.getData().read(data4); - } catch (Exception e) { - e.printStackTrace(); - } - assertArrayEquals(data0, dataFromFile0); - assertArrayEquals(data3, dataFromFile3); - 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}; - // 测试每一页是否能正常读写 - for (var pageId : testPage) { - // 准备标志数据 - byte[] data = new byte[PageManager.PAGE_SIZE]; - Arrays.fill(data, (byte) (0xF0 | pageId)); - // 获取页 - var page = storage.get(pageId); - page.pin(); - // 写入页 - try { - // 写数据 - page.patchData(0, data); - } finally { - page.unpin(); - } - } - //将内存中的所有页都写回 - PageManager.flush(); - for (var pageId : testPage) { - byte[] data = new byte[PageManager.PAGE_SIZE]; - Arrays.fill(data, (byte) (0xF0 | pageId)); - // 获取页 - var page = storage.get(pageId); - page.pin(); - // 写入页 - try { - // 检查页数据 - var tempStorage = PageManager.fromFile(filePath); - var pageData = tempStorage.get(pageId).getDataBytes(); - assertArrayEquals(data, pageData); - } finally { - page.unpin(); - } - - } - } -} \ No newline at end of file diff --git a/src/test/java/net/kaaass/rumbase/page/PageTest.java b/src/test/java/net/kaaass/rumbase/page/PageTest.java deleted file mode 100644 index 3f28b21..0000000 --- a/src/test/java/net/kaaass/rumbase/page/PageTest.java +++ /dev/null @@ -1,89 +0,0 @@ -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; -import java.util.Arrays; -import java.util.Random; - -import static org.junit.Assert.assertArrayEquals; - -/** - * 页管理测试 - * - * @author XuanLaoYee - * @see net.kaaass.rumbase.page.Page - */ -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]; - for (int i = 0; i < data.length; i++) { - data[i] = (byte) (i % 120); - } - - try { - PageStorage pc = PageManager.fromFile(filePath); - Page p0 = pc.get(0); - byte[] originalData = p0.getDataBytes(); - p0.patchData(offset, data); - byte[] newData = new byte[PageManager.PAGE_SIZE]; - System.arraycopy(originalData, 0, newData, 0, offset); - System.arraycopy(data, 0, newData, offset, data.length); - assertArrayEquals(newData, p0.getDataBytes()); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Test - public void testPatchOffset() throws FileException, PageException { - var storage = PageManager.fromFile(filePath); - var rand = new Random(); - var page = storage.get(2); - page.pin(); - try { - for (int i = 0; i < 50; i++) { - // 随机决定开始、结束 - var st = rand.nextInt(4000); - var ed = st + rand.nextInt(2000); - if (ed > 4096) { - ed = 4096; - } - // 生成相关数据 - byte[] data = new byte[ed - st]; - Arrays.fill(data, (byte) st); - // 写入 - page.patchData(st, data); - // 检查写入效果 - var pageData = page.getDataBytes(); - for (int j = st; j < ed; j++) { - Assert.assertEquals((byte) st, pageData[j]); - } - } - } finally { - page.unpin(); - } - } -} \ No newline at end of file diff --git a/src/test/java/net/kaaass/rumbase/parse/ConditionExpressionTest.java b/src/test/java/net/kaaass/rumbase/parse/ConditionExpressionTest.java deleted file mode 100644 index f848629..0000000 --- a/src/test/java/net/kaaass/rumbase/parse/ConditionExpressionTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package net.kaaass.rumbase.parse; - -import junit.framework.TestCase; -import lombok.extern.slf4j.Slf4j; -import net.sf.jsqlparser.JSQLParserException; -import net.sf.jsqlparser.parser.CCJSqlParserUtil; - -import java.util.ArrayList; -import java.util.HashMap; - -@Slf4j -public class ConditionExpressionTest extends TestCase { - - public void testEvaluate() throws JSQLParserException { - var exp = CCJSqlParserUtil.parseCondExpression("a.ID - b.ID + ID >= 3"); - var cond = new ConditionExpression(exp, "c"); - // 测试 - var params = new HashMap(); - params.put(new ColumnIdentifier("a", "ID"), 1); - params.put(new ColumnIdentifier("b", "ID"), 2); - params.put(new ColumnIdentifier("c", "ID"), 3); - assertFalse(cond.evaluate(params)); - // - params.replace(new ColumnIdentifier("b", "ID"), 1); - assertTrue(cond.evaluate(params)); - } - - public void testEvaluateString() throws JSQLParserException { - var exp = CCJSqlParserUtil.parseCondExpression("Name <= 'Kaaass'"); - var cond = new ConditionExpression(exp, "stu"); - // 测试 - var params = new HashMap(); - params.put(new ColumnIdentifier("stu", "Name"), "KAAAsS"); - assertTrue(cond.evaluate(params)); - // - params.put(new ColumnIdentifier("stu", "Name"), "kaaass"); - assertFalse(cond.evaluate(params)); - // - params.put(new ColumnIdentifier("stu", "Name"), "Kaaass"); - assertTrue(cond.evaluate(params)); - } - - public void testGetParams() throws JSQLParserException { - var exp = CCJSqlParserUtil.parseExpression("a.ID - b.ID + ID >= 3"); - var cond = new ConditionExpression(exp, "c"); - var result = cond.getParams(); - log.info("Parsed: {}", result); - // 比较结果 - var expected = new ArrayList(); - assertTrue(result.contains(new ColumnIdentifier("a", "ID"))); - assertTrue(result.contains(new ColumnIdentifier("b", "ID"))); - assertTrue(result.contains(new ColumnIdentifier("c", "ID"))); - } -} \ No newline at end of file diff --git a/src/test/java/net/kaaass/rumbase/parse/SqlTest.java b/src/test/java/net/kaaass/rumbase/parse/SqlTest.java deleted file mode 100644 index 031a630..0000000 --- a/src/test/java/net/kaaass/rumbase/parse/SqlTest.java +++ /dev/null @@ -1,98 +0,0 @@ -package net.kaaass.rumbase.parse; - -import junit.framework.TestCase; -import lombok.extern.slf4j.Slf4j; -import net.sf.jsqlparser.JSQLParserException; -import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; -import net.sf.jsqlparser.parser.CCJSqlParserUtil; -import net.sf.jsqlparser.schema.Column; -import net.sf.jsqlparser.statement.create.index.CreateIndex; -import net.sf.jsqlparser.statement.create.table.CreateTable; -import net.sf.jsqlparser.statement.delete.Delete; -import net.sf.jsqlparser.statement.insert.Insert; -import net.sf.jsqlparser.statement.select.PlainSelect; -import net.sf.jsqlparser.statement.select.Select; -import net.sf.jsqlparser.statement.select.SelectVisitorAdapter; -import net.sf.jsqlparser.statement.update.Update; - -@Slf4j -public class SqlTest extends TestCase { - - public void testParseSelect() throws JSQLParserException { - Select select = (Select) CCJSqlParserUtil.parse( - "SELECT name, a.ID as aid, `account`.`balance` " + - "from `account` as a join `payment` as p on a.ID = p.ID, `file` as f " + - "WHERE a.`ID` > 1 and (p.`type` = 'N' or p.`type` = 'T') " + - "order by acc.ID desc;" - ); - final PlainSelect[] selectStmtArr = {null}; - select.getSelectBody().accept(new SelectVisitorAdapter() { - @Override - public void visit(PlainSelect plainSelect) { - selectStmtArr[0] = plainSelect; - } - }); - PlainSelect selectStmt = selectStmtArr[0]; - log.info("Select: {}", selectStmt.getSelectItems()); - log.info("From: {}", selectStmt.getFromItem()); - log.info("Join: {}", selectStmt.getJoins()); - log.info("Where: {}", selectStmt.getWhere()); - log.info("OrderBy: {}", selectStmt.getOrderByElements()); - var expr = selectStmt.getWhere(); - } - - public void testParseInsert() throws JSQLParserException { - Insert insert = (Insert) CCJSqlParserUtil.parse( - "INSERT INTO Persons (LastName, Address) VALUES ('Wilson', 'Champs-Elysees')" - ); - log.info("Table: {}", insert.getTable()); - log.info("Values: {}", insert.getItemsList()); - log.info("Columns: {}", insert.getColumns()); - } - - public void testParseUpdate() throws JSQLParserException { - Update stmt = (Update) CCJSqlParserUtil.parse( - "UPDATE Person SET Address = 'Zhongshan 23', City = 'Nanjing'\n" + - "WHERE LastName = 'Wilson'" - ); - log.info("Table: {}", stmt.getTable()); - log.info("Columns: {}", stmt.getColumns()); - log.info("Expressions: {}", stmt.getExpressions()); - log.info("Where: {}", stmt.getWhere()); - stmt.getWhere().accept(new ExpressionVisitorAdapter() { - - @Override - public void visit(Column column) { - log.info("Column in where: {} {}", column.getTable(), column.getColumnName()); - } - }); - } - - public void testParseDelete() throws JSQLParserException { - Delete stmt = (Delete) CCJSqlParserUtil.parse("DELETE FROM Person WHERE LastName = 'Wilson'"); - log.info("Table: {}", stmt.getTable()); - log.info("Where: {}", stmt.getWhere()); - } - - public void testParseCreateTable() throws JSQLParserException { - CreateTable stmt = (CreateTable) CCJSqlParserUtil.parse( - "CREATE TABLE Persons\n" + - "(\n" + - "Id_P int,\n" + - "LastName varchar(255),\n" + - "FirstName varchar(255),\n" + - "Address varchar(255),\n" + - "City varchar(255)\n" + - ")" - ); - log.info("Table: {}", stmt.getTable()); - log.info("Columns: {}", stmt.getColumnDefinitions()); - } - - public void testCreateIndex() throws JSQLParserException { - CreateIndex stmt = (CreateIndex) CCJSqlParserUtil.parse("CREATE INDEX PersonIndex ON Person (LastName) "); - log.info("Table: {}", stmt.getTable()); - log.info("Name: {}", stmt.getIndex().getName()); - log.info("Columns: {}", stmt.getIndex().getColumns()); - } -} diff --git a/src/test/java/net/kaaass/rumbase/parse/parser/CreateIndexStatementParserTest.java b/src/test/java/net/kaaass/rumbase/parse/parser/CreateIndexStatementParserTest.java deleted file mode 100644 index 79e43b4..0000000 --- a/src/test/java/net/kaaass/rumbase/parse/parser/CreateIndexStatementParserTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package net.kaaass.rumbase.parse.parser; - -import junit.framework.TestCase; -import lombok.extern.slf4j.Slf4j; -import net.kaaass.rumbase.parse.ColumnIdentifier; -import net.kaaass.rumbase.parse.SqlParser; -import net.kaaass.rumbase.parse.exception.SqlSyntaxException; -import net.kaaass.rumbase.parse.stmt.CreateIndexStatement; - -import java.util.ArrayList; - -@Slf4j -public class CreateIndexStatementParserTest extends TestCase { - - public void testParseSingle() throws SqlSyntaxException { - var sql = "CREATE INDEX PersonIndex ON Person (LastName) ;"; - // 解析 - var stmt = SqlParser.parseStatement(sql); - assertTrue(stmt instanceof CreateIndexStatement); - log.info("Parsed: {}", stmt); - // 准备预期结果 - var columns = new ArrayList(); - columns.add(new ColumnIdentifier("Person", "LastName")); - var expected = new CreateIndexStatement( - "PersonIndex", - "Person", - columns - ); - // 比较 - assertEquals(expected, stmt); - } - - public void testParseMulti() throws SqlSyntaxException { - var sql = "CREATE INDEX PersonIndex ON Person (LastName, ID) ;"; - // 解析 - var stmt = SqlParser.parseStatement(sql); - assertTrue(stmt instanceof CreateIndexStatement); - log.info("Parsed: {}", stmt); - // 准备预期结果 - var columns = new ArrayList(); - columns.add(new ColumnIdentifier("Person", "LastName")); - columns.add(new ColumnIdentifier("Person", "ID")); - var expected = new CreateIndexStatement( - "PersonIndex", - "Person", - columns - ); - // 比较 - assertEquals(expected, stmt); - } -} \ No newline at end of file diff --git a/src/test/java/net/kaaass/rumbase/parse/parser/CreateTableStatementParserTest.java b/src/test/java/net/kaaass/rumbase/parse/parser/CreateTableStatementParserTest.java deleted file mode 100644 index 79e3e97..0000000 --- a/src/test/java/net/kaaass/rumbase/parse/parser/CreateTableStatementParserTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package net.kaaass.rumbase.parse.parser; - -import junit.framework.TestCase; -import lombok.extern.slf4j.Slf4j; -import net.kaaass.rumbase.parse.SqlParser; -import net.kaaass.rumbase.parse.exception.SqlSyntaxException; -import net.kaaass.rumbase.parse.stmt.CreateTableStatement; - -import java.util.ArrayList; -import java.util.List; - -@Slf4j -public class CreateTableStatementParserTest extends TestCase { - - public void testParse() throws SqlSyntaxException { - var sql = "CREATE TABLE Persons\n" + - "(\n" + - "Id_P int not null,\n" + - "LastName varchar(255),\n" + - "FirstName varchar(255) NOT NULL\n" + - ")"; - // 解析 - var stmt = SqlParser.parseStatement(sql); - assertTrue(stmt instanceof CreateTableStatement); - log.info("Parsed: {}", stmt); - // 准备预期结果 - var columns = new ArrayList(); - columns.add(new CreateTableStatement.ColumnDefinition( - new CreateTableStatement.ColumnType("int", null), - "Id_P", - true - )); - columns.add(new CreateTableStatement.ColumnDefinition( - new CreateTableStatement.ColumnType("varchar", List.of("255")), - "LastName", - false - )); - columns.add(new CreateTableStatement.ColumnDefinition( - new CreateTableStatement.ColumnType("varchar", List.of("255")), - "FirstName", - true - )); - var expected = new CreateTableStatement( - "Persons", - columns - ); - // 比较 - assertEquals(expected, stmt); - } -} \ No newline at end of file diff --git a/src/test/java/net/kaaass/rumbase/parse/parser/DeleteStatementParserTest.java b/src/test/java/net/kaaass/rumbase/parse/parser/DeleteStatementParserTest.java deleted file mode 100644 index d54fdf7..0000000 --- a/src/test/java/net/kaaass/rumbase/parse/parser/DeleteStatementParserTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package net.kaaass.rumbase.parse.parser; - -import junit.framework.TestCase; -import lombok.extern.slf4j.Slf4j; -import net.kaaass.rumbase.parse.ColumnIdentifier; -import net.kaaass.rumbase.parse.SqlParser; -import net.kaaass.rumbase.parse.exception.SqlSyntaxException; -import net.kaaass.rumbase.parse.stmt.DeleteStatement; - -import java.util.HashMap; - -@Slf4j -public class DeleteStatementParserTest extends TestCase { - - public void testParse() throws SqlSyntaxException { - var sql = "DELETE FROM Person WHERE LastName = 'Wilson'"; - // 解析 - var stmt = SqlParser.parseStatement(sql); - assertTrue(stmt instanceof DeleteStatement); - log.info("Parsed: {}", stmt); - // 比较 - assertEquals("Person", ((DeleteStatement) stmt).getTableName()); - // 测试 where - var params = new HashMap(); - params.put(new ColumnIdentifier("Person", "LastName"), "Wilson"); - assertTrue(((DeleteStatement) stmt).getWhere().evaluate(params)); - // - params.put(new ColumnIdentifier("Person", "LastName"), "KAAAsS"); - assertFalse(((DeleteStatement) stmt).getWhere().evaluate(params)); - } - - public void testParseNull() throws SqlSyntaxException { - var sql = "DELETE FROM Person "; - // 解析 - var stmt = SqlParser.parseStatement(sql); - assertTrue(stmt instanceof DeleteStatement); - log.info("Parsed: {}", stmt); - // 比较 - assertEquals("Person", ((DeleteStatement) stmt).getTableName()); - assertNull(((DeleteStatement) stmt).getWhere()); - } -} \ No newline at end of file diff --git a/src/test/java/net/kaaass/rumbase/parse/parser/InsertStatementParserTest.java b/src/test/java/net/kaaass/rumbase/parse/parser/InsertStatementParserTest.java deleted file mode 100644 index 08736f1..0000000 --- a/src/test/java/net/kaaass/rumbase/parse/parser/InsertStatementParserTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.kaaass.rumbase.parse.parser; - -import junit.framework.TestCase; -import lombok.extern.slf4j.Slf4j; -import net.kaaass.rumbase.parse.ColumnIdentifier; -import net.kaaass.rumbase.parse.SqlParser; -import net.kaaass.rumbase.parse.exception.SqlSyntaxException; -import net.kaaass.rumbase.parse.stmt.InsertStatement; - -import java.util.ArrayList; - -@Slf4j -public class InsertStatementParserTest extends TestCase { - - public void testParseColumnValue() throws SqlSyntaxException { - var sql = "INSERT INTO Persons (Persons.LastName, Address) VALUES ('Wilson', 'Champs-Elysees')"; - // 解析 - var stmt = SqlParser.parseStatement(sql); - assertTrue(stmt instanceof InsertStatement); - log.info("Parsed: {}", stmt); - // 准备预期结果 - var columns = new ArrayList(); - columns.add(new ColumnIdentifier("Persons", "LastName")); - columns.add(new ColumnIdentifier("Persons", "Address")); - var values = new ArrayList(); - values.add("'Wilson'"); - values.add("'Champs-Elysees'"); - var expected = new InsertStatement( - "Persons", - columns, - values - ); - // 比较 - assertEquals(expected, stmt); - } - - public void testParseValue() throws SqlSyntaxException { - var sql = "INSERT INTO stu VALUES (20200101, 'KAAAsS', true, 3.9)"; - // 解析 - var stmt = SqlParser.parseStatement(sql); - assertTrue(stmt instanceof InsertStatement); - log.info("Parsed: {}", stmt); - // 准备预期结果 - var values = new ArrayList(); - values.add("20200101"); - values.add("'KAAAsS'"); - values.add("true"); - values.add("3.9"); - var expected = new InsertStatement( - "stu", - null, - values - ); - // 比较 - assertEquals(expected, stmt); - } -} \ No newline at end of file diff --git a/src/test/java/net/kaaass/rumbase/parse/parser/SelectStatementParserTest.java b/src/test/java/net/kaaass/rumbase/parse/parser/SelectStatementParserTest.java deleted file mode 100644 index 64a4413..0000000 --- a/src/test/java/net/kaaass/rumbase/parse/parser/SelectStatementParserTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package net.kaaass.rumbase.parse.parser; - -import junit.framework.TestCase; -import lombok.extern.slf4j.Slf4j; -import net.kaaass.rumbase.parse.ColumnIdentifier; -import net.kaaass.rumbase.parse.SqlParser; -import net.kaaass.rumbase.parse.exception.SqlSyntaxException; -import net.kaaass.rumbase.parse.stmt.SelectStatement; - -import java.util.HashMap; - -@Slf4j -public class SelectStatementParserTest extends TestCase { - - public void testParse() throws SqlSyntaxException { - var sql = "SELECT distinct name, account.ID, account.balance \n" + - "from account join payment on account.ID = payment.ID, file\n" + - "WHERE account.ID > 1 and (payment.type = 'N' or payment.type = 'T') \n" + - "order by account.ID desc;"; - // 解析 - var stmt = SqlParser.parseStatement(sql); - assertTrue(stmt instanceof SelectStatement); - log.info("Parsed: {}", stmt); - // 测试 - var where = ((SelectStatement) stmt).getWhere(); - var params = new HashMap(); - params.put(new ColumnIdentifier("account", "ID"), 2); - params.put(new ColumnIdentifier("payment", "type"), "L"); - assertFalse(where.evaluate(params)); - // - params.put(new ColumnIdentifier("payment", "type"), "N"); - assertTrue(where.evaluate(params)); - // TODO 其他测试暂时懒得写,太麻烦了,目检正确 - } -} \ No newline at end of file diff --git a/src/test/java/net/kaaass/rumbase/parse/parser/UpdateStatementParserTest.java b/src/test/java/net/kaaass/rumbase/parse/parser/UpdateStatementParserTest.java deleted file mode 100644 index 8a71284..0000000 --- a/src/test/java/net/kaaass/rumbase/parse/parser/UpdateStatementParserTest.java +++ /dev/null @@ -1,56 +0,0 @@ -package net.kaaass.rumbase.parse.parser; - -import junit.framework.TestCase; -import lombok.extern.slf4j.Slf4j; -import net.kaaass.rumbase.parse.ColumnIdentifier; -import net.kaaass.rumbase.parse.SqlParser; -import net.kaaass.rumbase.parse.exception.SqlSyntaxException; -import net.kaaass.rumbase.parse.stmt.UpdateStatement; - -import java.util.HashMap; -import java.util.List; - -@Slf4j -public class UpdateStatementParserTest extends TestCase { - - public void testParse() throws SqlSyntaxException { - var sql = "UPDATE Person SET Address = 'Zhongshan 23', City = 'Nanjing'\n" + - "WHERE LastName = 'Wilson'"; - // 解析 - var stmt = SqlParser.parseStatement(sql); - assertTrue(stmt instanceof UpdateStatement); - log.info("Parsed: {}", stmt); - // 比较 - assertEquals("Person", ((UpdateStatement) stmt).getTableName()); - assertEquals(List.of( - new ColumnIdentifier("Person", "Address"), - new ColumnIdentifier("Person", "City") - ), ((UpdateStatement) stmt).getColumns()); - assertEquals("Person", ((UpdateStatement) stmt).getTableName()); - assertEquals(List.of("'Zhongshan 23'", "'Nanjing'"), ((UpdateStatement) stmt).getValues()); - // 测试 where - var params = new HashMap(); - params.put(new ColumnIdentifier("Person", "LastName"), "Wilson"); - assertTrue(((UpdateStatement) stmt).getWhere().evaluate(params)); - // - params.put(new ColumnIdentifier("Person", "LastName"), "KAAAsS"); - assertFalse(((UpdateStatement) stmt).getWhere().evaluate(params)); - } - - public void testParseNull() throws SqlSyntaxException { - var sql = "UPDATE Person SET Address = 'Zhongshan 23', City = 'Nanjing'"; - // 解析 - var stmt = SqlParser.parseStatement(sql); - assertTrue(stmt instanceof UpdateStatement); - log.info("Parsed: {}", stmt); - // 比较 - assertEquals("Person", ((UpdateStatement) stmt).getTableName()); - assertEquals(List.of( - new ColumnIdentifier("Person", "Address"), - new ColumnIdentifier("Person", "City") - ), ((UpdateStatement) stmt).getColumns()); - assertEquals("Person", ((UpdateStatement) stmt).getTableName()); - assertEquals(List.of("'Zhongshan 23'", "'Nanjing'"), ((UpdateStatement) stmt).getValues()); - assertNull(((UpdateStatement) stmt).getWhere()); - } -} \ No newline at end of file diff --git a/src/test/java/net/kaaass/rumbase/query/CreateIndexExecutorTest.java b/src/test/java/net/kaaass/rumbase/query/CreateIndexExecutorTest.java deleted file mode 100644 index 0a52345..0000000 --- a/src/test/java/net/kaaass/rumbase/query/CreateIndexExecutorTest.java +++ /dev/null @@ -1,109 +0,0 @@ -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; -import net.kaaass.rumbase.parse.stmt.CreateIndexStatement; -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 { - - @BeforeClass - @AfterClass - public static void clearDataFolder() { - log.info("清除数据文件夹..."); - FileUtil.removeDir(FileUtil.DATA_PATH); - } - - @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); - Assert.assertTrue(stmt instanceof CreateIndexStatement); - // 准备预期结果 - var manager = new TableManager(); - var context = TransactionContext.empty(); - var fields = new ArrayList(); - fields.add(new VarcharField("LastName", 20, false, null)); - try { - manager.createTable(context, "testParseSingle$Person", fields, FileUtil.TABLE_PATH + "testParseSingle.Person.db"); - } catch (TableExistenceException | RecordNotFoundException | ArgumentException | TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - try { - var table = manager.getTable("testParseSingle$Person"); - var field = table.getField("LastName"); - Assert.assertTrue(field.isPresent()); - Assert.assertFalse(field.get().indexed()); - - var createExe = new CreateIndexExecutor((CreateIndexStatement) stmt, manager, context); - createExe.execute(); - - Assert.assertTrue(field.get().indexed()); - Assert.assertEquals("data/index/testParseSingle$Person$LastName", field.get().getIndexName()); - } catch (TableExistenceException | IndexAlreadyExistException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - } - - @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); - Assert.assertTrue(stmt instanceof CreateIndexStatement); - // 准备预期结果 - var manager = new TableManager(); - var context = TransactionContext.empty(); - var fields = new ArrayList(); - fields.add(new VarcharField("LastName", 20, false, null)); - fields.add(new IntField("ID", false, null)); - try { - manager.createTable(context, "testParseMulti$Person", fields, FileUtil.TABLE_PATH + "testParseMulti.Person.db"); - } catch (TableExistenceException | RecordNotFoundException | ArgumentException | TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - try { - var table = manager.getTable("testParseMulti$Person"); - var field1 = table.getField("LastName"); - var field2 = table.getField("ID"); - 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, context); - createExe.execute(); - - 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); - Assert.fail(); - } - } -} diff --git a/src/test/java/net/kaaass/rumbase/query/CreateTableExecutorTest.java b/src/test/java/net/kaaass/rumbase/query/CreateTableExecutorTest.java deleted file mode 100644 index 7c1b01d..0000000 --- a/src/test/java/net/kaaass/rumbase/query/CreateTableExecutorTest.java +++ /dev/null @@ -1,85 +0,0 @@ -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; -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; -import net.kaaass.rumbase.table.exception.TableExistenceException; -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 { - - @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" + - "LastName varchar(255),\n" + - "FirstName varchar(255) NOT NULL\n" + - ")"; - // 解析 - var stmt = SqlParser.parseStatement(sql); - Assert.assertTrue(stmt instanceof CreateTableStatement); - // 执行 - var manager = new TableManager(); - var context = TransactionContext.empty(); - var exe = new CreateTableExecutor((CreateTableStatement) stmt, manager, context); - try { - exe.execute(); - } catch (TableExistenceException | TableConflictException | ArgumentException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - // 确认结果 - Table table = null; - try { - table = manager.getTable("testCreate$Persons"); - } catch (TableExistenceException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - Assert.assertNotNull(table); - var fields = table.getFields(); - 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()); - - - 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()); - - - 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 deleted file mode 100644 index 0a8387d..0000000 --- a/src/test/java/net/kaaass/rumbase/query/DeleteExecutorTest.java +++ /dev/null @@ -1,195 +0,0 @@ -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; -import net.kaaass.rumbase.parse.stmt.DeleteStatement; -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; -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 DeleteExecutorTest { - - @BeforeClass - @AfterClass - public static void clearDataFolder() { - log.info("清除数据文件夹..."); - FileUtil.removeDir(new File(FileUtil.DATA_PATH)); - } - - @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); - Assert.assertTrue(stmt instanceof DeleteStatement); - - var manager = new TableManager(); - var context = TransactionContext.empty(); - var fields = new ArrayList(); - 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, FileUtil.TABLE_PATH + "testDelete.Person.db"); - id.createIndex(); - table = manager.getTable("testDelete$Person"); - } catch (TableExistenceException | IndexAlreadyExistException | RecordNotFoundException | ArgumentException | TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - Assert.assertNotNull(table); - try { - table.insert(context, new ArrayList<>() {{ - add(0, "'KevinAxel'"); - add(1, "1"); - }}); - table.insert(context, new ArrayList<>() {{ - add(0, "'KAAAsS'"); - add(1, "2"); - }}); - - } catch (TableConflictException | TableExistenceException | ArgumentException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - // 测试插入结果 - try { - var data = table.readAll(context); - Assert.assertEquals(2, data.size()); - - 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)); - - 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); - Assert.fail(); - } - - // 执行 - var exe = new DeleteExecutor((DeleteStatement) stmt, manager, context); - try { - exe.execute(); - } catch (TableExistenceException | ArgumentException | IndexAlreadyExistException | TableConflictException | RecordNotFoundException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - // 测试执行结果 - try { - var data = table.readAll(context); - Assert.assertEquals(1, data.size()); - - 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); - Assert.fail(); - } - } - - @Test - public void testDeleteAll() throws SqlSyntaxException, IndexAlreadyExistException, TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { - var sql = "DELETE FROM testDeleteAll$Person "; - // 解析 - var stmt = SqlParser.parseStatement(sql); - Assert.assertTrue(stmt instanceof DeleteStatement); - - var manager = new TableManager(); - var context = TransactionContext.empty(); - var fields = new ArrayList(); - 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, FileUtil.TABLE_PATH + "testDeleteAll.Person.db"); - id.createIndex(); - table = manager.getTable("testDeleteAll$Person"); - } catch (TableExistenceException | IndexAlreadyExistException | RecordNotFoundException | ArgumentException | TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - Assert.assertNotNull(table); - try { - table.insert(context, new ArrayList<>() {{ - add(0, "'KevinAxel'"); - add(1, "1"); - }}); - table.insert(context, new ArrayList<>() {{ - add(0, "'KAAAsS'"); - add(1, "2"); - }}); - - } catch (TableConflictException | TableExistenceException | ArgumentException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - // 测试插入结果 - try { - var data = table.readAll(context); - Assert.assertEquals(2, data.size()); - - 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)); - - 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); - Assert.fail(); - } - - // 执行 - var exe = new DeleteExecutor((DeleteStatement) stmt, manager, context); - try { - exe.execute(); - } catch (TableExistenceException | ArgumentException | IndexAlreadyExistException | TableConflictException | RecordNotFoundException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - // 测试执行结果 - try { - var data = table.readAll(context); - Assert.assertEquals(0, data.size()); - - } catch (TableExistenceException | TableConflictException | ArgumentException | RecordNotFoundException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - } -} diff --git a/src/test/java/net/kaaass/rumbase/query/InsertExecutorTest.java b/src/test/java/net/kaaass/rumbase/query/InsertExecutorTest.java deleted file mode 100644 index 2755b12..0000000 --- a/src/test/java/net/kaaass/rumbase/query/InsertExecutorTest.java +++ /dev/null @@ -1,109 +0,0 @@ -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; -import net.kaaass.rumbase.parse.stmt.InsertStatement; -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; -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 InsertExecutorTest { - - @BeforeClass - @AfterClass - public static void clearDataFolder() { - log.info("清除数据文件夹..."); - FileUtil.removeDir(new File(FileUtil.DATA_PATH)); - } - - @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); - Assert.assertTrue(stmt instanceof InsertStatement); - - var manager = new TableManager(); - var context = TransactionContext.empty(); - var fields = new ArrayList(); - var lastName = new VarcharField("LastName", 20, false, null); - fields.add(lastName); - fields.add(new VarcharField("Address", 255, false, null)); - Table table = null; - try { - manager.createTable(context, "Persons", fields, FileUtil.TABLE_PATH + "testInsertColumnValue.Persons.db"); - lastName.createIndex(); - table = manager.getTable("Persons"); - } catch (TableExistenceException | IndexAlreadyExistException | RecordNotFoundException | ArgumentException | TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - Assert.assertNotNull(table); - - // 执行 - var exe = new InsertExecutor((InsertStatement) stmt, manager, context); - try { - exe.execute(); - } catch (TableExistenceException | TableConflictException | ArgumentException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - // 确认结果 - try { - var data = table.readAll(context); - 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); - Assert.fail(); - } - } - - @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); - Assert.assertTrue(stmt instanceof InsertStatement); - - var manager = new TableManager(); - var context = TransactionContext.empty(); - var fields = new ArrayList(); - 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, FileUtil.TABLE_PATH + "testInsertValue.Person.db"); - id.createIndex(); - table = manager.getTable("Person"); - } catch (TableExistenceException | IndexAlreadyExistException | RecordNotFoundException | ArgumentException | TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - 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 deleted file mode 100644 index 7b3f7c9..0000000 --- a/src/test/java/net/kaaass/rumbase/query/SelectExecutorTest.java +++ /dev/null @@ -1,205 +0,0 @@ -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; -import net.kaaass.rumbase.parse.stmt.SelectStatement; -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; -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; - -@Slf4j -public class SelectExecutorTest { - - @BeforeClass - @AfterClass - public static void clearDataFolder() { - log.info("清除数据文件夹..."); - FileUtil.removeDir(new File(FileUtil.DATA_PATH)); - } - - @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" + - "order by testSelect$account.ID desc;"; - // 解析 - var stmt = SqlParser.parseStatement(sql); - - // 创建测试表 - var manager = new TableManager(); - var context = TransactionContext.empty(); - - // 创建account表 - var accountFields = new ArrayList(); - var id = new IntField("ID", false, null); - accountFields.add(id); - 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, FileUtil.TABLE_PATH + "testSelect.account.db"); - id.createIndex(); - account = manager.getTable("testSelect$account"); - } catch (TableExistenceException | IndexAlreadyExistException | RecordNotFoundException | ArgumentException | TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - Assert.assertNotNull(account); - try { - account.insert(context, new ArrayList<>() {{ - add(0, "1"); - add(1, "'KevinAxel'"); - add(2, "5000"); - }}); - account.insert(context, new ArrayList<>() {{ - add(0, "2"); - add(1, "'KAAAsS'"); - add(2, "8000"); - }}); - account.insert(context, new ArrayList<>() {{ - add(0, "3"); - add(1, "'kkk'"); - add(2, "8000"); - }}); - - } catch (TableConflictException | TableExistenceException | ArgumentException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - // 测试插入结果 - try { - var data = account.readAll(context); - Assert.assertEquals(3, data.size()); - - 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)); - - 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)); - - 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); - Assert.fail(); - } - - // 创建payment表 - var paymentFields = new ArrayList(); - var paymentId = new IntField("ID", false, null); - paymentFields.add(paymentId); - paymentFields.add(new VarcharField("type", 1, false, null)); - Table payment = null; - try { - manager.createTable(context, "testSelect$payment", paymentFields, FileUtil.TABLE_PATH + "testSelect.payment.db"); - paymentId.createIndex(); - payment = manager.getTable("testSelect$payment"); - } catch (TableExistenceException | IndexAlreadyExistException | RecordNotFoundException | ArgumentException | TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - Assert.assertNotNull(payment); - try { - payment.insert(context, new ArrayList<>() {{ - add(0, "1"); - add(1, "'N'"); - }}); - payment.insert(context, new ArrayList<>() {{ - add(0, "2"); - add(1, "'T'"); - }}); - payment.insert(context, new ArrayList<>() {{ - add(0, "3"); - add(1, "'T'"); - }}); - - } catch (TableConflictException | TableExistenceException | ArgumentException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - // 测试插入结果 - try { - var data = payment.readAll(context); - Assert.assertEquals(3, data.size()); - - 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)); - - 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)); - - 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); - Assert.fail(); - } - - // 执行语句 - var exe = new SelectExecutor((SelectStatement) stmt, manager, context); - try { - exe.execute(); - } catch (TableConflictException | ArgumentException | TableExistenceException | IndexAlreadyExistException | RecordNotFoundException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - var cols = exe.getResultTable(); - var data = exe.getResultData(); - - 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 deleted file mode 100644 index 0de8f0a..0000000 --- a/src/test/java/net/kaaass/rumbase/query/UpdateExecutorTest.java +++ /dev/null @@ -1,225 +0,0 @@ -package net.kaaass.rumbase.query; - -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.UpdateStatement; -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; -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 { - - @BeforeClass - @AfterClass - public static void clearDataFolder() { - log.info("清除数据文件夹..."); - FileUtil.removeDir(new File(FileUtil.DATA_PATH)); - } - - @Test - public void testUpdateWithCondition() throws SqlSyntaxException, IndexAlreadyExistException, TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { - var sql = "UPDATE testUpdateWithCondition$Person SET Address = 'Zhongshan 23', City = 'Nanjing'\n" + - "WHERE ID = 2"; - // 解析 - var stmt = SqlParser.parseStatement(sql); - 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 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, FileUtil.TABLE_PATH + "testUpdateWithCondition.Person.db"); - lastName.createIndex(); - table = manager.getTable("testUpdateWithCondition$Person"); - } catch (TableExistenceException | IndexAlreadyExistException | RecordNotFoundException | ArgumentException | TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - Assert.assertNotNull(table); - try { - table.insert(context, new ArrayList<>() {{ - 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); - Assert.fail(); - } - - // 测试插入结果 - try { - var data = table.readAll(context); - Assert.assertEquals(2, data.size()); - - 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)); - - - } catch (TableExistenceException | TableConflictException | ArgumentException | RecordNotFoundException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - // 执行 - var exe = new UpdateExecutor((UpdateStatement) stmt, manager, context); - try { - exe.execute(); - } catch (TableExistenceException | ArgumentException | IndexAlreadyExistException | TableConflictException | RecordNotFoundException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - // 检查执行结果 - try { - var data = table.readAll(context); - log.info("Result: {}", data); - Assert.assertEquals(2, data.size()); - - 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)); - - 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); - Assert.fail(); - } - } - - @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); - - - var manager = new TableManager(); - var context = TransactionContext.empty(); - var fields = new ArrayList(); - var lastName = new IntField("ID", false, null); - fields.add(lastName); - 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, FileUtil.TABLE_PATH + "testUpdateWithoutCondition.Person.db"); - lastName.createIndex(); - table = manager.getTable("testUpdateWithoutCondition$Person"); - } catch (TableExistenceException | IndexAlreadyExistException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - Assert.assertNotNull(table); - try { - table.insert(context, new ArrayList<>() {{ - add(0, "1"); - add(1, "'JiaXing'"); - add(2, "'Zhongshan 45'"); - }}); - table.insert(context, new ArrayList<>() {{ - add(0, "2"); - add(1, "'WenZhou'"); - add(2, "'Zhongshan 78'"); - }}); - - } catch (TableConflictException | TableExistenceException | ArgumentException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - // 测试插入结果 - try { - var data = table.readAll(context); - Assert.assertEquals(2, data.size()); - - 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)); - - 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); - Assert.fail(); - } - - // 执行 - var exe = new UpdateExecutor((UpdateStatement) stmt, manager, context); - try { - exe.execute(); - } catch (TableExistenceException | ArgumentException | IndexAlreadyExistException | TableConflictException | RecordNotFoundException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - // 检查执行结果 - try { - var data = table.readAll(context); - log.info("Result: {}", data); - Assert.assertEquals(2, data.size()); - - 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)); - - 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); - Assert.fail(); - } - } -} diff --git a/src/test/java/net/kaaass/rumbase/record/FakeTxContext.java b/src/test/java/net/kaaass/rumbase/record/FakeTxContext.java deleted file mode 100644 index f830edb..0000000 --- a/src/test/java/net/kaaass/rumbase/record/FakeTxContext.java +++ /dev/null @@ -1,52 +0,0 @@ -package net.kaaass.rumbase.record; - -import lombok.Data; -import lombok.extern.slf4j.Slf4j; -import net.kaaass.rumbase.transaction.TransactionContext; -import net.kaaass.rumbase.transaction.TransactionIsolation; -import net.kaaass.rumbase.transaction.TransactionManager; -import net.kaaass.rumbase.transaction.TransactionStatus; - -import java.util.List; - -/** - * 用于测试可见性等的假事务上下文 - */ -@Slf4j -@Data -public class FakeTxContext implements TransactionContext { - - private List snapshot; - - private TransactionIsolation isolation; - - private TransactionStatus status; - - private TransactionManager manager; - - private int xid; - - @Override - public void start() { - } - - @Override - public void commit() { - this.status = TransactionStatus.COMMITTED; - } - - @Override - public void rollback() { - this.status = TransactionStatus.ABORTED; - } - - @Override - public void sharedLock(long uuid, String tableName) { - log.info("申请共享锁 {}.{}", tableName, uuid); - } - - @Override - public void exclusiveLock(long uuid, String tableName) { - log.info("申请互斥锁 {}.{}", tableName, uuid); - } -} diff --git a/src/test/java/net/kaaass/rumbase/record/FakeTxManager.java b/src/test/java/net/kaaass/rumbase/record/FakeTxManager.java deleted file mode 100644 index f52adf0..0000000 --- a/src/test/java/net/kaaass/rumbase/record/FakeTxManager.java +++ /dev/null @@ -1,75 +0,0 @@ -package net.kaaass.rumbase.record; - -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import net.kaaass.rumbase.transaction.TransactionContext; -import net.kaaass.rumbase.transaction.TransactionIsolation; -import net.kaaass.rumbase.transaction.TransactionManager; -import net.kaaass.rumbase.transaction.TransactionStatus; - -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Collectors; - -/** - * 用于测试可见性等的假事务管理器 - */ -@RequiredArgsConstructor -public class FakeTxManager implements TransactionManager { - - private int txCount = 0; - - private final Map txContextMap = new HashMap<>(); - - @NonNull - private final TransactionIsolation isolation; - - @Override - public TransactionContext createTransactionContext(TransactionIsolation isolation) { - var newTx = new FakeTxContext(); - newTx.setXid(++txCount); - newTx.setIsolation(isolation); - newTx.setManager(this); - var snapshot = - txContextMap.entrySet() - .stream() - .filter(tx -> tx.getValue().getStatus() == TransactionStatus.ACTIVE) - .map(Map.Entry::getKey) - .collect(Collectors.toList()); - newTx.setSnapshot(snapshot); - newTx.setStatus(TransactionStatus.ACTIVE); - txContextMap.put(txCount, newTx); - return newTx; - } - - public TransactionContext begin() { - return createTransactionContext(this.isolation); - } - - public TransactionContext begin(int xid) { - var newTx = new FakeTxContext(); - newTx.setXid(xid); - newTx.setIsolation(this.isolation); - newTx.setManager(this); - var snapshot = - txContextMap.entrySet() - .stream() - .filter(tx -> tx.getValue().getStatus() == TransactionStatus.ACTIVE) - .map(Map.Entry::getKey) - .collect(Collectors.toList()); - newTx.setSnapshot(snapshot); - newTx.setStatus(TransactionStatus.ACTIVE); - txContextMap.put(xid, newTx); - return newTx; - } - - @Override - public TransactionContext getContext(int xid) { - return txContextMap.get(xid); - } - - @Override - public void changeTransactionStatus(int xid, TransactionStatus status) { - throw new UnsupportedOperationException(); - } -} diff --git a/src/test/java/net/kaaass/rumbase/record/IRecordStorageTest.java b/src/test/java/net/kaaass/rumbase/record/IRecordStorageTest.java deleted file mode 100644 index 5667e1e..0000000 --- a/src/test/java/net/kaaass/rumbase/record/IRecordStorageTest.java +++ /dev/null @@ -1,92 +0,0 @@ -package net.kaaass.rumbase.record; - -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; - -import static org.junit.Assert.assertArrayEquals; - -/** - * 测试记录存储接口 - * - * @author kaaass - * @see net.kaaass.rumbase.record.IRecordStorage - */ -@Slf4j -public class IRecordStorageTest { - - @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()); - 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(); - - var id = storage.insert(context, new byte[]{0x1, 0x2, 0x1f}); - var result = storage.queryOptional(context, id); - - 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(); - - storage.insert(context, new byte[]{0x1, 0x2}); - 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); - Assert.assertTrue("result should present", result.isPresent()); - - storage.delete(context, id); - result = storage.queryOptional(context, id); - - Assert.assertTrue("record should be deleted", result.isEmpty()); - } - - @Test - public void testMetadata() { - var storage = RecordManager.fromFile(PATH + "test_metadata"); - var context = TransactionContext.empty(); - - var result = storage.getMetadata(context); - assertArrayEquals("default metadata should be empty", new byte[0], result); - - storage.setMetadata(context, new byte[]{0x23, 0x45, 0x67}); - assertArrayEquals(new byte[]{0x23, 0x45, 0x67}, storage.getMetadata(context)); - } -} \ No newline at end of file diff --git a/src/test/java/net/kaaass/rumbase/record/MvccReadCommitTest.java b/src/test/java/net/kaaass/rumbase/record/MvccReadCommitTest.java deleted file mode 100644 index 772c9e8..0000000 --- a/src/test/java/net/kaaass/rumbase/record/MvccReadCommitTest.java +++ /dev/null @@ -1,192 +0,0 @@ -package net.kaaass.rumbase.record; - -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 net.kaaass.rumbase.transaction.exception.StatusException; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import java.io.IOException; - -@Slf4j -public class MvccReadCommitTest { - - @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); - // 创建事务1 - var tx1 = manager.begin(); - // 事务1的记录自身可见 - var a1 = storage.insert(tx1, new byte[]{0x23, 0x63}); - Assert.assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); - // 事务2不可见a1 - var tx2 = manager.begin(); - 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}); - Assert.assertTrue("uuid see a1", storage.queryOptional(tx1, uuid).isPresent()); - } - } - - @Test - public void testReadOther() throws RecordNotFoundException, StatusException { - var storage = RecordManager.fromFile(PATH + "testReadOther"); - var manager = new FakeTxManager(TransactionIsolation.READ_COMMITTED); - // 创建事务12 - var tx1 = manager.begin(); - var tx2 = manager.begin(); - // 事务2创建的b1,事务1不可见 - var b1 = storage.insert(tx2, new byte[]{0x1, 0x2, 0x3}); - 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}); - 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(); - Assert.assertTrue("tx1 see b1 after commit", storage.queryOptional(tx1, b1).isPresent()); - // 新建事务3 - var tx3 = manager.begin(); - // 事务3可以看到b1,但是不能看到a1 - 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(); - Assert.assertTrue("tx3 see a1 after commit", storage.queryOptional(tx3, a1).isPresent()); - } - - @Test - public void testDelete() throws RecordNotFoundException, StatusException { - var storage = RecordManager.fromFile(PATH + "testDelete"); - var manager = new FakeTxManager(TransactionIsolation.READ_COMMITTED); - // 创建事务1、记录a1a2 - var tx1 = manager.begin(); - var a1 = storage.insert(tx1, new byte[]{0x1, 0x2, 0x3}); - var a2 = storage.insert(tx1, new byte[]{0x5, 0x6, 0x7}); - Assert.assertTrue(storage.queryOptional(tx1, a1).isPresent()); - Assert.assertTrue(storage.queryOptional(tx1, a2).isPresent()); - // 自身删除 - storage.delete(tx1, a1); - 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); - 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(); - Assert.assertTrue("tx3 blind a2 after commit", storage.queryOptional(tx3, a2).isEmpty()); - } - - @Test - public void testReadSelfReal() throws RecordNotFoundException, IOException, FileException, StatusException { - var storage = RecordManager.fromFile(PATH + "testReadSelfReal"); - var manager = new TransactionManagerImpl(); - // 创建事务1 - var tx1 = manager.createTransactionContext(TransactionIsolation.READ_COMMITTED); - tx1.start(); - // 事务1的记录自身可见 - var a1 = storage.insert(tx1, new byte[]{0x23, 0x63}); - Assert.assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); - // 事务2不可见a1 - var tx2 = manager.createTransactionContext(TransactionIsolation.READ_COMMITTED); - tx2.start(); - 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}); - Assert.assertTrue("uuid see a1", storage.queryOptional(tx1, uuid).isPresent()); - } - // - tx1.commit(); - tx2.commit(); - } - - @Test - public void testReadOtherReal() throws RecordNotFoundException, IOException, FileException, StatusException { - var storage = RecordManager.fromFile(PATH + "testReadOtherReal"); - var manager = new TransactionManagerImpl(); - // 创建事务12 - var tx1 = manager.createTransactionContext(TransactionIsolation.READ_COMMITTED); - tx1.start(); - var tx2 = manager.createTransactionContext(TransactionIsolation.READ_COMMITTED); - tx2.start(); - // 事务2创建的b1,事务1不可见 - var b1 = storage.insert(tx2, new byte[]{0x1, 0x2, 0x3}); - 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}); - 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(); - 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 - 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(); - Assert.assertTrue("tx3 see a1 after commit", storage.queryOptional(tx3, a1).isPresent()); - tx3.commit(); - } - - @Test - public void testDeleteReal() throws RecordNotFoundException, IOException, FileException, StatusException { - var storage = RecordManager.fromFile(PATH + "testDeleteReal"); - var manager = new TransactionManagerImpl(); - // 创建事务1、记录a1a2 - var tx1 = manager.createTransactionContext(TransactionIsolation.READ_COMMITTED); - tx1.start(); - var a1 = storage.insert(tx1, new byte[]{0x1, 0x2, 0x3}); - var a2 = storage.insert(tx1, new byte[]{0x5, 0x6, 0x7}); - Assert.assertTrue(storage.queryOptional(tx1, a1).isPresent()); - Assert.assertTrue(storage.queryOptional(tx1, a2).isPresent()); - // 自身删除 - storage.delete(tx1, a1); - Assert.assertTrue("a1 should be deleted", storage.queryOptional(tx1, a1).isEmpty()); - // 提交事务1 - tx1.commit(); - // 事务2删除,事务3仍然可见a2 - var tx2 = manager.createTransactionContext(TransactionIsolation.READ_COMMITTED); - tx2.start(); - var tx3 = manager.createTransactionContext(TransactionIsolation.READ_COMMITTED); - tx3.start(); - storage.delete(tx2, a2); - 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(); - 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 deleted file mode 100644 index 91d1e2e..0000000 --- a/src/test/java/net/kaaass/rumbase/record/MvccReadRepeatableTest.java +++ /dev/null @@ -1,243 +0,0 @@ -package net.kaaass.rumbase.record; - -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; -import net.kaaass.rumbase.transaction.TransactionContext; -import net.kaaass.rumbase.transaction.TransactionIsolation; -import net.kaaass.rumbase.transaction.TransactionManager; -import net.kaaass.rumbase.transaction.TransactionManagerImpl; -import net.kaaass.rumbase.transaction.exception.StatusException; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import java.io.IOException; - -@Slf4j -public class MvccReadRepeatableTest { - - @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); - // 创建事务1 - var tx1 = manager.begin(); - // 事务1的记录自身可见 - var a1 = storage.insert(tx1, new byte[]{0x23, 0x63}); - Assert.assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); - // 事务2不可见a1 - var tx2 = manager.begin(); - 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}); - Assert.assertTrue("uuid see a1", storage.queryOptional(tx1, uuid).isPresent()); - } - } - - @Test - public void testReadOther() throws RecordNotFoundException, StatusException { - var storage = RecordManager.fromFile(PATH + "testReadOther"); - var manager = new FakeTxManager(TransactionIsolation.REPEATABLE_READ); - // 创建事务12 - var tx1 = manager.begin(); - var tx2 = manager.begin(); - // 事务2创建的b1,事务1不可见 - var b1 = storage.insert(tx2, new byte[]{0x1, 0x2, 0x3}); - 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}); - 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(); - Assert.assertTrue("tx1 blind b1 after commit", storage.queryOptional(tx1, b1).isEmpty()); - // 新建事务3 - var tx3 = manager.begin(); - // 事务3可以看到b1,但是不能看到a1 - 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(); - Assert.assertTrue("tx3 blind a1 after commit", storage.queryOptional(tx3, a1).isEmpty()); - } - - @Test - public void testDelete() throws RecordNotFoundException, StatusException { - var storage = RecordManager.fromFile(PATH + "testDelete"); - var manager = new FakeTxManager(TransactionIsolation.REPEATABLE_READ); - // 创建事务1、记录a1a2 - var tx1 = manager.begin(); - var a1 = storage.insert(tx1, new byte[]{0x1, 0x2, 0x3}); - var a2 = storage.insert(tx1, new byte[]{0x5, 0x6, 0x7}); - Assert.assertTrue(storage.queryOptional(tx1, a1).isPresent()); - Assert.assertTrue(storage.queryOptional(tx1, a2).isPresent()); - // 自身删除 - storage.delete(tx1, a1); - 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); - 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(); - Assert.assertTrue("tx3 see a2 after commit", storage.queryOptional(tx3, a2).isPresent()); - } - - @Test - public void testVersionSkip() throws RecordNotFoundException, NeedRollbackException, StatusException { - var storage = RecordManager.fromFile(PATH + "testDelete"); - var manager = new FakeTxManager(TransactionIsolation.REPEATABLE_READ); - // 创建公共版本 - var r = storage.insert(TransactionContext.empty(), new byte[]{0x1, 0x2, 0x3, 0x4}); - // 进行版本跳跃操作 - var tx1 = manager.begin(); - var tx2 = manager.begin(); - 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); - 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, StatusException { - var storage = RecordManager.fromFile(PATH + "testReadSelfReal"); - var manager = new TransactionManagerImpl(); - // 创建事务1 - var tx1 = manager.createTransactionContext(TransactionIsolation.REPEATABLE_READ); - tx1.start(); - // 事务1的记录自身可见 - var a1 = storage.insert(tx1, new byte[]{0x23, 0x63}); - Assert.assertTrue("tx1 see a1", storage.queryOptional(tx1, a1).isPresent()); - // 事务2不可见a1 - var tx2 = manager.createTransactionContext(TransactionIsolation.REPEATABLE_READ); - tx2.start(); - 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}); - Assert.assertTrue("uuid see a1", storage.queryOptional(tx1, uuid).isPresent()); - } - // - tx1.commit(); - tx2.commit(); - } - - @Test - public void testReadOtherReal() throws RecordNotFoundException, IOException, FileException, StatusException { - var storage = RecordManager.fromFile(PATH + "testReadOtherReal"); - var manager = new TransactionManagerImpl(); - // 创建事务12 - var tx1 = manager.createTransactionContext(TransactionIsolation.REPEATABLE_READ); - tx1.start(); - var tx2 = manager.createTransactionContext(TransactionIsolation.REPEATABLE_READ); - tx2.start(); - // 事务2创建的b1,事务1不可见 - var b1 = storage.insert(tx2, new byte[]{0x1, 0x2, 0x3}); - 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}); - 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(); - 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 - 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(); - Assert.assertTrue("tx3 blind a1 after commit", storage.queryOptional(tx3, a1).isEmpty()); - // - tx3.commit(); - } - - @Test - public void testDeleteReal() throws RecordNotFoundException, IOException, FileException, StatusException { - var storage = RecordManager.fromFile(PATH + "testDeleteReal"); - var manager = new TransactionManagerImpl(); - // 创建事务1、记录a1a2 - var tx1 = manager.createTransactionContext(TransactionIsolation.REPEATABLE_READ); - tx1.start(); - var a1 = storage.insert(tx1, new byte[]{0x1, 0x2, 0x3}); - var a2 = storage.insert(tx1, new byte[]{0x5, 0x6, 0x7}); - Assert.assertTrue(storage.queryOptional(tx1, a1).isPresent()); - Assert.assertTrue(storage.queryOptional(tx1, a2).isPresent()); - // 自身删除 - storage.delete(tx1, a1); - Assert.assertTrue("a1 should be deleted", storage.queryOptional(tx1, a1).isEmpty()); - // 提交事务1 - tx1.commit(); - // 事务2删除,事务3仍然可见a2 - var tx2 = manager.createTransactionContext(TransactionIsolation.REPEATABLE_READ); - tx2.start(); - var tx3 = manager.createTransactionContext(TransactionIsolation.REPEATABLE_READ); - tx3.start(); - storage.delete(tx2, a2); - 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(); - Assert.assertTrue("tx3 see a2 after commit", storage.queryOptional(tx3, a2).isPresent()); - // - tx3.commit(); - } - - @Test - public void testVersionSkipReal() throws RecordNotFoundException, NeedRollbackException, IOException, FileException, StatusException { - var storage = RecordManager.fromFile(PATH + "testDeleteReal"); - var manager = new TransactionManagerImpl(); - // 创建公共版本 - var r = storage.insert(TransactionContext.empty(), new byte[]{0x1, 0x2, 0x3, 0x4}); - // 进行版本跳跃操作 - var tx1 = manager.createTransactionContext(TransactionIsolation.REPEATABLE_READ); - tx1.start(); - var tx2 = manager.createTransactionContext(TransactionIsolation.REPEATABLE_READ); - tx2.start(); - 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); - Assert.fail("Should rollback tx2 at here"); - tx2.commit(); - } catch (NeedRollbackException e) { - log.info("Expected runtime exception: ", e); - tx2.rollback(); - } - } -} diff --git a/src/test/java/net/kaaass/rumbase/record/MvccUtilTest.java b/src/test/java/net/kaaass/rumbase/record/MvccUtilTest.java deleted file mode 100644 index f239fac..0000000 --- a/src/test/java/net/kaaass/rumbase/record/MvccUtilTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.kaaass.rumbase.record; - -import junit.framework.TestCase; -import lombok.extern.slf4j.Slf4j; - -import java.util.Random; - -@Slf4j -public class MvccUtilTest extends TestCase { - - public void testReadWriteInt() { - byte[] arr = new byte[5]; - for (int i = 0; i < Integer.MAX_VALUE - 100; i += 50) { - MvccUtil.writeInt(arr, 1, i); - assertEquals(i, MvccUtil.readInt(arr, 1)); - } - } - - public void testReadWriteLong() { - byte[] arr = new byte[13]; - var rand = new Random(); - for (int i = 0; i < 10000; i++) { - long num = rand.nextLong(); - MvccUtil.writeLong(arr, 4, num); - assertEquals(num, MvccUtil.readLong(arr, 4)); - } - } -} \ No newline at end of file diff --git a/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java b/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java deleted file mode 100644 index a94f553..0000000 --- a/src/test/java/net/kaaass/rumbase/recovery/IRecoveryTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package net.kaaass.rumbase.recovery; - -import junit.framework.TestCase; -import lombok.extern.slf4j.Slf4j; - -import java.util.ArrayList; -import java.util.List; - -import static org.junit.Assert.assertArrayEquals; - -/** - * TODO 文档 - */ -@Slf4j -public class IRecoveryTest extends TestCase { - - public void testBegin() { - IRecoveryStorage iRecoveryStorage = RecoveryManager.recovery("user.db"); - List l = new ArrayList<>(); - int xid = 1; - l.add(3); - l.add(2); - iRecoveryStorage.begin(xid, l); - - var content = iRecoveryStorage.getContent(); - String beginStr = "begin " + xid; - String snapStr = "snap " + l.toString(); - List result = new ArrayList<>(); - result.add(beginStr.getBytes()); - result.add(snapStr.getBytes()); - assertEquals(result.size(), content.size()); - assertArrayEquals(result.get(0), content.get(0)); - assertArrayEquals(result.get(1), content.get(1)); - } -} diff --git a/src/test/java/net/kaaass/rumbase/table/BaseFieldTest.java b/src/test/java/net/kaaass/rumbase/table/BaseFieldTest.java deleted file mode 100644 index b9076df..0000000 --- a/src/test/java/net/kaaass/rumbase/table/BaseFieldTest.java +++ /dev/null @@ -1,559 +0,0 @@ -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.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; -import java.util.ArrayList; - -import static org.junit.Assert.assertArrayEquals; - -/** - * 字段结构测试 - * - * @author @KveinAxel - * @see BaseField - */ -@Slf4j -public class BaseFieldTest { - - @BeforeClass - @AfterClass - public static void clearDataFolder() { - log.info("清除数据文件夹..."); - FileUtil.removeDir(FileUtil.DATA_PATH); - } - - @Test - public void testCheckStr() { - - // test int - 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, 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, null); - Assert.assertTrue(varcharField.checkStr("'aaaa'")); - Assert.assertFalse(varcharField.checkStr("'aaaa aaaa aaaa aaaa aaaa'")); - - } - - @Test - public void testDeserialize() { - - // 测试数据 - var bytes = new byte[]{ - 0, - 0, 0, 0, 33, // int 33 - 0, - 63, -103, -103, -102, // float 1.2 - 0, - 12, - 116, 101, 115, 116, - 32, 118, 97, 114, - 99, 104, 97, 114 // varchar test varchar - }; - var inputStream = new ByteArrayInputStream(bytes); - - var intField = new IntField("testDeserializeInt", false, null); - try { - var intRes = (int) intField.deserialize(inputStream); - Assert.assertEquals(33, intRes); - } catch (TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail("proper format should not fail to parse"); - } - - var floatField = new FloatField("testDeserializeFloat", false, null); - try { - var floatRes = (float) floatField.deserialize(inputStream); - Assert.assertTrue(1.2f - floatRes < 0.0001); - } catch (TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail("proper format should not fail to parse"); - } - - var varcharField = new VarcharField("testDeserializeVarchar", 20, false, null); - try { - var varcharRes = (String) varcharField.deserialize(inputStream); - Assert.assertEquals("test varchar", varcharRes); - } catch (TableConflictException e) { - Assert.fail("proper format should not fail to parse"); - } - - Assert.assertEquals(0, inputStream.available()); - - } - - @Test - public void testCheckInputStream() { - - // 测试数据 - var bytes = new byte[]{ - 0, - 0, 0, 0, 33, // int 33 - 0, - 63, -103, -103, -102, // float 1.2 - 0, - 12, - 116, 101, 115, 116, - 32, 118, 97, 114, - 99, 104, 97, 114 // varchar test varchar - }; - var inputStream = new ByteArrayInputStream(bytes); - - var intField = new IntField("testCheckInputStreamInt", false, null); - Assert.assertTrue(intField.checkInputStream(inputStream)); - - var floatField = new FloatField("testCheckInputStreamFloat", false, null); - Assert.assertTrue(floatField.checkInputStream(inputStream)); - - var varcharField = new VarcharField("testCheckInputStreamVarchar", 20, false, null); - Assert.assertTrue(varcharField.checkInputStream(inputStream)); - - Assert.assertEquals(0, inputStream.available()); - } - - @Test - public void testSerialize() { - - - var intField = new IntField("testSerializeInt", false, null); - var intBos1 = new ByteArrayOutputStream(); - var intBos2 = new ByteArrayOutputStream(); - - try { - intField.serialize(intBos1, "33"); - var expected = new byte[]{ - 0, - 0, 0, 0, 33, // int 33 - }; - assertArrayEquals(expected, intBos1.toByteArray()); - } catch (TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - intField.serialize(intBos2, "'xx'"); - Assert.fail(); - } catch (TableConflictException e) { - log.error("Exception expected: ", e); - } - - var floatField = new FloatField("testSerializeFloat", false, null); - var floatBos1 = new ByteArrayOutputStream(); - var floatBos2 = new ByteArrayOutputStream(); - - try { - floatField.serialize(floatBos1, "1.2"); - var expected = new byte[]{ - 0, - 63, -103, -103, -102, // float 1.2 - }; - assertArrayEquals(expected, floatBos1.toByteArray()); - } catch (TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - floatField.serialize(floatBos2, "'xx'"); - Assert.fail(); - } catch (TableConflictException e) { - log.error("Exception expected: ", e); - } - - var varcharField = new VarcharField("testSerializeVarchar", 20, false, null); - var varcharBos1 = new ByteArrayOutputStream(); - var varcharBos2 = new ByteArrayOutputStream(); - - try { - varcharField.serialize(varcharBos1, "'test varchar'"); - var expected = new byte[]{ - 0, - 12, - 116, 101, 115, 116, - 32, 118, 97, 114, - 99, 104, 97, 114 // varchar test varchar - }; - assertArrayEquals(expected, varcharBos1.toByteArray()); - } catch (TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - varcharField.serialize(varcharBos2, "'test varchar too looooooooooooong'"); - Assert.fail(); - } catch (TableConflictException e) { - log.error("Exception expected: ", e); - } - - } - - @Test - public void testDoubleCreateIndex() { - 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); - Assert.fail(); - } - - try { - field.createIndex(); - Assert.fail(); - } catch (IndexAlreadyExistException e) { - log.error("Exception expected: ", e); - } - } - - @Test - public void testInsertIndex() { - var dummy = new Table("testInsertIndexTable", new ArrayList<>()); - - var intField = new IntField("testInsertIndexInt", false, dummy); - - try { - intField.insertIndex("1", 1); - Assert.fail(); - } catch (TableExistenceException | TableConflictException e) { - log.error("Exception expected: ", e); - } - - try { - intField.createIndex(); - } catch (IndexAlreadyExistException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - intField.insertIndex("1", 1); - intField.insertIndex("1", 1); - } catch (TableExistenceException | TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - intField.insertIndex("1xx", 1); - Assert.fail(); - } catch (TableExistenceException | TableConflictException e) { - log.error("Exception expected: ", e); - } - - var floatField = new FloatField("testInsertIndexFloat", false, dummy); - - try { - floatField.insertIndex("1.2", 1); - Assert.fail(); - } catch (TableExistenceException | TableConflictException e) { - log.error("Exception expected: ", e); - } - - try { - floatField.createIndex(); - } catch (IndexAlreadyExistException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - floatField.insertIndex("1.2", 1); - floatField.insertIndex("1.2", 1); - } catch (TableExistenceException | TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - floatField.insertIndex("1xx", 1); - Assert.fail(); - } catch (TableExistenceException | TableConflictException e) { - log.error("Exception expected: ", e); - } - - - var varcharField = new VarcharField("testInsertIndexVarchar", 20, false, dummy); - - try { - varcharField.insertIndex("xxx", 1); - Assert.fail(); - } catch (TableExistenceException e) { - log.error("Exception expected: ", e); - } - - try { - varcharField.createIndex(); - } catch (IndexAlreadyExistException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - varcharField.insertIndex("xxx", 1); - varcharField.insertIndex("xxx", 1); - } catch (TableExistenceException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - } - - @Test - public void testQueryIndex() { - - var dummy = new Table("testQueryIndexTable", new ArrayList<>()); - - var intField = new IntField("testQueryIndexInt", false, dummy); - - try { - intField.createIndex(); - } catch (IndexAlreadyExistException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - intField.insertIndex("1", 1); - intField.insertIndex("1", 1); - } catch (TableExistenceException | TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - var uuid = intField.queryIndex("1"); - Assert.assertEquals(1, uuid.get(0).longValue()); - Assert.assertEquals(1, uuid.get(1).longValue()); - } catch (TableExistenceException | TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - var uuid = intField.queryIndex("2"); - Assert.assertTrue(uuid.isEmpty()); - } catch (TableExistenceException | TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - var floatField = new FloatField("testQueryIndexFloat", false, dummy); - - try { - floatField.createIndex(); - } catch (IndexAlreadyExistException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - floatField.insertIndex("1.2", 1); - floatField.insertIndex("1.2", 1); - } catch (TableExistenceException | TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - var uuid = floatField.queryIndex("1.2"); - Assert.assertEquals(1, uuid.get(0).longValue()); - Assert.assertEquals(1, uuid.get(1).longValue()); - } catch (TableExistenceException | TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - var uuid = floatField.queryIndex("2.2"); - Assert.assertTrue(uuid.isEmpty()); - } catch (TableExistenceException | TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - var varcharField = new VarcharField("testQueryIndexVarchar", 20, false, dummy); - - try { - varcharField.createIndex(); - } catch (IndexAlreadyExistException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - varcharField.insertIndex("xxx", 1); - varcharField.insertIndex("xxx", 1); - } catch (TableExistenceException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - var uuid = varcharField.queryIndex("xxx"); - Assert.assertEquals(1, uuid.get(0).longValue()); - Assert.assertEquals(1, uuid.get(1).longValue()); - } catch (TableExistenceException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - var uuid = varcharField.queryIndex("x"); - Assert.assertTrue(uuid.isEmpty()); - } catch (TableExistenceException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - } - - @Test - public void testLoad() throws IndexNotFoundException { - var bytes = new byte[]{ - // testLoadInt - 11, - 116, 101, 115, 116, - 76, 111, 97, 100, - 73, 110, 116, - - // INT - 3, - 73, 78, 84, - - // 00 not nullable and no index - 0, - - // testLoadFloat - 13, - 116, 101, 115, 116, - 76, 111, 97, 100, - 70, 108, 111, 97, 116, - - // FLOAT - 5, - 70, 76, 79, 65, 84, - - 0, - - // testLoadVarchar - 15, - 116, 101, 115, 116, - 76, 111, 97, 100, - 86, 97, 114, 99, - 104, 97, 114, - - // VARCHAR - 7, - 86, 65, 82, 67, - 72, 65, 82, - - 0, - - // 12 - 0, 0, 0, 12 - - }; - var stream = new ByteArrayInputStream(bytes); - - 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, null); - Assert.assertNotNull(floatField); - Assert.assertEquals("testLoadFloat", floatField.getName()); - Assert.assertEquals(FieldType.FLOAT, floatField.getType()); - - 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 out = new ByteArrayOutputStream(); - - 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); - varcharField.persist(out); - - var expected = new byte[]{ - // testPersistInt - 14, - 116, 101, 115, 116, - 80, 101, 114, 115, - 105, 115, 116, 73, 110, 116, - - // INT - 3, - 73, 78, 84, - - 0, - - // testPersistFloat - 16, - 116, 101, 115, 116, - 80, 101, 114, 115, - 105, 115, 116, 70, - 108, 111, 97, 116, - - // FLOAT - 5, - 70, 76, 79, 65, 84, - - 0, - - // testPersistVarchar - 18, - 116, 101, 115, 116, - 80, 101, 114, 115, - 105, 115, 116, 86, - 97, 114, 99, 104, 97, 114, - - // VARCHAR - 7, - 86, 65, 82, 67, - 72, 65, 82, - - 0, - - // 12 - 0, 0, 0, 12 - }; - - assertArrayEquals(expected, out.toByteArray()); - } -} diff --git a/src/test/java/net/kaaass/rumbase/table/TableManagerTest.java b/src/test/java/net/kaaass/rumbase/table/TableManagerTest.java deleted file mode 100644 index 9128abf..0000000 --- a/src/test/java/net/kaaass/rumbase/table/TableManagerTest.java +++ /dev/null @@ -1,130 +0,0 @@ -package net.kaaass.rumbase.table; - -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; - -/** - * 表管理器的测试 - * - * @author @KveinAxel - * @see net.kaaass.rumbase.table.TableManager - */ -@Slf4j -public class TableManagerTest { - - @BeforeClass - @AfterClass - public static void clearDataFolder() { - log.info("清除数据文件夹..."); - FileUtil.removeDir(new File(FileUtil.DATA_PATH)); - } - - @Test - public void testShowTables() throws IndexAlreadyExistException, TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { - var prefix = "testShowTables"; - - var tbm = new TableManager(); - - var fieldList = new ArrayList(); - - // 增加测试表字段 - 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, FileUtil.TABLE_PATH + prefix + ".db"); - } catch (TableExistenceException | RecordNotFoundException | ArgumentException | TableConflictException e) { - e.printStackTrace(); - Assert.fail(); - } - - var tables = tbm.showTables(); - Assert.assertEquals(4, tables.size()); - Assert.assertEquals(prefix + "Table", tables.get(0)); - } - - @Test - public void testCreateTable() throws IndexAlreadyExistException, TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { - var prefix = "testCreateTable"; - - var tbm = new TableManager(); - - var fieldList = new ArrayList(); - - // 增加测试表字段 - 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, FileUtil.TABLE_PATH + prefix + ".db"); - } catch (TableExistenceException e) { - e.printStackTrace(); - Assert.fail(); - } - } - - @Test - public void testGetTable() throws IndexAlreadyExistException, TableExistenceException, TableConflictException, RecordNotFoundException, ArgumentException { - var prefix = "testGetTable"; - - var tbm = new TableManager(); - - var fieldList = new ArrayList(); - - // 增加测试表字段 - 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, FileUtil.TABLE_PATH + prefix + ".db"); - } catch (TableExistenceException e) { - e.printStackTrace(); - Assert.fail(); - } - - try { - var t = tbm.getTable(prefix + "Table"); - 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) { - Assert.fail(); - } - } - -} diff --git a/src/test/java/net/kaaass/rumbase/table/TableTest.java b/src/test/java/net/kaaass/rumbase/table/TableTest.java deleted file mode 100644 index 100edf8..0000000 --- a/src/test/java/net/kaaass/rumbase/table/TableTest.java +++ /dev/null @@ -1,633 +0,0 @@ -package net.kaaass.rumbase.table; - -import com.igormaznitsa.jbbp.io.JBBPBitOutputStream; -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; -import net.kaaass.rumbase.table.exception.TableConflictException; -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; - -import static org.junit.Assert.assertArrayEquals; - -/** - * 表结构测试 - * - * @author @KveinAxel - * @see Table - */ -@Slf4j -public class TableTest { - - @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 = "testLoad"; - - var byteOS = new ByteArrayOutputStream(); - var out = new JBBPBitOutputStream(byteOS); - try { - out.writeString("testLoadTable", JBBPByteOrder.BIG_ENDIAN); - out.writeString("NORMAL", JBBPByteOrder.BIG_ENDIAN); - out.writeLong(-1, JBBPByteOrder.BIG_ENDIAN); - out.writeInt(3, JBBPByteOrder.BIG_ENDIAN); - out.writeString("testLoadInt", JBBPByteOrder.BIG_ENDIAN); - out.writeString("INT", JBBPByteOrder.BIG_ENDIAN); - out.writeBytes(new byte[]{0}, 1, JBBPByteOrder.BIG_ENDIAN); - out.writeString("testLoadFloat", JBBPByteOrder.BIG_ENDIAN); - out.writeString("FLOAT", JBBPByteOrder.BIG_ENDIAN); - out.writeBytes(new byte[]{0}, 1, JBBPByteOrder.BIG_ENDIAN); - out.writeString("testLoadVarchar", JBBPByteOrder.BIG_ENDIAN); - out.writeString("VARCHAR", JBBPByteOrder.BIG_ENDIAN); - out.writeBytes(new byte[]{0}, 1, JBBPByteOrder.BIG_ENDIAN); - out.writeInt(12, JBBPByteOrder.BIG_ENDIAN); - } catch (IOException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - var storage = RecordManager.fromFile(FileUtil.TEST_PATH + prefix + "Table"); - storage.setMetadata(TransactionContext.empty(), byteOS.toByteArray()); - - var table = Table.load(RecordManager.fromFile(FileUtil.TEST_PATH + prefix + "Table")); - - Assert.assertNotNull(table); - Assert.assertEquals("testLoadTable", table.getTableName()); - Assert.assertEquals(-1L, table.getNext()); - Assert.assertEquals(TableStatus.NORMAL, table.getStatus()); - - var fields = table.getFields(); - 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(); - var table = new Table("testPersistTable", fieldList); - var context = TransactionContext.empty(); - - fieldList.add(new IntField("testPersistInt", false, table)); - fieldList.add(new FloatField("testPersistFloat", false, table)); - fieldList.add(new VarcharField("testPersistVarchar", 12, false, table)); - - var byteOS = new ByteArrayOutputStream(); - var out = new JBBPBitOutputStream(byteOS); - try { - out.writeString("testPersistTable", JBBPByteOrder.BIG_ENDIAN); - out.writeString("NORMAL", JBBPByteOrder.BIG_ENDIAN); - out.writeLong(-1, JBBPByteOrder.BIG_ENDIAN); - out.writeInt(3, JBBPByteOrder.BIG_ENDIAN); - out.writeString("testPersistInt", JBBPByteOrder.BIG_ENDIAN); - out.writeString("INT", JBBPByteOrder.BIG_ENDIAN); - out.writeBytes(new byte[]{0}, 1, JBBPByteOrder.BIG_ENDIAN); - out.writeString("testPersistFloat", JBBPByteOrder.BIG_ENDIAN); - out.writeString("FLOAT", JBBPByteOrder.BIG_ENDIAN); - out.writeBytes(new byte[]{0}, 1, JBBPByteOrder.BIG_ENDIAN); - out.writeString("testPersistVarchar", JBBPByteOrder.BIG_ENDIAN); - out.writeString("VARCHAR", JBBPByteOrder.BIG_ENDIAN); - out.writeBytes(new byte[]{0}, 1, JBBPByteOrder.BIG_ENDIAN); - out.writeInt(12, JBBPByteOrder.BIG_ENDIAN); - } catch (IOException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - assertArrayEquals(new byte[0], table.getRecordStorage().getMetadata(context)); - table.persist(TransactionContext.empty()); - assertArrayEquals(byteOS.toByteArray(), table.getRecordStorage().getMetadata(context)); - - } - - Table createTestTable(String prefix) { - 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); - fieldList.add(intField); - fieldList.add(floatField); - fieldList.add(varcharField); - - // 创建字段索引 - try { - intField.createIndex(); - floatField.createIndex(); - } catch (IndexAlreadyExistException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - return table; - } - - @Test - public void testCURD() { - - var prefix = "testCURD"; - - // 创建待测试表 - var context = TransactionContext.empty(); - var table = createTestTable(prefix); - - // 添加记录 - var data = new ArrayList(); - data.add("33"); - data.add("1.2"); - data.add("'test varchar'"); - - var data2 = new ArrayList(); - data2.add("1"); - data2.add("-0.4"); - data2.add("'ya test varchar'"); - - // 插入记录 - try { - table.insert(context, data); - table.insert(context, data2); - } catch (TableConflictException | TableExistenceException | ArgumentException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - // 查询记录,测试插入情况与查询情况 - var iter = table.searchFirst(prefix + "age", "0"); - Assert.assertTrue(iter.hasNext()); - var pair1 = iter.next(); - Assert.assertTrue(iter.hasNext()); - var pair2 = iter.next(); - 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()); - - Assert.assertTrue(res1.isPresent()); - Assert.assertTrue(res2.isPresent()); - - 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)); - - 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"); - Assert.assertTrue(iter2.hasNext()); - var pair3 = iter2.next(); - Assert.assertEquals(33L, pair3.getKey()); - - var res3 = table.read(context, pair3.getUuid()); - Assert.assertTrue(res3.isEmpty()); // 记录不存在 - - // 测试更新记录 - table.update(context, pair1.getUuid(), data); - - var iter3 = table.searchFirst(prefix + "age", "33"); - Assert.assertTrue(iter3.hasNext()); - var pair4 = iter3.next(); - Assert.assertTrue(iter3.hasNext()); - var pair5 = iter3.next(); - - // 有效的被更新记录 - Assert.assertEquals(33L, pair4.getKey()); - var res4 = table.read(context, pair4.getUuid()); - Assert.assertTrue(res4.isPresent()); - - // 四记录 - Assert.assertEquals(33L, pair5.getKey()); - var res5 = table.read(context, pair5.getUuid()); - Assert.assertTrue(res5.isEmpty()); - - // 测试记录是否被更新 - 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); - Assert.fail(); - } - - } - - void addTestData(TransactionContext context, Table table) throws TableConflictException, TableExistenceException, ArgumentException { - table.insert(context, new ArrayList<>() {{ - add("1"); - add("1.2"); - add("'test varchar'"); - }}); - table.insert(context, new ArrayList<>() {{ - add("2"); - add("1.2"); - add("'test varchar'"); - }}); - table.insert(context, new ArrayList<>() {{ - add("3"); - add("1.2"); - add("'test varchar'"); - }}); - table.insert(context, new ArrayList<>() {{ - add("3"); - add("1.2"); - add("'test varchar'"); - }}); - table.insert(context, new ArrayList<>() {{ - add("4"); - add("1.2"); - add("'test varchar'"); - }}); - table.insert(context, new ArrayList<>() {{ - add("5"); - add("1.2"); - add("'test varchar'"); - }}); - table.insert(context, new ArrayList<>() {{ - add("6"); - add("1.2"); - add("'test varchar'"); - }}); - table.insert(context, new ArrayList<>() {{ - add("7"); - add("1.2"); - add("'test varchar'"); - }}); - table.insert(context, new ArrayList<>() {{ - add("7"); - add("1.2"); - add("'test varchar'"); - }}); - table.insert(context, new ArrayList<>() {{ - add("8"); - add("1.2"); - add("'test varchar'"); - }}); - } - - @Test - public void testSearch() { - - var prefix = "testSearch"; - - // 创建待测试表 - var context = TransactionContext.empty(); - var table = createTestTable(prefix); - - // 添加记录 - try { - addTestData(context, table); - } catch (TableConflictException | TableExistenceException | ArgumentException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - // 查询记录 - // 测试search - try { - var uuids = table.search(prefix + "age", "7"); - var resList = new ArrayList>(); - for (var uuid : uuids) { - var res = table.read(context, uuid); - res.ifPresent(resList::add); - } - 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)); - - 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); - Assert.fail(); - } - - } - - @Test - public void testSearchAll() { - - var prefix = "testSearchAll"; - - // 创建待测试表 - var context = TransactionContext.empty(); - var table = createTestTable(prefix); - - // 添加记录 - try { - addTestData(context, table); - } catch (TableConflictException | TableExistenceException | ArgumentException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - - // 测试searchAll - try { - var uuids = table.searchAll(prefix + "age"); - var resList = new ArrayList>(); - while (uuids.hasNext()) { - var uuid = uuids.next(); - table.read(context, uuid.getUuid()).ifPresent(resList::add); - } - - 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)); - - 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)); - - 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)); - - 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)); - - 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)); - - 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)); - - 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)); - - 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)); - - 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)); - - 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); - Assert.fail(); - } - } - - @Test - public void testSearchFirst() { - var prefix = "testSearchFirst"; - - // 创建待测试表 - var context = TransactionContext.empty(); - var table = createTestTable(prefix); - - // 添加记录 - try { - addTestData(context, table); - } catch (TableConflictException | TableExistenceException | ArgumentException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - // 测试searchFirst - try { - var uuids = table.searchFirst(prefix + "age", "3"); - var resList = new ArrayList>(); - while (uuids.hasNext()) { - var uuid = uuids.next(); - table.read(context, uuid.getUuid()).ifPresent(resList::add); - } - - 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)); - - 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)); - - 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); - Assert.fail(); - } - } - - @Test - public void testSearchFirstNotEqual() { - var prefix = "testSearchFirstNotEqual"; - - // 创建待测试表 - var context = TransactionContext.empty(); - var table = createTestTable(prefix); - - // 添加记录 - try { - addTestData(context, table); - } catch (TableConflictException | TableExistenceException | ArgumentException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - // 测试searchFirstNotEqual - try { - var uuids = table.searchFirstNotEqual(prefix + "age", "3"); - var resList = new ArrayList>(); - while (uuids.hasNext()) { - var uuid = uuids.next(); - table.read(context, uuid.getUuid()).ifPresent(resList::add); - } - - 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); - Assert.fail(); - } - } - - @Test - public void testCheckStringEntry() { - var passEntry = new ArrayList(); - passEntry.add("33"); - passEntry.add("1.2"); - passEntry.add("'test varchar'"); - - var failEntry = new ArrayList(); - failEntry.add("33"); - failEntry.add("'test varchar'"); - failEntry.add("1.2"); - - var fieldList = new ArrayList(); - var table = new Table("testCheckStringEntryTable", fieldList); - var intField = new IntField("testCheckStringEntryInt", false, table); - var floatField = new FloatField("testCheckStringEntryFloat", false, table); - var varcharField = new VarcharField("testCheckStringEntryVarchar", 20, false, table); - fieldList.add(intField); - fieldList.add(floatField); - fieldList.add(varcharField); - - Assert.assertTrue(table.checkStringEntry(passEntry)); - Assert.assertFalse(table.checkStringEntry(failEntry)); - - } - - @Test - public void testStringEntryToBytes() { - var passEntry = new ArrayList(); - passEntry.add("33"); - passEntry.add("1.2"); - passEntry.add("'test varchar'"); - - var failEntry = new ArrayList(); - failEntry.add("33"); - failEntry.add("'test varchar'"); - failEntry.add("1.2"); - - var fieldList = new ArrayList(); - var table = new Table("testStringEntryToBytesTable", fieldList); - var intField = new IntField("testStringEntryToBytesInt", false, table); - var floatField = new FloatField("testStringEntryToBytesFloat", false, table); - var varcharField = new VarcharField("testStringEntryToBytesVarchar", 20, false, table); - fieldList.add(intField); - fieldList.add(floatField); - fieldList.add(varcharField); - - try { - var bytes = table.stringEntryToBytes(passEntry); - var expected = new byte[]{ - 0, - 0, 0, 0, 33, // int 33 - 0, - 63, -103, -103, -102, // float 1.2 - 0, - 12, - 116, 101, 115, 116, - 32, 118, 97, 114, - 99, 104, 97, 114 // varchar test varchar - }; - assertArrayEquals(expected, bytes); - } catch (TableConflictException e) { - log.error("Exception expected: ", e); - Assert.fail(); - } - - try { - table.stringEntryToBytes(failEntry); - Assert.fail(""); - } catch (TableConflictException e) { - log.error("Exception expected: ", e); - } - } - - @Test - public void testParseEntry() { - var passEntry = new byte[]{ - 0, - 0, 0, 0, 33, // int 33 - 0, - 63, -103, -103, -102, // float 1.2 - 0, - 12, - 116, 101, 115, 116, - 32, 118, 97, 114, - 99, 104, 97, 114 // varchar test varchar - }; - - var failEntry = new byte[]{ - 0, - 0, 0, 0, 33, // int 33 - 0, - 12, - 116, 101, 115, 116, - 32, 118, 97, 114, - 99, 104, 97, 114, // varchar test varchar - 0, - 63, -103, -103, -102, // float 1.2 - }; - - var fieldList = new ArrayList(); - var table = new Table("testParseEntryTable", fieldList); - var intField = new IntField("testParseEntryInt", false, table); - var floatField = new FloatField("testParseEntryFloat", false, table); - var varcharField = new VarcharField("testParseEntryVarchar", 20, false, table); - fieldList.add(intField); - fieldList.add(floatField); - fieldList.add(varcharField); - - try { - var list = table.parseEntry(passEntry); - 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); - Assert.fail(); - } - - try { - table.parseEntry(failEntry); - 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 deleted file mode 100644 index 6dc4f0e..0000000 --- a/src/test/java/net/kaaass/rumbase/transaction/TransactionContextTest.java +++ /dev/null @@ -1,232 +0,0 @@ -package net.kaaass.rumbase.transaction; - -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 net.kaaass.rumbase.transaction.exception.StatusException; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -import java.io.File; -import java.io.IOException; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * 测试事务上下文 - * - * @author criki - */ -@Slf4j -public class TransactionContextTest { - - @BeforeClass - public static void createDataFolder() { - log.info("创建测试文件夹..."); - FileUtil.createDir(FileUtil.TEST_PATH); - } - - @AfterClass - public static void clearDataFolder() { - log.info("清除测试文件夹..."); - FileUtil.removeDir(FileUtil.TEST_PATH); - } - - /** - * 测试创建事务 - */ - @Test - public void testCreateTransaction() throws IOException, FileException { - var manager = new TransactionManagerImpl("test_gen_files/test_create.log"); - - // 空事务 - var emptyTransaction = TransactionContext.empty(); - Assert.assertEquals(0, emptyTransaction.getXid()); - Assert.assertEquals(TransactionStatus.COMMITTED, emptyTransaction.getStatus()); - Assert.assertEquals(TransactionIsolation.READ_UNCOMMITTED, emptyTransaction.getIsolation()); - - // 普通事务 - var transaction = manager.createTransactionContext(TransactionIsolation.READ_COMMITTED); - Assert.assertEquals(1, transaction.getXid()); - Assert.assertEquals(TransactionStatus.PREPARING, transaction.getStatus()); - Assert.assertEquals(TransactionIsolation.READ_COMMITTED, transaction.getIsolation()); - } - - /** - * 测试事务变化 - */ - @Test - public void testChangeStatus() throws IOException, FileException, StatusException { - var manager = new TransactionManagerImpl("test_gen_files/test_change.log"); - var committedTransaction = manager.createTransactionContext(TransactionIsolation.READ_COMMITTED); - // 事务初始状态 - Assert.assertEquals("new transaction's default status should be PREPARING", TransactionStatus.PREPARING, committedTransaction.getStatus()); - - // 事务开始 - committedTransaction.start(); - Assert.assertEquals("starting transaction's default status should be ACTIVE", TransactionStatus.ACTIVE, committedTransaction.getStatus()); - - // 事务提交 - committedTransaction.commit(); - Assert.assertEquals("committed transaction's default status should be COMMITTED", TransactionStatus.COMMITTED, committedTransaction.getStatus()); - - // 事务中止 - var abortedTransaction = manager.createTransactionContext(TransactionIsolation.READ_COMMITTED); - abortedTransaction.start(); - abortedTransaction.rollback(); - Assert.assertEquals("aborted transaction's default status should be ABORTED", TransactionStatus.ABORTED, abortedTransaction.getStatus()); - } - - /** - * 测试事务持久化 - */ - @Test - public void testTransactionPersistence() throws IOException, FileException, StatusException { - var manager = new TransactionManagerImpl("test_gen_files/test_persistence.log"); - // 事务创建,事务状态记录数改变 - var transaction1 = manager.createTransactionContext(TransactionIsolation.READ_UNCOMMITTED); - Assert.assertEquals(1, manager.getSIZE().get()); - - var transaction2 = manager.createTransactionContext(TransactionIsolation.READ_UNCOMMITTED); - Assert.assertEquals(2, manager.getSIZE().get()); - - // 事务状态持久化 - var txFromDisk1 = manager.getContext(1); - var txFromDisk2 = manager.getContext(2); - Assert.assertEquals(TransactionStatus.PREPARING, txFromDisk1.getStatus()); - Assert.assertEquals(TransactionStatus.PREPARING, txFromDisk2.getStatus()); - - transaction1.start(); - txFromDisk1 = manager.getContext(1); - Assert.assertEquals(TransactionStatus.ACTIVE, txFromDisk1.getStatus()); - - transaction1.commit(); - txFromDisk1 = manager.getContext(1); - Assert.assertEquals(TransactionStatus.COMMITTED, txFromDisk1.getStatus()); - - transaction2.start(); - transaction2.rollback(); - txFromDisk2 = manager.getContext(2); - Assert.assertEquals(TransactionStatus.ABORTED, txFromDisk2.getStatus()); - } - - /** - * 测试事务状态复原 - */ - @Test - public void testTransactionRecovery() throws IOException, FileException, StatusException { - var manager = new TransactionManagerImpl("test_gen_files/test_recovery.log"); - // 事务创建,事务状态记录数改变 - var transaction1 = manager.createTransactionContext(TransactionIsolation.READ_UNCOMMITTED); - int xid = transaction1.getXid(); - - // 复原事务 - var transactionR = manager.getContext(xid); - Assert.assertEquals(TransactionStatus.PREPARING, transactionR.getStatus()); - Assert.assertEquals(TransactionIsolation.READ_UNCOMMITTED, transactionR.getIsolation()); - - // 改变事务状态 - transaction1.start(); - transactionR = manager.getContext(xid); - Assert.assertEquals(TransactionStatus.ACTIVE, transactionR.getStatus()); - } - - /** - * 测试事务上锁 - */ - @Test - public void testAddLock() throws IOException, FileException, StatusException { - 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); - String tableName = "test"; - - transaction1.start(); - transaction2.start(); - - // 互斥锁 - new Thread(() -> { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - log.info("transaction2 commit"); - try { - transaction2.commit(); - } catch (StatusException e) { - e.printStackTrace(); - } - }).start(); - try { - transaction1.exclusiveLock(1, tableName); - transaction2.exclusiveLock(2, tableName); - transaction1.exclusiveLock(2, tableName); - log.info("transaction1 got exclusiveLock on 2"); - } catch (DeadlockException e) { - e.printStackTrace(); - } - transaction1.commit(); - - try { - transaction1.sharedLock(1, tableName); - transaction2.sharedLock(1, tableName); - transaction2.sharedLock(2, tableName); - transaction1.sharedLock(2, tableName); - - transaction1.commit(); - transaction2.rollback(); - } catch (DeadlockException | StatusException e) { - e.printStackTrace(); - } - } - - /** - * 测试死锁 - */ - @Test - public void testDeadlock() throws IOException, FileException, InterruptedException, StatusException { - var manager = new TransactionManagerImpl("test_gen_files/test_deadlock.log"); - var transaction1 = manager.createTransactionContext(TransactionIsolation.READ_UNCOMMITTED); - var transaction2 = manager.createTransactionContext(TransactionIsolation.READ_UNCOMMITTED); - String tableName = "test"; - - transaction1.start(); - transaction2.start(); - - AtomicBoolean deadlockDetect = new AtomicBoolean(false); - new Thread(() -> { - try { - Thread.sleep(3); - } catch (InterruptedException e) { - e.printStackTrace(); - } - try { - transaction2.exclusiveLock(1, tableName); - } catch (DeadlockException e) { - deadlockDetect.set(true); - try { - transaction2.rollback(); - } catch (StatusException statusException) { - statusException.printStackTrace(); - } - e.printStackTrace(); - } catch (StatusException e) { - e.printStackTrace(); - } - }).start(); - try { - transaction1.exclusiveLock(1, tableName); - transaction2.exclusiveLock(2, tableName); - transaction1.exclusiveLock(2, tableName); - } catch (DeadlockException e) { - deadlockDetect.set(true); - transaction2.rollback(); - e.printStackTrace(); - } - Thread.sleep(10); - Assert.assertTrue("Deadlock should be detected", deadlockDetect.get()); - } -}