@voidhash/mimic-effect 1.0.0-beta.1 → 1.0.0-beta.10
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/.turbo/turbo-build.log +116 -74
- package/dist/ColdStorage.cjs +9 -5
- package/dist/ColdStorage.d.cts.map +1 -1
- package/dist/ColdStorage.d.mts.map +1 -1
- package/dist/ColdStorage.mjs +9 -5
- package/dist/ColdStorage.mjs.map +1 -1
- package/dist/DocumentInstance.cjs +263 -0
- package/dist/DocumentInstance.d.cts +78 -0
- package/dist/DocumentInstance.d.cts.map +1 -0
- package/dist/DocumentInstance.d.mts +78 -0
- package/dist/DocumentInstance.d.mts.map +1 -0
- package/dist/DocumentInstance.mjs +264 -0
- package/dist/DocumentInstance.mjs.map +1 -0
- package/dist/Errors.cjs +10 -1
- package/dist/Errors.d.cts +18 -3
- package/dist/Errors.d.cts.map +1 -1
- package/dist/Errors.d.mts +18 -3
- package/dist/Errors.d.mts.map +1 -1
- package/dist/Errors.mjs +9 -1
- package/dist/Errors.mjs.map +1 -1
- package/dist/HotStorage.cjs +39 -12
- package/dist/HotStorage.d.cts +17 -1
- package/dist/HotStorage.d.cts.map +1 -1
- package/dist/HotStorage.d.mts +17 -1
- package/dist/HotStorage.d.mts.map +1 -1
- package/dist/HotStorage.mjs +39 -12
- package/dist/HotStorage.mjs.map +1 -1
- package/dist/Metrics.cjs +29 -1
- package/dist/Metrics.d.cts +5 -0
- package/dist/Metrics.d.cts.map +1 -1
- package/dist/Metrics.d.mts +5 -0
- package/dist/Metrics.d.mts.map +1 -1
- package/dist/Metrics.mjs +26 -1
- package/dist/Metrics.mjs.map +1 -1
- package/dist/MimicClusterServerEngine.cjs +44 -139
- package/dist/MimicClusterServerEngine.d.cts.map +1 -1
- package/dist/MimicClusterServerEngine.d.mts +1 -1
- package/dist/MimicClusterServerEngine.d.mts.map +1 -1
- package/dist/MimicClusterServerEngine.mjs +46 -141
- package/dist/MimicClusterServerEngine.mjs.map +1 -1
- package/dist/MimicServer.cjs +20 -20
- package/dist/MimicServer.d.cts.map +1 -1
- package/dist/MimicServer.d.mts.map +1 -1
- package/dist/MimicServer.mjs +20 -20
- package/dist/MimicServer.mjs.map +1 -1
- package/dist/MimicServerEngine.cjs +92 -11
- package/dist/MimicServerEngine.d.cts +12 -4
- package/dist/MimicServerEngine.d.cts.map +1 -1
- package/dist/MimicServerEngine.d.mts +12 -4
- package/dist/MimicServerEngine.d.mts.map +1 -1
- package/dist/MimicServerEngine.mjs +94 -13
- package/dist/MimicServerEngine.mjs.map +1 -1
- package/dist/PresenceManager.cjs +5 -5
- package/dist/PresenceManager.d.cts.map +1 -1
- package/dist/PresenceManager.d.mts.map +1 -1
- package/dist/PresenceManager.mjs +5 -5
- package/dist/PresenceManager.mjs.map +1 -1
- package/dist/Protocol.d.cts +1 -1
- package/dist/Protocol.d.mts +1 -1
- package/dist/Types.d.cts +9 -2
- package/dist/Types.d.cts.map +1 -1
- package/dist/Types.d.mts +9 -2
- package/dist/Types.d.mts.map +1 -1
- package/dist/index.cjs +5 -6
- package/dist/index.d.cts +3 -3
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +3 -3
- package/dist/testing/ColdStorageTestSuite.cjs +508 -0
- package/dist/testing/ColdStorageTestSuite.d.cts +36 -0
- package/dist/testing/ColdStorageTestSuite.d.cts.map +1 -0
- package/dist/testing/ColdStorageTestSuite.d.mts +36 -0
- package/dist/testing/ColdStorageTestSuite.d.mts.map +1 -0
- package/dist/testing/ColdStorageTestSuite.mjs +508 -0
- package/dist/testing/ColdStorageTestSuite.mjs.map +1 -0
- package/dist/testing/FailingStorage.cjs +162 -0
- package/dist/testing/FailingStorage.d.cts +43 -0
- package/dist/testing/FailingStorage.d.cts.map +1 -0
- package/dist/testing/FailingStorage.d.mts +43 -0
- package/dist/testing/FailingStorage.d.mts.map +1 -0
- package/dist/testing/FailingStorage.mjs +163 -0
- package/dist/testing/FailingStorage.mjs.map +1 -0
- package/dist/testing/HotStorageTestSuite.cjs +820 -0
- package/dist/testing/HotStorageTestSuite.d.cts +42 -0
- package/dist/testing/HotStorageTestSuite.d.cts.map +1 -0
- package/dist/testing/HotStorageTestSuite.d.mts +42 -0
- package/dist/testing/HotStorageTestSuite.d.mts.map +1 -0
- package/dist/testing/HotStorageTestSuite.mjs +820 -0
- package/dist/testing/HotStorageTestSuite.mjs.map +1 -0
- package/dist/testing/StorageIntegrationTestSuite.cjs +487 -0
- package/dist/testing/StorageIntegrationTestSuite.d.cts +37 -0
- package/dist/testing/StorageIntegrationTestSuite.d.cts.map +1 -0
- package/dist/testing/StorageIntegrationTestSuite.d.mts +37 -0
- package/dist/testing/StorageIntegrationTestSuite.d.mts.map +1 -0
- package/dist/testing/StorageIntegrationTestSuite.mjs +487 -0
- package/dist/testing/StorageIntegrationTestSuite.mjs.map +1 -0
- package/dist/testing/assertions.cjs +117 -0
- package/dist/testing/assertions.mjs +112 -0
- package/dist/testing/assertions.mjs.map +1 -0
- package/dist/testing/index.cjs +14 -0
- package/dist/testing/index.d.cts +6 -0
- package/dist/testing/index.d.mts +6 -0
- package/dist/testing/index.mjs +7 -0
- package/dist/testing/types.cjs +15 -0
- package/dist/testing/types.d.cts +90 -0
- package/dist/testing/types.d.cts.map +1 -0
- package/dist/testing/types.d.mts +90 -0
- package/dist/testing/types.d.mts.map +1 -0
- package/dist/testing/types.mjs +16 -0
- package/dist/testing/types.mjs.map +1 -0
- package/package.json +8 -3
- package/src/ColdStorage.ts +21 -12
- package/src/DocumentInstance.ts +527 -0
- package/src/Errors.ts +15 -1
- package/src/HotStorage.ts +115 -24
- package/src/Metrics.ts +30 -0
- package/src/MimicClusterServerEngine.ts +120 -275
- package/src/MimicServer.ts +83 -75
- package/src/MimicServerEngine.ts +230 -30
- package/src/PresenceManager.ts +44 -34
- package/src/Types.ts +9 -2
- package/src/index.ts +5 -35
- package/src/testing/ColdStorageTestSuite.ts +589 -0
- package/src/testing/FailingStorage.ts +338 -0
- package/src/testing/HotStorageTestSuite.ts +1105 -0
- package/src/testing/StorageIntegrationTestSuite.ts +736 -0
- package/src/testing/assertions.ts +188 -0
- package/src/testing/index.ts +83 -0
- package/src/testing/types.ts +100 -0
- package/tests/ColdStorage.test.ts +8 -120
- package/tests/DocumentInstance.test.ts +669 -0
- package/tests/HotStorage.test.ts +7 -126
- package/tests/StorageIntegration.test.ts +259 -0
- package/tsdown.config.ts +1 -1
- package/dist/DocumentManager.cjs +0 -229
- package/dist/DocumentManager.d.cts +0 -59
- package/dist/DocumentManager.d.cts.map +0 -1
- package/dist/DocumentManager.d.mts +0 -59
- package/dist/DocumentManager.d.mts.map +0 -1
- package/dist/DocumentManager.mjs +0 -227
- package/dist/DocumentManager.mjs.map +0 -1
- package/src/DocumentManager.ts +0 -506
- package/tests/DocumentManager.test.ts +0 -335
package/src/HotStorage.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { Context, Effect, HashMap, Layer, Ref } from "effect";
|
|
7
7
|
import type { WalEntry } from "./Types";
|
|
8
|
-
import { HotStorageError } from "./Errors";
|
|
8
|
+
import { HotStorageError, WalVersionGapError } from "./Errors";
|
|
9
9
|
|
|
10
10
|
// =============================================================================
|
|
11
11
|
// HotStorage Interface
|
|
@@ -27,6 +27,27 @@ export interface HotStorage {
|
|
|
27
27
|
entry: WalEntry
|
|
28
28
|
) => Effect.Effect<void, HotStorageError>;
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Append a WAL entry with version gap checking.
|
|
32
|
+
*
|
|
33
|
+
* This is an atomic operation that:
|
|
34
|
+
* 1. Verifies the previous entry has version = expectedVersion - 1
|
|
35
|
+
* (or this is the first entry if expectedVersion === 1)
|
|
36
|
+
* 2. Appends the entry if check passes
|
|
37
|
+
*
|
|
38
|
+
* Use this for two-phase commit to guarantee WAL ordering at write time.
|
|
39
|
+
*
|
|
40
|
+
* @param documentId - Document ID
|
|
41
|
+
* @param entry - WAL entry to append
|
|
42
|
+
* @param expectedVersion - The version this entry should have (entry.version)
|
|
43
|
+
* @returns Effect that fails with WalVersionGapError if gap detected
|
|
44
|
+
*/
|
|
45
|
+
readonly appendWithCheck: (
|
|
46
|
+
documentId: string,
|
|
47
|
+
entry: WalEntry,
|
|
48
|
+
expectedVersion: number
|
|
49
|
+
) => Effect.Effect<void, HotStorageError | WalVersionGapError>;
|
|
50
|
+
|
|
30
51
|
/**
|
|
31
52
|
* Get all WAL entries for a document since a given version.
|
|
32
53
|
* Returns entries with version > sinceVersion, ordered by version.
|
|
@@ -115,20 +136,86 @@ export namespace InMemory {
|
|
|
115
136
|
export const make = (): Layer.Layer<HotStorageTag> =>
|
|
116
137
|
Layer.effect(
|
|
117
138
|
HotStorageTag,
|
|
118
|
-
Effect.
|
|
139
|
+
Effect.fn("hot-storage.in-memory.create")(function* () {
|
|
119
140
|
const store = yield* Ref.make(HashMap.empty<string, WalEntry[]>());
|
|
120
141
|
|
|
121
142
|
return {
|
|
122
|
-
append: (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
143
|
+
append: Effect.fn("hot-storage.append")(
|
|
144
|
+
function* (documentId: string, entry: WalEntry) {
|
|
145
|
+
yield* Ref.update(store, (map) => {
|
|
146
|
+
const existing = HashMap.get(map, documentId);
|
|
147
|
+
const entries =
|
|
148
|
+
existing._tag === "Some" ? existing.value : [];
|
|
149
|
+
return HashMap.set(map, documentId, [...entries, entry]);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
),
|
|
153
|
+
|
|
154
|
+
appendWithCheck: Effect.fn("hot-storage.append-with-check")(
|
|
155
|
+
function* (
|
|
156
|
+
documentId: string,
|
|
157
|
+
entry: WalEntry,
|
|
158
|
+
expectedVersion: number
|
|
159
|
+
) {
|
|
160
|
+
type CheckResult =
|
|
161
|
+
| { type: "ok" }
|
|
162
|
+
| { type: "gap"; lastVersion: number | undefined };
|
|
163
|
+
|
|
164
|
+
// Use Ref.modify for atomic check + update
|
|
165
|
+
const result: CheckResult = yield* Ref.modify(
|
|
166
|
+
store,
|
|
167
|
+
(map): [CheckResult, HashMap.HashMap<string, WalEntry[]>] => {
|
|
168
|
+
const existing = HashMap.get(map, documentId);
|
|
169
|
+
const entries =
|
|
170
|
+
existing._tag === "Some" ? existing.value : [];
|
|
129
171
|
|
|
130
|
-
|
|
131
|
-
|
|
172
|
+
// Find the highest version in existing entries
|
|
173
|
+
const lastVersion =
|
|
174
|
+
entries.length > 0
|
|
175
|
+
? Math.max(...entries.map((e) => e.version))
|
|
176
|
+
: 0;
|
|
177
|
+
|
|
178
|
+
// Gap check
|
|
179
|
+
if (expectedVersion === 1) {
|
|
180
|
+
// First entry: should have no entries with version >= 1
|
|
181
|
+
if (lastVersion >= 1) {
|
|
182
|
+
return [{ type: "gap", lastVersion }, map];
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
// Not first: last entry should have version = expectedVersion - 1
|
|
186
|
+
if (lastVersion !== expectedVersion - 1) {
|
|
187
|
+
return [
|
|
188
|
+
{
|
|
189
|
+
type: "gap",
|
|
190
|
+
lastVersion: lastVersion > 0 ? lastVersion : undefined,
|
|
191
|
+
},
|
|
192
|
+
map,
|
|
193
|
+
];
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// No gap: append and return success
|
|
198
|
+
return [
|
|
199
|
+
{ type: "ok" },
|
|
200
|
+
HashMap.set(map, documentId, [...entries, entry]),
|
|
201
|
+
];
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
if (result.type === "gap") {
|
|
206
|
+
return yield* Effect.fail(
|
|
207
|
+
new WalVersionGapError({
|
|
208
|
+
documentId,
|
|
209
|
+
expectedVersion,
|
|
210
|
+
actualPreviousVersion: result.lastVersion,
|
|
211
|
+
})
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
),
|
|
216
|
+
|
|
217
|
+
getEntries: Effect.fn("hot-storage.get-entries")(
|
|
218
|
+
function* (documentId: string, sinceVersion: number) {
|
|
132
219
|
const current = yield* Ref.get(store);
|
|
133
220
|
const existing = HashMap.get(current, documentId);
|
|
134
221
|
const entries =
|
|
@@ -136,21 +223,25 @@ export namespace InMemory {
|
|
|
136
223
|
return entries
|
|
137
224
|
.filter((e) => e.version > sinceVersion)
|
|
138
225
|
.sort((a, b) => a.version - b.version);
|
|
139
|
-
}
|
|
226
|
+
}
|
|
227
|
+
),
|
|
140
228
|
|
|
141
|
-
truncate: (
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
229
|
+
truncate: Effect.fn("hot-storage.truncate")(
|
|
230
|
+
function* (documentId: string, upToVersion: number) {
|
|
231
|
+
yield* Ref.update(store, (map) => {
|
|
232
|
+
const existing = HashMap.get(map, documentId);
|
|
233
|
+
if (existing._tag === "None") {
|
|
234
|
+
return map;
|
|
235
|
+
}
|
|
236
|
+
const filtered = existing.value.filter(
|
|
237
|
+
(e) => e.version > upToVersion
|
|
238
|
+
);
|
|
239
|
+
return HashMap.set(map, documentId, filtered);
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
),
|
|
152
243
|
};
|
|
153
|
-
})
|
|
244
|
+
})()
|
|
154
245
|
);
|
|
155
246
|
}
|
|
156
247
|
|
package/src/Metrics.ts
CHANGED
|
@@ -99,6 +99,11 @@ export const transactionsLatency = Metric.histogram(
|
|
|
99
99
|
*/
|
|
100
100
|
export const storageSnapshots = Metric.counter("mimic.storage.snapshots");
|
|
101
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Snapshots triggered by idle document detection
|
|
104
|
+
*/
|
|
105
|
+
export const storageIdleSnapshots = Metric.counter("mimic.storage.idle_snapshots");
|
|
106
|
+
|
|
102
107
|
/**
|
|
103
108
|
* Snapshot save duration histogram (milliseconds)
|
|
104
109
|
*/
|
|
@@ -116,6 +121,26 @@ export const storageSnapshotLatency = Metric.histogram(
|
|
|
116
121
|
*/
|
|
117
122
|
export const storageWalAppends = Metric.counter("mimic.storage.wal_appends");
|
|
118
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Version gaps detected during WAL replay
|
|
126
|
+
*/
|
|
127
|
+
export const storageVersionGaps = Metric.counter("mimic.storage.version_gaps");
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Failed WAL appends causing transaction rollback
|
|
131
|
+
*/
|
|
132
|
+
export const walAppendFailures = Metric.counter("mimic.storage.wal_append_failures");
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* ColdStorage load failures during document restore
|
|
136
|
+
*/
|
|
137
|
+
export const coldStorageLoadFailures = Metric.counter("mimic.storage.cold_load_failures");
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* HotStorage getEntries failures during document restore
|
|
141
|
+
*/
|
|
142
|
+
export const hotStorageLoadFailures = Metric.counter("mimic.storage.hot_load_failures");
|
|
143
|
+
|
|
119
144
|
// =============================================================================
|
|
120
145
|
// Presence Metrics
|
|
121
146
|
// =============================================================================
|
|
@@ -154,8 +179,13 @@ export const MimicMetrics = {
|
|
|
154
179
|
|
|
155
180
|
// Storage
|
|
156
181
|
storageSnapshots,
|
|
182
|
+
storageIdleSnapshots,
|
|
157
183
|
storageSnapshotLatency,
|
|
158
184
|
storageWalAppends,
|
|
185
|
+
storageVersionGaps,
|
|
186
|
+
walAppendFailures,
|
|
187
|
+
coldStorageLoadFailures,
|
|
188
|
+
hotStorageLoadFailures,
|
|
159
189
|
|
|
160
190
|
// Presence
|
|
161
191
|
presenceUpdates,
|