-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Paged File, I/O System] 초코칩(권기호) 미션 제출합니다. (#3)
* feat: 페이지 구조 구현 * feat: 페이지 직렬화 * feat: 페이지 팩터리 패턴 적용 * feat: 페이지 매니저 생성 * test: DisplayName 수정 * feat: 불필요 PageManager 삭제 * feat: 버퍼풀 구현 * refactor: innodb 패키지 생성 * feat: 더티 상태 구현 * feat: 페이지 내의 레코드 기능 구현 * feat: 페이지 디렉터리 구현 * feat: 레코드 추가 기능 구현 * feat: 레코드 변경 시, 더티 체크 * feat: 테이블 별로 페이지 저장 * feat: 페이지 번호 반환 * refactor: 버퍼풀 패키지 생성 * feat: 페이지 교체 알고리즘 전략 패턴 적용 * refactor: 포트에 final 적용 * refactor: 코드 포멧팅 * feat: 핸들러 삽입 구현 * refactor: 레코드 파일 분리 * refactor: 패키지명 변경 * feat: 레코드 자료형 변경 * refactor: pageManager 버퍼풀 내로 이동 * refactor: 페이지 키 객체화 * refactor: key 변경 * refactor: filemanager로 클래스명 변경 * refactor: 개행 추가 * refactor(FileHeader): 불필요 체크섬 필드 제거 * refactor(FileExtension): 파일 확장자 분리 * refactor: 예외처리 구분 * refactor: 테스트 수정
- Loading branch information
1 parent
2083b70
commit dc15cdf
Showing
32 changed files
with
1,098 additions
and
22 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 3 additions & 2 deletions
5
src/main/java/database/DatabaseServer.java → .../java/database/engine/DatabaseServer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package database.engine; | ||
|
||
import java.util.List; | ||
|
||
public interface Handler { | ||
|
||
void insert(String tableName, Record record); | ||
|
||
List<Record> search(String tableName, Object key); | ||
|
||
void update(String tableName, Object key, byte[] newRecord); | ||
|
||
void delete(String tableName, Object key); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package database.engine; | ||
|
||
import java.util.List; | ||
|
||
public class Record { | ||
|
||
private final List<Object> values; | ||
|
||
public Record(List<Object> values) { | ||
this.values = values; | ||
} | ||
|
||
public List<Object> getValues() { | ||
return values; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "Record{" + | ||
"values=" + values + | ||
'}'; | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
65 changes: 65 additions & 0 deletions
65
src/main/java/database/storageEngine/StorageEngineHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package database.storageEngine; | ||
|
||
import database.engine.Handler; | ||
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.StorageRecord; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
public class StorageEngineHandler implements Handler { | ||
|
||
private static final int BUFFER_SIZE = 40; | ||
|
||
private final BufferPool bufferPool; | ||
|
||
public StorageEngineHandler() { | ||
PageReplacementStrategy<TablePageKey> lruStrategy = new LRUStrategy<>(BUFFER_SIZE); | ||
this.bufferPool = new BufferPool(BUFFER_SIZE, lruStrategy); | ||
} | ||
|
||
@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<Record> search(String tableName, Object key) { | ||
List<Record> results = new ArrayList<>(); | ||
|
||
for (long pageNumber = 0; ; pageNumber++) { | ||
TablePageKey tablePageKey = new TablePageKey(tableName, pageNumber); | ||
Optional<Page> pageOpt = bufferPool.getPage(tablePageKey); | ||
|
||
if (pageOpt.isPresent()) { | ||
Page page = pageOpt.get(); | ||
List<Record> records = page.searchRecords(key).stream() | ||
.map(storageRecord -> new Record(storageRecord.getValues())) | ||
.toList(); | ||
if (!records.isEmpty()) { | ||
results.addAll(records); | ||
} | ||
} else { | ||
break; | ||
} | ||
} | ||
return results; | ||
} | ||
|
||
@Override | ||
public void update(String tableName, Object key, byte[] newRecord) { | ||
// 디스크에서 레코드를 업데이트하는 로직 | ||
} | ||
|
||
@Override | ||
public void delete(String tableName, Object key) { | ||
// 디스크에서 레코드를 삭제하는 로직 | ||
} | ||
} |
87 changes: 87 additions & 0 deletions
87
src/main/java/database/storageEngine/bufferpool/BufferPool.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package database.storageEngine.bufferpool; | ||
|
||
import database.storageEngine.page.FileExtension; | ||
import database.storageEngine.page.FileManager; | ||
import database.storageEngine.page.Page; | ||
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<TablePageKey> strategy; | ||
private final Map<TablePageKey, Page> pages; | ||
private final FileManager fileManager; | ||
|
||
public BufferPool(int capacity, PageReplacementStrategy<TablePageKey> strategy) { | ||
this.capacity = capacity; | ||
this.strategy = strategy; | ||
this.pages = new HashMap<>(); | ||
this.fileManager = new FileManager(FileExtension.IDB); | ||
} | ||
|
||
public Optional<Page> getPage(TablePageKey key) { | ||
// Cache hit | ||
if (pages.containsKey(key)) { | ||
strategy.get(key); | ||
return Optional.of(pages.get(key)); | ||
} | ||
|
||
// Cache miss | ||
Page page = fileManager.loadPage(key); | ||
putPage(key, page); | ||
return Optional.of(page); | ||
} | ||
|
||
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 void flushPage(TablePageKey key) { | ||
if (pages.containsKey(key)) { | ||
Page page = pages.get(key); | ||
if (page.isDirty()) { | ||
fileManager.savePage(key.tableName(), page); | ||
page.clean(); | ||
} | ||
} | ||
} | ||
|
||
public void flushAllPages() { | ||
for (Map.Entry<TablePageKey, Page> entry : pages.entrySet()) { | ||
flushPage(entry.getKey()); | ||
} | ||
} | ||
|
||
public void removePage(TablePageKey key) { | ||
if (pages.containsKey(key)) { | ||
flushPage(key); | ||
pages.remove(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); | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
src/main/java/database/storageEngine/bufferpool/PageReplacementStrategy.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package database.storageEngine.bufferpool; | ||
|
||
import java.util.Optional; | ||
|
||
public interface PageReplacementStrategy<K> { | ||
|
||
Optional<K> get(K key); | ||
|
||
void put(K key); | ||
|
||
K evict(); | ||
|
||
boolean contains(K key); | ||
} |
5 changes: 5 additions & 0 deletions
5
src/main/java/database/storageEngine/bufferpool/TablePageKey.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package database.storageEngine.bufferpool; | ||
|
||
public record TablePageKey(String tableName, long pageNumber) { | ||
|
||
} |
66 changes: 66 additions & 0 deletions
66
src/main/java/database/storageEngine/bufferpool/pageReplacementStrategies/LFUStrategy.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package database.storageEngine.bufferpool.pageReplacementStrategies; | ||
|
||
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<K> implements PageReplacementStrategy<K> { | ||
|
||
private final int capacity; | ||
private final Map<K, Integer> usageCount; | ||
private final Map<K, Long> cache; | ||
|
||
public LFUStrategy(int capacity) { | ||
this.capacity = capacity; | ||
this.usageCount = new HashMap<>(); | ||
this.cache = new HashMap<>(); | ||
} | ||
|
||
@Override | ||
public void put(K key) { | ||
if (cache.size() >= capacity) { | ||
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); | ||
} | ||
return leastUsedKey; | ||
} | ||
|
||
@Override | ||
public boolean contains(K key) { | ||
return cache.containsKey(key); | ||
} | ||
|
||
private K findLeastUsedKey() { | ||
Optional<Entry<K, Integer>> 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 Optional<K> get(K key) { | ||
if (cache.containsKey(key)) { | ||
usageCount.put(key, usageCount.get(key) + 1); | ||
return Optional.of(key); | ||
} | ||
return Optional.empty(); | ||
} | ||
} |
49 changes: 49 additions & 0 deletions
49
src/main/java/database/storageEngine/bufferpool/pageReplacementStrategies/LRUStrategy.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package database.storageEngine.bufferpool.pageReplacementStrategies; | ||
|
||
import database.storageEngine.bufferpool.PageReplacementStrategy; | ||
import java.util.LinkedHashSet; | ||
import java.util.Optional; | ||
|
||
public class LRUStrategy<K> implements PageReplacementStrategy<K> { | ||
|
||
private final int capacity; | ||
private final LinkedHashSet<K> cache; | ||
|
||
public LRUStrategy(int capacity) { | ||
this.capacity = capacity; | ||
this.cache = new LinkedHashSet<>(capacity); | ||
} | ||
|
||
@Override | ||
public void put(K key) { | ||
if (cache.contains(key)) { | ||
cache.remove(key); | ||
} else if (cache.size() >= capacity) { | ||
evict(); | ||
} | ||
cache.add(key); | ||
} | ||
|
||
@Override | ||
public K evict() { | ||
K firstKey = cache.iterator().next(); | ||
cache.remove(firstKey); | ||
return firstKey; | ||
} | ||
|
||
@Override | ||
public boolean contains(K key) { | ||
return cache.contains(key); | ||
} | ||
|
||
@Override | ||
public Optional<K> get(K key) { | ||
if (cache.contains(key)) { | ||
cache.remove(key); | ||
cache.add(key); | ||
return Optional.of(key); | ||
} | ||
return Optional.empty(); | ||
} | ||
} | ||
|
Oops, something went wrong.