document-dataply 0.0.4-alpha.3 → 0.0.4-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +98 -20
- package/package.json +2 -2
package/dist/cjs/index.js
CHANGED
|
@@ -7434,9 +7434,6 @@ var require_cjs = __commonJS({
|
|
|
7434
7434
|
promises.push(writePage(pageId, data));
|
|
7435
7435
|
}
|
|
7436
7436
|
await Promise.all(promises);
|
|
7437
|
-
if (restoredPages.size > 0) {
|
|
7438
|
-
await this.clear();
|
|
7439
|
-
}
|
|
7440
7437
|
}
|
|
7441
7438
|
/**
|
|
7442
7439
|
* WAL에 페이지 데이터를 기록합니다 (Phase 1: Prepare).
|
|
@@ -7595,6 +7592,8 @@ var require_cjs = __commonJS({
|
|
|
7595
7592
|
}
|
|
7596
7593
|
/** LRU 캐시 (페이지 ID -> 페이지 데이터) */
|
|
7597
7594
|
cache;
|
|
7595
|
+
/** 디스크에 기록되지 않은 변경된 페이지들 (페이지 ID -> 페이지 데이터) */
|
|
7596
|
+
dirtyPages = /* @__PURE__ */ new Map();
|
|
7598
7597
|
/** 파일 크기 (논리적) */
|
|
7599
7598
|
fileSize;
|
|
7600
7599
|
/**
|
|
@@ -7604,6 +7603,12 @@ var require_cjs = __commonJS({
|
|
|
7604
7603
|
* @returns 페이지 데이터
|
|
7605
7604
|
*/
|
|
7606
7605
|
async read(pageId) {
|
|
7606
|
+
const dirty = this.dirtyPages.get(pageId);
|
|
7607
|
+
if (dirty) {
|
|
7608
|
+
const copy = new Uint8Array(this.pageSize);
|
|
7609
|
+
copy.set(dirty);
|
|
7610
|
+
return copy;
|
|
7611
|
+
}
|
|
7607
7612
|
const cached = this.cache.get(pageId);
|
|
7608
7613
|
if (cached) {
|
|
7609
7614
|
const copy = new Uint8Array(this.pageSize);
|
|
@@ -7631,21 +7636,50 @@ var require_cjs = __commonJS({
|
|
|
7631
7636
|
if (pageStartPos + this.pageSize > 512 * 1024 * 1024) {
|
|
7632
7637
|
throw new Error(`[Safety Limit] File write exceeds 512MB limit at position ${pageStartPos}`);
|
|
7633
7638
|
}
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
this.cache.set(pageId,
|
|
7639
|
+
const dataCopy = new Uint8Array(this.pageSize);
|
|
7640
|
+
dataCopy.set(data);
|
|
7641
|
+
this.dirtyPages.set(pageId, dataCopy);
|
|
7642
|
+
this.cache.set(pageId, dataCopy);
|
|
7638
7643
|
const endPosition = pageStartPos + this.pageSize;
|
|
7639
7644
|
if (endPosition > this.fileSize) {
|
|
7640
7645
|
this.fileSize = endPosition;
|
|
7641
7646
|
}
|
|
7642
7647
|
}
|
|
7648
|
+
/**
|
|
7649
|
+
* 더티 페이지들을 메인 디스크 파일에 일괄 기록합니다.
|
|
7650
|
+
* WAL 체크포인트 시점에 호출되어야 합니다.
|
|
7651
|
+
*/
|
|
7652
|
+
async flush() {
|
|
7653
|
+
if (this.dirtyPages.size === 0) {
|
|
7654
|
+
return;
|
|
7655
|
+
}
|
|
7656
|
+
const snapshot = new Map(this.dirtyPages);
|
|
7657
|
+
const sortedPageIds = Array.from(snapshot.keys()).sort((a, b) => a - b);
|
|
7658
|
+
for (const pageId of sortedPageIds) {
|
|
7659
|
+
const data = snapshot.get(pageId);
|
|
7660
|
+
const position = pageId * this.pageSize;
|
|
7661
|
+
await this._writeToDisk(data, position);
|
|
7662
|
+
this.dirtyPages.delete(pageId);
|
|
7663
|
+
}
|
|
7664
|
+
}
|
|
7665
|
+
/**
|
|
7666
|
+
* 메인 DB 파일의 물리적 동기화를 수행합니다 (fsync).
|
|
7667
|
+
*/
|
|
7668
|
+
async sync() {
|
|
7669
|
+
return new Promise((resolve, reject) => {
|
|
7670
|
+
import_node_fs2.default.fsync(this.fileHandle, (err) => {
|
|
7671
|
+
if (err) return reject(err);
|
|
7672
|
+
resolve();
|
|
7673
|
+
});
|
|
7674
|
+
});
|
|
7675
|
+
}
|
|
7643
7676
|
/**
|
|
7644
7677
|
* 페이지 삭제 (실제로는 캐시에서만 제거)
|
|
7645
7678
|
* 실제 페이지 해제는 상위 레이어(FreeList)에서 관리합니다.
|
|
7646
7679
|
* @param pageId 페이지 ID
|
|
7647
7680
|
*/
|
|
7648
7681
|
async delete(pageId) {
|
|
7682
|
+
this.dirtyPages.delete(pageId);
|
|
7649
7683
|
this.cache.delete(pageId);
|
|
7650
7684
|
}
|
|
7651
7685
|
/**
|
|
@@ -7654,6 +7688,9 @@ var require_cjs = __commonJS({
|
|
|
7654
7688
|
* @returns 존재하면 true
|
|
7655
7689
|
*/
|
|
7656
7690
|
async exists(pageId) {
|
|
7691
|
+
if (this.dirtyPages.has(pageId)) {
|
|
7692
|
+
return true;
|
|
7693
|
+
}
|
|
7657
7694
|
const pageStartPos = pageId * this.pageSize;
|
|
7658
7695
|
return pageStartPos < this.fileSize;
|
|
7659
7696
|
}
|
|
@@ -7708,6 +7745,25 @@ var require_cjs = __commonJS({
|
|
|
7708
7745
|
walManager;
|
|
7709
7746
|
pageManagerFactory;
|
|
7710
7747
|
pageStrategy;
|
|
7748
|
+
/** 글로벌 동기화(체크포인트/커밋)를 위한 Mutex */
|
|
7749
|
+
lockPromise = Promise.resolve();
|
|
7750
|
+
/**
|
|
7751
|
+
* 글로벌 동기화 범위 내에서 작업을 실행합니다.
|
|
7752
|
+
* @param task 수행할 비동기 작업
|
|
7753
|
+
*/
|
|
7754
|
+
async runGlobalLock(task) {
|
|
7755
|
+
const previous = this.lockPromise;
|
|
7756
|
+
let resolveLock;
|
|
7757
|
+
this.lockPromise = new Promise((resolve) => {
|
|
7758
|
+
resolveLock = resolve;
|
|
7759
|
+
});
|
|
7760
|
+
await previous;
|
|
7761
|
+
try {
|
|
7762
|
+
return await task();
|
|
7763
|
+
} finally {
|
|
7764
|
+
resolveLock();
|
|
7765
|
+
}
|
|
7766
|
+
}
|
|
7711
7767
|
/**
|
|
7712
7768
|
* Initializes the page file system.
|
|
7713
7769
|
* Performs WAL recovery if necessary.
|
|
@@ -7717,6 +7773,7 @@ var require_cjs = __commonJS({
|
|
|
7717
7773
|
await this.walManager.recover(async (pageId, data) => {
|
|
7718
7774
|
await this.pageStrategy.write(pageId, data);
|
|
7719
7775
|
});
|
|
7776
|
+
await this.checkpoint();
|
|
7720
7777
|
}
|
|
7721
7778
|
}
|
|
7722
7779
|
/**
|
|
@@ -8016,15 +8073,30 @@ var require_cjs = __commonJS({
|
|
|
8016
8073
|
async commitToWAL(dirtyPages) {
|
|
8017
8074
|
if (this.walManager) {
|
|
8018
8075
|
await this.walManager.prepareCommit(dirtyPages);
|
|
8019
|
-
await this.walManager.finalizeCommit(
|
|
8076
|
+
await this.walManager.finalizeCommit(true);
|
|
8020
8077
|
}
|
|
8021
8078
|
}
|
|
8079
|
+
/**
|
|
8080
|
+
* 체크포인트를 수행합니다.
|
|
8081
|
+
* 1. 메모리의 더티 페이지를 DB 파일에 기록 (Flush)
|
|
8082
|
+
* 2. DB 파일 물리적 동기화 (Sync/fsync)
|
|
8083
|
+
* 3. WAL 로그 파일 비우기 (Clear/Truncate)
|
|
8084
|
+
*/
|
|
8085
|
+
async checkpoint() {
|
|
8086
|
+
await this.runGlobalLock(async () => {
|
|
8087
|
+
await this.pageStrategy.flush();
|
|
8088
|
+
await this.pageStrategy.sync();
|
|
8089
|
+
if (this.walManager) {
|
|
8090
|
+
await this.walManager.clear();
|
|
8091
|
+
}
|
|
8092
|
+
});
|
|
8093
|
+
}
|
|
8022
8094
|
/**
|
|
8023
8095
|
* Closes the page file system.
|
|
8024
8096
|
*/
|
|
8025
8097
|
async close() {
|
|
8098
|
+
await this.checkpoint();
|
|
8026
8099
|
if (this.walManager) {
|
|
8027
|
-
await this.walManager.clear();
|
|
8028
8100
|
this.walManager.close();
|
|
8029
8101
|
}
|
|
8030
8102
|
}
|
|
@@ -8836,18 +8908,24 @@ var require_cjs = __commonJS({
|
|
|
8836
8908
|
await hook();
|
|
8837
8909
|
}
|
|
8838
8910
|
});
|
|
8839
|
-
|
|
8840
|
-
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
await this.pageStrategy.write(pageId, data);
|
|
8845
|
-
}
|
|
8846
|
-
if (this.pfs.wal) {
|
|
8847
|
-
this.pfs.wal.incrementWrittenPages(this.dirtyPages.size);
|
|
8848
|
-
if (this.pfs.wal.shouldCheckpoint(this.pfs.options.walCheckpointThreshold)) {
|
|
8849
|
-
await this.pfs.wal.clear();
|
|
8911
|
+
let shouldTriggerCheckpoint = false;
|
|
8912
|
+
await this.pfs.runGlobalLock(async () => {
|
|
8913
|
+
if (this.pfs.wal && this.dirtyPages.size > 0) {
|
|
8914
|
+
await this.pfs.wal.prepareCommit(this.dirtyPages);
|
|
8915
|
+
await this.pfs.wal.writeCommitMarker();
|
|
8850
8916
|
}
|
|
8917
|
+
for (const [pageId, data] of this.dirtyPages) {
|
|
8918
|
+
await this.pageStrategy.write(pageId, data);
|
|
8919
|
+
}
|
|
8920
|
+
if (this.pfs.wal) {
|
|
8921
|
+
this.pfs.wal.incrementWrittenPages(this.dirtyPages.size);
|
|
8922
|
+
if (this.pfs.wal.shouldCheckpoint(this.pfs.options.walCheckpointThreshold)) {
|
|
8923
|
+
shouldTriggerCheckpoint = true;
|
|
8924
|
+
}
|
|
8925
|
+
}
|
|
8926
|
+
});
|
|
8927
|
+
if (shouldTriggerCheckpoint) {
|
|
8928
|
+
await this.pfs.checkpoint();
|
|
8851
8929
|
}
|
|
8852
8930
|
this.dirtyPages.clear();
|
|
8853
8931
|
this.undoPages.clear();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "document-dataply",
|
|
3
|
-
"version": "0.0.4-alpha.
|
|
3
|
+
"version": "0.0.4-alpha.4",
|
|
4
4
|
"description": "Simple and powerful JSON document database supporting complex queries and flexible indexing policies.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "izure <admin@izure.org>",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"dataply"
|
|
43
43
|
],
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"dataply": "^0.0.20-alpha.
|
|
45
|
+
"dataply": "^0.0.20-alpha.4"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/jest": "^30.0.0",
|