-
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 관리] 로키 미션 제출합니다. #2
base: HaiSeong
Are you sure you want to change the base?
Changes from all commits
3493bb4
95a6a91
0fe5cac
720127b
49f47f6
640d81d
2a2e5bb
fef0303
0d7d7f0
a760ba8
8ddf5a7
4535388
d3fad54
f83aca2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package database; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
public class ParameterHandler { | ||
|
||
private static final Map<String, String> DEFAULT_OPTIONS = Map.of( | ||
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. 저도 적용해봐야겠네요 👍🏻 |
||
"-port", "3306", | ||
"-u", "root" | ||
); | ||
|
||
private final Map<String, String> options; | ||
|
||
public ParameterHandler(String[] args) { | ||
options = new HashMap<>(DEFAULT_OPTIONS); | ||
|
||
for (int i = 0; i < args.length; i += 2) { | ||
String option = args[i]; | ||
if (!DEFAULT_OPTIONS.containsKey(option)) { | ||
throw new IllegalArgumentException("Unknown option: " + option); | ||
} | ||
|
||
String optionValue = args[i + 1]; | ||
options.put(option, optionValue); | ||
} | ||
} | ||
|
||
public int getPort() { | ||
return Integer.parseInt(options.get("-port")); | ||
} | ||
|
||
public String getOption(String option) { | ||
return options.get(option); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package database.page; | ||
|
||
import java.util.Map; | ||
import java.util.Set; | ||
|
||
public class Buffer { | ||
|
||
private final int bufferSize; | ||
private final Map<PageId, Page> pageBuffer; | ||
|
||
public Buffer(int bufferSize, Map<PageId, Page> pageBuffer) { | ||
this.bufferSize = bufferSize; | ||
this.pageBuffer = pageBuffer; | ||
} | ||
|
||
public Page getPage(PageId pageId) { | ||
if (!pageBuffer.containsKey(pageId)) { | ||
return null; | ||
} | ||
return pageBuffer.get(pageId); | ||
} | ||
Comment on lines
+16
to
+21
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. Optional을 활용해보는 것은 어떠신가요? |
||
|
||
public void putPage(PageId pageId, Page page) { | ||
if (pageBuffer.size() >= bufferSize) { | ||
throw new IllegalStateException("Buffer is full"); | ||
} | ||
pageBuffer.put(pageId, page); | ||
} | ||
|
||
public Page removePage(PageId pageId) { | ||
if (!pageBuffer.containsKey(pageId)) { | ||
throw new IllegalStateException("Page not found in buffer"); | ||
} | ||
return pageBuffer.remove(pageId); | ||
} | ||
|
||
public boolean containsPage(PageId pageId) { | ||
return pageBuffer.containsKey(pageId); | ||
} | ||
|
||
public boolean isFull() { | ||
return pageBuffer.size() >= bufferSize; | ||
} | ||
|
||
public boolean isReferenced(String filename) { | ||
return pageBuffer.keySet().stream() | ||
.map(PageId::filename) | ||
.anyMatch(filename::equals); | ||
} | ||
|
||
public Set<PageId> getPageIds() { | ||
return pageBuffer.keySet(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package database.page; | ||
|
||
import java.io.IOException; | ||
|
||
public class BufferManager { | ||
private final Buffer buffer; | ||
private final PageReplacementPolicy pageReplacementPolicy; | ||
private final PagedFileManager pagedFileManager; | ||
private final ScratchPageManager scratchPageManager; | ||
|
||
public BufferManager( | ||
Buffer buffer, | ||
PageReplacementPolicy pageReplacementPolicy, | ||
PagedFileManager pagedFileManager, | ||
ScratchPageManager scratchPageManager | ||
) { | ||
this.buffer = buffer; | ||
this.pageReplacementPolicy = pageReplacementPolicy; | ||
this.pagedFileManager = pagedFileManager; | ||
this.scratchPageManager = scratchPageManager; | ||
} | ||
|
||
public Page getPage(PageId pageId) throws IOException { | ||
if (scratchPageManager.isScratchPage(pageId)) { | ||
return buffer.getPage(pageId); | ||
} | ||
if (buffer.containsPage(pageId)) { | ||
pageReplacementPolicy.updatePage(pageId); | ||
return buffer.getPage(pageId); | ||
} | ||
|
||
PagedFile pagedFile = pagedFileManager.openFile(pageId.filename()); | ||
|
||
Page page = pagedFile.readPage(pageId.pageNum()); | ||
if (buffer.isFull()) { | ||
evictPage(); | ||
} | ||
|
||
buffer.putPage(pageId, page); | ||
pageReplacementPolicy.addPage(pageId); | ||
return page; | ||
} | ||
|
||
public void flushPage(PageId pageId) throws IOException { | ||
if (isFlushAble(pageId)) { | ||
Page page = buffer.getPage(pageId); | ||
PagedFile pagedFile = pagedFileManager.openFile(pageId.filename()); | ||
pagedFile.writePage(pageId.pageNum(), page.getData()); | ||
page.setClean(); | ||
} | ||
} | ||
|
||
public void flushAllPages() throws IOException { | ||
for (PageId pageId : buffer.getPageIds()) { | ||
if (isFlushAble(pageId)) { | ||
Page page = buffer.getPage(pageId); | ||
PagedFile pagedFile = pagedFileManager.openFile(pageId.filename()); | ||
pagedFile.writePage(page.getPageNum(), page.getData()); | ||
page.setClean(); | ||
} | ||
} | ||
} | ||
|
||
public Page createScratchPage(byte[] data) throws IOException { | ||
if (buffer.isFull()) { | ||
evictPage(); | ||
} | ||
|
||
PageId scratchPageId = scratchPageManager.allocateScratchPageId(); | ||
Page scratchPage = new Page(scratchPageId.pageNum(), data); | ||
buffer.putPage(scratchPageId, scratchPage); | ||
|
||
return scratchPage; | ||
} | ||
|
||
public void releaseScratchPage(PageId pageId) { | ||
if (!scratchPageManager.isScratchPage(pageId)) { | ||
throw new IllegalArgumentException("Page is not a scratch page"); | ||
} | ||
buffer.removePage(pageId); | ||
} | ||
|
||
private void evictPage() throws IOException { | ||
PageId pageIdToEvict = pageReplacementPolicy.evictPage(); | ||
Page pageToEvict = buffer.removePage(pageIdToEvict); | ||
String filename = pageIdToEvict.filename(); | ||
if (pageToEvict.isDirty()) { | ||
PagedFile pagedFile = pagedFileManager.openFile(filename); | ||
pagedFile.writePage(pageToEvict.getPageNum(), pageToEvict.getData()); | ||
} | ||
|
||
if (!buffer.isReferenced(filename)) { | ||
pagedFileManager.closeFile(pageIdToEvict.filename()); | ||
} | ||
} | ||
|
||
private boolean isFlushAble(PageId pageId) { | ||
if (!buffer.containsPage(pageId)) { | ||
return false; | ||
} | ||
if (scratchPageManager.isScratchPage(pageId)) { | ||
return false; | ||
} | ||
|
||
Page page = buffer.getPage(pageId); | ||
return page.isDirty(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package database.page; | ||
|
||
import java.io.IOException; | ||
import java.io.RandomAccessFile; | ||
|
||
public class FileAccessor { | ||
private final RandomAccessFile file; | ||
private final int pageSize; | ||
private final int headerSize; | ||
|
||
public FileAccessor(RandomAccessFile file, int pageSize, int headerSize) { | ||
this.file = file; | ||
this.pageSize = pageSize; | ||
this.headerSize = headerSize; | ||
} | ||
|
||
public void writePage(int pageNum, byte[] data) throws IOException { | ||
long offset = calculatePageOffset(pageNum); | ||
file.seek(offset); | ||
file.write(data); | ||
} | ||
|
||
public void readPage(int pageNum, byte[] buffer) throws IOException { | ||
long offset = calculatePageOffset(pageNum); | ||
file.seek(offset); | ||
file.readFully(buffer); | ||
} | ||
|
||
public void clearPage(int pageNum) throws IOException { | ||
long offset = calculatePageOffset(pageNum); | ||
file.seek(offset); | ||
file.write(new byte[pageSize]); | ||
} | ||
|
||
private long calculatePageOffset(int pageNum) { | ||
return headerSize + (long) pageNum * pageSize; | ||
} | ||
|
||
public void writeHeader(byte[] headerData) throws IOException { | ||
file.seek(0); | ||
file.write(headerData); | ||
} | ||
|
||
public void readHeader(byte[] buffer) throws IOException { | ||
file.seek(0); | ||
file.readFully(buffer); | ||
} | ||
|
||
public long getFileLength() throws IOException { | ||
return file.length(); | ||
} | ||
|
||
public boolean isFileEmpty() throws IOException { | ||
return file.length() == 0; | ||
} | ||
|
||
public void close() throws IOException { | ||
file.close(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package database.page; | ||
|
||
import java.io.IOException; | ||
import java.util.PriorityQueue; | ||
|
||
public class FileHeader { | ||
static final int HEADER_SIZE = 16 * 1024; | ||
|
||
private final byte[] pageAllocationBitMap; | ||
private final PriorityQueue<Integer> freePages; | ||
private final FileAccessor fileAccessor; | ||
private int numPages; | ||
|
||
public FileHeader( | ||
FileAccessor fileAccessor, | ||
byte[] pageAllocationBitMap, | ||
PriorityQueue<Integer> freePages | ||
) throws IOException { | ||
this.fileAccessor = fileAccessor; | ||
this.pageAllocationBitMap = pageAllocationBitMap; | ||
this.freePages = freePages; | ||
|
||
if (fileAccessor.isFileEmpty()) { | ||
fileAccessor.writeHeader(pageAllocationBitMap); | ||
} else { | ||
fileAccessor.readHeader(pageAllocationBitMap); | ||
} | ||
|
||
this.numPages = (int) (fileAccessor.getFileLength() - HEADER_SIZE) / PagedFile.PAGE_SIZE; | ||
for (int i = 0; i < numPages; i++) { | ||
if (!isPageAllocated(i)) { | ||
freePages.add(i); | ||
} | ||
} | ||
} | ||
|
||
public boolean isPageAllocated(int pageNum) { | ||
int byteIndex = pageNum / 8; | ||
int bitIndex = pageNum % 8; | ||
return (pageAllocationBitMap[byteIndex] & (1 << bitIndex)) != 0; | ||
} | ||
|
||
public int allocatePage() throws IOException { | ||
int pageNum; | ||
if (!freePages.isEmpty()) { | ||
pageNum = freePages.poll(); | ||
} else { | ||
pageNum = numPages++; | ||
} | ||
|
||
int byteIndex = pageNum / 8; | ||
int bitIndex = pageNum % 8; | ||
pageAllocationBitMap[byteIndex] |= (byte) (1 << bitIndex); | ||
|
||
fileAccessor.writeHeader(pageAllocationBitMap); | ||
|
||
return pageNum; | ||
} | ||
|
||
public void deallocatePage(int pageNum) throws IOException { | ||
int byteIndex = pageNum / 8; | ||
int bitIndex = pageNum % 8; | ||
pageAllocationBitMap[byteIndex] &= (byte) ~(1 << bitIndex); | ||
freePages.add(pageNum); | ||
|
||
fileAccessor.writeHeader(pageAllocationBitMap); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package database.page; | ||
|
||
import java.util.LinkedList; | ||
|
||
public class LRUReplacementPolicy implements PageReplacementPolicy { | ||
|
||
private final LinkedList<PageId> lruList; | ||
|
||
public LRUReplacementPolicy(LinkedList<PageId> lruList) { | ||
this.lruList = lruList; | ||
} | ||
|
||
@Override | ||
public void addPage(PageId pageId) { | ||
lruList.addFirst(pageId); | ||
} | ||
|
||
@Override | ||
public void updatePage(PageId pageId) { | ||
lruList.remove(pageId); | ||
lruList.addFirst(pageId); | ||
} | ||
|
||
@Override | ||
public PageId evictPage() { | ||
return lruList.removeLast(); | ||
} | ||
} |
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.
👍🏻