dataply 0.0.17-alpha.0 → 0.0.17-alpha.1

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 CHANGED
@@ -30,6 +30,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
+ AsyncMVCCStrategy: () => AsyncMVCCStrategy2,
34
+ AsyncMVCCTransaction: () => AsyncMVCCTransaction2,
33
35
  BPTreeAsync: () => BPTreeAsync,
34
36
  BPTreeAsyncTransaction: () => BPTreeAsyncTransaction,
35
37
  BPTreeSync: () => BPTreeSync,
@@ -47,6 +49,8 @@ __export(src_exports, {
47
49
  IndexPageManager: () => IndexPageManager,
48
50
  InvertedWeakMap: () => InvertedWeakMap,
49
51
  LRUMap: () => LRUMap2,
52
+ MVCCStrategy: () => MVCCStrategy2,
53
+ MVCCTransaction: () => MVCCTransaction2,
50
54
  MetadataPageManager: () => MetadataPageManager,
51
55
  NumericComparator: () => NumericComparator,
52
56
  OverflowPageManager: () => OverflowPageManager,
@@ -56,6 +60,8 @@ __export(src_exports, {
56
60
  SerializeStrategyAsync: () => SerializeStrategyAsync,
57
61
  SerializeStrategySync: () => SerializeStrategySync,
58
62
  StringComparator: () => StringComparator,
63
+ SyncMVCCStrategy: () => SyncMVCCStrategy2,
64
+ SyncMVCCTransaction: () => SyncMVCCTransaction2,
59
65
  Transaction: () => Transaction,
60
66
  UnknownPageManager: () => UnknownPageManager,
61
67
  ValueComparator: () => ValueComparator
@@ -4561,6 +4567,1125 @@ var InvertedWeakMap = class {
4561
4567
  }
4562
4568
  };
4563
4569
 
4570
+ // node_modules/mvcc-api/dist/esm/index.mjs
4571
+ var MVCCStrategy2 = class {
4572
+ };
4573
+ var MVCCTransaction2 = class {
4574
+ committed;
4575
+ snapshotVersion;
4576
+ snapshotLocalVersion;
4577
+ writeBuffer;
4578
+ deleteBuffer;
4579
+ createdKeys;
4580
+ // create()로 생성된 키 추적
4581
+ deletedValues;
4582
+ // delete 시 삭제 전 값 저장
4583
+ originallyExisted;
4584
+ // 트랜잭션 시작 시점에 디스크에 존재했던 키 (deleted 결과 필터링용)
4585
+ // Nested Transaction Properties
4586
+ parent;
4587
+ localVersion;
4588
+ // Local version for Nested Conflict Detection
4589
+ keyVersions;
4590
+ // Key -> Local Version (When it was modified locally)
4591
+ // Root Transaction Properties (Only populated if this is Root)
4592
+ root;
4593
+ strategy;
4594
+ version = 0;
4595
+ versionIndex = /* @__PURE__ */ new Map();
4596
+ deletedCache = /* @__PURE__ */ new Map();
4597
+ activeTransactions = /* @__PURE__ */ new Set();
4598
+ constructor(strategy, parent, snapshotVersion) {
4599
+ this.snapshotVersion = snapshotVersion ?? 0;
4600
+ this.writeBuffer = /* @__PURE__ */ new Map();
4601
+ this.deleteBuffer = /* @__PURE__ */ new Set();
4602
+ this.createdKeys = /* @__PURE__ */ new Set();
4603
+ this.deletedValues = /* @__PURE__ */ new Map();
4604
+ this.originallyExisted = /* @__PURE__ */ new Set();
4605
+ this.committed = false;
4606
+ this.parent = parent;
4607
+ this.keyVersions = /* @__PURE__ */ new Map();
4608
+ if (parent) {
4609
+ this.localVersion = parent.localVersion;
4610
+ this.snapshotLocalVersion = parent.localVersion;
4611
+ this.strategy = void 0;
4612
+ this.root = parent.root;
4613
+ } else {
4614
+ if (!strategy) throw new Error("Root Transaction must get Strategy");
4615
+ this.strategy = strategy;
4616
+ this.version = 0;
4617
+ this.localVersion = 0;
4618
+ this.snapshotLocalVersion = 0;
4619
+ this.root = this;
4620
+ }
4621
+ }
4622
+ isRoot() {
4623
+ return !this.parent;
4624
+ }
4625
+ /**
4626
+ * Checks if any ancestor transaction has already been committed.
4627
+ * A nested transaction cannot commit if its parent or any higher ancestor is committed.
4628
+ * @returns True if at least one ancestor is committed, false otherwise.
4629
+ */
4630
+ hasCommittedAncestor() {
4631
+ let current = this.parent;
4632
+ while (current) {
4633
+ if (current.committed) return true;
4634
+ current = current.parent;
4635
+ }
4636
+ return false;
4637
+ }
4638
+ // --- Internal buffer manipulation helpers ---
4639
+ _bufferCreate(key, value) {
4640
+ this.localVersion++;
4641
+ this.writeBuffer.set(key, value);
4642
+ this.createdKeys.add(key);
4643
+ this.deleteBuffer.delete(key);
4644
+ this.originallyExisted.delete(key);
4645
+ this.keyVersions.set(key, this.localVersion);
4646
+ }
4647
+ _bufferWrite(key, value) {
4648
+ this.localVersion++;
4649
+ this.writeBuffer.set(key, value);
4650
+ this.deleteBuffer.delete(key);
4651
+ this.keyVersions.set(key, this.localVersion);
4652
+ }
4653
+ _bufferDelete(key) {
4654
+ this.localVersion++;
4655
+ this.deleteBuffer.add(key);
4656
+ this.writeBuffer.delete(key);
4657
+ this.createdKeys.delete(key);
4658
+ this.keyVersions.set(key, this.localVersion);
4659
+ }
4660
+ /**
4661
+ * Returns the entries that will be created, updated, and deleted by this transaction.
4662
+ * @returns An object containing arrays of created, updated, and deleted entries.
4663
+ */
4664
+ getResultEntries() {
4665
+ const created = [];
4666
+ const updated = [];
4667
+ for (const [key, data] of this.writeBuffer.entries()) {
4668
+ if (this.createdKeys.has(key)) {
4669
+ created.push({ key, data });
4670
+ } else {
4671
+ updated.push({ key, data });
4672
+ }
4673
+ }
4674
+ const deleted = [];
4675
+ for (const key of this.deleteBuffer) {
4676
+ if (!this.originallyExisted.has(key)) continue;
4677
+ const data = this.deletedValues.get(key);
4678
+ if (data !== void 0) {
4679
+ deleted.push({ key, data });
4680
+ }
4681
+ }
4682
+ return { created, updated, deleted };
4683
+ }
4684
+ /**
4685
+ * Rolls back the transaction.
4686
+ * Clears all buffers and marks the transaction as finished.
4687
+ * @returns The result object with success, created, updated, and deleted keys.
4688
+ */
4689
+ rollback() {
4690
+ const { created, updated, deleted } = this.getResultEntries();
4691
+ this.writeBuffer.clear();
4692
+ this.deleteBuffer.clear();
4693
+ this.createdKeys.clear();
4694
+ this.deletedValues.clear();
4695
+ this.originallyExisted.clear();
4696
+ this.committed = true;
4697
+ if (this.root !== this) {
4698
+ this.root.activeTransactions.delete(this);
4699
+ }
4700
+ return { success: true, created, updated, deleted };
4701
+ }
4702
+ };
4703
+ var SyncMVCCStrategy2 = class extends MVCCStrategy2 {
4704
+ };
4705
+ var SyncMVCCTransaction2 = class _SyncMVCCTransaction2 extends MVCCTransaction2 {
4706
+ create(key, value) {
4707
+ if (this.committed) throw new Error("Transaction already committed");
4708
+ if (this.writeBuffer.has(key) || !this.deleteBuffer.has(key) && this.read(key) !== null) {
4709
+ throw new Error(`Key already exists: ${key}`);
4710
+ }
4711
+ this._bufferCreate(key, value);
4712
+ return this;
4713
+ }
4714
+ write(key, value) {
4715
+ if (this.committed) throw new Error("Transaction already committed");
4716
+ if (!this.writeBuffer.has(key) && (this.deleteBuffer.has(key) || this.read(key) === null)) {
4717
+ throw new Error(`Key not found: ${key}`);
4718
+ }
4719
+ this._bufferWrite(key, value);
4720
+ return this;
4721
+ }
4722
+ delete(key) {
4723
+ if (this.committed) throw new Error("Transaction already committed");
4724
+ let valueToDelete = null;
4725
+ let wasInWriteBuffer = false;
4726
+ if (this.writeBuffer.has(key)) {
4727
+ valueToDelete = this.writeBuffer.get(key);
4728
+ wasInWriteBuffer = true;
4729
+ } else if (!this.deleteBuffer.has(key)) {
4730
+ valueToDelete = this.read(key);
4731
+ }
4732
+ if (valueToDelete === null) {
4733
+ throw new Error(`Key not found: ${key}`);
4734
+ }
4735
+ this.deletedValues.set(key, valueToDelete);
4736
+ if (!wasInWriteBuffer || !this.createdKeys.has(key)) {
4737
+ this.originallyExisted.add(key);
4738
+ }
4739
+ this._bufferDelete(key);
4740
+ return this;
4741
+ }
4742
+ createNested() {
4743
+ if (this.committed) throw new Error("Transaction already committed");
4744
+ const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
4745
+ const child = new _SyncMVCCTransaction2(void 0, this, childVersion);
4746
+ this.root.activeTransactions.add(child);
4747
+ return child;
4748
+ }
4749
+ read(key) {
4750
+ if (this.committed) throw new Error("Transaction already committed");
4751
+ if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
4752
+ if (this.deleteBuffer.has(key)) return null;
4753
+ return this.root._diskRead(key, this.snapshotVersion);
4754
+ }
4755
+ exists(key) {
4756
+ if (this.committed) throw new Error("Transaction already committed");
4757
+ if (this.deleteBuffer.has(key)) return false;
4758
+ if (this.writeBuffer.has(key)) return true;
4759
+ return this.root._diskExists(key, this.snapshotVersion);
4760
+ }
4761
+ _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
4762
+ if (this.writeBuffer.has(key)) {
4763
+ const keyModVersion = this.keyVersions.get(key);
4764
+ if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
4765
+ return this.writeBuffer.get(key);
4766
+ }
4767
+ }
4768
+ if (this.deleteBuffer.has(key)) {
4769
+ const keyModVersion = this.keyVersions.get(key);
4770
+ if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
4771
+ return null;
4772
+ }
4773
+ }
4774
+ if (this.parent) {
4775
+ return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
4776
+ } else {
4777
+ return this._diskRead(key, snapshotVersion);
4778
+ }
4779
+ }
4780
+ commit(label) {
4781
+ const { created, updated, deleted } = this.getResultEntries();
4782
+ if (this.committed) {
4783
+ return {
4784
+ label,
4785
+ success: false,
4786
+ error: "Transaction already committed",
4787
+ conflict: void 0,
4788
+ created,
4789
+ updated,
4790
+ deleted
4791
+ };
4792
+ }
4793
+ if (this.hasCommittedAncestor()) {
4794
+ return {
4795
+ label,
4796
+ success: false,
4797
+ error: "Ancestor transaction already committed",
4798
+ conflict: void 0,
4799
+ created,
4800
+ updated,
4801
+ deleted
4802
+ };
4803
+ }
4804
+ if (this.parent) {
4805
+ const failure = this.parent._merge(this);
4806
+ if (failure) {
4807
+ return {
4808
+ label,
4809
+ success: false,
4810
+ error: failure.error,
4811
+ conflict: failure.conflict,
4812
+ created,
4813
+ updated,
4814
+ deleted
4815
+ };
4816
+ }
4817
+ this.committed = true;
4818
+ } else {
4819
+ if (this.writeBuffer.size > 0 || this.deleteBuffer.size > 0) {
4820
+ const failure = this._merge(this);
4821
+ if (failure) {
4822
+ return {
4823
+ label,
4824
+ success: false,
4825
+ error: failure.error,
4826
+ conflict: failure.conflict,
4827
+ created: [],
4828
+ updated: [],
4829
+ deleted: []
4830
+ };
4831
+ }
4832
+ this.writeBuffer.clear();
4833
+ this.deleteBuffer.clear();
4834
+ this.createdKeys.clear();
4835
+ this.deletedValues.clear();
4836
+ this.originallyExisted.clear();
4837
+ this.keyVersions.clear();
4838
+ this.localVersion = 0;
4839
+ this.snapshotVersion = this.version;
4840
+ }
4841
+ }
4842
+ return {
4843
+ label,
4844
+ success: true,
4845
+ created,
4846
+ updated,
4847
+ deleted
4848
+ };
4849
+ }
4850
+ _merge(child) {
4851
+ if (this.parent) {
4852
+ for (const key of child.writeBuffer.keys()) {
4853
+ const lastModLocalVer = this.keyVersions.get(key);
4854
+ if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
4855
+ return {
4856
+ error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
4857
+ conflict: {
4858
+ key,
4859
+ parent: this.read(key),
4860
+ child: child.read(key)
4861
+ }
4862
+ };
4863
+ }
4864
+ }
4865
+ for (const key of child.deleteBuffer) {
4866
+ const lastModLocalVer = this.keyVersions.get(key);
4867
+ if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
4868
+ return {
4869
+ error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
4870
+ conflict: {
4871
+ key,
4872
+ parent: this.read(key),
4873
+ child: child.read(key)
4874
+ }
4875
+ };
4876
+ }
4877
+ }
4878
+ const newLocalVersion = this.localVersion + 1;
4879
+ for (const key of child.writeBuffer.keys()) {
4880
+ this.writeBuffer.set(key, child.writeBuffer.get(key));
4881
+ this.deleteBuffer.delete(key);
4882
+ this.keyVersions.set(key, newLocalVersion);
4883
+ if (child.createdKeys.has(key)) {
4884
+ this.createdKeys.add(key);
4885
+ }
4886
+ }
4887
+ for (const key of child.deleteBuffer) {
4888
+ this.deleteBuffer.add(key);
4889
+ this.writeBuffer.delete(key);
4890
+ this.createdKeys.delete(key);
4891
+ this.keyVersions.set(key, newLocalVersion);
4892
+ const deletedValue = child.deletedValues.get(key);
4893
+ if (deletedValue !== void 0) {
4894
+ this.deletedValues.set(key, deletedValue);
4895
+ }
4896
+ if (child.originallyExisted.has(key)) {
4897
+ this.originallyExisted.add(key);
4898
+ }
4899
+ }
4900
+ this.localVersion = newLocalVersion;
4901
+ this.root.activeTransactions.delete(child);
4902
+ } else {
4903
+ const newVersion = this.version + 1;
4904
+ if (child !== this) {
4905
+ const modifiedKeys = /* @__PURE__ */ new Set([...child.writeBuffer.keys(), ...child.deleteBuffer]);
4906
+ for (const key of modifiedKeys) {
4907
+ const versions = this.versionIndex.get(key);
4908
+ if (versions && versions.length > 0) {
4909
+ const lastVer = versions[versions.length - 1].version;
4910
+ if (lastVer > child.snapshotVersion) {
4911
+ return {
4912
+ error: `Commit conflict: Key '${key}' was modified by a newer transaction (v${lastVer})`,
4913
+ conflict: {
4914
+ key,
4915
+ parent: this.read(key),
4916
+ child: child.read(key)
4917
+ }
4918
+ };
4919
+ }
4920
+ }
4921
+ }
4922
+ }
4923
+ for (const [key, value] of child.writeBuffer) {
4924
+ this.writeBuffer.set(key, value);
4925
+ this.deleteBuffer.delete(key);
4926
+ if (child.createdKeys.has(key)) {
4927
+ this.createdKeys.add(key);
4928
+ }
4929
+ }
4930
+ for (const key of child.deleteBuffer) {
4931
+ this.deleteBuffer.add(key);
4932
+ this.writeBuffer.delete(key);
4933
+ this.createdKeys.delete(key);
4934
+ const deletedValue = child.deletedValues.get(key);
4935
+ if (deletedValue !== void 0) {
4936
+ this.deletedValues.set(key, deletedValue);
4937
+ }
4938
+ if (child.originallyExisted.has(key)) {
4939
+ this.originallyExisted.add(key);
4940
+ }
4941
+ }
4942
+ for (const [key, value] of child.writeBuffer) {
4943
+ this._diskWrite(key, value, newVersion);
4944
+ }
4945
+ for (const key of child.deleteBuffer) {
4946
+ this._diskDelete(key, newVersion);
4947
+ }
4948
+ this.version = newVersion;
4949
+ this.root.activeTransactions.delete(child);
4950
+ this._cleanupDeletedCache();
4951
+ }
4952
+ return null;
4953
+ }
4954
+ // --- Internal IO Helpers (Root Only) ---
4955
+ _diskWrite(key, value, version) {
4956
+ const strategy = this.strategy;
4957
+ if (!strategy) throw new Error("Root Transaction missing strategy");
4958
+ if (strategy.exists(key)) {
4959
+ const currentVal = strategy.read(key);
4960
+ if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
4961
+ this.deletedCache.get(key).push({
4962
+ value: currentVal,
4963
+ deletedAtVersion: version
4964
+ });
4965
+ }
4966
+ strategy.write(key, value);
4967
+ if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
4968
+ this.versionIndex.get(key).push({ version, exists: true });
4969
+ }
4970
+ _diskRead(key, snapshotVersion) {
4971
+ const strategy = this.strategy;
4972
+ if (!strategy) throw new Error("Root Transaction missing strategy");
4973
+ const versions = this.versionIndex.get(key);
4974
+ if (!versions) {
4975
+ return strategy.exists(key) ? strategy.read(key) : null;
4976
+ }
4977
+ let targetVerObj = null;
4978
+ let nextVerObj = null;
4979
+ for (const v of versions) {
4980
+ if (v.version <= snapshotVersion) {
4981
+ targetVerObj = v;
4982
+ } else {
4983
+ nextVerObj = v;
4984
+ break;
4985
+ }
4986
+ }
4987
+ if (!targetVerObj) {
4988
+ if (nextVerObj) {
4989
+ const cached2 = this.deletedCache.get(key);
4990
+ if (cached2) {
4991
+ const match = cached2.find((c) => c.deletedAtVersion === nextVerObj.version);
4992
+ if (match) return match.value;
4993
+ }
4994
+ }
4995
+ return null;
4996
+ }
4997
+ if (!targetVerObj.exists) return null;
4998
+ if (!nextVerObj) {
4999
+ return strategy.read(key);
5000
+ }
5001
+ const cached = this.deletedCache.get(key);
5002
+ if (cached) {
5003
+ const match = cached.find((c) => c.deletedAtVersion === nextVerObj.version);
5004
+ if (match) return match.value;
5005
+ }
5006
+ return null;
5007
+ }
5008
+ _diskExists(key, snapshotVersion) {
5009
+ const strategy = this.strategy;
5010
+ if (!strategy) throw new Error("Root Transaction missing strategy");
5011
+ const versions = this.versionIndex.get(key);
5012
+ if (!versions) {
5013
+ return strategy.exists(key);
5014
+ }
5015
+ let targetVerObj = null;
5016
+ for (const v of versions) {
5017
+ if (v.version <= snapshotVersion) {
5018
+ targetVerObj = v;
5019
+ } else {
5020
+ break;
5021
+ }
5022
+ }
5023
+ if (!targetVerObj) return strategy.exists(key);
5024
+ return targetVerObj.exists;
5025
+ }
5026
+ _diskDelete(key, snapshotVersion) {
5027
+ const strategy = this.strategy;
5028
+ if (!strategy) throw new Error("Root Transaction missing strategy");
5029
+ if (strategy.exists(key)) {
5030
+ const currentVal = strategy.read(key);
5031
+ if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
5032
+ this.deletedCache.get(key).push({
5033
+ value: currentVal,
5034
+ deletedAtVersion: snapshotVersion
5035
+ });
5036
+ }
5037
+ strategy.delete(key);
5038
+ if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
5039
+ this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
5040
+ }
5041
+ _cleanupDeletedCache() {
5042
+ if (this.deletedCache.size === 0) return;
5043
+ let minActiveVersion = this.version;
5044
+ if (this.activeTransactions.size > 0) {
5045
+ for (const tx of this.activeTransactions) {
5046
+ if (!tx.committed && tx.snapshotVersion < minActiveVersion) {
5047
+ minActiveVersion = tx.snapshotVersion;
5048
+ }
5049
+ }
5050
+ }
5051
+ for (const [key, cachedList] of this.deletedCache) {
5052
+ const remaining = cachedList.filter((item) => item.deletedAtVersion > minActiveVersion);
5053
+ if (remaining.length === 0) {
5054
+ this.deletedCache.delete(key);
5055
+ } else {
5056
+ this.deletedCache.set(key, remaining);
5057
+ }
5058
+ }
5059
+ }
5060
+ };
5061
+ var AsyncMVCCStrategy2 = class extends MVCCStrategy2 {
5062
+ };
5063
+ var Ryoiki4 = class _Ryoiki4 {
5064
+ readings;
5065
+ writings;
5066
+ readQueue;
5067
+ writeQueue;
5068
+ static async CatchError(promise) {
5069
+ return await promise.then((v) => [void 0, v]).catch((err) => [err]);
5070
+ }
5071
+ static IsRangeOverlap(a, b) {
5072
+ const [start1, end1] = a;
5073
+ const [start2, end2] = b;
5074
+ if (end1 <= start2 || end2 <= start1) {
5075
+ return false;
5076
+ }
5077
+ return true;
5078
+ }
5079
+ static ERR_ALREADY_EXISTS(lockId) {
5080
+ return new Error(`The '${lockId}' task already existing in queue or running.`);
5081
+ }
5082
+ static ERR_NOT_EXISTS(lockId) {
5083
+ return new Error(`The '${lockId}' task not existing in task queue.`);
5084
+ }
5085
+ static ERR_TIMEOUT(lockId, timeout) {
5086
+ return new Error(`The task with ID '${lockId}' failed to acquire the lock within the timeout(${timeout}ms).`);
5087
+ }
5088
+ /**
5089
+ * Constructs a new instance of the Ryoiki class.
5090
+ */
5091
+ constructor() {
5092
+ this.readings = /* @__PURE__ */ new Map();
5093
+ this.writings = /* @__PURE__ */ new Map();
5094
+ this.readQueue = /* @__PURE__ */ new Map();
5095
+ this.writeQueue = /* @__PURE__ */ new Map();
5096
+ }
5097
+ /**
5098
+ * Creates a range based on a start value and length.
5099
+ * @param start - The starting value of the range.
5100
+ * @param length - The length of the range.
5101
+ * @returns A range tuple [start, start + length].
5102
+ */
5103
+ range(start, length) {
5104
+ return [start, start + length];
5105
+ }
5106
+ rangeOverlapping(tasks, range) {
5107
+ return Array.from(tasks.values()).some((t) => _Ryoiki4.IsRangeOverlap(t.range, range));
5108
+ }
5109
+ isSameRange(a, b) {
5110
+ const [a1, a2] = a;
5111
+ const [b1, b2] = b;
5112
+ return a1 === b1 && a2 === b2;
5113
+ }
5114
+ fetchUnitAndRun(queue, workspaces) {
5115
+ for (const [id, unit] of queue) {
5116
+ if (!unit.condition()) {
5117
+ continue;
5118
+ }
5119
+ this._alloc(queue, workspaces, id);
5120
+ }
5121
+ }
5122
+ _handleOverload(args, handlers, argPatterns) {
5123
+ for (const [key, pattern] of Object.entries(argPatterns)) {
5124
+ if (this._matchArgs(args, pattern)) {
5125
+ return handlers[key](...args);
5126
+ }
5127
+ }
5128
+ throw new Error("Invalid arguments");
5129
+ }
5130
+ _matchArgs(args, pattern) {
5131
+ return args.every((arg, index) => {
5132
+ const expectedType = pattern[index];
5133
+ if (expectedType === void 0) return typeof arg === "undefined";
5134
+ if (expectedType === Function) return typeof arg === "function";
5135
+ if (expectedType === Number) return typeof arg === "number";
5136
+ if (expectedType === Array) return Array.isArray(arg);
5137
+ return false;
5138
+ });
5139
+ }
5140
+ _createRandomId() {
5141
+ const timestamp = Date.now().toString(36);
5142
+ const random = Math.random().toString(36).substring(2);
5143
+ return `${timestamp}${random}`;
5144
+ }
5145
+ _alloc(queue, workspaces, lockId) {
5146
+ const unit = queue.get(lockId);
5147
+ if (!unit) {
5148
+ throw _Ryoiki4.ERR_NOT_EXISTS(lockId);
5149
+ }
5150
+ workspaces.set(lockId, unit);
5151
+ queue.delete(lockId);
5152
+ unit.alloc();
5153
+ }
5154
+ _free(workspaces, lockId) {
5155
+ const unit = workspaces.get(lockId);
5156
+ if (!unit) {
5157
+ throw _Ryoiki4.ERR_NOT_EXISTS(lockId);
5158
+ }
5159
+ workspaces.delete(lockId);
5160
+ unit.free();
5161
+ }
5162
+ _lock(queue, range, timeout, task, condition) {
5163
+ return new Promise((resolve, reject) => {
5164
+ let timeoutId = null;
5165
+ if (timeout >= 0) {
5166
+ timeoutId = setTimeout(() => {
5167
+ reject(_Ryoiki4.ERR_TIMEOUT(id, timeout));
5168
+ }, timeout);
5169
+ }
5170
+ const id = this._createRandomId();
5171
+ const alloc = async () => {
5172
+ if (timeoutId !== null) {
5173
+ clearTimeout(timeoutId);
5174
+ }
5175
+ const [err, v] = await _Ryoiki4.CatchError(task(id));
5176
+ if (err) reject(err);
5177
+ else resolve(v);
5178
+ };
5179
+ const fetch = () => {
5180
+ this.fetchUnitAndRun(this.readQueue, this.readings);
5181
+ this.fetchUnitAndRun(this.writeQueue, this.writings);
5182
+ };
5183
+ queue.set(id, { id, range, condition, alloc, free: fetch });
5184
+ fetch();
5185
+ });
5186
+ }
5187
+ _checkWorking(range, workspaces) {
5188
+ let isLocked = false;
5189
+ for (const lock of workspaces.values()) {
5190
+ if (_Ryoiki4.IsRangeOverlap(range, lock.range)) {
5191
+ isLocked = true;
5192
+ break;
5193
+ }
5194
+ }
5195
+ return isLocked;
5196
+ }
5197
+ /**
5198
+ * Checks if there is any active read lock within the specified range.
5199
+ * @param range The range to check for active read locks.
5200
+ * @returns `true` if there is an active read lock within the range, `false` otherwise.
5201
+ */
5202
+ isReading(range) {
5203
+ return this._checkWorking(range, this.readings);
5204
+ }
5205
+ /**
5206
+ * Checks if there is any active write lock within the specified range.
5207
+ * @param range The range to check for active write locks.
5208
+ * @returns `true` if there is an active write lock within the range, `false` otherwise.
5209
+ */
5210
+ isWriting(range) {
5211
+ return this._checkWorking(range, this.writings);
5212
+ }
5213
+ /**
5214
+ * Checks if a read lock can be acquired within the specified range.
5215
+ * @param range The range to check for read lock availability.
5216
+ * @returns `true` if a read lock can be acquired, `false` otherwise.
5217
+ */
5218
+ canRead(range) {
5219
+ const writing = this.isWriting(range);
5220
+ return !writing;
5221
+ }
5222
+ /**
5223
+ * Checks if a write lock can be acquired within the specified range.
5224
+ * @param range The range to check for write lock availability.
5225
+ * @returns `true` if a write lock can be acquired, `false` otherwise.
5226
+ */
5227
+ canWrite(range) {
5228
+ const reading = this.isReading(range);
5229
+ const writing = this.isWriting(range);
5230
+ return !reading && !writing;
5231
+ }
5232
+ /**
5233
+ * Internal implementation of the read lock. Handles both overloads.
5234
+ * @template T - The return type of the task.
5235
+ * @param arg0 - Either a range or a task callback.
5236
+ * If a range is provided, the task is the second argument.
5237
+ * @param arg1 - The task to execute, required if a range is provided.
5238
+ * @param arg2 - The timeout for acquiring the lock.
5239
+ * If the lock cannot be acquired within this period, an error will be thrown.
5240
+ * If this value is not provided, no timeout will be set.
5241
+ * @returns A promise resolving to the result of the task execution.
5242
+ */
5243
+ readLock(arg0, arg1, arg2) {
5244
+ const [range, task, timeout] = this._handleOverload(
5245
+ [arg0, arg1, arg2],
5246
+ {
5247
+ rangeTask: (range2, task2) => [range2, task2, -1],
5248
+ rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
5249
+ task: (task2) => [[-Infinity, Infinity], task2, -1],
5250
+ taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
5251
+ },
5252
+ {
5253
+ task: [Function],
5254
+ taskTimeout: [Function, Number],
5255
+ rangeTask: [Array, Function],
5256
+ rangeTaskTimeout: [Array, Function, Number]
5257
+ }
5258
+ );
5259
+ return this._lock(
5260
+ this.readQueue,
5261
+ range,
5262
+ timeout,
5263
+ task,
5264
+ () => !this.rangeOverlapping(this.writings, range)
5265
+ );
5266
+ }
5267
+ /**
5268
+ * Internal implementation of the write lock. Handles both overloads.
5269
+ * @template T - The return type of the task.
5270
+ * @param arg0 - Either a range or a task callback.
5271
+ * If a range is provided, the task is the second argument.
5272
+ * @param arg1 - The task to execute, required if a range is provided.
5273
+ * @param arg2 - The timeout for acquiring the lock.
5274
+ * If the lock cannot be acquired within this period, an error will be thrown.
5275
+ * If this value is not provided, no timeout will be set.
5276
+ * @returns A promise resolving to the result of the task execution.
5277
+ */
5278
+ writeLock(arg0, arg1, arg2) {
5279
+ const [range, task, timeout] = this._handleOverload(
5280
+ [arg0, arg1, arg2],
5281
+ {
5282
+ rangeTask: (range2, task2) => [range2, task2, -1],
5283
+ rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
5284
+ task: (task2) => [[-Infinity, Infinity], task2, -1],
5285
+ taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
5286
+ },
5287
+ {
5288
+ task: [Function],
5289
+ taskTimeout: [Function, Number],
5290
+ rangeTask: [Array, Function],
5291
+ rangeTaskTimeout: [Array, Function, Number]
5292
+ }
5293
+ );
5294
+ return this._lock(
5295
+ this.writeQueue,
5296
+ range,
5297
+ timeout,
5298
+ task,
5299
+ () => {
5300
+ return !this.rangeOverlapping(this.writings, range) && !this.rangeOverlapping(this.readings, range);
5301
+ }
5302
+ );
5303
+ }
5304
+ /**
5305
+ * Releases a read lock by its lock ID.
5306
+ * @param lockId - The unique identifier for the lock to release.
5307
+ */
5308
+ readUnlock(lockId) {
5309
+ this._free(this.readings, lockId);
5310
+ }
5311
+ /**
5312
+ * Releases a write lock by its lock ID.
5313
+ * @param lockId - The unique identifier for the lock to release.
5314
+ */
5315
+ writeUnlock(lockId) {
5316
+ this._free(this.writings, lockId);
5317
+ }
5318
+ };
5319
+ var AsyncMVCCTransaction2 = class _AsyncMVCCTransaction2 extends MVCCTransaction2 {
5320
+ lock = new Ryoiki4();
5321
+ async writeLock(fn) {
5322
+ let lockId;
5323
+ return this.lock.writeLock(async (_lockId) => {
5324
+ lockId = _lockId;
5325
+ return fn();
5326
+ }).finally(() => {
5327
+ this.lock.writeUnlock(lockId);
5328
+ });
5329
+ }
5330
+ async create(key, value) {
5331
+ if (this.committed) throw new Error("Transaction already committed");
5332
+ if (this.writeBuffer.has(key) || !this.deleteBuffer.has(key) && await this.read(key) !== null) {
5333
+ throw new Error(`Key already exists: ${key}`);
5334
+ }
5335
+ this._bufferCreate(key, value);
5336
+ return this;
5337
+ }
5338
+ async write(key, value) {
5339
+ if (this.committed) throw new Error("Transaction already committed");
5340
+ if (!this.writeBuffer.has(key) && (this.deleteBuffer.has(key) || await this.read(key) === null)) {
5341
+ throw new Error(`Key not found: ${key}`);
5342
+ }
5343
+ this._bufferWrite(key, value);
5344
+ return this;
5345
+ }
5346
+ async delete(key) {
5347
+ if (this.committed) throw new Error("Transaction already committed");
5348
+ let valueToDelete = null;
5349
+ let wasInWriteBuffer = false;
5350
+ if (this.writeBuffer.has(key)) {
5351
+ valueToDelete = this.writeBuffer.get(key);
5352
+ wasInWriteBuffer = true;
5353
+ } else if (!this.deleteBuffer.has(key)) {
5354
+ valueToDelete = await this.read(key);
5355
+ }
5356
+ if (valueToDelete === null) {
5357
+ throw new Error(`Key not found: ${key}`);
5358
+ }
5359
+ this.deletedValues.set(key, valueToDelete);
5360
+ if (!wasInWriteBuffer || !this.createdKeys.has(key)) {
5361
+ this.originallyExisted.add(key);
5362
+ }
5363
+ this._bufferDelete(key);
5364
+ return this;
5365
+ }
5366
+ createNested() {
5367
+ if (this.committed) throw new Error("Transaction already committed");
5368
+ const childVersion = this.isRoot() ? this.version : this.snapshotVersion;
5369
+ const child = new _AsyncMVCCTransaction2(void 0, this, childVersion);
5370
+ this.root.activeTransactions.add(child);
5371
+ return child;
5372
+ }
5373
+ async read(key) {
5374
+ if (this.committed) throw new Error("Transaction already committed");
5375
+ if (this.writeBuffer.has(key)) return this.writeBuffer.get(key);
5376
+ if (this.deleteBuffer.has(key)) return null;
5377
+ return this.root._diskRead(key, this.snapshotVersion);
5378
+ }
5379
+ async exists(key) {
5380
+ if (this.committed) throw new Error("Transaction already committed");
5381
+ if (this.deleteBuffer.has(key)) return false;
5382
+ if (this.writeBuffer.has(key)) return true;
5383
+ return this.root._diskExists(key, this.snapshotVersion);
5384
+ }
5385
+ async _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
5386
+ if (this.writeBuffer.has(key)) {
5387
+ const keyModVersion = this.keyVersions.get(key);
5388
+ if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
5389
+ return this.writeBuffer.get(key);
5390
+ }
5391
+ }
5392
+ if (this.deleteBuffer.has(key)) {
5393
+ const keyModVersion = this.keyVersions.get(key);
5394
+ if (snapshotLocalVersion === void 0 || keyModVersion === void 0 || keyModVersion <= snapshotLocalVersion) {
5395
+ return null;
5396
+ }
5397
+ }
5398
+ if (this.parent) {
5399
+ return this.parent._readSnapshot(key, snapshotVersion, this.snapshotLocalVersion);
5400
+ } else {
5401
+ return this._diskRead(key, snapshotVersion);
5402
+ }
5403
+ }
5404
+ async commit(label) {
5405
+ const { created, updated, deleted } = this.getResultEntries();
5406
+ if (this.committed) {
5407
+ return {
5408
+ label,
5409
+ success: false,
5410
+ error: "Transaction already committed",
5411
+ conflict: void 0,
5412
+ created,
5413
+ updated,
5414
+ deleted
5415
+ };
5416
+ }
5417
+ if (this.hasCommittedAncestor()) {
5418
+ return {
5419
+ label,
5420
+ success: false,
5421
+ error: "Ancestor transaction already committed",
5422
+ conflict: void 0,
5423
+ created,
5424
+ updated,
5425
+ deleted
5426
+ };
5427
+ }
5428
+ if (this.parent) {
5429
+ const failure = await this.parent._merge(this);
5430
+ if (failure) {
5431
+ return {
5432
+ label,
5433
+ success: false,
5434
+ error: failure.error,
5435
+ conflict: failure.conflict,
5436
+ created,
5437
+ updated,
5438
+ deleted
5439
+ };
5440
+ }
5441
+ this.committed = true;
5442
+ } else {
5443
+ if (this.writeBuffer.size > 0 || this.deleteBuffer.size > 0) {
5444
+ const failure = await this._merge(this);
5445
+ if (failure) {
5446
+ return {
5447
+ label,
5448
+ success: false,
5449
+ error: failure.error,
5450
+ conflict: failure.conflict,
5451
+ created: [],
5452
+ updated: [],
5453
+ deleted: []
5454
+ };
5455
+ }
5456
+ this.writeBuffer.clear();
5457
+ this.deleteBuffer.clear();
5458
+ this.createdKeys.clear();
5459
+ this.deletedValues.clear();
5460
+ this.originallyExisted.clear();
5461
+ this.keyVersions.clear();
5462
+ this.localVersion = 0;
5463
+ this.snapshotVersion = this.version;
5464
+ }
5465
+ }
5466
+ return {
5467
+ label,
5468
+ success: true,
5469
+ created,
5470
+ updated,
5471
+ deleted
5472
+ };
5473
+ }
5474
+ async _merge(child) {
5475
+ return this.writeLock(async () => {
5476
+ if (this.parent) {
5477
+ for (const key of child.writeBuffer.keys()) {
5478
+ const lastModLocalVer = this.keyVersions.get(key);
5479
+ if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
5480
+ return {
5481
+ error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
5482
+ conflict: {
5483
+ key,
5484
+ parent: await this.read(key),
5485
+ child: await child.read(key)
5486
+ }
5487
+ };
5488
+ }
5489
+ }
5490
+ for (const key of child.deleteBuffer) {
5491
+ const lastModLocalVer = this.keyVersions.get(key);
5492
+ if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
5493
+ return {
5494
+ error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
5495
+ conflict: {
5496
+ key,
5497
+ parent: await this.read(key),
5498
+ child: await child.read(key)
5499
+ }
5500
+ };
5501
+ }
5502
+ }
5503
+ const newLocalVersion = this.localVersion + 1;
5504
+ for (const key of child.writeBuffer.keys()) {
5505
+ this.writeBuffer.set(key, child.writeBuffer.get(key));
5506
+ this.deleteBuffer.delete(key);
5507
+ this.keyVersions.set(key, newLocalVersion);
5508
+ if (child.createdKeys.has(key)) {
5509
+ this.createdKeys.add(key);
5510
+ }
5511
+ }
5512
+ for (const key of child.deleteBuffer) {
5513
+ this.deleteBuffer.add(key);
5514
+ this.writeBuffer.delete(key);
5515
+ this.createdKeys.delete(key);
5516
+ this.keyVersions.set(key, newLocalVersion);
5517
+ const deletedValue = child.deletedValues.get(key);
5518
+ if (deletedValue !== void 0) {
5519
+ this.deletedValues.set(key, deletedValue);
5520
+ }
5521
+ if (child.originallyExisted.has(key)) {
5522
+ this.originallyExisted.add(key);
5523
+ }
5524
+ }
5525
+ this.localVersion = newLocalVersion;
5526
+ this.root.activeTransactions.delete(child);
5527
+ return null;
5528
+ } else {
5529
+ const newVersion = this.version + 1;
5530
+ if (child !== this) {
5531
+ const modifiedKeys = /* @__PURE__ */ new Set([...child.writeBuffer.keys(), ...child.deleteBuffer]);
5532
+ for (const key of modifiedKeys) {
5533
+ const versions = this.versionIndex.get(key);
5534
+ if (versions && versions.length > 0) {
5535
+ const lastVer = versions[versions.length - 1].version;
5536
+ if (lastVer > child.snapshotVersion) {
5537
+ return {
5538
+ error: `Commit conflict: Key '${key}' was modified by a newer transaction (v${lastVer})`,
5539
+ conflict: {
5540
+ key,
5541
+ parent: await this.read(key),
5542
+ child: await child.read(key)
5543
+ }
5544
+ };
5545
+ }
5546
+ }
5547
+ }
5548
+ }
5549
+ for (const [key, value] of child.writeBuffer) {
5550
+ this.writeBuffer.set(key, value);
5551
+ this.deleteBuffer.delete(key);
5552
+ if (child.createdKeys.has(key)) {
5553
+ this.createdKeys.add(key);
5554
+ }
5555
+ }
5556
+ for (const key of child.deleteBuffer) {
5557
+ this.deleteBuffer.add(key);
5558
+ this.writeBuffer.delete(key);
5559
+ this.createdKeys.delete(key);
5560
+ const deletedValue = child.deletedValues.get(key);
5561
+ if (deletedValue !== void 0) {
5562
+ this.deletedValues.set(key, deletedValue);
5563
+ }
5564
+ if (child.originallyExisted.has(key)) {
5565
+ this.originallyExisted.add(key);
5566
+ }
5567
+ }
5568
+ for (const [key, value] of child.writeBuffer) {
5569
+ await this._diskWrite(key, value, newVersion);
5570
+ }
5571
+ for (const key of child.deleteBuffer) {
5572
+ await this._diskDelete(key, newVersion);
5573
+ }
5574
+ this.version = newVersion;
5575
+ this.root.activeTransactions.delete(child);
5576
+ this._cleanupDeletedCache();
5577
+ return null;
5578
+ }
5579
+ });
5580
+ }
5581
+ // --- Internal IO Helpers (Root Only) ---
5582
+ async _diskWrite(key, value, version) {
5583
+ const strategy = this.strategy;
5584
+ if (!strategy) throw new Error("Root Transaction missing strategy");
5585
+ if (await strategy.exists(key)) {
5586
+ const currentVal = await strategy.read(key);
5587
+ if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
5588
+ this.deletedCache.get(key).push({
5589
+ value: currentVal,
5590
+ deletedAtVersion: version
5591
+ });
5592
+ }
5593
+ await strategy.write(key, value);
5594
+ if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
5595
+ this.versionIndex.get(key).push({ version, exists: true });
5596
+ }
5597
+ async _diskRead(key, snapshotVersion) {
5598
+ const strategy = this.strategy;
5599
+ if (!strategy) throw new Error("Root Transaction missing strategy");
5600
+ const versions = this.versionIndex.get(key);
5601
+ if (!versions) {
5602
+ return await strategy.exists(key) ? strategy.read(key) : null;
5603
+ }
5604
+ let targetVerObj = null;
5605
+ let nextVerObj = null;
5606
+ for (const v of versions) {
5607
+ if (v.version <= snapshotVersion) {
5608
+ targetVerObj = v;
5609
+ } else {
5610
+ nextVerObj = v;
5611
+ break;
5612
+ }
5613
+ }
5614
+ if (!targetVerObj) {
5615
+ if (nextVerObj) {
5616
+ const cached2 = this.deletedCache.get(key);
5617
+ if (cached2) {
5618
+ const match = cached2.find((c) => c.deletedAtVersion === nextVerObj.version);
5619
+ if (match) return match.value;
5620
+ }
5621
+ }
5622
+ return null;
5623
+ }
5624
+ if (!targetVerObj.exists) return null;
5625
+ if (!nextVerObj) {
5626
+ return strategy.read(key);
5627
+ }
5628
+ const cached = this.deletedCache.get(key);
5629
+ if (cached) {
5630
+ const match = cached.find((c) => c.deletedAtVersion === nextVerObj.version);
5631
+ if (match) return match.value;
5632
+ }
5633
+ return null;
5634
+ }
5635
+ async _diskExists(key, snapshotVersion) {
5636
+ const strategy = this.strategy;
5637
+ if (!strategy) throw new Error("Root Transaction missing strategy");
5638
+ const versions = this.versionIndex.get(key);
5639
+ if (!versions) {
5640
+ return strategy.exists(key);
5641
+ }
5642
+ let targetVerObj = null;
5643
+ for (const v of versions) {
5644
+ if (v.version <= snapshotVersion) {
5645
+ targetVerObj = v;
5646
+ } else {
5647
+ break;
5648
+ }
5649
+ }
5650
+ if (!targetVerObj) return strategy.exists(key);
5651
+ return targetVerObj.exists;
5652
+ }
5653
+ async _diskDelete(key, snapshotVersion) {
5654
+ const strategy = this.strategy;
5655
+ if (!strategy) throw new Error("Root Transaction missing strategy");
5656
+ if (await strategy.exists(key)) {
5657
+ const currentVal = await strategy.read(key);
5658
+ if (!this.deletedCache.has(key)) this.deletedCache.set(key, []);
5659
+ this.deletedCache.get(key).push({
5660
+ value: currentVal,
5661
+ deletedAtVersion: snapshotVersion
5662
+ });
5663
+ }
5664
+ await strategy.delete(key);
5665
+ if (!this.versionIndex.has(key)) this.versionIndex.set(key, []);
5666
+ this.versionIndex.get(key).push({ version: snapshotVersion, exists: false });
5667
+ }
5668
+ _cleanupDeletedCache() {
5669
+ if (this.deletedCache.size === 0) return;
5670
+ let minActiveVersion = this.version;
5671
+ if (this.activeTransactions.size > 0) {
5672
+ for (const tx of this.activeTransactions) {
5673
+ if (!tx.committed && tx.snapshotVersion < minActiveVersion) {
5674
+ minActiveVersion = tx.snapshotVersion;
5675
+ }
5676
+ }
5677
+ }
5678
+ for (const [key, cachedList] of this.deletedCache) {
5679
+ const remaining = cachedList.filter((item) => item.deletedAtVersion > minActiveVersion);
5680
+ if (remaining.length === 0) {
5681
+ this.deletedCache.delete(key);
5682
+ } else {
5683
+ this.deletedCache.set(key, remaining);
5684
+ }
5685
+ }
5686
+ }
5687
+ };
5688
+
4564
5689
  // src/utils/numberToBytes.ts
4565
5690
  function numberToBytes(value, buffer, offset = 0, length = buffer.length) {
4566
5691
  if (length === 4) {
@@ -5921,7 +7046,7 @@ var PageManagerFactory = class _PageManagerFactory {
5921
7046
  };
5922
7047
 
5923
7048
  // src/core/DataplyAPI.ts
5924
- var import_node_fs4 = __toESM(require("node:fs"));
7049
+ var import_node_fs3 = __toESM(require("node:fs"));
5925
7050
 
5926
7051
  // node_modules/hookall/dist/esm/index.mjs
5927
7052
  var HookallStore = class extends WeakMap {
@@ -6234,12 +7359,9 @@ var HookallSync = class _HookallSync {
6234
7359
  }
6235
7360
  };
6236
7361
 
6237
- // src/core/VirtualFileSystem.ts
6238
- var import_node_fs2 = __toESM(require("node:fs"));
6239
-
6240
- // src/core/LogManager.ts
7362
+ // src/core/WALManager.ts
6241
7363
  var import_node_fs = __toESM(require("node:fs"));
6242
- var LogManager = class {
7364
+ var WALManager = class {
6243
7365
  fd = null;
6244
7366
  walFilePath;
6245
7367
  pageSize;
@@ -6252,6 +7374,9 @@ var LogManager = class {
6252
7374
  * @param pageSize Page size
6253
7375
  */
6254
7376
  constructor(walFilePath, pageSize) {
7377
+ if ((pageSize & pageSize - 1) !== 0) {
7378
+ throw new Error("Page size must be a power of 2");
7379
+ }
6255
7380
  this.walFilePath = walFilePath;
6256
7381
  this.pageSize = pageSize;
6257
7382
  this.entrySize = 4 + pageSize;
@@ -6264,6 +7389,63 @@ var LogManager = class {
6264
7389
  open() {
6265
7390
  this.fd = import_node_fs.default.openSync(this.walFilePath, "a+");
6266
7391
  }
7392
+ // ─────────────────────────────────────────────────────────────
7393
+ // High-level WAL operations (2-Phase Commit)
7394
+ // ─────────────────────────────────────────────────────────────
7395
+ /**
7396
+ * Performs recovery (Redo) using WAL logs.
7397
+ * Called during initialization, ensuring data is fully restored before operations start.
7398
+ * @param writePage Callback to write recovered pages to disk
7399
+ */
7400
+ async recover(writePage) {
7401
+ this.open();
7402
+ const restoredPages = this.readAllSync();
7403
+ if (restoredPages.size === 0) {
7404
+ return;
7405
+ }
7406
+ const promises = [];
7407
+ for (const [pageId, data] of restoredPages) {
7408
+ if (pageId > 1e6) continue;
7409
+ try {
7410
+ const manager = new PageManagerFactory().getManager(data);
7411
+ if (!manager.verifyChecksum(data)) {
7412
+ console.warn(`[WALManager] Checksum verification failed for PageID ${pageId} during recovery. Ignoring changes.`);
7413
+ continue;
7414
+ }
7415
+ } catch (e) {
7416
+ console.warn(`[WALManager] Failed to verify checksum for PageID ${pageId} during recovery: ${e}. Ignoring changes.`);
7417
+ continue;
7418
+ }
7419
+ promises.push(writePage(pageId, data));
7420
+ }
7421
+ await Promise.all(promises);
7422
+ if (restoredPages.size > 0) {
7423
+ await this.clear();
7424
+ }
7425
+ }
7426
+ /**
7427
+ * WAL에 페이지 데이터를 기록합니다 (Phase 1: Prepare).
7428
+ * @param dirtyPages 변경된 페이지들 (pageId -> data)
7429
+ */
7430
+ async prepareCommit(dirtyPages) {
7431
+ if (dirtyPages.size === 0) {
7432
+ return;
7433
+ }
7434
+ await this.append(dirtyPages);
7435
+ }
7436
+ /**
7437
+ * WAL에 커밋 마커를 기록하고 로그를 정리합니다 (Phase 2: Finalize).
7438
+ * @param hasActiveTransactions 아직 활성 트랜잭션이 있는지 여부
7439
+ */
7440
+ async finalizeCommit(hasActiveTransactions) {
7441
+ await this.writeCommitMarker();
7442
+ if (!hasActiveTransactions) {
7443
+ await this.clear();
7444
+ }
7445
+ }
7446
+ // ─────────────────────────────────────────────────────────────
7447
+ // Low-level WAL operations
7448
+ // ─────────────────────────────────────────────────────────────
6267
7449
  /**
6268
7450
  * Appends changed pages to the log file.
6269
7451
  * Records them sorted by page ID.
@@ -6317,7 +7499,7 @@ var LogManager = class {
6317
7499
  }
6318
7500
  /**
6319
7501
  * Reads the log file to recover the page map.
6320
- * Runs synchronously as it is called by the VFS constructor.
7502
+ * Runs synchronously as it is called during initialization.
6321
7503
  * Only returns pages from committed transactions (ended with a commit marker).
6322
7504
  * @returns Recovered page map
6323
7505
  */
@@ -6372,173 +7554,15 @@ var LogManager = class {
6372
7554
  }
6373
7555
  };
6374
7556
 
6375
- // src/core/VirtualFileSystem.ts
6376
- var VirtualFileSystem = class {
6377
- /** Track logical file size */
6378
- fileSize;
6379
- /** Page size */
6380
- pageSize;
6381
- /** File handle */
6382
- fileHandle;
6383
- /** WAL Log Manager */
6384
- logManager;
6385
- constructor(fileHandle, pageSize, pageCacheCapacity, walPath) {
6386
- if ((pageSize & pageSize - 1) !== 0) {
6387
- throw new Error("Page size must be a power of 2");
6388
- }
6389
- this.fileHandle = fileHandle;
6390
- this.pageSize = pageSize;
6391
- this.fileSize = import_node_fs2.default.fstatSync(fileHandle).size;
6392
- if (walPath) {
6393
- this.logManager = new LogManager(walPath, pageSize);
6394
- }
6395
- }
6396
- /**
6397
- * Performs recovery (Redo) using WAL logs.
6398
- * Called during initialization (DataplyAPI.init), ensuring data is fully restored before operations start.
6399
- */
6400
- async recover() {
6401
- if (!this.logManager) return;
6402
- this.logManager.open();
6403
- const restoredPages = this.logManager.readAllSync();
6404
- if (restoredPages.size === 0) {
6405
- return;
6406
- }
6407
- const promises = [];
6408
- for (const [pageId, data] of restoredPages) {
6409
- if (pageId > 1e6) continue;
6410
- try {
6411
- const manager = new PageManagerFactory().getManager(data);
6412
- if (!manager.verifyChecksum(data)) {
6413
- console.warn(`[VFS] Checksum verification failed for PageID ${pageId} during recovery. Ignoring changes.`);
6414
- continue;
6415
- }
6416
- } catch (e) {
6417
- console.warn(`[VFS] Failed to verify checksum for PageID ${pageId} during recovery: ${e}. Ignoring changes.`);
6418
- continue;
6419
- }
6420
- promises.push(this._writeAsync(
6421
- this.fileHandle,
6422
- data,
6423
- 0,
6424
- this.pageSize,
6425
- pageId * this.pageSize
6426
- ));
6427
- const endPos = (pageId + 1) * this.pageSize;
6428
- if (endPos > this.fileSize) {
6429
- this.fileSize = endPos;
6430
- }
6431
- }
6432
- await Promise.all(promises);
6433
- if (this.logManager && restoredPages.size > 0) {
6434
- await this.logManager.clear();
6435
- }
6436
- }
6437
- /**
6438
- * WAL에 페이지 데이터를 기록합니다 (Phase 1).
6439
- * @param dirtyPages 변경된 페이지들 (pageId -> data)
6440
- */
6441
- async prepareCommitWAL(dirtyPages) {
6442
- if (!this.logManager || dirtyPages.size === 0) {
6443
- return;
6444
- }
6445
- await this.logManager.append(dirtyPages);
6446
- }
6447
- /**
6448
- * WAL에 커밋 마커를 기록하고 로그를 정리합니다 (Phase 2).
6449
- * @param hasActiveTransactions 아직 활성 트랜잭션이 있는지 여부
6450
- */
6451
- async finalizeCommitWAL(hasActiveTransactions) {
6452
- if (!this.logManager) {
6453
- return;
6454
- }
6455
- await this.logManager.writeCommitMarker();
6456
- if (!hasActiveTransactions) {
6457
- await this.logManager.clear();
6458
- }
6459
- }
6460
- /**
6461
- * 디스크에서 페이지를 읽습니다.
6462
- * @param pageId Page ID
6463
- * @returns Page data
6464
- */
6465
- async readPage(pageId) {
6466
- const buffer = new Uint8Array(this.pageSize);
6467
- const pageStartPos = pageId * this.pageSize;
6468
- if (pageStartPos >= this.fileSize) {
6469
- return buffer;
6470
- }
6471
- await this._readAsync(this.fileHandle, buffer, 0, this.pageSize, pageStartPos);
6472
- return buffer;
6473
- }
6474
- /**
6475
- * 디스크에 페이지를 씁니다.
6476
- * @param pageId Page ID
6477
- * @param data Page data
6478
- */
6479
- async writePage(pageId, data) {
6480
- const pageStartPos = pageId * this.pageSize;
6481
- if (pageStartPos + this.pageSize > 512 * 1024 * 1024) {
6482
- throw new Error(`[Safety Limit] File write exceeds 512MB limit at position ${pageStartPos}`);
6483
- }
6484
- await this._writeAsync(this.fileHandle, data, 0, this.pageSize, pageStartPos);
6485
- const endPosition = pageStartPos + this.pageSize;
6486
- if (endPosition > this.fileSize) {
6487
- this.fileSize = endPosition;
6488
- }
6489
- }
6490
- /**
6491
- * 현재 파일 크기 반환
6492
- */
6493
- getFileSize() {
6494
- return this.fileSize;
6495
- }
6496
- /**
6497
- * Closes the file.
6498
- */
6499
- async close() {
6500
- if (this.logManager) {
6501
- this.logManager.close();
6502
- }
6503
- }
6504
- _readAsync(handle, buffer, offset, length, position) {
6505
- return new Promise((resolve, reject) => {
6506
- import_node_fs2.default.read(handle, buffer, offset, length, position, (err, bytesRead) => {
6507
- if (err) return reject(err);
6508
- resolve(bytesRead);
6509
- });
6510
- });
6511
- }
6512
- _writeAsync(handle, buffer, offset, length, position) {
6513
- if (position + length > 512 * 1024 * 1024) {
6514
- return Promise.reject(new Error(`[Safety Limit] File write exceeds 512MB limit at position ${position}`));
6515
- }
6516
- return new Promise((resolve, reject) => {
6517
- import_node_fs2.default.write(handle, buffer, offset, length, position, (err, bytesWritten) => {
6518
- if (err) return reject(err);
6519
- resolve(bytesWritten);
6520
- });
6521
- });
6522
- }
6523
- };
6524
-
6525
- // src/core/PageMVCCStrategy.ts
6526
- var import_node_fs3 = __toESM(require("node:fs"));
6527
-
6528
- // node_modules/mvcc-api/dist/esm/index.mjs
6529
- var MVCCStrategy2 = class {
6530
- };
6531
- var AsyncMVCCStrategy2 = class extends MVCCStrategy2 {
6532
- };
6533
-
6534
7557
  // src/core/PageMVCCStrategy.ts
7558
+ var import_node_fs2 = __toESM(require("node:fs"));
6535
7559
  var PageMVCCStrategy = class extends AsyncMVCCStrategy2 {
6536
7560
  constructor(fileHandle, pageSize, cacheCapacity) {
6537
7561
  super();
6538
7562
  this.fileHandle = fileHandle;
6539
7563
  this.pageSize = pageSize;
6540
7564
  this.cache = new LRUMap2(cacheCapacity);
6541
- this.fileSize = import_node_fs3.default.fstatSync(fileHandle).size;
7565
+ this.fileSize = import_node_fs2.default.fstatSync(fileHandle).size;
6542
7566
  }
6543
7567
  /** LRU 캐시 (페이지 ID -> 페이지 데이터) */
6544
7568
  cache;
@@ -6621,7 +7645,7 @@ var PageMVCCStrategy = class extends AsyncMVCCStrategy2 {
6621
7645
  // ─────────────────────────────────────────────────────────────
6622
7646
  _readFromDisk(buffer, position) {
6623
7647
  return new Promise((resolve, reject) => {
6624
- import_node_fs3.default.read(this.fileHandle, buffer, 0, this.pageSize, position, (err, bytesRead) => {
7648
+ import_node_fs2.default.read(this.fileHandle, buffer, 0, this.pageSize, position, (err, bytesRead) => {
6625
7649
  if (err) return reject(err);
6626
7650
  resolve(bytesRead);
6627
7651
  });
@@ -6629,7 +7653,7 @@ var PageMVCCStrategy = class extends AsyncMVCCStrategy2 {
6629
7653
  }
6630
7654
  _writeToDisk(buffer, position) {
6631
7655
  return new Promise((resolve, reject) => {
6632
- import_node_fs3.default.write(this.fileHandle, buffer, 0, this.pageSize, position, (err, bytesWritten) => {
7656
+ import_node_fs2.default.write(this.fileHandle, buffer, 0, this.pageSize, position, (err, bytesWritten) => {
6633
7657
  if (err) return reject(err);
6634
7658
  resolve(bytesWritten);
6635
7659
  });
@@ -6650,20 +7674,24 @@ var PageFileSystem = class {
6650
7674
  this.pageSize = pageSize;
6651
7675
  this.pageCacheCapacity = pageCacheCapacity;
6652
7676
  this.walPath = walPath;
6653
- this.vfs = new VirtualFileSystem(fileHandle, pageSize, pageCacheCapacity, walPath);
7677
+ this.walManager = walPath ? new WALManager(walPath, pageSize) : null;
6654
7678
  this.pageManagerFactory = new PageManagerFactory();
6655
7679
  this.pageStrategy = new PageMVCCStrategy(fileHandle, pageSize, pageCacheCapacity);
6656
7680
  }
6657
7681
  pageFactory = new PageManagerFactory();
6658
- vfs;
7682
+ walManager;
6659
7683
  pageManagerFactory;
6660
7684
  pageStrategy;
6661
7685
  /**
6662
7686
  * Initializes the page file system.
6663
- * Performs VFS recovery if necessary.
7687
+ * Performs WAL recovery if necessary.
6664
7688
  */
6665
7689
  async init() {
6666
- await this.vfs.recover();
7690
+ if (this.walManager) {
7691
+ await this.walManager.recover(async (pageId, data) => {
7692
+ await this.pageStrategy.write(pageId, data);
7693
+ });
7694
+ }
6667
7695
  }
6668
7696
  /**
6669
7697
  * Returns the page strategy for transaction use.
@@ -6709,10 +7737,10 @@ var PageFileSystem = class {
6709
7737
  await this.setPage(currentBitmapPageId, targetBitmapPage, tx);
6710
7738
  }
6711
7739
  /**
6712
- * VFS 인스턴스를 반환합니다.
7740
+ * WAL Manager 인스턴스를 반환합니다.
6713
7741
  */
6714
- get vfsInstance() {
6715
- return this.vfs;
7742
+ get wal() {
7743
+ return this.walManager;
6716
7744
  }
6717
7745
  /**
6718
7746
  * 페이지 Strategy를 반환합니다.
@@ -6947,14 +7975,18 @@ var PageFileSystem = class {
6947
7975
  * @param dirtyPages 변경된 페이지들
6948
7976
  */
6949
7977
  async commitToWAL(dirtyPages) {
6950
- await this.vfs.prepareCommitWAL(dirtyPages);
6951
- await this.vfs.finalizeCommitWAL(false);
7978
+ if (this.walManager) {
7979
+ await this.walManager.prepareCommit(dirtyPages);
7980
+ await this.walManager.finalizeCommit(false);
7981
+ }
6952
7982
  }
6953
7983
  /**
6954
7984
  * Closes the page file system.
6955
7985
  */
6956
7986
  async close() {
6957
- await this.vfs.close();
7987
+ if (this.walManager) {
7988
+ this.walManager.close();
7989
+ }
6958
7990
  }
6959
7991
  };
6960
7992
 
@@ -7835,7 +8867,7 @@ var DataplyAPI = class {
7835
8867
  this.file = file;
7836
8868
  this.hook = useHookall(this);
7837
8869
  this.options = this.verboseOptions(options);
7838
- this.isNewlyCreated = !import_node_fs4.default.existsSync(file);
8870
+ this.isNewlyCreated = !import_node_fs3.default.existsSync(file);
7839
8871
  this.fileHandle = this.createOrOpen(file, this.options);
7840
8872
  this.pfs = new PageFileSystem(
7841
8873
  this.fileHandle,
@@ -7884,7 +8916,7 @@ var DataplyAPI = class {
7884
8916
  verifyFormat(fileHandle) {
7885
8917
  const size = MetadataPageManager.CONSTANT.OFFSET_MAGIC_STRING + MetadataPageManager.CONSTANT.MAGIC_STRING.length;
7886
8918
  const metadataPage = new Uint8Array(size);
7887
- import_node_fs4.default.readSync(fileHandle, metadataPage, 0, size, 0);
8919
+ import_node_fs3.default.readSync(fileHandle, metadataPage, 0, size, 0);
7888
8920
  if (!MetadataPageManager.IsMetadataPage(metadataPage)) {
7889
8921
  return false;
7890
8922
  }
@@ -7946,7 +8978,7 @@ var DataplyAPI = class {
7946
8978
  -1,
7947
8979
  options.pageSize - DataPageManager.CONSTANT.SIZE_PAGE_HEADER
7948
8980
  );
7949
- import_node_fs4.default.appendFileSync(fileHandle, new Uint8Array([
8981
+ import_node_fs3.default.appendFileSync(fileHandle, new Uint8Array([
7950
8982
  ...metadataPage,
7951
8983
  ...bitmapPage,
7952
8984
  ...dataPage
@@ -7963,18 +8995,18 @@ var DataplyAPI = class {
7963
8995
  if (options.pageCacheCapacity < 100) {
7964
8996
  throw new Error("Page cache capacity must be at least 100");
7965
8997
  }
7966
- if (!import_node_fs4.default.existsSync(file)) {
8998
+ if (!import_node_fs3.default.existsSync(file)) {
7967
8999
  if (options.pageSize < 4096) {
7968
9000
  throw new Error("Page size must be at least 4096 bytes");
7969
9001
  }
7970
- fileHandle = import_node_fs4.default.openSync(file, "w+");
9002
+ fileHandle = import_node_fs3.default.openSync(file, "w+");
7971
9003
  this.initializeFile(file, fileHandle, options);
7972
9004
  } else {
7973
- fileHandle = import_node_fs4.default.openSync(file, "r+");
9005
+ fileHandle = import_node_fs3.default.openSync(file, "r+");
7974
9006
  const buffer = new Uint8Array(
7975
9007
  MetadataPageManager.CONSTANT.OFFSET_PAGE_SIZE + MetadataPageManager.CONSTANT.SIZE_PAGE_SIZE
7976
9008
  );
7977
- import_node_fs4.default.readSync(fileHandle, buffer);
9009
+ import_node_fs3.default.readSync(fileHandle, buffer);
7978
9010
  const metadataManager = new MetadataPageManager();
7979
9011
  if (metadataManager.isMetadataPage(buffer)) {
7980
9012
  const storedPageSize = metadataManager.getPageSize(buffer);
@@ -8169,7 +9201,7 @@ var DataplyAPI = class {
8169
9201
  }
8170
9202
  return this.hook.trigger("close", void 0, async () => {
8171
9203
  await this.pfs.close();
8172
- import_node_fs4.default.closeSync(this.fileHandle);
9204
+ import_node_fs3.default.closeSync(this.fileHandle);
8173
9205
  });
8174
9206
  }
8175
9207
  };
@@ -8301,6 +9333,8 @@ var GlobalTransaction = class {
8301
9333
  };
8302
9334
  // Annotate the CommonJS export names for ESM import in node:
8303
9335
  0 && (module.exports = {
9336
+ AsyncMVCCStrategy,
9337
+ AsyncMVCCTransaction,
8304
9338
  BPTreeAsync,
8305
9339
  BPTreeAsyncTransaction,
8306
9340
  BPTreeSync,
@@ -8318,6 +9352,8 @@ var GlobalTransaction = class {
8318
9352
  IndexPageManager,
8319
9353
  InvertedWeakMap,
8320
9354
  LRUMap,
9355
+ MVCCStrategy,
9356
+ MVCCTransaction,
8321
9357
  MetadataPageManager,
8322
9358
  NumericComparator,
8323
9359
  OverflowPageManager,
@@ -8327,6 +9363,8 @@ var GlobalTransaction = class {
8327
9363
  SerializeStrategyAsync,
8328
9364
  SerializeStrategySync,
8329
9365
  StringComparator,
9366
+ SyncMVCCStrategy,
9367
+ SyncMVCCTransaction,
8330
9368
  Transaction,
8331
9369
  UnknownPageManager,
8332
9370
  ValueComparator