-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Page File Management] 재즈(함석명) 미션 제출합니다. #5
Changes from all commits
4f31b12
dbefaf9
fa5bfb4
ad34432
05172c3
7bbf7f4
c590b69
f07396a
83a2755
9af29d5
426db15
8eedadb
51ad914
04a3344
28f1132
d3f1c15
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,4 +23,4 @@ java { | |
|
||
test { | ||
useJUnitPlatform() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package database; | ||
|
||
import java.util.Map; | ||
|
||
public class BufferPool { | ||
|
||
private static final int BUFFER_SIZE = 40; | ||
|
||
private final Map<PageId, Page> bufferPool; | ||
private final PageManager pageManager; | ||
|
||
public BufferPool(PageManager pageManager) { | ||
this.bufferPool = new LRUCache<>(BUFFER_SIZE, 0.75f, true, pageManager); | ||
this.pageManager = pageManager; | ||
} | ||
|
||
public Page getPage(PageId pageId) { | ||
Page page = bufferPool.computeIfAbsent(pageId, id -> pageManager.loadPage(pageId)); | ||
page.pin(); | ||
return page; | ||
} | ||
|
||
public void modifyPage(PageId pageId) { | ||
Page page = getPage(pageId); | ||
/* | ||
..modify.. | ||
*/ | ||
page.setDirty(true); | ||
page.unPin(); | ||
} | ||
|
||
/** | ||
* 플러시 리스트 플러시 | ||
*/ | ||
public void flush() { | ||
for (Map.Entry<PageId, Page> entry : bufferPool.entrySet()) { | ||
Page page = entry.getValue(); | ||
|
||
if (!page.isPinned() && page.isDirty()) { | ||
pageManager.savePage(entry.getKey(), page); | ||
page.setDirty(false); | ||
} | ||
} | ||
} | ||
|
||
public Map<PageId, Page> getBufferPool() { | ||
return bufferPool; | ||
} | ||
|
||
public PageManager getPageManager() { | ||
return pageManager; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package database; | ||
|
||
import java.io.FileInputStream; | ||
import java.io.FileOutputStream; | ||
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 FileManager { | ||
|
||
private static final String DIRECTORY_PATH = "data/files/"; | ||
private static final String FILE_EXTENSION = ".ibd"; | ||
|
||
public FileManager() { | ||
createDirectory(); | ||
} | ||
|
||
private void createDirectory() { | ||
Path directory = Paths.get(DIRECTORY_PATH); | ||
if (Files.notExists(directory)) { | ||
try { | ||
Files.createDirectories(directory); | ||
} catch (IOException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
} | ||
|
||
public Page readPage(PageId pageId) { | ||
Path filePath = Paths.get(DIRECTORY_PATH, pageId.getFileName() + FILE_EXTENSION); | ||
|
||
try (RandomAccessFile file = new RandomAccessFile(filePath.toString(), "r")) { | ||
long offset = (long) pageId.getPageNum() * Page.PAGE_SIZE; | ||
file.seek(offset); | ||
|
||
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file.getFD()))) { | ||
return (Page) ois.readObject(); | ||
} | ||
} catch (IOException | ClassNotFoundException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
public void writePage(PageId pageId, Page page) { | ||
Path filePath = Paths.get(DIRECTORY_PATH, pageId.getFileName() + FILE_EXTENSION); | ||
|
||
try (RandomAccessFile file = new RandomAccessFile(filePath.toString(), "rw")) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍🏻 |
||
long offset = (long) pageId.getPageNum() * Page.PAGE_SIZE; | ||
file.seek(offset); | ||
|
||
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file.getFD()))) { | ||
oos.writeObject(page); | ||
} | ||
} catch (IOException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,34 @@ | ||||||
package database; | ||||||
|
||||||
import java.util.LinkedHashMap; | ||||||
import java.util.Map; | ||||||
|
||||||
public class LRUCache<K, V> extends LinkedHashMap<K, V> { | ||||||
|
||||||
private final int bufferSize; | ||||||
private final PageManager pageManager; | ||||||
|
||||||
public LRUCache(int initialCapacity, float loadFactor, boolean accessOrder, PageManager pageManager) { | ||||||
super(initialCapacity, loadFactor, accessOrder); | ||||||
this.pageManager = pageManager; | ||||||
this.bufferSize = initialCapacity; | ||||||
} | ||||||
|
||||||
@Override | ||||||
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { | ||||||
boolean isBufferPoolOverCapacity = size() > bufferSize; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 메서드가 아닌 변수로 분리한 이유가 있나요? |
||||||
boolean isUnpinned = !((Page) eldest.getValue()).isPinned(); | ||||||
|
||||||
if (isBufferPoolOverCapacity && isUnpinned) { | ||||||
flushIfDirty((PageId) eldest.getKey(), (Page) eldest.getValue()); | ||||||
return true; | ||||||
} | ||||||
return false; | ||||||
} | ||||||
|
||||||
private void flushIfDirty(PageId pageId, Page page) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
해당 메서드를 사용하는 측에서는 더티 페이지의 여부가 중요하나요? |
||||||
if (page.isDirty()) { | ||||||
pageManager.savePage(pageId, page); | ||||||
} | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package database; | ||
|
||
import java.io.Serializable; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class Page implements Serializable { | ||
|
||
public static final int PAGE_SIZE = 16 * 1024; | ||
|
||
private final PageHeader header; | ||
private final List<Record> records; | ||
private int freeSpace; | ||
private int pinCount; | ||
|
||
public Page(int pageNum, PageType pageType) { | ||
this.header = new PageHeader(pageNum, pageType); | ||
this.records = new ArrayList<>(); | ||
this.freeSpace = PAGE_SIZE - header.getHeaderSize(); | ||
} | ||
|
||
public boolean addRecord(Record record) { | ||
if (freeSpace >= record.getSize()) { | ||
records.add(record); | ||
freeSpace -= record.getSize(); | ||
|
||
header.incrementRecordCount(); | ||
header.setDirty(true); | ||
|
||
return true; | ||
} else { | ||
return false; | ||
} | ||
} | ||
|
||
public boolean deleteRecord(Record record) { | ||
if (records.remove(record)) { | ||
freeSpace += record.getSize(); | ||
|
||
header.setDirty(true); | ||
header.decrementRecordCount(); | ||
|
||
return true; | ||
} else { | ||
return false; | ||
} | ||
} | ||
|
||
public void pin() { | ||
this.pinCount++; | ||
} | ||
|
||
public void unPin() { | ||
this.pinCount--; | ||
} | ||
|
||
public boolean isPinned() { | ||
return this.pinCount > 0; | ||
} | ||
|
||
public PageHeader getHeader() { | ||
return header; | ||
} | ||
|
||
public List<Record> getRecords() { | ||
return records; | ||
} | ||
|
||
public int getFreeSpace() { | ||
return freeSpace; | ||
} | ||
|
||
public int getPinCount() { | ||
return pinCount; | ||
} | ||
|
||
public void setDirty(boolean isDirty) { | ||
header.setDirty(isDirty); | ||
} | ||
|
||
public boolean isDirty() { | ||
return header.isDirty(); | ||
} | ||
|
||
public PageType getPageType() { | ||
return header.getPageType(); | ||
} | ||
|
||
public int getPageNum() { | ||
return header.getPageNum(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package database; | ||
|
||
import java.io.Serializable; | ||
|
||
public class PageHeader implements Serializable { | ||
|
||
public static final int HEADER_SIZE = 13; | ||
|
||
private final int pageNum; | ||
private final PageType pageType; | ||
private int recordCount; | ||
private boolean isDirty; | ||
|
||
public PageHeader(int pageNum, PageType pageType) { | ||
this.pageNum = pageNum; | ||
this.pageType = pageType; | ||
this.recordCount = 0; | ||
this.isDirty = false; | ||
} | ||
|
||
public void incrementRecordCount() { | ||
this.recordCount++; | ||
} | ||
|
||
public void decrementRecordCount() { | ||
this.recordCount--; | ||
} | ||
|
||
public void setDirty(boolean isDirty) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 더 의미있는 메서드들로 나눌수 있을 것 같아요. |
||
this.isDirty = isDirty; | ||
} | ||
|
||
public int getPageNum() { | ||
return pageNum; | ||
} | ||
|
||
public PageType getPageType() { | ||
return pageType; | ||
} | ||
|
||
public int getRecordCount() { | ||
return recordCount; | ||
} | ||
|
||
public boolean isDirty() { | ||
return isDirty; | ||
} | ||
|
||
public int getHeaderSize() { | ||
return HEADER_SIZE; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package database; | ||
|
||
import java.util.Objects; | ||
|
||
public class PageId { | ||
|
||
private final String fileName; | ||
private final int PageNum; | ||
|
||
public PageId(String fileName, int pageNum) { | ||
this.fileName = fileName; | ||
this.PageNum = pageNum; | ||
} | ||
|
||
public String getFileName() { | ||
return fileName; | ||
} | ||
|
||
public int getPageNum() { | ||
return PageNum; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) { | ||
return true; | ||
} | ||
if (o == null || getClass() != o.getClass()) { | ||
return false; | ||
} | ||
PageId pageId = (PageId) o; | ||
return PageNum == pageId.PageNum && Objects.equals(fileName, pageId.fileName); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(fileName, PageNum); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package database; | ||
|
||
public class PageManager { | ||
|
||
private final FileManager fileManager; | ||
|
||
public PageManager(FileManager fileManager) { | ||
this.fileManager = fileManager; | ||
} | ||
|
||
public Page loadPage(PageId pageId) { | ||
return fileManager.readPage(pageId); | ||
} | ||
|
||
public void savePage(PageId pageId, Page page) { | ||
fileManager.writePage(pageId, page); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package database; | ||
|
||
public enum PageType { | ||
|
||
CLUSTERED_INDEX, | ||
SECONDARY_INDEX, | ||
UNDO_LOG; | ||
} | ||
Comment on lines
+3
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 페이지 타입은 어떤 기준으로 나누셨나요? |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package database; | ||
|
||
import java.io.Serializable; | ||
|
||
public class Record implements Serializable { | ||
|
||
private final int recordId; | ||
private final byte[] data; | ||
|
||
public Record(int recordId, byte[] data) { | ||
this.recordId = recordId; | ||
this.data = data; | ||
} | ||
|
||
public int getRecordId() { | ||
return recordId; | ||
} | ||
|
||
public byte[] getData() { | ||
return data; | ||
} | ||
|
||
public int getSize() { | ||
return data.length; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오 플러시 리스트 플러시까지 구현하셨군요 👍🏻