envio 3.11.0 → 3.12.0
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/index.d.ts +3 -0
- package/package.json +6 -6
- package/src/Batch.res +111 -78
- package/src/Batch.res.mjs +53 -46
- package/src/BatchProcessing.res +1 -11
- package/src/BatchProcessing.res.mjs +1 -4
- package/src/ChainState.res +72 -19
- package/src/ChainState.res.mjs +50 -12
- package/src/ChainState.resi +5 -0
- package/src/Config.res +58 -37
- package/src/Config.res.mjs +63 -53
- package/src/CrossChainState.res +49 -52
- package/src/CrossChainState.res.mjs +25 -23
- package/src/CrossChainState.resi +6 -13
- package/src/EffectState.res +13 -4
- package/src/EffectState.resi +7 -1
- package/src/EventProcessing.res +6 -6
- package/src/EventProcessing.res.mjs +6 -6
- package/src/FetchState.res +14 -0
- package/src/FetchState.res.mjs +14 -0
- package/src/FinalizeBackfill.res +16 -12
- package/src/FinalizeBackfill.res.mjs +3 -3
- package/src/HistoryPolicy.res +46 -0
- package/src/HistoryPolicy.res.mjs +50 -0
- package/src/InMemoryStore.res +30 -32
- package/src/InMemoryStore.res.mjs +33 -28
- package/src/IndexerState.res +66 -45
- package/src/IndexerState.res.mjs +57 -29
- package/src/IndexerState.resi +8 -13
- package/src/Internal.res +4 -2
- package/src/LoadLayer.res +11 -4
- package/src/LoadLayer.res.mjs +8 -5
- package/src/Main.res +25 -24
- package/src/Main.res.mjs +24 -25
- package/src/Metrics.res +49 -1
- package/src/Metrics.res.mjs +26 -3
- package/src/Persistence.res +55 -16
- package/src/Persistence.res.mjs +18 -3
- package/src/PgStorage.res +194 -118
- package/src/PgStorage.res.mjs +132 -72
- package/src/PruneStaleHistory.res +9 -15
- package/src/PruneStaleHistory.res.mjs +11 -20
- package/src/Rollback.res +9 -14
- package/src/Rollback.res.mjs +5 -3
- package/src/Sink.res +7 -5
- package/src/Sink.res.mjs +4 -4
- package/src/Staging.res +298 -0
- package/src/Staging.res.mjs +257 -0
- package/src/TestIndexer.res +5 -5
- package/src/TestIndexer.res.mjs +7 -6
- package/src/UserContext.res +7 -4
- package/src/UserContext.res.mjs +5 -2
- package/src/Utils.res +9 -0
- package/src/Utils.res.mjs +9 -0
- package/src/Writing.res +34 -20
- package/src/Writing.res.mjs +15 -20
- package/src/bindings/ClickHouse.res +41 -34
- package/src/bindings/ClickHouse.res.mjs +36 -30
- package/src/bindings/ClickHouseSink.res +45 -186
- package/src/bindings/ClickHouseSink.res.mjs +21 -174
- package/src/db/CheckpointSequence.res +109 -0
- package/src/db/CheckpointSequence.res.mjs +99 -0
- package/src/db/EntityHistory.res +6 -5
- package/src/db/EntityHistory.res.mjs +5 -5
- package/src/db/Frontier.res +86 -0
- package/src/db/Frontier.res.mjs +126 -0
- package/src/db/InternalTable.res +145 -27
- package/src/db/InternalTable.res.mjs +115 -29
- package/src/db/RollbackFloors.res +34 -41
- package/src/db/RollbackFloors.res.mjs +27 -71
- package/src/sources/BlockStore.res +3 -0
- package/src/sources/EvmHyperSyncSource.res +3 -1
- package/src/sources/EvmHyperSyncSource.res.mjs +2 -1
- package/src/sources/HyperSync.res +2 -0
- package/src/sources/HyperSync.res.mjs +1 -0
- package/src/sources/HyperSync.resi +1 -0
- package/src/sources/HyperSyncClient.res +3 -0
- package/src/sources/RequestStat.res +8 -1
- package/src/sources/Source.res +4 -3
- package/src/sources/SourceManager.res +30 -10
- package/src/sources/SourceManager.res.mjs +24 -7
- package/src/sources/SourceManager.resi +2 -0
- package/src/tui/Tui.res +56 -143
- package/src/tui/Tui.res.mjs +70 -166
- package/src/tui/components/TuiData.res +61 -16
- package/src/tui/components/TuiData.res.mjs +53 -15
- package/svm.schema.json +0 -7
- package/src/db/CheckpointBounds.res +0 -53
- package/src/db/CheckpointBounds.res.mjs +0 -44
|
@@ -110,8 +110,8 @@ async function preloadBatchOrThrow(batch, loadManager, persistence, config, inde
|
|
|
110
110
|
let itemIdx = 0;
|
|
111
111
|
for (let checkpointIdx = 0, checkpointIdx_finish = batch.checkpointIds.length; checkpointIdx < checkpointIdx_finish; ++checkpointIdx) {
|
|
112
112
|
let checkpointId = batch.checkpointIds[checkpointIdx];
|
|
113
|
-
let
|
|
114
|
-
for (let idx = 0; idx <
|
|
113
|
+
let checkpointItemsCount = batch.checkpointItemsCount[checkpointIdx];
|
|
114
|
+
for (let idx = 0; idx < checkpointItemsCount; ++idx) {
|
|
115
115
|
let item = batch.items[itemIdx + idx | 0];
|
|
116
116
|
if (item.kind === 0) {
|
|
117
117
|
let match = item.onEventRegistration;
|
|
@@ -158,7 +158,7 @@ async function preloadBatchOrThrow(batch, loadManager, persistence, config, inde
|
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
|
-
itemIdx = itemIdx +
|
|
161
|
+
itemIdx = itemIdx + checkpointItemsCount | 0;
|
|
162
162
|
}
|
|
163
163
|
await Promise.all(promises);
|
|
164
164
|
}
|
|
@@ -167,12 +167,12 @@ async function runBatchHandlersOrThrow(batch, indexerState, loadManager, persist
|
|
|
167
167
|
let itemIdx = 0;
|
|
168
168
|
for (let checkpointIdx = 0, checkpointIdx_finish = batch.checkpointIds.length; checkpointIdx < checkpointIdx_finish; ++checkpointIdx) {
|
|
169
169
|
let checkpointId = batch.checkpointIds[checkpointIdx];
|
|
170
|
-
let
|
|
171
|
-
for (let idx = 0; idx <
|
|
170
|
+
let checkpointItemsCount = batch.checkpointItemsCount[checkpointIdx];
|
|
171
|
+
for (let idx = 0; idx < checkpointItemsCount; ++idx) {
|
|
172
172
|
let item = batch.items[itemIdx + idx | 0];
|
|
173
173
|
await runHandlerOrThrow(item, checkpointId, indexerState, loadManager, persistence, config, chains);
|
|
174
174
|
}
|
|
175
|
-
itemIdx = itemIdx +
|
|
175
|
+
itemIdx = itemIdx + checkpointItemsCount | 0;
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
|
package/src/FetchState.res
CHANGED
|
@@ -979,6 +979,20 @@ let compareBufferItem = (a: Internal.item, b: Internal.item): int => {
|
|
|
979
979
|
}
|
|
980
980
|
}
|
|
981
981
|
|
|
982
|
+
// Whether two adjacent buffer items came from one log routed to two
|
|
983
|
+
// registrations: everything `compareBufferItem` orders on except the
|
|
984
|
+
// registration index is equal. Only meaningful on neighbours of a sorted
|
|
985
|
+
// buffer, where such items sit next to each other.
|
|
986
|
+
let isSameLog = (a: Internal.item, b: Internal.item): bool =>
|
|
987
|
+
a->Internal.getItemKind === 0 &&
|
|
988
|
+
b->Internal.getItemKind === 0 &&
|
|
989
|
+
a->Internal.getItemBlockNumber === b->Internal.getItemBlockNumber &&
|
|
990
|
+
a->Internal.getItemLogIndex === b->Internal.getItemLogIndex &&
|
|
991
|
+
switch (a->Internal.getItemOrderPath, b->Internal.getItemOrderPath) {
|
|
992
|
+
| (Value(pa), Value(pb)) => comparePath(pa, pb) === 0
|
|
993
|
+
| _ => true
|
|
994
|
+
}
|
|
995
|
+
|
|
982
996
|
// Merge a maybe-unsorted `newItems` run into the already-sorted, already-deduped
|
|
983
997
|
// `buffer`, dropping items equal on every component of `compareBufferItem`.
|
|
984
998
|
// Single linear pass over both runs after ordering `newItems` in place; every
|
package/src/FetchState.res.mjs
CHANGED
|
@@ -795,6 +795,19 @@ function compareBufferItem(a, b) {
|
|
|
795
795
|
}
|
|
796
796
|
}
|
|
797
797
|
|
|
798
|
+
function isSameLog(a, b) {
|
|
799
|
+
if (a.kind !== 0 || b.kind !== 0 || a.blockNumber !== b.blockNumber || a.logIndex !== b.logIndex) {
|
|
800
|
+
return false;
|
|
801
|
+
}
|
|
802
|
+
let match = a.orderPath;
|
|
803
|
+
let match$1 = b.orderPath;
|
|
804
|
+
if ((match == null) || (match$1 == null)) {
|
|
805
|
+
return true;
|
|
806
|
+
} else {
|
|
807
|
+
return comparePath(match, match$1) === 0;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
|
|
798
811
|
function mergeIntoBuffer(buffer, newItems) {
|
|
799
812
|
let n = newItems.length;
|
|
800
813
|
for (let i = 1; i < n; ++i) {
|
|
@@ -2113,6 +2126,7 @@ export {
|
|
|
2113
2126
|
comparePath,
|
|
2114
2127
|
compareTiebreak,
|
|
2115
2128
|
compareBufferItem,
|
|
2129
|
+
isSameLog,
|
|
2116
2130
|
mergeIntoBuffer,
|
|
2117
2131
|
appendOnBlockItems,
|
|
2118
2132
|
updateInternal,
|
package/src/FinalizeBackfill.res
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
// The FinalizingIndexes phase. Reached from the processing loop when
|
|
2
|
-
//
|
|
3
|
-
// pending writes are flushed, then storage builds every
|
|
4
|
-
//
|
|
5
|
-
// leaves the indexes built so far in place and
|
|
6
|
-
// error boundary; the retry only owes what's left.
|
|
7
|
-
// reports ready with an index the schema promised
|
|
1
|
+
// The FinalizingIndexes phase. Reached from the processing loop when the chains
|
|
2
|
+
// this process drives have caught up: processing is already paused (the loop
|
|
3
|
+
// awaits this), pending writes are flushed, then storage builds every index the
|
|
4
|
+
// schema promises for those chains and, once they all verify, commits their
|
|
5
|
+
// `ready_at`. A failure part-way leaves the indexes built so far in place and
|
|
6
|
+
// reaches the processing loop's error boundary; the retry only owes what's left.
|
|
7
|
+
// Either way a chain never reports ready with an index the schema promised for
|
|
8
|
+
// it still missing.
|
|
9
|
+
//
|
|
10
|
+
// A chain's rows live in a partition of its own, so this touches nothing another
|
|
11
|
+
// `envio start --chain` process is indexing and never waits on one.
|
|
8
12
|
|
|
9
13
|
let runOnce = async (state: IndexerState.t) => {
|
|
10
14
|
Logging.info(
|
|
@@ -22,10 +26,7 @@ let runOnce = async (state: IndexerState.t) => {
|
|
|
22
26
|
|
|
23
27
|
await storage.finalizeBackfill(
|
|
24
28
|
~entities=persistence.allEntities,
|
|
25
|
-
~chainIds=state
|
|
26
|
-
->IndexerState.chainStates
|
|
27
|
-
->Dict.valuesToArray
|
|
28
|
-
->Array.map(cs => (cs->ChainState.chainConfig).id),
|
|
29
|
+
~chainIds=state->IndexerState.crossChainState->CrossChainState.chainIds,
|
|
29
30
|
~readyAt,
|
|
30
31
|
)
|
|
31
32
|
|
|
@@ -57,5 +58,8 @@ let run = (state: IndexerState.t) =>
|
|
|
57
58
|
let repairSchemaIndexes = (state: IndexerState.t) => {
|
|
58
59
|
let persistence = state->IndexerState.persistence
|
|
59
60
|
let storage = persistence->Persistence.getInitializedStorageOrThrow
|
|
60
|
-
storage.ensureSchemaIndexes(
|
|
61
|
+
storage.ensureSchemaIndexes(
|
|
62
|
+
~entities=persistence.allEntities,
|
|
63
|
+
~chainIds=state->IndexerState.crossChainState->CrossChainState.chainIds,
|
|
64
|
+
)
|
|
61
65
|
}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Logging from "./Logging.res.mjs";
|
|
4
4
|
import * as Writing from "./Writing.res.mjs";
|
|
5
|
-
import * as ChainState from "./ChainState.res.mjs";
|
|
6
5
|
import * as Persistence from "./Persistence.res.mjs";
|
|
7
6
|
import * as IndexerState from "./IndexerState.res.mjs";
|
|
7
|
+
import * as CrossChainState from "./CrossChainState.res.mjs";
|
|
8
8
|
|
|
9
9
|
async function runOnce(state) {
|
|
10
10
|
Logging.info("All chains are caught up. Finalizing the indexer before switching to realtime: flushing pending writes, then creating the indexes the schema promises.");
|
|
@@ -15,7 +15,7 @@ async function runOnce(state) {
|
|
|
15
15
|
let persistence = IndexerState.persistence(state);
|
|
16
16
|
let storage = Persistence.getInitializedStorageOrThrow(persistence);
|
|
17
17
|
let readyAt = new Date();
|
|
18
|
-
await storage.finalizeBackfill(persistence.allEntities,
|
|
18
|
+
await storage.finalizeBackfill(persistence.allEntities, CrossChainState.chainIds(IndexerState.crossChainState(state)), readyAt);
|
|
19
19
|
IndexerState.markReady(state, readyAt);
|
|
20
20
|
return Logging.info("The indexer is ready. Switching to realtime indexing.");
|
|
21
21
|
}
|
|
@@ -33,7 +33,7 @@ function run(state) {
|
|
|
33
33
|
function repairSchemaIndexes(state) {
|
|
34
34
|
let persistence = IndexerState.persistence(state);
|
|
35
35
|
let storage = Persistence.getInitializedStorageOrThrow(persistence);
|
|
36
|
-
return storage.ensureSchemaIndexes(persistence.allEntities);
|
|
36
|
+
return storage.ensureSchemaIndexes(persistence.allEntities, CrossChainState.chainIds(IndexerState.crossChainState(state)));
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export {
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Whether each chain's rows get history on a write, keyed by chain id. History
|
|
2
|
+
// is only ever kept for what a rollback could reach: under one shared sequence
|
|
3
|
+
// any chain's rollback reaches every chain's rows, so the run decides together;
|
|
4
|
+
// with a counter per chain only the group's own chain can reach its rows.
|
|
5
|
+
type t = dict<bool>
|
|
6
|
+
|
|
7
|
+
%%private(
|
|
8
|
+
let anyChainSaves = (shouldSaveHistory: dict<bool>) =>
|
|
9
|
+
shouldSaveHistory->Dict.valuesToArray->Array.some(saves => saves)
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
let decide = (config: Config.t, ~shouldSaveHistory: dict<bool>): t =>
|
|
13
|
+
if config.shouldSaveFullHistory {
|
|
14
|
+
shouldSaveHistory->Utils.Dict.mapValues(_ => true)
|
|
15
|
+
} else {
|
|
16
|
+
switch config.checkpointSequence {
|
|
17
|
+
| SharedAcrossChains =>
|
|
18
|
+
let saves = shouldSaveHistory->anyChainSaves
|
|
19
|
+
shouldSaveHistory->Utils.Dict.mapValues(_ => saves)
|
|
20
|
+
| PerChain => shouldSaveHistory
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Every chain the run indexes was decided for, so an absent one is a bug —
|
|
25
|
+
// answering `false` for it would silently leave the chain with nothing to roll
|
|
26
|
+
// back to.
|
|
27
|
+
let forChain = (t: t, chainId: ChainId.t): bool =>
|
|
28
|
+
switch t->ChainId.Dict.dangerouslyGetNonOption(chainId) {
|
|
29
|
+
| Some(saves) => saves
|
|
30
|
+
| None =>
|
|
31
|
+
JsError.throwWithMessage(
|
|
32
|
+
`Internal error: no history decision for chain ${chainId->ChainId.toString}. The policy is decided for every chain the run indexes.`,
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// A cross-chain group's rows are reachable by any chain's rollback.
|
|
37
|
+
let forScope = (t: t, ~scope: Internal.chainScope): bool =>
|
|
38
|
+
switch scope {
|
|
39
|
+
| Chain(chainId) => t->forChain(chainId)
|
|
40
|
+
| CrossChain => t->anyChainSaves
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Whether a run has stale history to prune at all: history it keeps but doesn't
|
|
44
|
+
// keep forever.
|
|
45
|
+
let mayPrune = (config: Config.t, ~shouldSaveHistory: dict<bool>) =>
|
|
46
|
+
!config.shouldSaveFullHistory && shouldSaveHistory->anyChainSaves
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Utils from "./Utils.res.mjs";
|
|
4
|
+
import * as ChainId from "./ChainId.res.mjs";
|
|
5
|
+
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
6
|
+
|
|
7
|
+
function decide(config, shouldSaveHistory) {
|
|
8
|
+
if (config.shouldSaveFullHistory) {
|
|
9
|
+
return Utils.Dict.mapValues(shouldSaveHistory, param => true);
|
|
10
|
+
}
|
|
11
|
+
let match = config.checkpointSequence;
|
|
12
|
+
if (match !== "SharedAcrossChains") {
|
|
13
|
+
return shouldSaveHistory;
|
|
14
|
+
}
|
|
15
|
+
let saves = Object.values(shouldSaveHistory).some(saves => saves);
|
|
16
|
+
return Utils.Dict.mapValues(shouldSaveHistory, param => saves);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function forChain(t, chainId) {
|
|
20
|
+
let saves = t[chainId];
|
|
21
|
+
if (saves !== undefined) {
|
|
22
|
+
return saves;
|
|
23
|
+
} else {
|
|
24
|
+
return Stdlib_JsError.throwWithMessage(`Internal error: no history decision for chain ` + ChainId.toString(chainId) + `. The policy is decided for every chain the run indexes.`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function forScope(t, scope) {
|
|
29
|
+
if (scope === "crossChain") {
|
|
30
|
+
return Object.values(t).some(saves => saves);
|
|
31
|
+
} else {
|
|
32
|
+
return forChain(t, scope);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function mayPrune(config, shouldSaveHistory) {
|
|
37
|
+
if (config.shouldSaveFullHistory) {
|
|
38
|
+
return false;
|
|
39
|
+
} else {
|
|
40
|
+
return Object.values(shouldSaveHistory).some(saves => saves);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export {
|
|
45
|
+
decide,
|
|
46
|
+
forChain,
|
|
47
|
+
forScope,
|
|
48
|
+
mayPrune,
|
|
49
|
+
}
|
|
50
|
+
/* Utils Not a pure module */
|
package/src/InMemoryStore.res
CHANGED
|
@@ -49,10 +49,7 @@ let getEffectInMemTable = (
|
|
|
49
49
|
) => state->IndexerState.effectState->EffectState.getTable(~effect, ~scope)
|
|
50
50
|
|
|
51
51
|
let hasEffectOutput = (inMemTable: EffectState.effectCacheInMemTable, key) =>
|
|
52
|
-
|
|
53
|
-
| Some(Set(_)) => true
|
|
54
|
-
| Some(Delete(_)) | None => false
|
|
55
|
-
}
|
|
52
|
+
inMemTable.dict->Utils.Dict.dangerouslyGetNonOption(key)->Option.isSome
|
|
56
53
|
|
|
57
54
|
// Returns the raw output. The output is itself an option for effects with an
|
|
58
55
|
// optional output, so it must never be wrapped in another option here: Some(None)
|
|
@@ -62,14 +59,15 @@ let getEffectOutputUnsafe = (
|
|
|
62
59
|
key,
|
|
63
60
|
): Internal.effectOutput =>
|
|
64
61
|
switch inMemTable.dict->Utils.Dict.dangerouslyGetNonOption(key) {
|
|
65
|
-
| Some(
|
|
66
|
-
|
|
|
62
|
+
| Some({output}) => output
|
|
63
|
+
| None => %raw(`undefined`)
|
|
67
64
|
}
|
|
68
65
|
|
|
69
66
|
// Records a handler output. Persisted on the next write only when shouldCache;
|
|
70
67
|
// otherwise kept in memory (re-run on a later miss) but never written to the db.
|
|
71
68
|
let setEffectOutput = (
|
|
72
69
|
inMemTable: EffectState.effectCacheInMemTable,
|
|
70
|
+
~chainId,
|
|
73
71
|
~checkpointId,
|
|
74
72
|
~cacheKey,
|
|
75
73
|
~output,
|
|
@@ -79,10 +77,7 @@ let setEffectOutput = (
|
|
|
79
77
|
| Some(_) => ()
|
|
80
78
|
| None => inMemTable.changesCount = inMemTable.changesCount +. 1.
|
|
81
79
|
}
|
|
82
|
-
inMemTable.dict->Dict.set(
|
|
83
|
-
cacheKey,
|
|
84
|
-
Set({entityId: cacheKey->EntityId.unsafeOfString, entity: output, checkpointId}),
|
|
85
|
-
)
|
|
80
|
+
inMemTable.dict->Dict.set(cacheKey, {output, chainId, checkpointId})
|
|
86
81
|
if shouldCache {
|
|
87
82
|
inMemTable.idsToStore->Array.push(cacheKey)->ignore
|
|
88
83
|
}
|
|
@@ -90,16 +85,17 @@ let setEffectOutput = (
|
|
|
90
85
|
|
|
91
86
|
// Seeds an entry from a db read. Stamped with loadedFromDbCheckpointId so it's
|
|
92
87
|
// always droppable (re-readable from the db) and never re-persisted.
|
|
93
|
-
let initEffectOutputFromDb = (
|
|
88
|
+
let initEffectOutputFromDb = (
|
|
89
|
+
inMemTable: EffectState.effectCacheInMemTable,
|
|
90
|
+
~chainId,
|
|
91
|
+
~cacheKey,
|
|
92
|
+
~output,
|
|
93
|
+
) =>
|
|
94
94
|
if inMemTable.dict->Utils.Dict.dangerouslyGetNonOption(cacheKey)->Option.isNone {
|
|
95
95
|
inMemTable.changesCount = inMemTable.changesCount +. 1.
|
|
96
96
|
inMemTable.dict->Dict.set(
|
|
97
97
|
cacheKey,
|
|
98
|
-
|
|
99
|
-
entityId: cacheKey->EntityId.unsafeOfString,
|
|
100
|
-
entity: output,
|
|
101
|
-
checkpointId: Internal.loadedFromDbCheckpointId,
|
|
102
|
-
}),
|
|
98
|
+
{output, chainId, checkpointId: Internal.loadedFromDbCheckpointId},
|
|
103
99
|
)
|
|
104
100
|
}
|
|
105
101
|
|
|
@@ -108,14 +104,13 @@ let initEffectOutputFromDb = (inMemTable: EffectState.effectCacheInMemTable, ~ca
|
|
|
108
104
|
// seeded from a db read are spared. Mirrors entity dropCommittedChanges.
|
|
109
105
|
let dropCommittedEffects = (
|
|
110
106
|
inMemTable: EffectState.effectCacheInMemTable,
|
|
111
|
-
~
|
|
107
|
+
~committedFrontier: Frontier.t,
|
|
112
108
|
~keepLoadedFromDb,
|
|
113
109
|
) => {
|
|
114
110
|
let keysToDelete = []
|
|
115
|
-
inMemTable.dict->Utils.Dict.forEachWithKey((
|
|
116
|
-
let checkpointId = change->Change.getCheckpointId
|
|
111
|
+
inMemTable.dict->Utils.Dict.forEachWithKey(({chainId, checkpointId}, key) => {
|
|
117
112
|
if (
|
|
118
|
-
!(checkpointId >
|
|
113
|
+
!(checkpointId > committedFrontier->Frontier.get(chainId)) &&
|
|
119
114
|
!(keepLoadedFromDb && checkpointId == Internal.loadedFromDbCheckpointId)
|
|
120
115
|
) {
|
|
121
116
|
keysToDelete->Array.push(key)
|
|
@@ -128,18 +123,21 @@ let dropCommittedEffects = (
|
|
|
128
123
|
let prepareRollbackDiff = async (
|
|
129
124
|
state: IndexerState.t,
|
|
130
125
|
~floors: RollbackFloors.t,
|
|
131
|
-
~rollbackDiffCheckpointId,
|
|
132
126
|
~progressedChains,
|
|
133
127
|
~rolledBackAddresses,
|
|
134
128
|
) => {
|
|
135
|
-
|
|
136
|
-
~
|
|
137
|
-
~floors,
|
|
138
|
-
~progressedChains,
|
|
139
|
-
~rolledBackAddresses,
|
|
140
|
-
)
|
|
129
|
+
let diffFrontier =
|
|
130
|
+
state->IndexerState.beginRollbackDiff(~floors, ~progressedChains, ~rolledBackAddresses)
|
|
141
131
|
let persistence = state->IndexerState.persistence
|
|
142
|
-
let
|
|
132
|
+
let sequence = (state->IndexerState.config).checkpointSequence
|
|
133
|
+
let diffCheckpointId = scope =>
|
|
134
|
+
switch sequence->CheckpointSequence.findForScope(diffFrontier, ~scope) {
|
|
135
|
+
| Some(checkpointId) => checkpointId
|
|
136
|
+
| None =>
|
|
137
|
+
JsError.throwWithMessage(
|
|
138
|
+
"Internal error: the rollback returned rows for a chain its diff never moved.",
|
|
139
|
+
)
|
|
140
|
+
}
|
|
143
141
|
|
|
144
142
|
let deletedEntities = Dict.make()
|
|
145
143
|
let setEntities = Dict.make()
|
|
@@ -160,10 +158,10 @@ let prepareRollbackDiff = async (
|
|
|
160
158
|
state
|
|
161
159
|
->getInMemTable(~entityConfig, ~scope)
|
|
162
160
|
->InMemoryTable.Entity.set(
|
|
163
|
-
~committedCheckpointId,
|
|
161
|
+
~committedCheckpointId=state->IndexerState.committedCheckpointIdFor(~scope),
|
|
164
162
|
Delete({
|
|
165
163
|
entityId,
|
|
166
|
-
checkpointId:
|
|
164
|
+
checkpointId: diffCheckpointId(scope),
|
|
167
165
|
}),
|
|
168
166
|
)
|
|
169
167
|
})
|
|
@@ -174,10 +172,10 @@ let prepareRollbackDiff = async (
|
|
|
174
172
|
state
|
|
175
173
|
->getInMemTable(~entityConfig, ~scope)
|
|
176
174
|
->InMemoryTable.Entity.set(
|
|
177
|
-
~committedCheckpointId,
|
|
175
|
+
~committedCheckpointId=state->IndexerState.committedCheckpointIdFor(~scope),
|
|
178
176
|
Set({
|
|
179
177
|
entityId: entity.id->EntityId.unsafeOfString,
|
|
180
|
-
checkpointId:
|
|
178
|
+
checkpointId: diffCheckpointId(scope),
|
|
181
179
|
entity,
|
|
182
180
|
}),
|
|
183
181
|
)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Table from "./db/Table.res.mjs";
|
|
4
4
|
import * as Utils from "./Utils.res.mjs";
|
|
5
|
+
import * as Frontier from "./db/Frontier.res.mjs";
|
|
5
6
|
import * as Internal from "./Internal.res.mjs";
|
|
6
7
|
import * as ChainState from "./ChainState.res.mjs";
|
|
7
8
|
import * as EffectState from "./EffectState.res.mjs";
|
|
@@ -11,6 +12,7 @@ import * as InMemoryTable from "./InMemoryTable.res.mjs";
|
|
|
11
12
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
12
13
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
13
14
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
15
|
+
import * as CheckpointSequence from "./db/CheckpointSequence.res.mjs";
|
|
14
16
|
|
|
15
17
|
function getInMemTable(state, entityConfig, scope) {
|
|
16
18
|
let tmp;
|
|
@@ -45,23 +47,19 @@ function getEffectInMemTable(state, effect, scope) {
|
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
function hasEffectOutput(inMemTable, key) {
|
|
48
|
-
|
|
49
|
-
if (match !== undefined) {
|
|
50
|
-
return match.type === "SET";
|
|
51
|
-
} else {
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
50
|
+
return Stdlib_Option.isSome(inMemTable.dict[key]);
|
|
54
51
|
}
|
|
55
52
|
|
|
56
53
|
function getEffectOutputUnsafe(inMemTable, key) {
|
|
57
54
|
let match = inMemTable.dict[key];
|
|
58
|
-
if (match !== undefined
|
|
59
|
-
return match.
|
|
55
|
+
if (match !== undefined) {
|
|
56
|
+
return match.output;
|
|
57
|
+
} else {
|
|
58
|
+
return undefined;
|
|
60
59
|
}
|
|
61
|
-
return undefined;
|
|
62
60
|
}
|
|
63
61
|
|
|
64
|
-
function setEffectOutput(inMemTable, checkpointId, cacheKey, output, shouldCache) {
|
|
62
|
+
function setEffectOutput(inMemTable, chainId, checkpointId, cacheKey, output, shouldCache) {
|
|
65
63
|
let match = inMemTable.dict[cacheKey];
|
|
66
64
|
if (match !== undefined) {
|
|
67
65
|
|
|
@@ -69,9 +67,8 @@ function setEffectOutput(inMemTable, checkpointId, cacheKey, output, shouldCache
|
|
|
69
67
|
inMemTable.changesCount = inMemTable.changesCount + 1;
|
|
70
68
|
}
|
|
71
69
|
inMemTable.dict[cacheKey] = {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
entity: output,
|
|
70
|
+
output: output,
|
|
71
|
+
chainId: chainId,
|
|
75
72
|
checkpointId: checkpointId
|
|
76
73
|
};
|
|
77
74
|
if (shouldCache) {
|
|
@@ -80,24 +77,23 @@ function setEffectOutput(inMemTable, checkpointId, cacheKey, output, shouldCache
|
|
|
80
77
|
}
|
|
81
78
|
}
|
|
82
79
|
|
|
83
|
-
function initEffectOutputFromDb(inMemTable, cacheKey, output) {
|
|
80
|
+
function initEffectOutputFromDb(inMemTable, chainId, cacheKey, output) {
|
|
84
81
|
if (Stdlib_Option.isNone(inMemTable.dict[cacheKey])) {
|
|
85
82
|
inMemTable.changesCount = inMemTable.changesCount + 1;
|
|
86
83
|
inMemTable.dict[cacheKey] = {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
entity: output,
|
|
84
|
+
output: output,
|
|
85
|
+
chainId: chainId,
|
|
90
86
|
checkpointId: Internal.loadedFromDbCheckpointId
|
|
91
87
|
};
|
|
92
88
|
return;
|
|
93
89
|
}
|
|
94
90
|
}
|
|
95
91
|
|
|
96
|
-
function dropCommittedEffects(inMemTable,
|
|
92
|
+
function dropCommittedEffects(inMemTable, committedFrontier, keepLoadedFromDb) {
|
|
97
93
|
let keysToDelete = [];
|
|
98
|
-
Utils.Dict.forEachWithKey(inMemTable.dict, (
|
|
99
|
-
let checkpointId =
|
|
100
|
-
if (checkpointId <=
|
|
94
|
+
Utils.Dict.forEachWithKey(inMemTable.dict, (param, key) => {
|
|
95
|
+
let checkpointId = param.checkpointId;
|
|
96
|
+
if (checkpointId <= Frontier.get(committedFrontier, param.chainId) && !(keepLoadedFromDb && checkpointId === Internal.loadedFromDbCheckpointId)) {
|
|
101
97
|
keysToDelete.push(key);
|
|
102
98
|
return;
|
|
103
99
|
}
|
|
@@ -106,31 +102,40 @@ function dropCommittedEffects(inMemTable, committedCheckpointId, keepLoadedFromD
|
|
|
106
102
|
inMemTable.changesCount = inMemTable.changesCount - keysToDelete.length;
|
|
107
103
|
}
|
|
108
104
|
|
|
109
|
-
async function prepareRollbackDiff(state, floors,
|
|
110
|
-
IndexerState.beginRollbackDiff(state,
|
|
105
|
+
async function prepareRollbackDiff(state, floors, progressedChains, rolledBackAddresses) {
|
|
106
|
+
let diffFrontier = IndexerState.beginRollbackDiff(state, floors, progressedChains, rolledBackAddresses);
|
|
111
107
|
let persistence = IndexerState.persistence(state);
|
|
112
|
-
let
|
|
108
|
+
let sequence = IndexerState.config(state).checkpointSequence;
|
|
109
|
+
let diffCheckpointId = scope => {
|
|
110
|
+
let checkpointId = CheckpointSequence.findForScope(sequence, diffFrontier, scope);
|
|
111
|
+
if (checkpointId !== undefined) {
|
|
112
|
+
return checkpointId;
|
|
113
|
+
} else {
|
|
114
|
+
return Stdlib_JsError.throwWithMessage("Internal error: the rollback returned rows for a chain its diff never moved.");
|
|
115
|
+
}
|
|
116
|
+
};
|
|
113
117
|
let deletedEntities = {};
|
|
114
118
|
let setEntities = {};
|
|
115
119
|
await Promise.all(persistence.allEntities.filter(entityConfig => entityConfig.storage.postgres).map(async entityConfig => {
|
|
116
120
|
let match = await persistence.storage.getRollbackData(entityConfig, floors);
|
|
117
121
|
match[0].forEach(param => {
|
|
122
|
+
let scope = param.scope;
|
|
118
123
|
let entityId = param.entityId;
|
|
119
124
|
Utils.Dict.push(deletedEntities, entityConfig.name, entityId);
|
|
120
|
-
InMemoryTable.Entity.set(getInMemTable(state, entityConfig,
|
|
125
|
+
InMemoryTable.Entity.set(getInMemTable(state, entityConfig, scope), IndexerState.committedCheckpointIdFor(state, scope), {
|
|
121
126
|
type: "DELETE",
|
|
122
127
|
entityId: entityId,
|
|
123
|
-
checkpointId:
|
|
128
|
+
checkpointId: diffCheckpointId(scope)
|
|
124
129
|
});
|
|
125
130
|
});
|
|
126
131
|
match[1].forEach(entity => {
|
|
127
132
|
let scope = takeRowScope(entity, entityConfig);
|
|
128
133
|
Utils.Dict.push(setEntities, entityConfig.name, entity.id);
|
|
129
|
-
InMemoryTable.Entity.set(getInMemTable(state, entityConfig, scope),
|
|
134
|
+
InMemoryTable.Entity.set(getInMemTable(state, entityConfig, scope), IndexerState.committedCheckpointIdFor(state, scope), {
|
|
130
135
|
type: "SET",
|
|
131
136
|
entityId: entity.id,
|
|
132
137
|
entity: entity,
|
|
133
|
-
checkpointId:
|
|
138
|
+
checkpointId: diffCheckpointId(scope)
|
|
134
139
|
});
|
|
135
140
|
});
|
|
136
141
|
}));
|