Skip to content
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

Open
wants to merge 14 commits into
base: HaiSeong
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion src/main/java/database/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
public class Application {

public static void main(String[] args) {
DatabaseServer server = new DatabaseServer(3306);
ParameterHandler parameterHandler = new ParameterHandler(args);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏻

DatabaseServer server = new DatabaseServer(parameterHandler.getPort());
server.start();
}
}
36 changes: 36 additions & 0 deletions src/main/java/database/ParameterHandler.java
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(
Copy link
Member

Choose a reason for hiding this comment

The 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);
}
}
54 changes: 54 additions & 0 deletions src/main/java/database/page/Buffer.java
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
Copy link
Member

Choose a reason for hiding this comment

The 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();
}
}
108 changes: 108 additions & 0 deletions src/main/java/database/page/BufferManager.java
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();
}
}
60 changes: 60 additions & 0 deletions src/main/java/database/page/FileAccessor.java
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();
}
}
68 changes: 68 additions & 0 deletions src/main/java/database/page/FileHeader.java
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);
}
}
28 changes: 28 additions & 0 deletions src/main/java/database/page/LRUReplacementPolicy.java
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();
}
}
Loading