From 9c43ee70685bc8931eccc3bd3642d931604e4033 Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Sun, 18 Aug 2024 12:17:23 +0900 Subject: [PATCH 01/27] =?UTF-8?q?feat:=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/database/PageManager.java | 30 +++++++++++++ src/main/java/database/page/FileHeader.java | 34 +++++++++++++++ src/main/java/database/page/Page.java | 31 ++++++++++---- src/main/java/database/page/PageHeader.java | 38 +++++++++++++++++ src/main/java/database/page/PageType.java | 8 ++++ .../java/database/page/PageHeaderTest.java | 42 +++++++++++++++++++ src/test/java/database/page/PageTest.java | 29 +++++++++++++ 7 files changed, 203 insertions(+), 9 deletions(-) create mode 100644 src/main/java/database/PageManager.java create mode 100644 src/main/java/database/page/FileHeader.java create mode 100644 src/main/java/database/page/PageHeader.java create mode 100644 src/main/java/database/page/PageType.java create mode 100644 src/test/java/database/page/PageHeaderTest.java create mode 100644 src/test/java/database/page/PageTest.java diff --git a/src/main/java/database/PageManager.java b/src/main/java/database/PageManager.java new file mode 100644 index 0000000..9dc7e94 --- /dev/null +++ b/src/main/java/database/PageManager.java @@ -0,0 +1,30 @@ +package database; + +import database.page.Page; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +public class PageManager { + public void saveToFile(String fileName) { + try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName))) { + out.writeObject(this); + System.out.println("페이지가 " + fileName + "에 저장되었습니다."); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static Page loadFromFile(String fileName) { + try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName))) { + Page page = (Page) in.readObject(); + System.out.println("페이지가 " + fileName + "에서 로드되었습니다."); + return page; + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/src/main/java/database/page/FileHeader.java b/src/main/java/database/page/FileHeader.java new file mode 100644 index 0000000..c1a0919 --- /dev/null +++ b/src/main/java/database/page/FileHeader.java @@ -0,0 +1,34 @@ +package database.page; + +public class FileHeader { + + private static final int HEADER_SIZE = 38; + + private final long pageNumber; + private final long checksum; + + public FileHeader(long pageNumber) { + this.pageNumber = pageNumber; + this.checksum = 0; + } + + public long getPageNumber() { + return pageNumber; + } + + public long getChecksum() { + return checksum; + } + + public int getHeaderSize() { + return HEADER_SIZE; + } + + @Override + public String toString() { + return "FileHeader{" + + "pageNumber=" + pageNumber + + ", checksum=" + checksum + + '}'; + } +} diff --git a/src/main/java/database/page/Page.java b/src/main/java/database/page/Page.java index b421f9e..39e17b4 100644 --- a/src/main/java/database/page/Page.java +++ b/src/main/java/database/page/Page.java @@ -1,19 +1,32 @@ package database.page; public class Page { - private final long pageNum; - private final byte[] data; - public Page(long pageNum, byte[] data) { - this.pageNum = pageNum; - this.data = data; + private static final int PAGE_SIZE = 16 * 1024; + + private final FileHeader fileHeader; + private final PageHeader pageHeader; + private int freeSpace; + + public Page(long pageNumber, PageType pageType) { + this.fileHeader = new FileHeader(pageNumber); + this.pageHeader = new PageHeader(pageType); + this.freeSpace = PAGE_SIZE - (this.fileHeader.getHeaderSize() + this.pageHeader.getHeaderSize()); + } + + public long getPageNumber() { + return fileHeader.getPageNumber(); + } + + public PageType getPageType() { + return pageHeader.getPageType(); } - public long getPageNum() { - return pageNum; + public int getRecordCount() { + return pageHeader.getRecordCount(); } - public byte[] getData() { - return data; + public int getFreeSpace() { + return freeSpace; } } diff --git a/src/main/java/database/page/PageHeader.java b/src/main/java/database/page/PageHeader.java new file mode 100644 index 0000000..fda15a4 --- /dev/null +++ b/src/main/java/database/page/PageHeader.java @@ -0,0 +1,38 @@ +package database.page; + +public class PageHeader { + + private static final int HEADER_SIZE = 56; + + private int recordCount; + private final PageType pageType; + + public PageHeader(PageType pageType) { + this.recordCount = 0; + this.pageType = pageType; + } + + public void incrementRecordCount() { + recordCount++; + } + + public int getRecordCount() { + return recordCount; + } + + public PageType getPageType() { + return pageType; + } + + public int getHeaderSize() { + return HEADER_SIZE; + } + + @Override + public String toString() { + return "PageHeader{" + + "recordCount=" + recordCount + + ", pageType=" + pageType + + '}'; + } +} diff --git a/src/main/java/database/page/PageType.java b/src/main/java/database/page/PageType.java new file mode 100644 index 0000000..8d8c971 --- /dev/null +++ b/src/main/java/database/page/PageType.java @@ -0,0 +1,8 @@ +package database.page; + +public enum PageType { + PAGE_TYPE_CLUSTERED, + PAGE_TYPE_BTR_INDEX, + PAGE_TYPE_UNDO, + ; +} diff --git a/src/test/java/database/page/PageHeaderTest.java b/src/test/java/database/page/PageHeaderTest.java new file mode 100644 index 0000000..a796cda --- /dev/null +++ b/src/test/java/database/page/PageHeaderTest.java @@ -0,0 +1,42 @@ +package database.page; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.stream.IntStream; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("페이지 헤더 테스트") +class PageHeaderTest { + + @DisplayName("페이지 헤더를 생성한다.") + @Test + void createPageHeader() { + // given + PageType pageType = PageType.PAGE_TYPE_CLUSTERED; + int initialRecordCnt = 0; + + // when + PageHeader pageHeader = new PageHeader(pageType); + + // then + assertThat(pageHeader.getPageType()).isEqualTo(pageType); + assertThat(pageHeader.getRecordCount()).isEqualTo(initialRecordCnt); + } + + @DisplayName("페이지 레코드 수가 증가한다.") + @Test + void incrementRecord() { + // given + PageType pageType = PageType.PAGE_TYPE_CLUSTERED; + int recordCnt = 2; + + // when + PageHeader pageHeader = new PageHeader(pageType); + IntStream.range(0, recordCnt) + .forEach(i -> pageHeader.incrementRecordCount()); + + // then + assertThat(pageHeader.getRecordCount()).isEqualTo(recordCnt); + } +} diff --git a/src/test/java/database/page/PageTest.java b/src/test/java/database/page/PageTest.java new file mode 100644 index 0000000..002d219 --- /dev/null +++ b/src/test/java/database/page/PageTest.java @@ -0,0 +1,29 @@ +package database.page; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("페이지 관련 테스트") +class PageTest { + + @DisplayName("페이지 생성에 성공하다.") + @Test + void createPage() { + // given + int pageNumber = 1; + PageType pageType = PageType.PAGE_TYPE_CLUSTERED; + + // when + Page page = new Page(pageNumber, pageType); + + // then + assertAll( + () -> assertThat(page.getPageNumber()).isEqualTo(pageNumber), + () -> assertThat(page.getPageType()).isEqualTo(pageType), + () -> assertThat(page.getRecordCount()).isEqualTo(0) + ); + } +} From 476502a8442e4d940d2c01f9d556eff591961f8b Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Mon, 26 Aug 2024 02:37:29 +0900 Subject: [PATCH 02/27] =?UTF-8?q?feat:=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EC=A7=81=EB=A0=AC=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/database/page/FileHeader.java | 4 +++- src/main/java/database/page/Page.java | 4 +++- src/main/java/database/page/PageHeader.java | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/database/page/FileHeader.java b/src/main/java/database/page/FileHeader.java index c1a0919..1054493 100644 --- a/src/main/java/database/page/FileHeader.java +++ b/src/main/java/database/page/FileHeader.java @@ -1,6 +1,8 @@ package database.page; -public class FileHeader { +import java.io.Serializable; + +public class FileHeader implements Serializable { private static final int HEADER_SIZE = 38; diff --git a/src/main/java/database/page/Page.java b/src/main/java/database/page/Page.java index 39e17b4..ebe0bd0 100644 --- a/src/main/java/database/page/Page.java +++ b/src/main/java/database/page/Page.java @@ -1,6 +1,8 @@ package database.page; -public class Page { +import java.io.Serializable; + +public class Page implements Serializable { private static final int PAGE_SIZE = 16 * 1024; diff --git a/src/main/java/database/page/PageHeader.java b/src/main/java/database/page/PageHeader.java index fda15a4..640c509 100644 --- a/src/main/java/database/page/PageHeader.java +++ b/src/main/java/database/page/PageHeader.java @@ -1,6 +1,8 @@ package database.page; -public class PageHeader { +import java.io.Serializable; + +public class PageHeader implements Serializable { private static final int HEADER_SIZE = 56; From d1fd4b413964425d43ab5cf9c0f006c356e02d06 Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Mon, 26 Aug 2024 02:37:45 +0900 Subject: [PATCH 03/27] =?UTF-8?q?feat:=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=ED=8C=A9=ED=84=B0=EB=A6=AC=20=ED=8C=A8=ED=84=B4=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/database/page/PageFactory.java | 16 +++++++ .../java/database/page/PageFactoryTest.java | 45 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/main/java/database/page/PageFactory.java create mode 100644 src/test/java/database/page/PageFactoryTest.java diff --git a/src/main/java/database/page/PageFactory.java b/src/main/java/database/page/PageFactory.java new file mode 100644 index 0000000..e5229fd --- /dev/null +++ b/src/main/java/database/page/PageFactory.java @@ -0,0 +1,16 @@ +package database.page; + +public class PageFactory { + + public static Page createDataPage(long pageNumber) { + return new Page(pageNumber, PageType.PAGE_TYPE_CLUSTERED); + } + + public static Page createIndexPage(long pageNumber) { + return new Page(pageNumber, PageType.PAGE_TYPE_BTR_INDEX); + } + + public static Page createUndoPage(long pageNumber) { + return new Page(pageNumber, PageType.PAGE_TYPE_UNDO); + } +} diff --git a/src/test/java/database/page/PageFactoryTest.java b/src/test/java/database/page/PageFactoryTest.java new file mode 100644 index 0000000..03059cc --- /dev/null +++ b/src/test/java/database/page/PageFactoryTest.java @@ -0,0 +1,45 @@ +package database.page; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("페이지 팩터리 테스트") +class PageFactoryTest { + + private final int pageNumber = 1234; + + @DisplayName("데이터 페이지 생성에 성공한다.") + @Test + void createDataPage() { + // given&when + Page page = PageFactory.createDataPage(pageNumber); + + // then + assertThat(page.getPageType()).isEqualTo(PageType.PAGE_TYPE_CLUSTERED); + assertThat(page.getPageNumber()).isEqualTo(pageNumber); + } + + @DisplayName("인덱스 페이지 생성에 성공한다.") + @Test + void createIndexPage() { + // given&when + Page page = PageFactory.createIndexPage(pageNumber); + + // then + assertThat(page.getPageType()).isEqualTo(PageType.PAGE_TYPE_BTR_INDEX); + assertThat(page.getPageNumber()).isEqualTo(pageNumber); + } + + @DisplayName("언두 페이지 생성에 성공한다.") + @Test + void createUndoPage() { + // given&when + Page page = PageFactory.createUndoPage(pageNumber); + + // then + assertThat(page.getPageType()).isEqualTo(PageType.PAGE_TYPE_UNDO); + assertThat(page.getPageNumber()).isEqualTo(pageNumber); + } +} From a4e8b4195f6b2e65a2eb60c16d629a039308dab9 Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Mon, 26 Aug 2024 02:38:28 +0900 Subject: [PATCH 04/27] =?UTF-8?q?feat:=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EB=A7=A4=EB=8B=88=EC=A0=80=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/database/page/PageManager.java | 53 ++++++++++++++ .../java/database/page/PageManagerTest.java | 72 +++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 src/main/java/database/page/PageManager.java create mode 100644 src/test/java/database/page/PageManagerTest.java diff --git a/src/main/java/database/page/PageManager.java b/src/main/java/database/page/PageManager.java new file mode 100644 index 0000000..8a5a2e7 --- /dev/null +++ b/src/main/java/database/page/PageManager.java @@ -0,0 +1,53 @@ +package database.page; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class PageManager { + + private static final String DIRECTORY_PATH = "disk"; + private static final String INFIX = "page_"; + private static final String FILE_EXTENSION = ".ibd"; + + public PageManager() { + createDirectoryIfNotExists(); + } + + private void createDirectoryIfNotExists() { + Path path = Paths.get(DIRECTORY_PATH); + if (!Files.exists(path)) { + try { + Files.createDirectories(path); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public void savePage(Page page) { + String fileName = DIRECTORY_PATH + File.separator + INFIX + page.getPageNumber() + FILE_EXTENSION; + try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName))) { + out.writeObject(page); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public Page loadPage(long pageNum) { + String fileName = DIRECTORY_PATH + File.separator + INFIX + pageNum + FILE_EXTENSION; + try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName))) { + Page page = (Page) in.readObject(); + return page; + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/src/test/java/database/page/PageManagerTest.java b/src/test/java/database/page/PageManagerTest.java new file mode 100644 index 0000000..5c704fd --- /dev/null +++ b/src/test/java/database/page/PageManagerTest.java @@ -0,0 +1,72 @@ +package database.page; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("페이지 매니저 테스트") +class PageManagerTest { + + private static final String DIRECTORY_PATH = "disk"; + private static final String INFIX = "page_"; + private static final String FILE_EXTENSION = ".ibd"; + + private PageManager pageManager; + private final int pageNumber = 1234; + + @BeforeEach + void setUp() { + pageManager = new PageManager(); + } + + @DisplayName("페이지 저장에 성공한다.") + @Test + void savePage() { + // given + Page page = PageFactory.createDataPage(pageNumber); + + // when + pageManager.savePage(page); + + // then + Path filePath = Paths.get(DIRECTORY_PATH, INFIX + pageNumber + FILE_EXTENSION); + assertThat(Files.exists(filePath)).isTrue(); + } + + @DisplayName("페이지 조회에 성공한다.") + @Test + void loadPage() { + // given + Page page = PageFactory.createDataPage(pageNumber); + pageManager.savePage(page); + + // when + Page foundPage = pageManager.loadPage(pageNumber); + + // then + assertThat(foundPage.getPageNumber()).isEqualTo(pageNumber); + } + + @AfterEach + void tearDown() { + Path filePath = Paths.get(DIRECTORY_PATH, INFIX + pageNumber + FILE_EXTENSION); + try { + Files.deleteIfExists(filePath); + } catch (IOException e) { + e.printStackTrace(); + } + + try { + Files.deleteIfExists(Paths.get(DIRECTORY_PATH)); + } catch (IOException e) { + e.printStackTrace(); + } + } +} From 76ac0c5e1908aa98b94d087e1ca3c07fb69fb159 Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Mon, 26 Aug 2024 02:39:45 +0900 Subject: [PATCH 05/27] =?UTF-8?q?test:=20DisplayName=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/database/page/PageTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/database/page/PageTest.java b/src/test/java/database/page/PageTest.java index 002d219..acc6016 100644 --- a/src/test/java/database/page/PageTest.java +++ b/src/test/java/database/page/PageTest.java @@ -6,7 +6,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -@DisplayName("페이지 관련 테스트") +@DisplayName("페이지 테스트") class PageTest { @DisplayName("페이지 생성에 성공하다.") From 7f03c3e9de991f41519b3f014a1bc87409df253b Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Mon, 26 Aug 2024 02:40:01 +0900 Subject: [PATCH 06/27] =?UTF-8?q?feat:=20=EB=B6=88=ED=95=84=EC=9A=94=20Pag?= =?UTF-8?q?eManager=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/database/PageManager.java | 30 ------------------------- 1 file changed, 30 deletions(-) delete mode 100644 src/main/java/database/PageManager.java diff --git a/src/main/java/database/PageManager.java b/src/main/java/database/PageManager.java deleted file mode 100644 index 9dc7e94..0000000 --- a/src/main/java/database/PageManager.java +++ /dev/null @@ -1,30 +0,0 @@ -package database; - -import database.page.Page; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - -public class PageManager { - public void saveToFile(String fileName) { - try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName))) { - out.writeObject(this); - System.out.println("페이지가 " + fileName + "에 저장되었습니다."); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public static Page loadFromFile(String fileName) { - try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName))) { - Page page = (Page) in.readObject(); - System.out.println("페이지가 " + fileName + "에서 로드되었습니다."); - return page; - } catch (IOException | ClassNotFoundException e) { - e.printStackTrace(); - return null; - } - } -} From 511b3d0fa804376972bd1d776c10662672193a7a Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Mon, 26 Aug 2024 03:00:07 +0900 Subject: [PATCH 07/27] =?UTF-8?q?feat:=20=EB=B2=84=ED=8D=BC=ED=92=80=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/database/BufferPool.java | 32 +++++++++++++ src/test/java/database/BufferPoolTest.java | 55 ++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 src/main/java/database/BufferPool.java create mode 100644 src/test/java/database/BufferPoolTest.java diff --git a/src/main/java/database/BufferPool.java b/src/main/java/database/BufferPool.java new file mode 100644 index 0000000..006caf4 --- /dev/null +++ b/src/main/java/database/BufferPool.java @@ -0,0 +1,32 @@ +package database; + +import database.page.Page; +import java.util.LinkedHashMap; +import java.util.Map; + +public class BufferPool { + + private final int capacity; + private final LinkedHashMap cache; + + public BufferPool(int capacity) { + this.capacity = capacity; + this.cache = new LinkedHashMap<>(capacity, 0.75f, true) { + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > BufferPool.this.capacity; + } + }; + } + + public Page getPage(long pageNum) { + return cache.get(pageNum); + } + + public void putPage(Page page) { + cache.put(page.getPageNumber(), page); + } + + public boolean containsPage(long pageNum) { + return cache.containsKey(pageNum); + } +} diff --git a/src/test/java/database/BufferPoolTest.java b/src/test/java/database/BufferPoolTest.java new file mode 100644 index 0000000..f3c2714 --- /dev/null +++ b/src/test/java/database/BufferPoolTest.java @@ -0,0 +1,55 @@ +package database; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import database.page.PageFactory; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("버퍼풀 테스트") +class BufferPoolTest { + + @DisplayName("버퍼풀 생성에 성공한다.") + @Test + void createBufferPool() { + // given + int capacity = 2; + int pageNumber1 = 1; + int pageNumber2 = 2; + + // when + BufferPool bufferPool = new BufferPool(capacity); + bufferPool.putPage(PageFactory.createDataPage(pageNumber1)); + bufferPool.putPage(PageFactory.createDataPage(pageNumber2)); + + // then + assertThat(bufferPool.containsPage(1)).isTrue(); + assertThat(bufferPool.containsPage(2)).isTrue(); + } + + @DisplayName("LRU 정책에 따라 가장 오래된 페이지가 제거된다.") + @Test + void lru() { + // given + int capacity = 2; + int pageNumber1 = 1; + int pageNumber2 = 2; + int pageNumber3 = 3; + + BufferPool bufferPool = new BufferPool(capacity); + bufferPool.putPage(PageFactory.createDataPage(pageNumber1)); + bufferPool.putPage(PageFactory.createDataPage(pageNumber2)); + + // when + bufferPool.getPage(pageNumber1); + bufferPool.putPage(PageFactory.createDataPage(pageNumber3)); + + // then + assertAll( + () -> assertThat(bufferPool.containsPage(pageNumber1)).isTrue(), + () -> assertThat(bufferPool.containsPage(pageNumber3)).isTrue(), + () -> assertThat(bufferPool.containsPage(pageNumber2)).isFalse() + ); + } +} From 8c0294212aa87e44878179bf17d1ef52e1e9c96c Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Mon, 26 Aug 2024 03:06:48 +0900 Subject: [PATCH 08/27] =?UTF-8?q?refactor:=20innodb=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/database/{ => innodb}/BufferPool.java | 4 ++-- src/main/java/database/{ => innodb}/page/FileHeader.java | 2 +- src/main/java/database/{ => innodb}/page/Page.java | 2 +- src/main/java/database/{ => innodb}/page/PageFactory.java | 2 +- src/main/java/database/{ => innodb}/page/PageHeader.java | 2 +- src/main/java/database/{ => innodb}/page/PageManager.java | 2 +- src/main/java/database/{ => innodb}/page/PageType.java | 2 +- src/test/java/database/{ => innodb}/BufferPoolTest.java | 4 ++-- src/test/java/database/{ => innodb}/page/PageFactoryTest.java | 2 +- src/test/java/database/{ => innodb}/page/PageHeaderTest.java | 2 +- src/test/java/database/{ => innodb}/page/PageManagerTest.java | 2 +- src/test/java/database/{ => innodb}/page/PageTest.java | 2 +- 12 files changed, 14 insertions(+), 14 deletions(-) rename src/main/java/database/{ => innodb}/BufferPool.java (92%) rename src/main/java/database/{ => innodb}/page/FileHeader.java (95%) rename src/main/java/database/{ => innodb}/page/Page.java (96%) rename src/main/java/database/{ => innodb}/page/PageFactory.java (93%) rename src/main/java/database/{ => innodb}/page/PageHeader.java (96%) rename src/main/java/database/{ => innodb}/page/PageManager.java (98%) rename src/main/java/database/{ => innodb}/page/PageType.java (77%) rename src/test/java/database/{ => innodb}/BufferPoolTest.java (96%) rename src/test/java/database/{ => innodb}/page/PageFactoryTest.java (97%) rename src/test/java/database/{ => innodb}/page/PageHeaderTest.java (97%) rename src/test/java/database/{ => innodb}/page/PageManagerTest.java (98%) rename src/test/java/database/{ => innodb}/page/PageTest.java (96%) diff --git a/src/main/java/database/BufferPool.java b/src/main/java/database/innodb/BufferPool.java similarity index 92% rename from src/main/java/database/BufferPool.java rename to src/main/java/database/innodb/BufferPool.java index 006caf4..db92788 100644 --- a/src/main/java/database/BufferPool.java +++ b/src/main/java/database/innodb/BufferPool.java @@ -1,6 +1,6 @@ -package database; +package database.innodb; -import database.page.Page; +import database.innodb.page.Page; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/main/java/database/page/FileHeader.java b/src/main/java/database/innodb/page/FileHeader.java similarity index 95% rename from src/main/java/database/page/FileHeader.java rename to src/main/java/database/innodb/page/FileHeader.java index 1054493..43e64ba 100644 --- a/src/main/java/database/page/FileHeader.java +++ b/src/main/java/database/innodb/page/FileHeader.java @@ -1,4 +1,4 @@ -package database.page; +package database.innodb.page; import java.io.Serializable; diff --git a/src/main/java/database/page/Page.java b/src/main/java/database/innodb/page/Page.java similarity index 96% rename from src/main/java/database/page/Page.java rename to src/main/java/database/innodb/page/Page.java index ebe0bd0..9243d52 100644 --- a/src/main/java/database/page/Page.java +++ b/src/main/java/database/innodb/page/Page.java @@ -1,4 +1,4 @@ -package database.page; +package database.innodb.page; import java.io.Serializable; diff --git a/src/main/java/database/page/PageFactory.java b/src/main/java/database/innodb/page/PageFactory.java similarity index 93% rename from src/main/java/database/page/PageFactory.java rename to src/main/java/database/innodb/page/PageFactory.java index e5229fd..6bc5a71 100644 --- a/src/main/java/database/page/PageFactory.java +++ b/src/main/java/database/innodb/page/PageFactory.java @@ -1,4 +1,4 @@ -package database.page; +package database.innodb.page; public class PageFactory { diff --git a/src/main/java/database/page/PageHeader.java b/src/main/java/database/innodb/page/PageHeader.java similarity index 96% rename from src/main/java/database/page/PageHeader.java rename to src/main/java/database/innodb/page/PageHeader.java index 640c509..22da576 100644 --- a/src/main/java/database/page/PageHeader.java +++ b/src/main/java/database/innodb/page/PageHeader.java @@ -1,4 +1,4 @@ -package database.page; +package database.innodb.page; import java.io.Serializable; diff --git a/src/main/java/database/page/PageManager.java b/src/main/java/database/innodb/page/PageManager.java similarity index 98% rename from src/main/java/database/page/PageManager.java rename to src/main/java/database/innodb/page/PageManager.java index 8a5a2e7..77bddac 100644 --- a/src/main/java/database/page/PageManager.java +++ b/src/main/java/database/innodb/page/PageManager.java @@ -1,4 +1,4 @@ -package database.page; +package database.innodb.page; import java.io.File; import java.io.FileInputStream; diff --git a/src/main/java/database/page/PageType.java b/src/main/java/database/innodb/page/PageType.java similarity index 77% rename from src/main/java/database/page/PageType.java rename to src/main/java/database/innodb/page/PageType.java index 8d8c971..517d807 100644 --- a/src/main/java/database/page/PageType.java +++ b/src/main/java/database/innodb/page/PageType.java @@ -1,4 +1,4 @@ -package database.page; +package database.innodb.page; public enum PageType { PAGE_TYPE_CLUSTERED, diff --git a/src/test/java/database/BufferPoolTest.java b/src/test/java/database/innodb/BufferPoolTest.java similarity index 96% rename from src/test/java/database/BufferPoolTest.java rename to src/test/java/database/innodb/BufferPoolTest.java index f3c2714..4997b5d 100644 --- a/src/test/java/database/BufferPoolTest.java +++ b/src/test/java/database/innodb/BufferPoolTest.java @@ -1,9 +1,9 @@ -package database; +package database.innodb; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; -import database.page.PageFactory; +import database.innodb.page.PageFactory; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/database/page/PageFactoryTest.java b/src/test/java/database/innodb/page/PageFactoryTest.java similarity index 97% rename from src/test/java/database/page/PageFactoryTest.java rename to src/test/java/database/innodb/page/PageFactoryTest.java index 03059cc..038f7ee 100644 --- a/src/test/java/database/page/PageFactoryTest.java +++ b/src/test/java/database/innodb/page/PageFactoryTest.java @@ -1,4 +1,4 @@ -package database.page; +package database.innodb.page; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/database/page/PageHeaderTest.java b/src/test/java/database/innodb/page/PageHeaderTest.java similarity index 97% rename from src/test/java/database/page/PageHeaderTest.java rename to src/test/java/database/innodb/page/PageHeaderTest.java index a796cda..99cf3ac 100644 --- a/src/test/java/database/page/PageHeaderTest.java +++ b/src/test/java/database/innodb/page/PageHeaderTest.java @@ -1,4 +1,4 @@ -package database.page; +package database.innodb.page; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/database/page/PageManagerTest.java b/src/test/java/database/innodb/page/PageManagerTest.java similarity index 98% rename from src/test/java/database/page/PageManagerTest.java rename to src/test/java/database/innodb/page/PageManagerTest.java index 5c704fd..00aa53f 100644 --- a/src/test/java/database/page/PageManagerTest.java +++ b/src/test/java/database/innodb/page/PageManagerTest.java @@ -1,4 +1,4 @@ -package database.page; +package database.innodb.page; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/database/page/PageTest.java b/src/test/java/database/innodb/page/PageTest.java similarity index 96% rename from src/test/java/database/page/PageTest.java rename to src/test/java/database/innodb/page/PageTest.java index acc6016..64e0b36 100644 --- a/src/test/java/database/page/PageTest.java +++ b/src/test/java/database/innodb/page/PageTest.java @@ -1,4 +1,4 @@ -package database.page; +package database.innodb.page; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; From e4e9aa401c71a293a2b586e1f9a9837b5054e2c0 Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Mon, 26 Aug 2024 03:45:42 +0900 Subject: [PATCH 09/27] =?UTF-8?q?feat:=20=EB=8D=94=ED=8B=B0=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/database/innodb/page/Page.java | 4 ++++ .../java/database/innodb/page/PageHeader.java | 11 ++++++++++ .../database/innodb/page/PageHeaderTest.java | 22 +++++++++++++++++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/main/java/database/innodb/page/Page.java b/src/main/java/database/innodb/page/Page.java index 9243d52..3fcd13a 100644 --- a/src/main/java/database/innodb/page/Page.java +++ b/src/main/java/database/innodb/page/Page.java @@ -16,6 +16,10 @@ public Page(long pageNumber, PageType pageType) { this.freeSpace = PAGE_SIZE - (this.fileHeader.getHeaderSize() + this.pageHeader.getHeaderSize()); } + public void markDirty() { + pageHeader.markDirty(); + } + public long getPageNumber() { return fileHeader.getPageNumber(); } diff --git a/src/main/java/database/innodb/page/PageHeader.java b/src/main/java/database/innodb/page/PageHeader.java index 22da576..fd0fb29 100644 --- a/src/main/java/database/innodb/page/PageHeader.java +++ b/src/main/java/database/innodb/page/PageHeader.java @@ -7,10 +7,12 @@ public class PageHeader implements Serializable { private static final int HEADER_SIZE = 56; private int recordCount; + private boolean isDirty; private final PageType pageType; public PageHeader(PageType pageType) { this.recordCount = 0; + this.isDirty = false; this.pageType = pageType; } @@ -18,10 +20,18 @@ public void incrementRecordCount() { recordCount++; } + public void markDirty() { + isDirty = true; + } + public int getRecordCount() { return recordCount; } + public boolean isDirty() { + return isDirty; + } + public PageType getPageType() { return pageType; } @@ -34,6 +44,7 @@ public int getHeaderSize() { public String toString() { return "PageHeader{" + "recordCount=" + recordCount + + ", isDirty=" + isDirty + ", pageType=" + pageType + '}'; } diff --git a/src/test/java/database/innodb/page/PageHeaderTest.java b/src/test/java/database/innodb/page/PageHeaderTest.java index 99cf3ac..c3c0f55 100644 --- a/src/test/java/database/innodb/page/PageHeaderTest.java +++ b/src/test/java/database/innodb/page/PageHeaderTest.java @@ -1,6 +1,7 @@ package database.innodb.page; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; import java.util.stream.IntStream; import org.junit.jupiter.api.DisplayName; @@ -20,8 +21,11 @@ void createPageHeader() { PageHeader pageHeader = new PageHeader(pageType); // then - assertThat(pageHeader.getPageType()).isEqualTo(pageType); - assertThat(pageHeader.getRecordCount()).isEqualTo(initialRecordCnt); + assertAll( + () -> assertThat(pageHeader.getPageType()).isEqualTo(pageType), + () -> assertThat(pageHeader.getRecordCount()).isEqualTo(initialRecordCnt), + () -> assertThat(pageHeader.isDirty()).isFalse() + ); } @DisplayName("페이지 레코드 수가 증가한다.") @@ -39,4 +43,18 @@ void incrementRecord() { // then assertThat(pageHeader.getRecordCount()).isEqualTo(recordCnt); } + + @DisplayName("더티 페이지로 설정한다.") + @Test + void markDirty() { + // given + PageType pageType = PageType.PAGE_TYPE_CLUSTERED; + PageHeader pageHeader = new PageHeader(pageType); + + // when + pageHeader.markDirty(); + + // then + assertThat(pageHeader.isDirty()).isTrue(); + } } From b2f400fcd7a322b700a6a58d06ebb39705dd552d Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Mon, 26 Aug 2024 14:54:05 +0900 Subject: [PATCH 10/27] =?UTF-8?q?feat:=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EB=82=B4=EC=9D=98=20=EB=A0=88=EC=BD=94=EB=93=9C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/database/innodb/page/Page.java | 14 +++++++++ .../java/database/innodb/page/Record.java | 29 +++++++++++++++++++ .../java/database/innodb/page/RecordTest.java | 29 +++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 src/main/java/database/innodb/page/Record.java create mode 100644 src/test/java/database/innodb/page/RecordTest.java diff --git a/src/main/java/database/innodb/page/Page.java b/src/main/java/database/innodb/page/Page.java index 3fcd13a..9934c23 100644 --- a/src/main/java/database/innodb/page/Page.java +++ b/src/main/java/database/innodb/page/Page.java @@ -1,6 +1,8 @@ package database.innodb.page; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; public class Page implements Serializable { @@ -8,11 +10,13 @@ public class Page implements Serializable { private final FileHeader fileHeader; private final PageHeader pageHeader; + private final List userRecords; private int freeSpace; public Page(long pageNumber, PageType pageType) { this.fileHeader = new FileHeader(pageNumber); this.pageHeader = new PageHeader(pageType); + this.userRecords = new ArrayList<>(); this.freeSpace = PAGE_SIZE - (this.fileHeader.getHeaderSize() + this.pageHeader.getHeaderSize()); } @@ -35,4 +39,14 @@ public int getRecordCount() { public int getFreeSpace() { return freeSpace; } + + @Override + public String toString() { + return "Page{" + + "fileHeader=" + fileHeader + + ", pageHeader=" + pageHeader + + ", userRecords=" + userRecords + + ", freeSpace=" + freeSpace + + '}'; + } } diff --git a/src/main/java/database/innodb/page/Record.java b/src/main/java/database/innodb/page/Record.java new file mode 100644 index 0000000..7e6c2dc --- /dev/null +++ b/src/main/java/database/innodb/page/Record.java @@ -0,0 +1,29 @@ +package database.innodb.page; + +import java.io.Serializable; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +public class Record implements Serializable { + + private final byte[] data; + + public Record(byte[] data) { + this.data = data; + } + + public byte[] getData() { + return data; + } + + public int getSize() { + return data.length; + } + + @Override + public String toString() { + return "Record{" + + "data=" + Arrays.toString(data) + + '}'; + } +} diff --git a/src/test/java/database/innodb/page/RecordTest.java b/src/test/java/database/innodb/page/RecordTest.java new file mode 100644 index 0000000..54701a6 --- /dev/null +++ b/src/test/java/database/innodb/page/RecordTest.java @@ -0,0 +1,29 @@ +package database.innodb.page; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("레코드 테스트") +class RecordTest { + + @DisplayName("레코드 생성에 성공한다.") + @Test + void createRecord() { + // given + byte[] data = new byte[]{1, 2, 3, 4}; + Record record = new Record(data); + + // when + byte[] retrievedData = record.getData(); + + // then + assertAll( + () -> assertArrayEquals(data, retrievedData), + () -> assertThat(record.getSize()).isEqualTo(data.length) + ); + } +} From 7e67c122a010496782c6226388f678cb2df8716c Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Mon, 26 Aug 2024 15:14:37 +0900 Subject: [PATCH 11/27] =?UTF-8?q?feat:=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EB=94=94=EB=A0=89=ED=84=B0=EB=A6=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/database/innodb/page/Page.java | 2 ++ .../database/innodb/page/PageDirectory.java | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 src/main/java/database/innodb/page/PageDirectory.java diff --git a/src/main/java/database/innodb/page/Page.java b/src/main/java/database/innodb/page/Page.java index 9934c23..a44a0d7 100644 --- a/src/main/java/database/innodb/page/Page.java +++ b/src/main/java/database/innodb/page/Page.java @@ -12,11 +12,13 @@ public class Page implements Serializable { private final PageHeader pageHeader; private final List userRecords; private int freeSpace; + private final PageDirectory pageDirectory; public Page(long pageNumber, PageType pageType) { this.fileHeader = new FileHeader(pageNumber); this.pageHeader = new PageHeader(pageType); this.userRecords = new ArrayList<>(); + this.pageDirectory = new PageDirectory(); this.freeSpace = PAGE_SIZE - (this.fileHeader.getHeaderSize() + this.pageHeader.getHeaderSize()); } diff --git a/src/main/java/database/innodb/page/PageDirectory.java b/src/main/java/database/innodb/page/PageDirectory.java new file mode 100644 index 0000000..2c0a585 --- /dev/null +++ b/src/main/java/database/innodb/page/PageDirectory.java @@ -0,0 +1,21 @@ +package database.innodb.page; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +public class PageDirectory implements Serializable { + + private final List recordPositions; + + public PageDirectory() { + this.recordPositions = new ArrayList<>(); + } + + @Override + public String toString() { + return "PageDirectory{" + + "recordPositions=" + recordPositions + + '}'; + } +} From aaa047fe51ec4d14f4847cada0a512ba689d3fd0 Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Mon, 26 Aug 2024 15:57:58 +0900 Subject: [PATCH 12/27] =?UTF-8?q?feat:=20=EB=A0=88=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/database/innodb/page/Page.java | 15 ++++++++++++- .../database/innodb/page/PageDirectory.java | 4 ++++ .../java/database/innodb/page/PageTest.java | 21 +++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/main/java/database/innodb/page/Page.java b/src/main/java/database/innodb/page/Page.java index a44a0d7..d65e1bd 100644 --- a/src/main/java/database/innodb/page/Page.java +++ b/src/main/java/database/innodb/page/Page.java @@ -11,8 +11,8 @@ public class Page implements Serializable { private final FileHeader fileHeader; private final PageHeader pageHeader; private final List userRecords; - private int freeSpace; private final PageDirectory pageDirectory; + private int freeSpace; public Page(long pageNumber, PageType pageType) { this.fileHeader = new FileHeader(pageNumber); @@ -22,6 +22,19 @@ public Page(long pageNumber, PageType pageType) { this.freeSpace = PAGE_SIZE - (this.fileHeader.getHeaderSize() + this.pageHeader.getHeaderSize()); } + public boolean addRecord(Record record) { + int recordSize = record.getSize(); + if (freeSpace >= recordSize) { + userRecords.add(record); + pageDirectory.addRecordPosition(userRecords.size() - 1); + freeSpace -= recordSize; + pageHeader.incrementRecordCount(); + return true; + } else { + return false; + } + } + public void markDirty() { pageHeader.markDirty(); } diff --git a/src/main/java/database/innodb/page/PageDirectory.java b/src/main/java/database/innodb/page/PageDirectory.java index 2c0a585..4e76c18 100644 --- a/src/main/java/database/innodb/page/PageDirectory.java +++ b/src/main/java/database/innodb/page/PageDirectory.java @@ -12,6 +12,10 @@ public PageDirectory() { this.recordPositions = new ArrayList<>(); } + public void addRecordPosition(int position) { + recordPositions.add(position); + } + @Override public String toString() { return "PageDirectory{" + diff --git a/src/test/java/database/innodb/page/PageTest.java b/src/test/java/database/innodb/page/PageTest.java index 64e0b36..dadc736 100644 --- a/src/test/java/database/innodb/page/PageTest.java +++ b/src/test/java/database/innodb/page/PageTest.java @@ -26,4 +26,25 @@ void createPage() { () -> assertThat(page.getRecordCount()).isEqualTo(0) ); } + + @DisplayName("레코드 추가에 성공한다.") + @Test + void addRecord() { + // given + int pageNumber = 1; + PageType pageType = PageType.PAGE_TYPE_CLUSTERED; + Page page = new Page(pageNumber, pageType); + Record record1 = new Record(new byte[]{1, 2, 3, 4}); + Record record2 = new Record(new byte[]{5, 6, 7, 8}); + + // when + page.addRecord(record1); + page.addRecord(record2); + + // then + assertAll( + () -> assertThat(page.getRecordCount()).isEqualTo(2), + () -> assertThat(page.getPageNumber()).isEqualTo(pageNumber) + ); + } } From 7f32e11071a7870d46f8567d4ba5653ce1e31f18 Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Tue, 27 Aug 2024 14:06:34 +0900 Subject: [PATCH 13/27] =?UTF-8?q?feat:=20=EB=A0=88=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EC=8B=9C,=20=EB=8D=94=ED=8B=B0=20?= =?UTF-8?q?=EC=B2=B4=ED=81=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/database/innodb/page/Page.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/database/innodb/page/Page.java b/src/main/java/database/innodb/page/Page.java index d65e1bd..4ee30a6 100644 --- a/src/main/java/database/innodb/page/Page.java +++ b/src/main/java/database/innodb/page/Page.java @@ -29,13 +29,14 @@ public boolean addRecord(Record record) { pageDirectory.addRecordPosition(userRecords.size() - 1); freeSpace -= recordSize; pageHeader.incrementRecordCount(); + markDirty(); return true; } else { return false; } } - public void markDirty() { + private void markDirty() { pageHeader.markDirty(); } @@ -61,6 +62,7 @@ public String toString() { "fileHeader=" + fileHeader + ", pageHeader=" + pageHeader + ", userRecords=" + userRecords + + ", pageDirectory=" + pageDirectory + ", freeSpace=" + freeSpace + '}'; } From d1a989f4719416b9811db0e2ffcbe6c6b957e72e Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Tue, 27 Aug 2024 14:49:59 +0900 Subject: [PATCH 14/27] =?UTF-8?q?feat:=20=ED=85=8C=EC=9D=B4=EB=B8=94=20?= =?UTF-8?q?=EB=B3=84=EB=A1=9C=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../database/innodb/page/PageManager.java | 45 +++++++++++++++---- .../database/innodb/page/PageManagerTest.java | 27 ++++++----- 2 files changed, 53 insertions(+), 19 deletions(-) diff --git a/src/main/java/database/innodb/page/PageManager.java b/src/main/java/database/innodb/page/PageManager.java index 77bddac..6852d05 100644 --- a/src/main/java/database/innodb/page/PageManager.java +++ b/src/main/java/database/innodb/page/PageManager.java @@ -6,18 +6,23 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.RandomAccessFile; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; public class PageManager { + private static final int PAGE_SIZE = 16 * 1024; private static final String DIRECTORY_PATH = "disk"; - private static final String INFIX = "page_"; private static final String FILE_EXTENSION = ".ibd"; - public PageManager() { + private final String tableName; + + public PageManager(String tableName) { + this.tableName = tableName; createDirectoryIfNotExists(); + createTableIfNotExists(); } private void createDirectoryIfNotExists() { @@ -31,20 +36,42 @@ private void createDirectoryIfNotExists() { } } + private void createTableIfNotExists() { + String fileName = DIRECTORY_PATH + File.separator + tableName + FILE_EXTENSION; + File file = new File(fileName); + if (!file.exists()) { + try { + file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + public void savePage(Page page) { - String fileName = DIRECTORY_PATH + File.separator + INFIX + page.getPageNumber() + FILE_EXTENSION; - try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName))) { - out.writeObject(page); + String fileName = DIRECTORY_PATH + File.separator + tableName + FILE_EXTENSION; + + try (RandomAccessFile file = new RandomAccessFile(fileName, "rw")) { + file.seek(page.getPageNumber() * PAGE_SIZE); + + try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file.getFD()))) { + out.writeObject(page); + } } catch (IOException e) { e.printStackTrace(); } } public Page loadPage(long pageNum) { - String fileName = DIRECTORY_PATH + File.separator + INFIX + pageNum + FILE_EXTENSION; - try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName))) { - Page page = (Page) in.readObject(); - return page; + String fileName = DIRECTORY_PATH + File.separator + tableName + FILE_EXTENSION; + + try (RandomAccessFile file = new RandomAccessFile(fileName, "r")) { + file.seek(pageNum * PAGE_SIZE); + + try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file.getFD()))) { + Page page = (Page) in.readObject(); + return page; + } } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); return null; diff --git a/src/test/java/database/innodb/page/PageManagerTest.java b/src/test/java/database/innodb/page/PageManagerTest.java index 00aa53f..96901d2 100644 --- a/src/test/java/database/innodb/page/PageManagerTest.java +++ b/src/test/java/database/innodb/page/PageManagerTest.java @@ -15,28 +15,27 @@ class PageManagerTest { private static final String DIRECTORY_PATH = "disk"; - private static final String INFIX = "page_"; private static final String FILE_EXTENSION = ".ibd"; private PageManager pageManager; - private final int pageNumber = 1234; + private final String tableName = "table"; @BeforeEach void setUp() { - pageManager = new PageManager(); + pageManager = new PageManager(tableName); } @DisplayName("페이지 저장에 성공한다.") @Test void savePage() { // given - Page page = PageFactory.createDataPage(pageNumber); + Page page = PageFactory.createDataPage(0); // when pageManager.savePage(page); // then - Path filePath = Paths.get(DIRECTORY_PATH, INFIX + pageNumber + FILE_EXTENSION); + Path filePath = Paths.get(DIRECTORY_PATH, tableName + FILE_EXTENSION); assertThat(Files.exists(filePath)).isTrue(); } @@ -44,19 +43,27 @@ void savePage() { @Test void loadPage() { // given - Page page = PageFactory.createDataPage(pageNumber); - pageManager.savePage(page); + int pageNumber1 = 1; + int pageNumber2 = 2; + + Page page1 = PageFactory.createDataPage(pageNumber1); + Page page2 = PageFactory.createUndoPage(pageNumber2); + + pageManager.savePage(page1); + pageManager.savePage(page2); // when - Page foundPage = pageManager.loadPage(pageNumber); + Page foundPage1 = pageManager.loadPage(pageNumber1); + Page foundPage2 = pageManager.loadPage(pageNumber2); // then - assertThat(foundPage.getPageNumber()).isEqualTo(pageNumber); + assertThat(foundPage1.getPageNumber()).isEqualTo(pageNumber1); + assertThat(foundPage2.getPageNumber()).isEqualTo(pageNumber2); } @AfterEach void tearDown() { - Path filePath = Paths.get(DIRECTORY_PATH, INFIX + pageNumber + FILE_EXTENSION); + Path filePath = Paths.get(DIRECTORY_PATH, tableName + FILE_EXTENSION); try { Files.deleteIfExists(filePath); } catch (IOException e) { From 74c8f413b97b83a86f354ae2789e66731220f4c1 Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Tue, 27 Aug 2024 14:59:26 +0900 Subject: [PATCH 15/27] =?UTF-8?q?feat:=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20=EB=B0=98=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/database/innodb/page/PageManager.java | 7 +++++++ src/test/java/database/innodb/page/PageManagerTest.java | 1 + 2 files changed, 8 insertions(+) diff --git a/src/main/java/database/innodb/page/PageManager.java b/src/main/java/database/innodb/page/PageManager.java index 6852d05..e1acbf7 100644 --- a/src/main/java/database/innodb/page/PageManager.java +++ b/src/main/java/database/innodb/page/PageManager.java @@ -18,11 +18,13 @@ public class PageManager { private static final String FILE_EXTENSION = ".ibd"; private final String tableName; + private int pageSize; public PageManager(String tableName) { this.tableName = tableName; createDirectoryIfNotExists(); createTableIfNotExists(); + this.pageSize = 0; } private void createDirectoryIfNotExists() { @@ -57,6 +59,7 @@ public void savePage(Page page) { try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file.getFD()))) { out.writeObject(page); } + pageSize++; } catch (IOException e) { e.printStackTrace(); } @@ -77,4 +80,8 @@ public Page loadPage(long pageNum) { return null; } } + + public int getNewPageNumber() { + return pageSize; + } } diff --git a/src/test/java/database/innodb/page/PageManagerTest.java b/src/test/java/database/innodb/page/PageManagerTest.java index 96901d2..f231556 100644 --- a/src/test/java/database/innodb/page/PageManagerTest.java +++ b/src/test/java/database/innodb/page/PageManagerTest.java @@ -37,6 +37,7 @@ void savePage() { // then Path filePath = Paths.get(DIRECTORY_PATH, tableName + FILE_EXTENSION); assertThat(Files.exists(filePath)).isTrue(); + assertThat(pageManager.getNewPageNumber()).isEqualTo(1); } @DisplayName("페이지 조회에 성공한다.") From 7142ae784cfbe2ad259247d13847e27dda9bf52e Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Tue, 27 Aug 2024 15:31:53 +0900 Subject: [PATCH 16/27] =?UTF-8?q?refactor:=20=EB=B2=84=ED=8D=BC=ED=92=80?= =?UTF-8?q?=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../innodb/{ => bufferpool}/BufferPool.java | 15 ++++++++++++++- .../innodb/{ => bufferpool}/BufferPoolTest.java | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) rename src/main/java/database/innodb/{ => bufferpool}/BufferPool.java (60%) rename src/test/java/database/innodb/{ => bufferpool}/BufferPoolTest.java (97%) diff --git a/src/main/java/database/innodb/BufferPool.java b/src/main/java/database/innodb/bufferpool/BufferPool.java similarity index 60% rename from src/main/java/database/innodb/BufferPool.java rename to src/main/java/database/innodb/bufferpool/BufferPool.java index db92788..9684189 100644 --- a/src/main/java/database/innodb/BufferPool.java +++ b/src/main/java/database/innodb/bufferpool/BufferPool.java @@ -1,8 +1,11 @@ -package database.innodb; +package database.innodb.bufferpool; import database.innodb.page.Page; +import database.innodb.page.Record; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Optional; +import java.util.stream.IntStream; public class BufferPool { @@ -12,6 +15,7 @@ public class BufferPool { public BufferPool(int capacity) { this.capacity = capacity; this.cache = new LinkedHashMap<>(capacity, 0.75f, true) { + // TODO: 전략 패턴 도입 protected boolean removeEldestEntry(Map.Entry eldest) { return size() > BufferPool.this.capacity; } @@ -29,4 +33,13 @@ public void putPage(Page page) { public boolean containsPage(long pageNum) { return cache.containsKey(pageNum); } + + public Optional findPageWithSpace(Record record) { + return IntStream.range(0, capacity) + .filter(this::containsPage) + .mapToObj(this::getPage) + .filter(page -> page.getFreeSpace() >= record.getSize()) + .findFirst() + .or(Optional::empty); + } } diff --git a/src/test/java/database/innodb/BufferPoolTest.java b/src/test/java/database/innodb/bufferpool/BufferPoolTest.java similarity index 97% rename from src/test/java/database/innodb/BufferPoolTest.java rename to src/test/java/database/innodb/bufferpool/BufferPoolTest.java index 4997b5d..cbbaae1 100644 --- a/src/test/java/database/innodb/BufferPoolTest.java +++ b/src/test/java/database/innodb/bufferpool/BufferPoolTest.java @@ -1,4 +1,4 @@ -package database.innodb; +package database.innodb.bufferpool; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; From a6c932d2f9171476a231d5f6567ecc1a828c00a1 Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Tue, 27 Aug 2024 15:42:01 +0900 Subject: [PATCH 17/27] =?UTF-8?q?feat:=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EA=B5=90=EC=B2=B4=20=EC=95=8C=EA=B3=A0=EB=A6=AC=EC=A6=98=20?= =?UTF-8?q?=EC=A0=84=EB=9E=B5=20=ED=8C=A8=ED=84=B4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../innodb/bufferpool/BufferPool.java | 13 ++--- .../bufferpool/PageReplacementStrategy.java | 10 ++++ .../LFUStrategy.java | 51 +++++++++++++++++++ .../LRUStrategy.java | 34 +++++++++++++ .../innodb/bufferpool/BufferPoolTest.java | 16 ++++-- 5 files changed, 110 insertions(+), 14 deletions(-) create mode 100644 src/main/java/database/innodb/bufferpool/PageReplacementStrategy.java create mode 100644 src/main/java/database/innodb/bufferpool/pageReplacementStrategies/LFUStrategy.java create mode 100644 src/main/java/database/innodb/bufferpool/pageReplacementStrategies/LRUStrategy.java diff --git a/src/main/java/database/innodb/bufferpool/BufferPool.java b/src/main/java/database/innodb/bufferpool/BufferPool.java index 9684189..4ca78e4 100644 --- a/src/main/java/database/innodb/bufferpool/BufferPool.java +++ b/src/main/java/database/innodb/bufferpool/BufferPool.java @@ -2,24 +2,17 @@ import database.innodb.page.Page; import database.innodb.page.Record; -import java.util.LinkedHashMap; -import java.util.Map; import java.util.Optional; import java.util.stream.IntStream; public class BufferPool { private final int capacity; - private final LinkedHashMap cache; + private final PageReplacementStrategy cache; - public BufferPool(int capacity) { + public BufferPool(int capacity, PageReplacementStrategy cacheStrategy) { this.capacity = capacity; - this.cache = new LinkedHashMap<>(capacity, 0.75f, true) { - // TODO: 전략 패턴 도입 - protected boolean removeEldestEntry(Map.Entry eldest) { - return size() > BufferPool.this.capacity; - } - }; + this.cache = cacheStrategy; } public Page getPage(long pageNum) { diff --git a/src/main/java/database/innodb/bufferpool/PageReplacementStrategy.java b/src/main/java/database/innodb/bufferpool/PageReplacementStrategy.java new file mode 100644 index 0000000..2d1530d --- /dev/null +++ b/src/main/java/database/innodb/bufferpool/PageReplacementStrategy.java @@ -0,0 +1,10 @@ +package database.innodb.bufferpool; + +public interface PageReplacementStrategy { + + void put(K key, V value); + + V get(K key); + + boolean containsKey(K key); +} diff --git a/src/main/java/database/innodb/bufferpool/pageReplacementStrategies/LFUStrategy.java b/src/main/java/database/innodb/bufferpool/pageReplacementStrategies/LFUStrategy.java new file mode 100644 index 0000000..1081ecd --- /dev/null +++ b/src/main/java/database/innodb/bufferpool/pageReplacementStrategies/LFUStrategy.java @@ -0,0 +1,51 @@ +package database.innodb.bufferpool.pageReplacementStrategies; + +import database.innodb.bufferpool.PageReplacementStrategy; +import java.util.HashMap; +import java.util.Map; + +public class LFUStrategy implements PageReplacementStrategy { + + private final int capacity; + private final Map cache; + private final Map usageCount; + + public LFUStrategy(int capacity) { + this.capacity = capacity; + this.cache = new HashMap<>(); + this.usageCount = new HashMap<>(); + } + + @Override + public void put(K key, V value) { + if (cache.size() >= capacity) { + K leastUsedKey = findLeastUsedKey(); + cache.remove(leastUsedKey); + usageCount.remove(leastUsedKey); + } + cache.put(key, value); + usageCount.put(key, 1); + } + + @Override + public V get(K key) { + if (cache.containsKey(key)) { + usageCount.put(key, usageCount.get(key) + 1); + return cache.get(key); + } + return null; + } + + @Override + public boolean containsKey(K key) { + return cache.containsKey(key); + } + + private K findLeastUsedKey() { + return usageCount.entrySet() + .stream() + .min(Map.Entry.comparingByValue()) + .get() + .getKey(); + } +} diff --git a/src/main/java/database/innodb/bufferpool/pageReplacementStrategies/LRUStrategy.java b/src/main/java/database/innodb/bufferpool/pageReplacementStrategies/LRUStrategy.java new file mode 100644 index 0000000..b345cf3 --- /dev/null +++ b/src/main/java/database/innodb/bufferpool/pageReplacementStrategies/LRUStrategy.java @@ -0,0 +1,34 @@ +package database.innodb.bufferpool.pageReplacementStrategies; + +import database.innodb.bufferpool.PageReplacementStrategy; +import java.util.LinkedHashMap; +import java.util.Map; + +public class LRUStrategy implements PageReplacementStrategy { + + private final LinkedHashMap cache; + + public LRUStrategy(int capacity) { + this.cache = new LinkedHashMap<>(capacity, 0.75f, true) { + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > capacity; + } + }; + } + + @Override + public void put(K key, V value) { + cache.put(key, value); + } + + @Override + public V get(K key) { + return cache.get(key); + } + + @Override + public boolean containsKey(K key) { + return cache.containsKey(key); + } +} + diff --git a/src/test/java/database/innodb/bufferpool/BufferPoolTest.java b/src/test/java/database/innodb/bufferpool/BufferPoolTest.java index cbbaae1..27ad98c 100644 --- a/src/test/java/database/innodb/bufferpool/BufferPoolTest.java +++ b/src/test/java/database/innodb/bufferpool/BufferPoolTest.java @@ -3,23 +3,33 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; +import database.innodb.bufferpool.pageReplacementStrategies.LRUStrategy; +import database.innodb.page.Page; import database.innodb.page.PageFactory; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @DisplayName("버퍼풀 테스트") class BufferPoolTest { + private final int capacity = 2; + private BufferPool bufferPool; + + @BeforeEach + void setUp() { + PageReplacementStrategy lruStrategy = new LRUStrategy<>(capacity); + bufferPool = new BufferPool(capacity, lruStrategy); + } + @DisplayName("버퍼풀 생성에 성공한다.") @Test void createBufferPool() { // given - int capacity = 2; int pageNumber1 = 1; int pageNumber2 = 2; // when - BufferPool bufferPool = new BufferPool(capacity); bufferPool.putPage(PageFactory.createDataPage(pageNumber1)); bufferPool.putPage(PageFactory.createDataPage(pageNumber2)); @@ -32,12 +42,10 @@ void createBufferPool() { @Test void lru() { // given - int capacity = 2; int pageNumber1 = 1; int pageNumber2 = 2; int pageNumber3 = 3; - BufferPool bufferPool = new BufferPool(capacity); bufferPool.putPage(PageFactory.createDataPage(pageNumber1)); bufferPool.putPage(PageFactory.createDataPage(pageNumber2)); From f57d61fc0568a644245243768da29307729cf516 Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Tue, 27 Aug 2024 15:48:05 +0900 Subject: [PATCH 18/27] =?UTF-8?q?refactor:=20=ED=8F=AC=ED=8A=B8=EC=97=90?= =?UTF-8?q?=20final=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/database/ClientHandler.java | 1 + src/main/java/database/DatabaseServer.java | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/database/ClientHandler.java b/src/main/java/database/ClientHandler.java index 48abec7..add8bb3 100644 --- a/src/main/java/database/ClientHandler.java +++ b/src/main/java/database/ClientHandler.java @@ -7,6 +7,7 @@ import java.net.Socket; public class ClientHandler implements Runnable { + private final Socket clientSocket; public ClientHandler(Socket clientSocket) { diff --git a/src/main/java/database/DatabaseServer.java b/src/main/java/database/DatabaseServer.java index 7ef6247..a16a079 100644 --- a/src/main/java/database/DatabaseServer.java +++ b/src/main/java/database/DatabaseServer.java @@ -5,7 +5,8 @@ import java.net.Socket; public class DatabaseServer { - private int port; + + private final int port; private boolean isRunning; public DatabaseServer(int port) { From 63d1330ea14d03ad485938889d6495d7e8a7d442 Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Tue, 27 Aug 2024 15:48:36 +0900 Subject: [PATCH 19/27] =?UTF-8?q?refactor:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=ED=8F=AC=EB=A9=A7=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../database/innodb/bufferpool/BufferPool.java | 16 ++++++++-------- .../pageReplacementStrategies/LFUStrategy.java | 16 ++++++++-------- .../java/database/innodb/page/PageHeader.java | 3 +-- src/main/java/database/innodb/page/Record.java | 1 - 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/main/java/database/innodb/bufferpool/BufferPool.java b/src/main/java/database/innodb/bufferpool/BufferPool.java index 4ca78e4..2dcb997 100644 --- a/src/main/java/database/innodb/bufferpool/BufferPool.java +++ b/src/main/java/database/innodb/bufferpool/BufferPool.java @@ -15,18 +15,10 @@ public BufferPool(int capacity, PageReplacementStrategy cacheStrateg this.cache = cacheStrategy; } - public Page getPage(long pageNum) { - return cache.get(pageNum); - } - public void putPage(Page page) { cache.put(page.getPageNumber(), page); } - public boolean containsPage(long pageNum) { - return cache.containsKey(pageNum); - } - public Optional findPageWithSpace(Record record) { return IntStream.range(0, capacity) .filter(this::containsPage) @@ -35,4 +27,12 @@ public Optional findPageWithSpace(Record record) { .findFirst() .or(Optional::empty); } + + public boolean containsPage(long pageNum) { + return cache.containsKey(pageNum); + } + + public Page getPage(long pageNum) { + return cache.get(pageNum); + } } diff --git a/src/main/java/database/innodb/bufferpool/pageReplacementStrategies/LFUStrategy.java b/src/main/java/database/innodb/bufferpool/pageReplacementStrategies/LFUStrategy.java index 1081ecd..ed575ea 100644 --- a/src/main/java/database/innodb/bufferpool/pageReplacementStrategies/LFUStrategy.java +++ b/src/main/java/database/innodb/bufferpool/pageReplacementStrategies/LFUStrategy.java @@ -27,6 +27,14 @@ public void put(K key, V value) { usageCount.put(key, 1); } + private K findLeastUsedKey() { + return usageCount.entrySet() + .stream() + .min(Map.Entry.comparingByValue()) + .get() + .getKey(); + } + @Override public V get(K key) { if (cache.containsKey(key)) { @@ -40,12 +48,4 @@ public V get(K key) { public boolean containsKey(K key) { return cache.containsKey(key); } - - private K findLeastUsedKey() { - return usageCount.entrySet() - .stream() - .min(Map.Entry.comparingByValue()) - .get() - .getKey(); - } } diff --git a/src/main/java/database/innodb/page/PageHeader.java b/src/main/java/database/innodb/page/PageHeader.java index fd0fb29..19ca344 100644 --- a/src/main/java/database/innodb/page/PageHeader.java +++ b/src/main/java/database/innodb/page/PageHeader.java @@ -5,10 +5,9 @@ public class PageHeader implements Serializable { private static final int HEADER_SIZE = 56; - + private final PageType pageType; private int recordCount; private boolean isDirty; - private final PageType pageType; public PageHeader(PageType pageType) { this.recordCount = 0; diff --git a/src/main/java/database/innodb/page/Record.java b/src/main/java/database/innodb/page/Record.java index 7e6c2dc..3eba79b 100644 --- a/src/main/java/database/innodb/page/Record.java +++ b/src/main/java/database/innodb/page/Record.java @@ -1,7 +1,6 @@ package database.innodb.page; import java.io.Serializable; -import java.nio.charset.StandardCharsets; import java.util.Arrays; public class Record implements Serializable { From 4dc0e44a6899066a8469a0ba5f588d53b07dc56b Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Tue, 27 Aug 2024 15:54:38 +0900 Subject: [PATCH 20/27] =?UTF-8?q?feat:=20=ED=95=B8=EB=93=A4=EB=9F=AC=20?= =?UTF-8?q?=EC=82=BD=EC=9E=85=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/database/Handler.java | 13 +++++ .../java/database/innodb/InnodbHandler.java | 54 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 src/main/java/database/Handler.java create mode 100644 src/main/java/database/innodb/InnodbHandler.java diff --git a/src/main/java/database/Handler.java b/src/main/java/database/Handler.java new file mode 100644 index 0000000..01aef01 --- /dev/null +++ b/src/main/java/database/Handler.java @@ -0,0 +1,13 @@ +package database; + +public interface Handler { + + void insert(byte[] record); + + byte[] search(Object key); + + void update(Object key, byte[] newRecord); + + void delete(Object key); +} + diff --git a/src/main/java/database/innodb/InnodbHandler.java b/src/main/java/database/innodb/InnodbHandler.java new file mode 100644 index 0000000..26acabd --- /dev/null +++ b/src/main/java/database/innodb/InnodbHandler.java @@ -0,0 +1,54 @@ +package database.innodb; + +import database.Handler; +import database.innodb.bufferpool.BufferPool; +import database.innodb.bufferpool.PageReplacementStrategy; +import database.innodb.bufferpool.pageReplacementStrategies.LRUStrategy; +import database.innodb.page.Page; +import database.innodb.page.PageFactory; +import database.innodb.page.PageManager; +import database.innodb.page.Record; + +public class InnodbHandler implements Handler { + + private static final int BUFFER_SIZE = 40; + + private final BufferPool bufferPool; + private final PageManager pageManager; + + public InnodbHandler(String tableName) { + PageReplacementStrategy lruStrategy = new LRUStrategy<>(BUFFER_SIZE); + this.bufferPool = new BufferPool(BUFFER_SIZE, lruStrategy); + this.pageManager = new PageManager(tableName); + } + + @Override + public void insert(byte[] recordData) { + Record record = new Record(recordData); + Page page = bufferPool.findPageWithSpace(record) + .orElseGet(this::createNewPage); + page.addRecord(record); + bufferPool.putPage(page); + } + + private Page createNewPage() { + long newPageNumber = pageManager.getNewPageNumber(); + return PageFactory.createDataPage(newPageNumber); + } + + @Override + public byte[] search(Object key) { + // 디스크에서 레코드를 검색하는 로직 + return null; + } + + @Override + public void update(Object key, byte[] newRecord) { + // 디스크에서 레코드를 업데이트하는 로직 + } + + @Override + public void delete(Object key) { + // 디스크에서 레코드를 삭제하는 로직 + } +} From ff5cfbbb5b36e5e8e7939eb23b08169122dbee72 Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Tue, 27 Aug 2024 16:34:33 +0900 Subject: [PATCH 21/27] =?UTF-8?q?refactor:=20=EB=A0=88=EC=BD=94=EB=93=9C?= =?UTF-8?q?=20=ED=8C=8C=EC=9D=BC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/database/Application.java | 2 ++ .../database/{ => engine}/ClientHandler.java | 2 +- .../database/{ => engine}/DatabaseServer.java | 2 +- .../java/database/{ => engine}/Handler.java | 6 ++-- .../{innodb/page => engine}/Record.java | 5 ++-- .../java/database/innodb/InnodbHandler.java | 14 ++++++---- .../innodb/bufferpool/BufferPool.java | 6 ++-- src/main/java/database/innodb/page/Page.java | 14 +++++----- .../database/innodb/page/StorageRecord.java | 28 +++++++++++++++++++ .../java/database/innodb/page/PageTest.java | 8 +++--- ...RecordTest.java => StorageRecordTest.java} | 8 +++--- 11 files changed, 64 insertions(+), 31 deletions(-) rename src/main/java/database/{ => engine}/ClientHandler.java (97%) rename src/main/java/database/{ => engine}/DatabaseServer.java (96%) rename src/main/java/database/{ => engine}/Handler.java (62%) rename src/main/java/database/{innodb/page => engine}/Record.java (79%) create mode 100644 src/main/java/database/innodb/page/StorageRecord.java rename src/test/java/database/innodb/page/{RecordTest.java => StorageRecordTest.java} (73%) diff --git a/src/main/java/database/Application.java b/src/main/java/database/Application.java index 7dce43a..40a152f 100644 --- a/src/main/java/database/Application.java +++ b/src/main/java/database/Application.java @@ -1,5 +1,7 @@ package database; +import database.engine.DatabaseServer; + public class Application { public static void main(String[] args) { diff --git a/src/main/java/database/ClientHandler.java b/src/main/java/database/engine/ClientHandler.java similarity index 97% rename from src/main/java/database/ClientHandler.java rename to src/main/java/database/engine/ClientHandler.java index add8bb3..ef98d7f 100644 --- a/src/main/java/database/ClientHandler.java +++ b/src/main/java/database/engine/ClientHandler.java @@ -1,4 +1,4 @@ -package database; +package database.engine; import java.io.BufferedReader; import java.io.InputStreamReader; diff --git a/src/main/java/database/DatabaseServer.java b/src/main/java/database/engine/DatabaseServer.java similarity index 96% rename from src/main/java/database/DatabaseServer.java rename to src/main/java/database/engine/DatabaseServer.java index a16a079..423b11e 100644 --- a/src/main/java/database/DatabaseServer.java +++ b/src/main/java/database/engine/DatabaseServer.java @@ -1,4 +1,4 @@ -package database; +package database.engine; import java.io.IOException; import java.net.ServerSocket; diff --git a/src/main/java/database/Handler.java b/src/main/java/database/engine/Handler.java similarity index 62% rename from src/main/java/database/Handler.java rename to src/main/java/database/engine/Handler.java index 01aef01..3ae4edd 100644 --- a/src/main/java/database/Handler.java +++ b/src/main/java/database/engine/Handler.java @@ -1,10 +1,12 @@ -package database; +package database.engine; + +import java.util.List; public interface Handler { void insert(byte[] record); - byte[] search(Object key); + List search(Object key); void update(Object key, byte[] newRecord); diff --git a/src/main/java/database/innodb/page/Record.java b/src/main/java/database/engine/Record.java similarity index 79% rename from src/main/java/database/innodb/page/Record.java rename to src/main/java/database/engine/Record.java index 3eba79b..cf11c1d 100644 --- a/src/main/java/database/innodb/page/Record.java +++ b/src/main/java/database/engine/Record.java @@ -1,9 +1,8 @@ -package database.innodb.page; +package database.engine; -import java.io.Serializable; import java.util.Arrays; -public class Record implements Serializable { +public class Record { private final byte[] data; diff --git a/src/main/java/database/innodb/InnodbHandler.java b/src/main/java/database/innodb/InnodbHandler.java index 26acabd..c2695f3 100644 --- a/src/main/java/database/innodb/InnodbHandler.java +++ b/src/main/java/database/innodb/InnodbHandler.java @@ -1,13 +1,15 @@ package database.innodb; -import database.Handler; +import database.engine.Handler; +import database.engine.Record; import database.innodb.bufferpool.BufferPool; import database.innodb.bufferpool.PageReplacementStrategy; import database.innodb.bufferpool.pageReplacementStrategies.LRUStrategy; import database.innodb.page.Page; import database.innodb.page.PageFactory; import database.innodb.page.PageManager; -import database.innodb.page.Record; +import database.innodb.page.StorageRecord; +import java.util.List; public class InnodbHandler implements Handler { @@ -24,10 +26,10 @@ public InnodbHandler(String tableName) { @Override public void insert(byte[] recordData) { - Record record = new Record(recordData); - Page page = bufferPool.findPageWithSpace(record) + StorageRecord storageRecord = new StorageRecord(recordData); + Page page = bufferPool.findPageWithSpace(storageRecord) .orElseGet(this::createNewPage); - page.addRecord(record); + page.addRecord(storageRecord); bufferPool.putPage(page); } @@ -37,7 +39,7 @@ private Page createNewPage() { } @Override - public byte[] search(Object key) { + public List search(Object key) { // 디스크에서 레코드를 검색하는 로직 return null; } diff --git a/src/main/java/database/innodb/bufferpool/BufferPool.java b/src/main/java/database/innodb/bufferpool/BufferPool.java index 2dcb997..cb8c8ef 100644 --- a/src/main/java/database/innodb/bufferpool/BufferPool.java +++ b/src/main/java/database/innodb/bufferpool/BufferPool.java @@ -1,7 +1,7 @@ package database.innodb.bufferpool; import database.innodb.page.Page; -import database.innodb.page.Record; +import database.innodb.page.StorageRecord; import java.util.Optional; import java.util.stream.IntStream; @@ -19,11 +19,11 @@ public void putPage(Page page) { cache.put(page.getPageNumber(), page); } - public Optional findPageWithSpace(Record record) { + public Optional findPageWithSpace(StorageRecord storageRecord) { return IntStream.range(0, capacity) .filter(this::containsPage) .mapToObj(this::getPage) - .filter(page -> page.getFreeSpace() >= record.getSize()) + .filter(page -> page.getFreeSpace() >= storageRecord.getSize()) .findFirst() .or(Optional::empty); } diff --git a/src/main/java/database/innodb/page/Page.java b/src/main/java/database/innodb/page/Page.java index 4ee30a6..d0ad507 100644 --- a/src/main/java/database/innodb/page/Page.java +++ b/src/main/java/database/innodb/page/Page.java @@ -10,23 +10,23 @@ public class Page implements Serializable { private final FileHeader fileHeader; private final PageHeader pageHeader; - private final List userRecords; + private final List userStorageRecords; private final PageDirectory pageDirectory; private int freeSpace; public Page(long pageNumber, PageType pageType) { this.fileHeader = new FileHeader(pageNumber); this.pageHeader = new PageHeader(pageType); - this.userRecords = new ArrayList<>(); + this.userStorageRecords = new ArrayList<>(); this.pageDirectory = new PageDirectory(); this.freeSpace = PAGE_SIZE - (this.fileHeader.getHeaderSize() + this.pageHeader.getHeaderSize()); } - public boolean addRecord(Record record) { - int recordSize = record.getSize(); + public boolean addRecord(StorageRecord storageRecord) { + int recordSize = storageRecord.getSize(); if (freeSpace >= recordSize) { - userRecords.add(record); - pageDirectory.addRecordPosition(userRecords.size() - 1); + userStorageRecords.add(storageRecord); + pageDirectory.addRecordPosition(userStorageRecords.size() - 1); freeSpace -= recordSize; pageHeader.incrementRecordCount(); markDirty(); @@ -61,7 +61,7 @@ public String toString() { return "Page{" + "fileHeader=" + fileHeader + ", pageHeader=" + pageHeader + - ", userRecords=" + userRecords + + ", userStorageRecords=" + userStorageRecords + ", pageDirectory=" + pageDirectory + ", freeSpace=" + freeSpace + '}'; diff --git a/src/main/java/database/innodb/page/StorageRecord.java b/src/main/java/database/innodb/page/StorageRecord.java new file mode 100644 index 0000000..25366fb --- /dev/null +++ b/src/main/java/database/innodb/page/StorageRecord.java @@ -0,0 +1,28 @@ +package database.innodb.page; + +import java.io.Serializable; +import java.util.Arrays; + +public class StorageRecord implements Serializable { + + private final byte[] data; + + public StorageRecord(byte[] data) { + this.data = data; + } + + public byte[] getData() { + return data; + } + + public int getSize() { + return data.length; + } + + @Override + public String toString() { + return "StorageRecord{" + + "data=" + Arrays.toString(data) + + '}'; + } +} diff --git a/src/test/java/database/innodb/page/PageTest.java b/src/test/java/database/innodb/page/PageTest.java index dadc736..f917e45 100644 --- a/src/test/java/database/innodb/page/PageTest.java +++ b/src/test/java/database/innodb/page/PageTest.java @@ -34,12 +34,12 @@ void addRecord() { int pageNumber = 1; PageType pageType = PageType.PAGE_TYPE_CLUSTERED; Page page = new Page(pageNumber, pageType); - Record record1 = new Record(new byte[]{1, 2, 3, 4}); - Record record2 = new Record(new byte[]{5, 6, 7, 8}); + StorageRecord storageRecord1 = new StorageRecord(new byte[]{1, 2, 3, 4}); + StorageRecord storageRecord2 = new StorageRecord(new byte[]{5, 6, 7, 8}); // when - page.addRecord(record1); - page.addRecord(record2); + page.addRecord(storageRecord1); + page.addRecord(storageRecord2); // then assertAll( diff --git a/src/test/java/database/innodb/page/RecordTest.java b/src/test/java/database/innodb/page/StorageRecordTest.java similarity index 73% rename from src/test/java/database/innodb/page/RecordTest.java rename to src/test/java/database/innodb/page/StorageRecordTest.java index 54701a6..7d93aa8 100644 --- a/src/test/java/database/innodb/page/RecordTest.java +++ b/src/test/java/database/innodb/page/StorageRecordTest.java @@ -8,22 +8,22 @@ import org.junit.jupiter.api.Test; @DisplayName("레코드 테스트") -class RecordTest { +class StorageRecordTest { @DisplayName("레코드 생성에 성공한다.") @Test void createRecord() { // given byte[] data = new byte[]{1, 2, 3, 4}; - Record record = new Record(data); + StorageRecord storageRecord = new StorageRecord(data); // when - byte[] retrievedData = record.getData(); + byte[] retrievedData = storageRecord.getData(); // then assertAll( () -> assertArrayEquals(data, retrievedData), - () -> assertThat(record.getSize()).isEqualTo(data.length) + () -> assertThat(storageRecord.getSize()).isEqualTo(data.length) ); } } From 52b7b34a85876069c8cc4f54b5aee2d3dbb50731 Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Tue, 27 Aug 2024 16:37:30 +0900 Subject: [PATCH 22/27] =?UTF-8?q?refactor:=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StorageEngineHandler.java} | 20 +++++++++---------- .../bufferpool/BufferPool.java | 6 +++--- .../bufferpool/PageReplacementStrategy.java | 2 +- .../LFUStrategy.java | 4 ++-- .../LRUStrategy.java | 4 ++-- .../page/FileHeader.java | 2 +- .../{innodb => storageEngine}/page/Page.java | 2 +- .../page/PageDirectory.java | 2 +- .../page/PageFactory.java | 2 +- .../page/PageHeader.java | 2 +- .../page/PageManager.java | 2 +- .../page/PageType.java | 2 +- .../page/StorageRecord.java | 2 +- .../bufferpool/BufferPoolTest.java | 8 ++++---- .../page/PageFactoryTest.java | 2 +- .../page/PageHeaderTest.java | 2 +- .../page/PageManagerTest.java | 2 +- .../page/PageTest.java | 2 +- .../page/StorageRecordTest.java | 2 +- 19 files changed, 35 insertions(+), 35 deletions(-) rename src/main/java/database/{innodb/InnodbHandler.java => storageEngine/StorageEngineHandler.java} (71%) rename src/main/java/database/{innodb => storageEngine}/bufferpool/BufferPool.java (87%) rename src/main/java/database/{innodb => storageEngine}/bufferpool/PageReplacementStrategy.java (75%) rename src/main/java/database/{innodb => storageEngine}/bufferpool/pageReplacementStrategies/LFUStrategy.java (90%) rename src/main/java/database/{innodb => storageEngine}/bufferpool/pageReplacementStrategies/LRUStrategy.java (83%) rename src/main/java/database/{innodb => storageEngine}/page/FileHeader.java (95%) rename src/main/java/database/{innodb => storageEngine}/page/Page.java (98%) rename src/main/java/database/{innodb => storageEngine}/page/PageDirectory.java (93%) rename src/main/java/database/{innodb => storageEngine}/page/PageFactory.java (91%) rename src/main/java/database/{innodb => storageEngine}/page/PageHeader.java (96%) rename src/main/java/database/{innodb => storageEngine}/page/PageManager.java (98%) rename src/main/java/database/{innodb => storageEngine}/page/PageType.java (73%) rename src/main/java/database/{innodb => storageEngine}/page/StorageRecord.java (93%) rename src/test/java/database/{innodb => storageEngine}/bufferpool/BufferPoolTest.java (89%) rename src/test/java/database/{innodb => storageEngine}/page/PageFactoryTest.java (97%) rename src/test/java/database/{innodb => storageEngine}/page/PageHeaderTest.java (97%) rename src/test/java/database/{innodb => storageEngine}/page/PageManagerTest.java (98%) rename src/test/java/database/{innodb => storageEngine}/page/PageTest.java (97%) rename src/test/java/database/{innodb => storageEngine}/page/StorageRecordTest.java (95%) diff --git a/src/main/java/database/innodb/InnodbHandler.java b/src/main/java/database/storageEngine/StorageEngineHandler.java similarity index 71% rename from src/main/java/database/innodb/InnodbHandler.java rename to src/main/java/database/storageEngine/StorageEngineHandler.java index c2695f3..14e1265 100644 --- a/src/main/java/database/innodb/InnodbHandler.java +++ b/src/main/java/database/storageEngine/StorageEngineHandler.java @@ -1,24 +1,24 @@ -package database.innodb; +package database.storageEngine; import database.engine.Handler; import database.engine.Record; -import database.innodb.bufferpool.BufferPool; -import database.innodb.bufferpool.PageReplacementStrategy; -import database.innodb.bufferpool.pageReplacementStrategies.LRUStrategy; -import database.innodb.page.Page; -import database.innodb.page.PageFactory; -import database.innodb.page.PageManager; -import database.innodb.page.StorageRecord; +import database.storageEngine.bufferpool.BufferPool; +import database.storageEngine.bufferpool.PageReplacementStrategy; +import database.storageEngine.bufferpool.pageReplacementStrategies.LRUStrategy; +import database.storageEngine.page.Page; +import database.storageEngine.page.PageFactory; +import database.storageEngine.page.PageManager; +import database.storageEngine.page.StorageRecord; import java.util.List; -public class InnodbHandler implements Handler { +public class StorageEngineHandler implements Handler { private static final int BUFFER_SIZE = 40; private final BufferPool bufferPool; private final PageManager pageManager; - public InnodbHandler(String tableName) { + public StorageEngineHandler(String tableName) { PageReplacementStrategy lruStrategy = new LRUStrategy<>(BUFFER_SIZE); this.bufferPool = new BufferPool(BUFFER_SIZE, lruStrategy); this.pageManager = new PageManager(tableName); diff --git a/src/main/java/database/innodb/bufferpool/BufferPool.java b/src/main/java/database/storageEngine/bufferpool/BufferPool.java similarity index 87% rename from src/main/java/database/innodb/bufferpool/BufferPool.java rename to src/main/java/database/storageEngine/bufferpool/BufferPool.java index cb8c8ef..4105565 100644 --- a/src/main/java/database/innodb/bufferpool/BufferPool.java +++ b/src/main/java/database/storageEngine/bufferpool/BufferPool.java @@ -1,7 +1,7 @@ -package database.innodb.bufferpool; +package database.storageEngine.bufferpool; -import database.innodb.page.Page; -import database.innodb.page.StorageRecord; +import database.storageEngine.page.Page; +import database.storageEngine.page.StorageRecord; import java.util.Optional; import java.util.stream.IntStream; diff --git a/src/main/java/database/innodb/bufferpool/PageReplacementStrategy.java b/src/main/java/database/storageEngine/bufferpool/PageReplacementStrategy.java similarity index 75% rename from src/main/java/database/innodb/bufferpool/PageReplacementStrategy.java rename to src/main/java/database/storageEngine/bufferpool/PageReplacementStrategy.java index 2d1530d..795494b 100644 --- a/src/main/java/database/innodb/bufferpool/PageReplacementStrategy.java +++ b/src/main/java/database/storageEngine/bufferpool/PageReplacementStrategy.java @@ -1,4 +1,4 @@ -package database.innodb.bufferpool; +package database.storageEngine.bufferpool; public interface PageReplacementStrategy { diff --git a/src/main/java/database/innodb/bufferpool/pageReplacementStrategies/LFUStrategy.java b/src/main/java/database/storageEngine/bufferpool/pageReplacementStrategies/LFUStrategy.java similarity index 90% rename from src/main/java/database/innodb/bufferpool/pageReplacementStrategies/LFUStrategy.java rename to src/main/java/database/storageEngine/bufferpool/pageReplacementStrategies/LFUStrategy.java index ed575ea..1bff119 100644 --- a/src/main/java/database/innodb/bufferpool/pageReplacementStrategies/LFUStrategy.java +++ b/src/main/java/database/storageEngine/bufferpool/pageReplacementStrategies/LFUStrategy.java @@ -1,6 +1,6 @@ -package database.innodb.bufferpool.pageReplacementStrategies; +package database.storageEngine.bufferpool.pageReplacementStrategies; -import database.innodb.bufferpool.PageReplacementStrategy; +import database.storageEngine.bufferpool.PageReplacementStrategy; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/database/innodb/bufferpool/pageReplacementStrategies/LRUStrategy.java b/src/main/java/database/storageEngine/bufferpool/pageReplacementStrategies/LRUStrategy.java similarity index 83% rename from src/main/java/database/innodb/bufferpool/pageReplacementStrategies/LRUStrategy.java rename to src/main/java/database/storageEngine/bufferpool/pageReplacementStrategies/LRUStrategy.java index b345cf3..bc70bc6 100644 --- a/src/main/java/database/innodb/bufferpool/pageReplacementStrategies/LRUStrategy.java +++ b/src/main/java/database/storageEngine/bufferpool/pageReplacementStrategies/LRUStrategy.java @@ -1,6 +1,6 @@ -package database.innodb.bufferpool.pageReplacementStrategies; +package database.storageEngine.bufferpool.pageReplacementStrategies; -import database.innodb.bufferpool.PageReplacementStrategy; +import database.storageEngine.bufferpool.PageReplacementStrategy; import java.util.LinkedHashMap; import java.util.Map; diff --git a/src/main/java/database/innodb/page/FileHeader.java b/src/main/java/database/storageEngine/page/FileHeader.java similarity index 95% rename from src/main/java/database/innodb/page/FileHeader.java rename to src/main/java/database/storageEngine/page/FileHeader.java index 43e64ba..d4aab13 100644 --- a/src/main/java/database/innodb/page/FileHeader.java +++ b/src/main/java/database/storageEngine/page/FileHeader.java @@ -1,4 +1,4 @@ -package database.innodb.page; +package database.storageEngine.page; import java.io.Serializable; diff --git a/src/main/java/database/innodb/page/Page.java b/src/main/java/database/storageEngine/page/Page.java similarity index 98% rename from src/main/java/database/innodb/page/Page.java rename to src/main/java/database/storageEngine/page/Page.java index d0ad507..9456c5c 100644 --- a/src/main/java/database/innodb/page/Page.java +++ b/src/main/java/database/storageEngine/page/Page.java @@ -1,4 +1,4 @@ -package database.innodb.page; +package database.storageEngine.page; import java.io.Serializable; import java.util.ArrayList; diff --git a/src/main/java/database/innodb/page/PageDirectory.java b/src/main/java/database/storageEngine/page/PageDirectory.java similarity index 93% rename from src/main/java/database/innodb/page/PageDirectory.java rename to src/main/java/database/storageEngine/page/PageDirectory.java index 4e76c18..ef6e38c 100644 --- a/src/main/java/database/innodb/page/PageDirectory.java +++ b/src/main/java/database/storageEngine/page/PageDirectory.java @@ -1,4 +1,4 @@ -package database.innodb.page; +package database.storageEngine.page; import java.io.Serializable; import java.util.ArrayList; diff --git a/src/main/java/database/innodb/page/PageFactory.java b/src/main/java/database/storageEngine/page/PageFactory.java similarity index 91% rename from src/main/java/database/innodb/page/PageFactory.java rename to src/main/java/database/storageEngine/page/PageFactory.java index 6bc5a71..5948a38 100644 --- a/src/main/java/database/innodb/page/PageFactory.java +++ b/src/main/java/database/storageEngine/page/PageFactory.java @@ -1,4 +1,4 @@ -package database.innodb.page; +package database.storageEngine.page; public class PageFactory { diff --git a/src/main/java/database/innodb/page/PageHeader.java b/src/main/java/database/storageEngine/page/PageHeader.java similarity index 96% rename from src/main/java/database/innodb/page/PageHeader.java rename to src/main/java/database/storageEngine/page/PageHeader.java index 19ca344..6d0be8f 100644 --- a/src/main/java/database/innodb/page/PageHeader.java +++ b/src/main/java/database/storageEngine/page/PageHeader.java @@ -1,4 +1,4 @@ -package database.innodb.page; +package database.storageEngine.page; import java.io.Serializable; diff --git a/src/main/java/database/innodb/page/PageManager.java b/src/main/java/database/storageEngine/page/PageManager.java similarity index 98% rename from src/main/java/database/innodb/page/PageManager.java rename to src/main/java/database/storageEngine/page/PageManager.java index e1acbf7..0908554 100644 --- a/src/main/java/database/innodb/page/PageManager.java +++ b/src/main/java/database/storageEngine/page/PageManager.java @@ -1,4 +1,4 @@ -package database.innodb.page; +package database.storageEngine.page; import java.io.File; import java.io.FileInputStream; diff --git a/src/main/java/database/innodb/page/PageType.java b/src/main/java/database/storageEngine/page/PageType.java similarity index 73% rename from src/main/java/database/innodb/page/PageType.java rename to src/main/java/database/storageEngine/page/PageType.java index 517d807..05798eb 100644 --- a/src/main/java/database/innodb/page/PageType.java +++ b/src/main/java/database/storageEngine/page/PageType.java @@ -1,4 +1,4 @@ -package database.innodb.page; +package database.storageEngine.page; public enum PageType { PAGE_TYPE_CLUSTERED, diff --git a/src/main/java/database/innodb/page/StorageRecord.java b/src/main/java/database/storageEngine/page/StorageRecord.java similarity index 93% rename from src/main/java/database/innodb/page/StorageRecord.java rename to src/main/java/database/storageEngine/page/StorageRecord.java index 25366fb..6c9952c 100644 --- a/src/main/java/database/innodb/page/StorageRecord.java +++ b/src/main/java/database/storageEngine/page/StorageRecord.java @@ -1,4 +1,4 @@ -package database.innodb.page; +package database.storageEngine.page; import java.io.Serializable; import java.util.Arrays; diff --git a/src/test/java/database/innodb/bufferpool/BufferPoolTest.java b/src/test/java/database/storageEngine/bufferpool/BufferPoolTest.java similarity index 89% rename from src/test/java/database/innodb/bufferpool/BufferPoolTest.java rename to src/test/java/database/storageEngine/bufferpool/BufferPoolTest.java index 27ad98c..be55725 100644 --- a/src/test/java/database/innodb/bufferpool/BufferPoolTest.java +++ b/src/test/java/database/storageEngine/bufferpool/BufferPoolTest.java @@ -1,11 +1,11 @@ -package database.innodb.bufferpool; +package database.storageEngine.bufferpool; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; -import database.innodb.bufferpool.pageReplacementStrategies.LRUStrategy; -import database.innodb.page.Page; -import database.innodb.page.PageFactory; +import database.storageEngine.bufferpool.pageReplacementStrategies.LRUStrategy; +import database.storageEngine.page.Page; +import database.storageEngine.page.PageFactory; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/database/innodb/page/PageFactoryTest.java b/src/test/java/database/storageEngine/page/PageFactoryTest.java similarity index 97% rename from src/test/java/database/innodb/page/PageFactoryTest.java rename to src/test/java/database/storageEngine/page/PageFactoryTest.java index 038f7ee..92944d0 100644 --- a/src/test/java/database/innodb/page/PageFactoryTest.java +++ b/src/test/java/database/storageEngine/page/PageFactoryTest.java @@ -1,4 +1,4 @@ -package database.innodb.page; +package database.storageEngine.page; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/database/innodb/page/PageHeaderTest.java b/src/test/java/database/storageEngine/page/PageHeaderTest.java similarity index 97% rename from src/test/java/database/innodb/page/PageHeaderTest.java rename to src/test/java/database/storageEngine/page/PageHeaderTest.java index c3c0f55..befb67e 100644 --- a/src/test/java/database/innodb/page/PageHeaderTest.java +++ b/src/test/java/database/storageEngine/page/PageHeaderTest.java @@ -1,4 +1,4 @@ -package database.innodb.page; +package database.storageEngine.page; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; diff --git a/src/test/java/database/innodb/page/PageManagerTest.java b/src/test/java/database/storageEngine/page/PageManagerTest.java similarity index 98% rename from src/test/java/database/innodb/page/PageManagerTest.java rename to src/test/java/database/storageEngine/page/PageManagerTest.java index f231556..5623aec 100644 --- a/src/test/java/database/innodb/page/PageManagerTest.java +++ b/src/test/java/database/storageEngine/page/PageManagerTest.java @@ -1,4 +1,4 @@ -package database.innodb.page; +package database.storageEngine.page; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/database/innodb/page/PageTest.java b/src/test/java/database/storageEngine/page/PageTest.java similarity index 97% rename from src/test/java/database/innodb/page/PageTest.java rename to src/test/java/database/storageEngine/page/PageTest.java index f917e45..790c7b6 100644 --- a/src/test/java/database/innodb/page/PageTest.java +++ b/src/test/java/database/storageEngine/page/PageTest.java @@ -1,4 +1,4 @@ -package database.innodb.page; +package database.storageEngine.page; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; diff --git a/src/test/java/database/innodb/page/StorageRecordTest.java b/src/test/java/database/storageEngine/page/StorageRecordTest.java similarity index 95% rename from src/test/java/database/innodb/page/StorageRecordTest.java rename to src/test/java/database/storageEngine/page/StorageRecordTest.java index 7d93aa8..2863013 100644 --- a/src/test/java/database/innodb/page/StorageRecordTest.java +++ b/src/test/java/database/storageEngine/page/StorageRecordTest.java @@ -1,4 +1,4 @@ -package database.innodb.page; +package database.storageEngine.page; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; From bb6571a5dad780ccd9078484e077d5cfe281f959 Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Tue, 27 Aug 2024 17:24:09 +0900 Subject: [PATCH 23/27] =?UTF-8?q?feat:=20=EB=A0=88=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=9E=90=EB=A3=8C=ED=98=95=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/database/engine/Handler.java | 2 +- src/main/java/database/engine/Record.java | 18 +++++------- .../storageEngine/StorageEngineHandler.java | 4 +-- .../storageEngine/page/StorageRecord.java | 28 +++++++++++++------ .../database/storageEngine/page/PageTest.java | 5 ++-- .../storageEngine/page/StorageRecordTest.java | 12 +++----- 6 files changed, 37 insertions(+), 32 deletions(-) diff --git a/src/main/java/database/engine/Handler.java b/src/main/java/database/engine/Handler.java index 3ae4edd..ac10a37 100644 --- a/src/main/java/database/engine/Handler.java +++ b/src/main/java/database/engine/Handler.java @@ -4,7 +4,7 @@ public interface Handler { - void insert(byte[] record); + void insert(Record record); List search(Object key); diff --git a/src/main/java/database/engine/Record.java b/src/main/java/database/engine/Record.java index cf11c1d..da52176 100644 --- a/src/main/java/database/engine/Record.java +++ b/src/main/java/database/engine/Record.java @@ -1,27 +1,23 @@ package database.engine; -import java.util.Arrays; +import java.util.List; public class Record { - private final byte[] data; + private final List values; - public Record(byte[] data) { - this.data = data; + public Record(List values) { + this.values = values; } - public byte[] getData() { - return data; - } - - public int getSize() { - return data.length; + public List getValues() { + return values; } @Override public String toString() { return "Record{" + - "data=" + Arrays.toString(data) + + "values=" + values + '}'; } } diff --git a/src/main/java/database/storageEngine/StorageEngineHandler.java b/src/main/java/database/storageEngine/StorageEngineHandler.java index 14e1265..c48b533 100644 --- a/src/main/java/database/storageEngine/StorageEngineHandler.java +++ b/src/main/java/database/storageEngine/StorageEngineHandler.java @@ -25,8 +25,8 @@ public StorageEngineHandler(String tableName) { } @Override - public void insert(byte[] recordData) { - StorageRecord storageRecord = new StorageRecord(recordData); + public void insert(Record record) { + StorageRecord storageRecord = new StorageRecord(record.getValues()); Page page = bufferPool.findPageWithSpace(storageRecord) .orElseGet(this::createNewPage); page.addRecord(storageRecord); diff --git a/src/main/java/database/storageEngine/page/StorageRecord.java b/src/main/java/database/storageEngine/page/StorageRecord.java index 6c9952c..691aa77 100644 --- a/src/main/java/database/storageEngine/page/StorageRecord.java +++ b/src/main/java/database/storageEngine/page/StorageRecord.java @@ -1,28 +1,40 @@ package database.storageEngine.page; +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; import java.io.Serializable; -import java.util.Arrays; +import java.util.List; public class StorageRecord implements Serializable { - private final byte[] data; + private final List values; - public StorageRecord(byte[] data) { - this.data = data; + public StorageRecord(List values) { + this.values = values; } - public byte[] getData() { - return data; + public List getValues() { + return values; } public int getSize() { - return data.length; + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(values); + oos.flush(); + oos.close(); + return baos.size(); + } catch (java.io.IOException e) { + e.printStackTrace(); + return 0; + } } @Override public String toString() { return "StorageRecord{" + - "data=" + Arrays.toString(data) + + "values=" + values + '}'; } } diff --git a/src/test/java/database/storageEngine/page/PageTest.java b/src/test/java/database/storageEngine/page/PageTest.java index 790c7b6..4d756e2 100644 --- a/src/test/java/database/storageEngine/page/PageTest.java +++ b/src/test/java/database/storageEngine/page/PageTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; +import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -34,8 +35,8 @@ void addRecord() { int pageNumber = 1; PageType pageType = PageType.PAGE_TYPE_CLUSTERED; Page page = new Page(pageNumber, pageType); - StorageRecord storageRecord1 = new StorageRecord(new byte[]{1, 2, 3, 4}); - StorageRecord storageRecord2 = new StorageRecord(new byte[]{5, 6, 7, 8}); + StorageRecord storageRecord1 = new StorageRecord(List.of(1, 2, 3, 4)); + StorageRecord storageRecord2 = new StorageRecord(List.of(5, 6, 7, 8)); // when page.addRecord(storageRecord1); diff --git a/src/test/java/database/storageEngine/page/StorageRecordTest.java b/src/test/java/database/storageEngine/page/StorageRecordTest.java index 2863013..8b9cb61 100644 --- a/src/test/java/database/storageEngine/page/StorageRecordTest.java +++ b/src/test/java/database/storageEngine/page/StorageRecordTest.java @@ -1,9 +1,8 @@ package database.storageEngine.page; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -14,16 +13,13 @@ class StorageRecordTest { @Test void createRecord() { // given - byte[] data = new byte[]{1, 2, 3, 4}; + List data = List.of("Chocochip", 123); StorageRecord storageRecord = new StorageRecord(data); // when - byte[] retrievedData = storageRecord.getData(); + List retrievedData = storageRecord.getValues(); // then - assertAll( - () -> assertArrayEquals(data, retrievedData), - () -> assertThat(storageRecord.getSize()).isEqualTo(data.length) - ); + assertThat(retrievedData.size()).isEqualTo(data.size()); } } From b0a18237315692f6af72d55458d2a37512ec588d Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Wed, 28 Aug 2024 03:31:11 +0900 Subject: [PATCH 24/27] =?UTF-8?q?refactor:=20pageManager=20=EB=B2=84?= =?UTF-8?q?=ED=8D=BC=ED=92=80=20=EB=82=B4=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storageEngine/StorageEngineHandler.java | 12 ++--------- .../storageEngine/bufferpool/BufferPool.java | 8 +++++--- .../storageEngine/page/PageManager.java | 20 +++++++++++-------- .../storageEngine/page/PageManagerTest.java | 13 ++++++------ 4 files changed, 25 insertions(+), 28 deletions(-) diff --git a/src/main/java/database/storageEngine/StorageEngineHandler.java b/src/main/java/database/storageEngine/StorageEngineHandler.java index c48b533..99d2558 100644 --- a/src/main/java/database/storageEngine/StorageEngineHandler.java +++ b/src/main/java/database/storageEngine/StorageEngineHandler.java @@ -16,28 +16,20 @@ public class StorageEngineHandler implements Handler { private static final int BUFFER_SIZE = 40; private final BufferPool bufferPool; - private final PageManager pageManager; - public StorageEngineHandler(String tableName) { + public StorageEngineHandler() { PageReplacementStrategy lruStrategy = new LRUStrategy<>(BUFFER_SIZE); this.bufferPool = new BufferPool(BUFFER_SIZE, lruStrategy); - this.pageManager = new PageManager(tableName); } @Override public void insert(Record record) { StorageRecord storageRecord = new StorageRecord(record.getValues()); - Page page = bufferPool.findPageWithSpace(storageRecord) - .orElseGet(this::createNewPage); + Page page = bufferPool.findPageWithSpace(storageRecord); page.addRecord(storageRecord); bufferPool.putPage(page); } - private Page createNewPage() { - long newPageNumber = pageManager.getNewPageNumber(); - return PageFactory.createDataPage(newPageNumber); - } - @Override public List search(Object key) { // 디스크에서 레코드를 검색하는 로직 diff --git a/src/main/java/database/storageEngine/bufferpool/BufferPool.java b/src/main/java/database/storageEngine/bufferpool/BufferPool.java index 4105565..a6a9080 100644 --- a/src/main/java/database/storageEngine/bufferpool/BufferPool.java +++ b/src/main/java/database/storageEngine/bufferpool/BufferPool.java @@ -1,31 +1,33 @@ package database.storageEngine.bufferpool; import database.storageEngine.page.Page; +import database.storageEngine.page.PageManager; import database.storageEngine.page.StorageRecord; -import java.util.Optional; import java.util.stream.IntStream; public class BufferPool { private final int capacity; private final PageReplacementStrategy cache; + private final PageManager pageManager; public BufferPool(int capacity, PageReplacementStrategy cacheStrategy) { this.capacity = capacity; this.cache = cacheStrategy; + this.pageManager = new PageManager(); } public void putPage(Page page) { cache.put(page.getPageNumber(), page); } - public Optional findPageWithSpace(StorageRecord storageRecord) { + public Page findPageWithSpace(StorageRecord storageRecord) { return IntStream.range(0, capacity) .filter(this::containsPage) .mapToObj(this::getPage) .filter(page -> page.getFreeSpace() >= storageRecord.getSize()) .findFirst() - .or(Optional::empty); + .orElseGet(pageManager::createNewDataPage); } public boolean containsPage(long pageNum) { diff --git a/src/main/java/database/storageEngine/page/PageManager.java b/src/main/java/database/storageEngine/page/PageManager.java index 0908554..1e186cf 100644 --- a/src/main/java/database/storageEngine/page/PageManager.java +++ b/src/main/java/database/storageEngine/page/PageManager.java @@ -17,13 +17,10 @@ public class PageManager { private static final String DIRECTORY_PATH = "disk"; private static final String FILE_EXTENSION = ".ibd"; - private final String tableName; private int pageSize; - public PageManager(String tableName) { - this.tableName = tableName; + public PageManager() { createDirectoryIfNotExists(); - createTableIfNotExists(); this.pageSize = 0; } @@ -38,7 +35,7 @@ private void createDirectoryIfNotExists() { } } - private void createTableIfNotExists() { + private void createTableIfNotExists(String tableName) { String fileName = DIRECTORY_PATH + File.separator + tableName + FILE_EXTENSION; File file = new File(fileName); if (!file.exists()) { @@ -50,7 +47,8 @@ private void createTableIfNotExists() { } } - public void savePage(Page page) { + public void savePage(String tableName, Page page) { + createTableIfNotExists(tableName); String fileName = DIRECTORY_PATH + File.separator + tableName + FILE_EXTENSION; try (RandomAccessFile file = new RandomAccessFile(fileName, "rw")) { @@ -65,7 +63,8 @@ public void savePage(Page page) { } } - public Page loadPage(long pageNum) { + public Page loadPage(String tableName, long pageNum) { + createTableIfNotExists(tableName); String fileName = DIRECTORY_PATH + File.separator + tableName + FILE_EXTENSION; try (RandomAccessFile file = new RandomAccessFile(fileName, "r")) { @@ -81,7 +80,12 @@ public Page loadPage(long pageNum) { } } - public int getNewPageNumber() { + public Page createNewDataPage() { + long newPageNumber = getNewPageNumber(); + return PageFactory.createDataPage(newPageNumber); + } + + private int getNewPageNumber() { return pageSize; } } diff --git a/src/test/java/database/storageEngine/page/PageManagerTest.java b/src/test/java/database/storageEngine/page/PageManagerTest.java index 5623aec..94e092f 100644 --- a/src/test/java/database/storageEngine/page/PageManagerTest.java +++ b/src/test/java/database/storageEngine/page/PageManagerTest.java @@ -22,7 +22,7 @@ class PageManagerTest { @BeforeEach void setUp() { - pageManager = new PageManager(tableName); + pageManager = new PageManager(); } @DisplayName("페이지 저장에 성공한다.") @@ -32,12 +32,11 @@ void savePage() { Page page = PageFactory.createDataPage(0); // when - pageManager.savePage(page); + pageManager.savePage(tableName, page); // then Path filePath = Paths.get(DIRECTORY_PATH, tableName + FILE_EXTENSION); assertThat(Files.exists(filePath)).isTrue(); - assertThat(pageManager.getNewPageNumber()).isEqualTo(1); } @DisplayName("페이지 조회에 성공한다.") @@ -50,12 +49,12 @@ void loadPage() { Page page1 = PageFactory.createDataPage(pageNumber1); Page page2 = PageFactory.createUndoPage(pageNumber2); - pageManager.savePage(page1); - pageManager.savePage(page2); + pageManager.savePage(tableName, page1); + pageManager.savePage(tableName, page2); // when - Page foundPage1 = pageManager.loadPage(pageNumber1); - Page foundPage2 = pageManager.loadPage(pageNumber2); + Page foundPage1 = pageManager.loadPage(tableName, pageNumber1); + Page foundPage2 = pageManager.loadPage(tableName, pageNumber2); // then assertThat(foundPage1.getPageNumber()).isEqualTo(pageNumber1); From f79eac01465ef64863636056fefad03db82c5f6f Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Wed, 28 Aug 2024 03:42:35 +0900 Subject: [PATCH 25/27] =?UTF-8?q?refactor:=20=ED=8E=98=EC=9D=B4=EC=A7=80?= =?UTF-8?q?=20=ED=82=A4=20=EA=B0=9D=EC=B2=B4=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storageEngine/StorageEngineHandler.java | 7 +++--- .../storageEngine/bufferpool/BufferPool.java | 22 ++++++++-------- .../bufferpool/TablePageKey.java | 5 ++++ .../bufferpool/BufferPoolTest.java | 25 ++++++++++--------- 4 files changed, 33 insertions(+), 26 deletions(-) create mode 100644 src/main/java/database/storageEngine/bufferpool/TablePageKey.java diff --git a/src/main/java/database/storageEngine/StorageEngineHandler.java b/src/main/java/database/storageEngine/StorageEngineHandler.java index 99d2558..c0346d4 100644 --- a/src/main/java/database/storageEngine/StorageEngineHandler.java +++ b/src/main/java/database/storageEngine/StorageEngineHandler.java @@ -4,6 +4,7 @@ import database.engine.Record; import database.storageEngine.bufferpool.BufferPool; import database.storageEngine.bufferpool.PageReplacementStrategy; +import database.storageEngine.bufferpool.TablePageKey; import database.storageEngine.bufferpool.pageReplacementStrategies.LRUStrategy; import database.storageEngine.page.Page; import database.storageEngine.page.PageFactory; @@ -18,16 +19,16 @@ public class StorageEngineHandler implements Handler { private final BufferPool bufferPool; public StorageEngineHandler() { - PageReplacementStrategy lruStrategy = new LRUStrategy<>(BUFFER_SIZE); + PageReplacementStrategy lruStrategy = new LRUStrategy<>(BUFFER_SIZE); this.bufferPool = new BufferPool(BUFFER_SIZE, lruStrategy); } @Override public void insert(Record record) { StorageRecord storageRecord = new StorageRecord(record.getValues()); - Page page = bufferPool.findPageWithSpace(storageRecord); + Page page = bufferPool.findPageWithSpace("", storageRecord); page.addRecord(storageRecord); - bufferPool.putPage(page); + bufferPool.putPage("tableName", page); } @Override diff --git a/src/main/java/database/storageEngine/bufferpool/BufferPool.java b/src/main/java/database/storageEngine/bufferpool/BufferPool.java index a6a9080..e2d14db 100644 --- a/src/main/java/database/storageEngine/bufferpool/BufferPool.java +++ b/src/main/java/database/storageEngine/bufferpool/BufferPool.java @@ -8,33 +8,33 @@ public class BufferPool { private final int capacity; - private final PageReplacementStrategy cache; + private final PageReplacementStrategy cache; private final PageManager pageManager; - public BufferPool(int capacity, PageReplacementStrategy cacheStrategy) { + public BufferPool(int capacity, PageReplacementStrategy cacheStrategy) { this.capacity = capacity; this.cache = cacheStrategy; this.pageManager = new PageManager(); } - public void putPage(Page page) { - cache.put(page.getPageNumber(), page); + public void putPage(String tableName, Page page) { + cache.put(new TablePageKey(tableName, page.getPageNumber()), page); } - public Page findPageWithSpace(StorageRecord storageRecord) { + public Page findPageWithSpace(String tableName, StorageRecord storageRecord) { return IntStream.range(0, capacity) - .filter(this::containsPage) - .mapToObj(this::getPage) + .filter(i -> containsPage(tableName, i)) + .mapToObj(i -> getPage(tableName, i)) .filter(page -> page.getFreeSpace() >= storageRecord.getSize()) .findFirst() .orElseGet(pageManager::createNewDataPage); } - public boolean containsPage(long pageNum) { - return cache.containsKey(pageNum); + public boolean containsPage(String tableName, long pageNum) { + return cache.containsKey(new TablePageKey(tableName, pageNum)); } - public Page getPage(long pageNum) { - return cache.get(pageNum); + public Page getPage(String tableName, long pageNum) { + return cache.get(new TablePageKey(tableName, pageNum)); } } diff --git a/src/main/java/database/storageEngine/bufferpool/TablePageKey.java b/src/main/java/database/storageEngine/bufferpool/TablePageKey.java new file mode 100644 index 0000000..de0a373 --- /dev/null +++ b/src/main/java/database/storageEngine/bufferpool/TablePageKey.java @@ -0,0 +1,5 @@ +package database.storageEngine.bufferpool; + +public record TablePageKey(String tableName, long pageNumber) { + +} diff --git a/src/test/java/database/storageEngine/bufferpool/BufferPoolTest.java b/src/test/java/database/storageEngine/bufferpool/BufferPoolTest.java index be55725..f9601b0 100644 --- a/src/test/java/database/storageEngine/bufferpool/BufferPoolTest.java +++ b/src/test/java/database/storageEngine/bufferpool/BufferPoolTest.java @@ -14,11 +14,12 @@ class BufferPoolTest { private final int capacity = 2; + private final String tableName = "table"; private BufferPool bufferPool; @BeforeEach void setUp() { - PageReplacementStrategy lruStrategy = new LRUStrategy<>(capacity); + PageReplacementStrategy lruStrategy = new LRUStrategy<>(capacity); bufferPool = new BufferPool(capacity, lruStrategy); } @@ -30,12 +31,12 @@ void createBufferPool() { int pageNumber2 = 2; // when - bufferPool.putPage(PageFactory.createDataPage(pageNumber1)); - bufferPool.putPage(PageFactory.createDataPage(pageNumber2)); + bufferPool.putPage(tableName, PageFactory.createDataPage(pageNumber1)); + bufferPool.putPage(tableName, PageFactory.createDataPage(pageNumber2)); // then - assertThat(bufferPool.containsPage(1)).isTrue(); - assertThat(bufferPool.containsPage(2)).isTrue(); + assertThat(bufferPool.containsPage(tableName, 1)).isTrue(); + assertThat(bufferPool.containsPage(tableName, 2)).isTrue(); } @DisplayName("LRU 정책에 따라 가장 오래된 페이지가 제거된다.") @@ -46,18 +47,18 @@ void lru() { int pageNumber2 = 2; int pageNumber3 = 3; - bufferPool.putPage(PageFactory.createDataPage(pageNumber1)); - bufferPool.putPage(PageFactory.createDataPage(pageNumber2)); + bufferPool.putPage(tableName, PageFactory.createDataPage(pageNumber1)); + bufferPool.putPage(tableName, PageFactory.createDataPage(pageNumber2)); // when - bufferPool.getPage(pageNumber1); - bufferPool.putPage(PageFactory.createDataPage(pageNumber3)); + bufferPool.getPage(tableName, pageNumber1); + bufferPool.putPage(tableName, PageFactory.createDataPage(pageNumber3)); // then assertAll( - () -> assertThat(bufferPool.containsPage(pageNumber1)).isTrue(), - () -> assertThat(bufferPool.containsPage(pageNumber3)).isTrue(), - () -> assertThat(bufferPool.containsPage(pageNumber2)).isFalse() + () -> assertThat(bufferPool.containsPage(tableName, pageNumber1)).isTrue(), + () -> assertThat(bufferPool.containsPage(tableName, pageNumber3)).isTrue(), + () -> assertThat(bufferPool.containsPage(tableName, pageNumber2)).isFalse() ); } } From 477047e55f1220af9bb6aa7f3401842ce03fc7b0 Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Wed, 28 Aug 2024 04:38:51 +0900 Subject: [PATCH 26/27] =?UTF-8?q?refactor:=20key=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/database/engine/Handler.java | 8 +-- .../storageEngine/StorageEngineHandler.java | 15 ++-- .../storageEngine/bufferpool/BufferPool.java | 72 ++++++++++++++----- .../bufferpool/PageReplacementStrategy.java | 12 ++-- .../LFUStrategy.java | 55 ++++++++------ .../LRUStrategy.java | 45 ++++++++---- .../database/storageEngine/page/Page.java | 8 +++ .../storageEngine/page/PageHeader.java | 4 ++ .../storageEngine/page/PageManager.java | 15 ++-- .../bufferpool/BufferPoolTest.java | 32 +++++---- .../storageEngine/page/PageManagerTest.java | 5 +- 11 files changed, 179 insertions(+), 92 deletions(-) diff --git a/src/main/java/database/engine/Handler.java b/src/main/java/database/engine/Handler.java index ac10a37..f4f56d3 100644 --- a/src/main/java/database/engine/Handler.java +++ b/src/main/java/database/engine/Handler.java @@ -4,12 +4,12 @@ public interface Handler { - void insert(Record record); + void insert(String tableName, Record record); - List search(Object key); + List search(String tableName, Object key); - void update(Object key, byte[] newRecord); + void update(String tableName, Object key, byte[] newRecord); - void delete(Object key); + void delete(String tableName, Object key); } diff --git a/src/main/java/database/storageEngine/StorageEngineHandler.java b/src/main/java/database/storageEngine/StorageEngineHandler.java index c0346d4..1d31cc6 100644 --- a/src/main/java/database/storageEngine/StorageEngineHandler.java +++ b/src/main/java/database/storageEngine/StorageEngineHandler.java @@ -11,6 +11,7 @@ import database.storageEngine.page.PageManager; import database.storageEngine.page.StorageRecord; import java.util.List; +import java.util.Optional; public class StorageEngineHandler implements Handler { @@ -19,31 +20,27 @@ public class StorageEngineHandler implements Handler { private final BufferPool bufferPool; public StorageEngineHandler() { - PageReplacementStrategy lruStrategy = new LRUStrategy<>(BUFFER_SIZE); + PageReplacementStrategy lruStrategy = new LRUStrategy<>(BUFFER_SIZE); this.bufferPool = new BufferPool(BUFFER_SIZE, lruStrategy); } @Override - public void insert(Record record) { - StorageRecord storageRecord = new StorageRecord(record.getValues()); - Page page = bufferPool.findPageWithSpace("", storageRecord); - page.addRecord(storageRecord); - bufferPool.putPage("tableName", page); + public void insert(String tableName, Record record) { } @Override - public List search(Object key) { + public List search(String tableName, Object key) { // 디스크에서 레코드를 검색하는 로직 return null; } @Override - public void update(Object key, byte[] newRecord) { + public void update(String tableName, Object key, byte[] newRecord) { // 디스크에서 레코드를 업데이트하는 로직 } @Override - public void delete(Object key) { + public void delete(String tableName, Object key) { // 디스크에서 레코드를 삭제하는 로직 } } diff --git a/src/main/java/database/storageEngine/bufferpool/BufferPool.java b/src/main/java/database/storageEngine/bufferpool/BufferPool.java index e2d14db..a92257f 100644 --- a/src/main/java/database/storageEngine/bufferpool/BufferPool.java +++ b/src/main/java/database/storageEngine/bufferpool/BufferPool.java @@ -2,39 +2,75 @@ import database.storageEngine.page.Page; import database.storageEngine.page.PageManager; -import database.storageEngine.page.StorageRecord; -import java.util.stream.IntStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; public class BufferPool { private final int capacity; - private final PageReplacementStrategy cache; + private final PageReplacementStrategy strategy; + private final Map pages; private final PageManager pageManager; - public BufferPool(int capacity, PageReplacementStrategy cacheStrategy) { + public BufferPool(int capacity, PageReplacementStrategy strategy) { this.capacity = capacity; - this.cache = cacheStrategy; + this.strategy = strategy; + this.pages = new HashMap<>(); this.pageManager = new PageManager(); } - public void putPage(String tableName, Page page) { - cache.put(new TablePageKey(tableName, page.getPageNumber()), page); + public Optional getPage(TablePageKey key) { + if (pages.containsKey(key)) { + strategy.get(key); + return Optional.of(pages.get(key)); + } + + Optional optionalPage = pageManager.loadPage(key); + if (optionalPage.isPresent()) { + Page page = optionalPage.get(); + putPage(key, page); + return Optional.of(page); + } + + return Optional.empty(); + } + + public void putPage(TablePageKey key, Page page) { + if (!pages.containsKey(key)) { + if (pages.size() >= capacity) { + TablePageKey evictedKey = strategy.evict(); + if (evictedKey != null) { + flushPage(evictedKey); + pages.remove(evictedKey); + } + } + pages.put(key, page); + strategy.put(key); + } } - public Page findPageWithSpace(String tableName, StorageRecord storageRecord) { - return IntStream.range(0, capacity) - .filter(i -> containsPage(tableName, i)) - .mapToObj(i -> getPage(tableName, i)) - .filter(page -> page.getFreeSpace() >= storageRecord.getSize()) - .findFirst() - .orElseGet(pageManager::createNewDataPage); + public void flushPage(TablePageKey key) { + if (pages.containsKey(key)) { + Page page = pages.get(key); + if (page.isDirty()) { + pageManager.savePage(key.tableName(), page); + page.clean(); + } + } } - public boolean containsPage(String tableName, long pageNum) { - return cache.containsKey(new TablePageKey(tableName, pageNum)); + public void flushAllPages() { + for (Map.Entry entry : pages.entrySet()) { + flushPage(entry.getKey()); + } } - public Page getPage(String tableName, long pageNum) { - return cache.get(new TablePageKey(tableName, pageNum)); + public void removePage(TablePageKey key) { + if (pages.containsKey(key)) { + flushPage(key); + pages.remove(key); + strategy.evict(); + } } } diff --git a/src/main/java/database/storageEngine/bufferpool/PageReplacementStrategy.java b/src/main/java/database/storageEngine/bufferpool/PageReplacementStrategy.java index 795494b..402a807 100644 --- a/src/main/java/database/storageEngine/bufferpool/PageReplacementStrategy.java +++ b/src/main/java/database/storageEngine/bufferpool/PageReplacementStrategy.java @@ -1,10 +1,14 @@ package database.storageEngine.bufferpool; -public interface PageReplacementStrategy { +import java.util.Optional; - void put(K key, V value); +public interface PageReplacementStrategy { - V get(K key); + Optional get(K key); - boolean containsKey(K key); + void put(K key); + + K evict(); + + boolean contains(K key); } diff --git a/src/main/java/database/storageEngine/bufferpool/pageReplacementStrategies/LFUStrategy.java b/src/main/java/database/storageEngine/bufferpool/pageReplacementStrategies/LFUStrategy.java index 1bff119..75b445c 100644 --- a/src/main/java/database/storageEngine/bufferpool/pageReplacementStrategies/LFUStrategy.java +++ b/src/main/java/database/storageEngine/bufferpool/pageReplacementStrategies/LFUStrategy.java @@ -3,49 +3,64 @@ import database.storageEngine.bufferpool.PageReplacementStrategy; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; -public class LFUStrategy implements PageReplacementStrategy { +public class LFUStrategy implements PageReplacementStrategy { private final int capacity; - private final Map cache; private final Map usageCount; + private final Map cache; public LFUStrategy(int capacity) { this.capacity = capacity; - this.cache = new HashMap<>(); this.usageCount = new HashMap<>(); + this.cache = new HashMap<>(); } @Override - public void put(K key, V value) { + public void put(K key) { if (cache.size() >= capacity) { - K leastUsedKey = findLeastUsedKey(); + evict(); + } + cache.put(key, System.nanoTime()); // 현재 시간으로 타임스탬프 저장 + usageCount.put(key, usageCount.getOrDefault(key, 0) + 1); + } + + @Override + public K evict() { + K leastUsedKey = findLeastUsedKey(); + if (leastUsedKey != null) { cache.remove(leastUsedKey); usageCount.remove(leastUsedKey); } - cache.put(key, value); - usageCount.put(key, 1); + return leastUsedKey; + } + + @Override + public boolean contains(K key) { + return cache.containsKey(key); } private K findLeastUsedKey() { - return usageCount.entrySet() - .stream() - .min(Map.Entry.comparingByValue()) - .get() - .getKey(); + Optional> minEntry = usageCount.entrySet().stream() + .min((entry1, entry2) -> { + int freqCompare = entry1.getValue().compareTo(entry2.getValue()); + if (freqCompare == 0) { + // 동일한 사용 빈도일 경우, 먼저 들어온 키를 우선 제거 + return cache.get(entry1.getKey()).compareTo(cache.get(entry2.getKey())); + } + return freqCompare; + }); + return minEntry.map(Map.Entry::getKey).orElse(null); } @Override - public V get(K key) { + public Optional get(K key) { if (cache.containsKey(key)) { usageCount.put(key, usageCount.get(key) + 1); - return cache.get(key); + return Optional.of(key); } - return null; - } - - @Override - public boolean containsKey(K key) { - return cache.containsKey(key); + return Optional.empty(); } } diff --git a/src/main/java/database/storageEngine/bufferpool/pageReplacementStrategies/LRUStrategy.java b/src/main/java/database/storageEngine/bufferpool/pageReplacementStrategies/LRUStrategy.java index bc70bc6..cad4c56 100644 --- a/src/main/java/database/storageEngine/bufferpool/pageReplacementStrategies/LRUStrategy.java +++ b/src/main/java/database/storageEngine/bufferpool/pageReplacementStrategies/LRUStrategy.java @@ -1,34 +1,49 @@ package database.storageEngine.bufferpool.pageReplacementStrategies; import database.storageEngine.bufferpool.PageReplacementStrategy; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.LinkedHashSet; +import java.util.Optional; -public class LRUStrategy implements PageReplacementStrategy { +public class LRUStrategy implements PageReplacementStrategy { - private final LinkedHashMap cache; + private final int capacity; + private final LinkedHashSet cache; public LRUStrategy(int capacity) { - this.cache = new LinkedHashMap<>(capacity, 0.75f, true) { - protected boolean removeEldestEntry(Map.Entry eldest) { - return size() > capacity; - } - }; + this.capacity = capacity; + this.cache = new LinkedHashSet<>(capacity); } @Override - public void put(K key, V value) { - cache.put(key, value); + public void put(K key) { + if (cache.contains(key)) { + cache.remove(key); + } else if (cache.size() >= capacity) { + evict(); + } + cache.add(key); } @Override - public V get(K key) { - return cache.get(key); + public K evict() { + K firstKey = cache.iterator().next(); + cache.remove(firstKey); + return firstKey; } @Override - public boolean containsKey(K key) { - return cache.containsKey(key); + public boolean contains(K key) { + return cache.contains(key); + } + + @Override + public Optional get(K key) { + if (cache.contains(key)) { + cache.remove(key); + cache.add(key); + return Optional.of(key); + } + return Optional.empty(); } } diff --git a/src/main/java/database/storageEngine/page/Page.java b/src/main/java/database/storageEngine/page/Page.java index 9456c5c..8386480 100644 --- a/src/main/java/database/storageEngine/page/Page.java +++ b/src/main/java/database/storageEngine/page/Page.java @@ -40,6 +40,14 @@ private void markDirty() { pageHeader.markDirty(); } + public boolean isDirty() { + return pageHeader.isDirty(); + } + + public void clean() { + pageHeader.clean(); + } + public long getPageNumber() { return fileHeader.getPageNumber(); } diff --git a/src/main/java/database/storageEngine/page/PageHeader.java b/src/main/java/database/storageEngine/page/PageHeader.java index 6d0be8f..a093dff 100644 --- a/src/main/java/database/storageEngine/page/PageHeader.java +++ b/src/main/java/database/storageEngine/page/PageHeader.java @@ -31,6 +31,10 @@ public boolean isDirty() { return isDirty; } + public void clean() { + this.isDirty = false; + } + public PageType getPageType() { return pageType; } diff --git a/src/main/java/database/storageEngine/page/PageManager.java b/src/main/java/database/storageEngine/page/PageManager.java index 1e186cf..b305ab4 100644 --- a/src/main/java/database/storageEngine/page/PageManager.java +++ b/src/main/java/database/storageEngine/page/PageManager.java @@ -1,5 +1,6 @@ package database.storageEngine.page; +import database.storageEngine.bufferpool.TablePageKey; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -10,6 +11,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Optional; public class PageManager { @@ -63,20 +65,19 @@ public void savePage(String tableName, Page page) { } } - public Page loadPage(String tableName, long pageNum) { - createTableIfNotExists(tableName); - String fileName = DIRECTORY_PATH + File.separator + tableName + FILE_EXTENSION; + public Optional loadPage(TablePageKey key) { + createTableIfNotExists(key.tableName()); + String fileName = DIRECTORY_PATH + File.separator + key.tableName() + FILE_EXTENSION; try (RandomAccessFile file = new RandomAccessFile(fileName, "r")) { - file.seek(pageNum * PAGE_SIZE); + file.seek(key.pageNumber() * PAGE_SIZE); try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file.getFD()))) { Page page = (Page) in.readObject(); - return page; + return Optional.of(page); } } catch (IOException | ClassNotFoundException e) { - e.printStackTrace(); - return null; + return Optional.empty(); } } diff --git a/src/test/java/database/storageEngine/bufferpool/BufferPoolTest.java b/src/test/java/database/storageEngine/bufferpool/BufferPoolTest.java index f9601b0..4998060 100644 --- a/src/test/java/database/storageEngine/bufferpool/BufferPoolTest.java +++ b/src/test/java/database/storageEngine/bufferpool/BufferPoolTest.java @@ -4,7 +4,6 @@ import static org.junit.jupiter.api.Assertions.assertAll; import database.storageEngine.bufferpool.pageReplacementStrategies.LRUStrategy; -import database.storageEngine.page.Page; import database.storageEngine.page.PageFactory; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -19,7 +18,7 @@ class BufferPoolTest { @BeforeEach void setUp() { - PageReplacementStrategy lruStrategy = new LRUStrategy<>(capacity); + PageReplacementStrategy lruStrategy = new LRUStrategy<>(capacity); bufferPool = new BufferPool(capacity, lruStrategy); } @@ -28,15 +27,19 @@ void setUp() { void createBufferPool() { // given int pageNumber1 = 1; + TablePageKey tablePageKey1 = new TablePageKey(tableName, pageNumber1); int pageNumber2 = 2; + TablePageKey tablePageKey2 = new TablePageKey(tableName, pageNumber2); // when - bufferPool.putPage(tableName, PageFactory.createDataPage(pageNumber1)); - bufferPool.putPage(tableName, PageFactory.createDataPage(pageNumber2)); + bufferPool.putPage(tablePageKey1, PageFactory.createDataPage(pageNumber1)); + bufferPool.putPage(tablePageKey2, PageFactory.createDataPage(pageNumber2)); // then - assertThat(bufferPool.containsPage(tableName, 1)).isTrue(); - assertThat(bufferPool.containsPage(tableName, 2)).isTrue(); + assertAll( + () -> assertThat(bufferPool.getPage(tablePageKey1)).isPresent(), + () -> assertThat(bufferPool.getPage(tablePageKey2)).isPresent() + ); } @DisplayName("LRU 정책에 따라 가장 오래된 페이지가 제거된다.") @@ -44,21 +47,24 @@ void createBufferPool() { void lru() { // given int pageNumber1 = 1; + TablePageKey tablePageKey1 = new TablePageKey(tableName, pageNumber1); int pageNumber2 = 2; + TablePageKey tablePageKey2 = new TablePageKey(tableName, pageNumber2); int pageNumber3 = 3; + TablePageKey tablePageKey3 = new TablePageKey(tableName, pageNumber3); - bufferPool.putPage(tableName, PageFactory.createDataPage(pageNumber1)); - bufferPool.putPage(tableName, PageFactory.createDataPage(pageNumber2)); + bufferPool.putPage(tablePageKey1, PageFactory.createDataPage(pageNumber1)); + bufferPool.putPage(tablePageKey2, PageFactory.createDataPage(pageNumber2)); // when - bufferPool.getPage(tableName, pageNumber1); - bufferPool.putPage(tableName, PageFactory.createDataPage(pageNumber3)); + bufferPool.getPage(tablePageKey1); + bufferPool.putPage(tablePageKey3, PageFactory.createDataPage(pageNumber3)); // then assertAll( - () -> assertThat(bufferPool.containsPage(tableName, pageNumber1)).isTrue(), - () -> assertThat(bufferPool.containsPage(tableName, pageNumber3)).isTrue(), - () -> assertThat(bufferPool.containsPage(tableName, pageNumber2)).isFalse() + () -> assertThat(bufferPool.getPage(tablePageKey1)).isPresent(), + () -> assertThat(bufferPool.getPage(tablePageKey2)).isEmpty(), + () -> assertThat(bufferPool.getPage(tablePageKey3)).isPresent() ); } } diff --git a/src/test/java/database/storageEngine/page/PageManagerTest.java b/src/test/java/database/storageEngine/page/PageManagerTest.java index 94e092f..92de075 100644 --- a/src/test/java/database/storageEngine/page/PageManagerTest.java +++ b/src/test/java/database/storageEngine/page/PageManagerTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import database.storageEngine.bufferpool.TablePageKey; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -53,8 +54,8 @@ void loadPage() { pageManager.savePage(tableName, page2); // when - Page foundPage1 = pageManager.loadPage(tableName, pageNumber1); - Page foundPage2 = pageManager.loadPage(tableName, pageNumber2); + Page foundPage1 = pageManager.loadPage(new TablePageKey(tableName, pageNumber1)).get(); + Page foundPage2 = pageManager.loadPage(new TablePageKey(tableName, pageNumber2)).get(); // then assertThat(foundPage1.getPageNumber()).isEqualTo(pageNumber1); From 709092c26e5029aa0d91a3c2a65e1f430cb7578b Mon Sep 17 00:00:00 2001 From: Kwoun Ki Ho Date: Wed, 28 Aug 2024 05:04:56 +0900 Subject: [PATCH 27/27] =?UTF-8?q?refactor:=20filemanager=EB=A1=9C=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storageEngine/StorageEngineHandler.java | 27 ++++++++++++++++--- .../storageEngine/bufferpool/BufferPool.java | 23 ++++++++++++---- .../{PageManager.java => FileManager.java} | 4 +-- .../database/storageEngine/page/Page.java | 7 +++++ .../storageEngine/page/StorageRecord.java | 4 +++ ...eManagerTest.java => FileManagerTest.java} | 18 ++++++------- 6 files changed, 63 insertions(+), 20 deletions(-) rename src/main/java/database/storageEngine/page/{PageManager.java => FileManager.java} (98%) rename src/test/java/database/storageEngine/page/{PageManagerTest.java => FileManagerTest.java} (81%) diff --git a/src/main/java/database/storageEngine/StorageEngineHandler.java b/src/main/java/database/storageEngine/StorageEngineHandler.java index 1d31cc6..7436175 100644 --- a/src/main/java/database/storageEngine/StorageEngineHandler.java +++ b/src/main/java/database/storageEngine/StorageEngineHandler.java @@ -7,9 +7,8 @@ import database.storageEngine.bufferpool.TablePageKey; import database.storageEngine.bufferpool.pageReplacementStrategies.LRUStrategy; import database.storageEngine.page.Page; -import database.storageEngine.page.PageFactory; -import database.storageEngine.page.PageManager; import database.storageEngine.page.StorageRecord; +import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -26,12 +25,32 @@ public StorageEngineHandler() { @Override public void insert(String tableName, Record record) { + StorageRecord storageRecord = new StorageRecord(record.getValues()); + Page page = bufferPool.findPageWithSpace(tableName, storageRecord); + page.addRecord(storageRecord); } @Override public List search(String tableName, Object key) { - // 디스크에서 레코드를 검색하는 로직 - return null; + List results = new ArrayList<>(); + + for (long pageNumber = 0; ; pageNumber++) { + TablePageKey tablePageKey = new TablePageKey(tableName, pageNumber); + Optional pageOpt = bufferPool.getPage(tablePageKey); + + if (pageOpt.isPresent()) { + Page page = pageOpt.get(); + List records = page.searchRecords(key).stream() + .map(storageRecord -> new Record(storageRecord.getValues())) + .toList(); + if (!records.isEmpty()) { + results.addAll(records); + } + } else { + break; + } + } + return results; } @Override diff --git a/src/main/java/database/storageEngine/bufferpool/BufferPool.java b/src/main/java/database/storageEngine/bufferpool/BufferPool.java index a92257f..38e1f17 100644 --- a/src/main/java/database/storageEngine/bufferpool/BufferPool.java +++ b/src/main/java/database/storageEngine/bufferpool/BufferPool.java @@ -1,23 +1,25 @@ package database.storageEngine.bufferpool; import database.storageEngine.page.Page; -import database.storageEngine.page.PageManager; +import database.storageEngine.page.FileManager; +import database.storageEngine.page.StorageRecord; import java.util.HashMap; import java.util.Map; import java.util.Optional; +import java.util.stream.IntStream; public class BufferPool { private final int capacity; private final PageReplacementStrategy strategy; private final Map pages; - private final PageManager pageManager; + private final FileManager fileManager; public BufferPool(int capacity, PageReplacementStrategy strategy) { this.capacity = capacity; this.strategy = strategy; this.pages = new HashMap<>(); - this.pageManager = new PageManager(); + this.fileManager = new FileManager(); } public Optional getPage(TablePageKey key) { @@ -26,7 +28,7 @@ public Optional getPage(TablePageKey key) { return Optional.of(pages.get(key)); } - Optional optionalPage = pageManager.loadPage(key); + Optional optionalPage = fileManager.loadPage(key); if (optionalPage.isPresent()) { Page page = optionalPage.get(); putPage(key, page); @@ -54,7 +56,7 @@ public void flushPage(TablePageKey key) { if (pages.containsKey(key)) { Page page = pages.get(key); if (page.isDirty()) { - pageManager.savePage(key.tableName(), page); + fileManager.savePage(key.tableName(), page); page.clean(); } } @@ -73,4 +75,15 @@ public void removePage(TablePageKey key) { strategy.evict(); } } + + public Page findPageWithSpace(String tableName, StorageRecord storageRecord) { + return IntStream.range(0, capacity) + .mapToObj(pageNumber -> { + TablePageKey key = new TablePageKey(tableName, pageNumber); + return pages.get(key); + }) + .filter(page -> page.getFreeSpace() >= storageRecord.getSize()) + .findFirst() + .orElseGet(fileManager::createNewDataPage); + } } diff --git a/src/main/java/database/storageEngine/page/PageManager.java b/src/main/java/database/storageEngine/page/FileManager.java similarity index 98% rename from src/main/java/database/storageEngine/page/PageManager.java rename to src/main/java/database/storageEngine/page/FileManager.java index b305ab4..bc96cc1 100644 --- a/src/main/java/database/storageEngine/page/PageManager.java +++ b/src/main/java/database/storageEngine/page/FileManager.java @@ -13,7 +13,7 @@ import java.nio.file.Paths; import java.util.Optional; -public class PageManager { +public class FileManager { private static final int PAGE_SIZE = 16 * 1024; private static final String DIRECTORY_PATH = "disk"; @@ -21,7 +21,7 @@ public class PageManager { private int pageSize; - public PageManager() { + public FileManager() { createDirectoryIfNotExists(); this.pageSize = 0; } diff --git a/src/main/java/database/storageEngine/page/Page.java b/src/main/java/database/storageEngine/page/Page.java index 8386480..6476d0a 100644 --- a/src/main/java/database/storageEngine/page/Page.java +++ b/src/main/java/database/storageEngine/page/Page.java @@ -1,5 +1,6 @@ package database.storageEngine.page; +import database.engine.Record; import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -48,6 +49,12 @@ public void clean() { pageHeader.clean(); } + public List searchRecords(Object key) { + return userStorageRecords.stream() + .filter(storageRecord -> storageRecord.contains(key)) + .toList(); + } + public long getPageNumber() { return fileHeader.getPageNumber(); } diff --git a/src/main/java/database/storageEngine/page/StorageRecord.java b/src/main/java/database/storageEngine/page/StorageRecord.java index 691aa77..6715a33 100644 --- a/src/main/java/database/storageEngine/page/StorageRecord.java +++ b/src/main/java/database/storageEngine/page/StorageRecord.java @@ -13,6 +13,10 @@ public StorageRecord(List values) { this.values = values; } + public boolean contains(Object key){ + return values.contains(key); + } + public List getValues() { return values; } diff --git a/src/test/java/database/storageEngine/page/PageManagerTest.java b/src/test/java/database/storageEngine/page/FileManagerTest.java similarity index 81% rename from src/test/java/database/storageEngine/page/PageManagerTest.java rename to src/test/java/database/storageEngine/page/FileManagerTest.java index 92de075..3371112 100644 --- a/src/test/java/database/storageEngine/page/PageManagerTest.java +++ b/src/test/java/database/storageEngine/page/FileManagerTest.java @@ -12,18 +12,18 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -@DisplayName("페이지 매니저 테스트") -class PageManagerTest { +@DisplayName("파일 매니저 테스트") +class FileManagerTest { private static final String DIRECTORY_PATH = "disk"; private static final String FILE_EXTENSION = ".ibd"; - private PageManager pageManager; + private FileManager fileManager; private final String tableName = "table"; @BeforeEach void setUp() { - pageManager = new PageManager(); + fileManager = new FileManager(); } @DisplayName("페이지 저장에 성공한다.") @@ -33,7 +33,7 @@ void savePage() { Page page = PageFactory.createDataPage(0); // when - pageManager.savePage(tableName, page); + fileManager.savePage(tableName, page); // then Path filePath = Paths.get(DIRECTORY_PATH, tableName + FILE_EXTENSION); @@ -50,12 +50,12 @@ void loadPage() { Page page1 = PageFactory.createDataPage(pageNumber1); Page page2 = PageFactory.createUndoPage(pageNumber2); - pageManager.savePage(tableName, page1); - pageManager.savePage(tableName, page2); + fileManager.savePage(tableName, page1); + fileManager.savePage(tableName, page2); // when - Page foundPage1 = pageManager.loadPage(new TablePageKey(tableName, pageNumber1)).get(); - Page foundPage2 = pageManager.loadPage(new TablePageKey(tableName, pageNumber2)).get(); + Page foundPage1 = fileManager.loadPage(new TablePageKey(tableName, pageNumber1)).get(); + Page foundPage2 = fileManager.loadPage(new TablePageKey(tableName, pageNumber2)).get(); // then assertThat(foundPage1.getPageNumber()).isEqualTo(pageNumber1);