envio 3.11.0 → 3.12.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/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/ChainFetching.res +7 -3
- package/src/ChainFetching.res.mjs +1 -1
- package/src/ChainState.res +82 -20
- package/src/ChainState.res.mjs +51 -13
- package/src/ChainState.resi +6 -1
- package/src/Config.res +58 -37
- package/src/Config.res.mjs +63 -53
- package/src/CrossChainState.res +50 -53
- 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 +65 -46
- package/src/FetchState.res.mjs +68 -36
- 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/InMemoryTable.res +155 -67
- package/src/InMemoryTable.res.mjs +151 -60
- 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 +68 -38
- package/src/LoadLayer.res.mjs +50 -64
- package/src/LoadLayer.resi +1 -1
- 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 +286 -180
- package/src/PgStorage.res.mjs +209 -122
- 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 +14 -30
- package/src/TestIndexer.res.mjs +11 -9
- package/src/UserContext.res +20 -36
- package/src/UserContext.res.mjs +6 -9
- package/src/Utils.res +10 -4
- package/src/Utils.res.mjs +16 -16
- 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/EntityFilter.res +487 -275
- package/src/db/EntityFilter.res.mjs +557 -309
- 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/db/Table.res +21 -6
- package/src/db/Table.res.mjs +13 -4
- package/src/sources/BlockStore.res +8 -0
- package/src/sources/EvmHyperSyncSource.res +5 -1
- package/src/sources/EvmHyperSyncSource.res.mjs +4 -3
- package/src/sources/FuelHyperSyncSource.res +1 -0
- package/src/sources/FuelHyperSyncSource.res.mjs +1 -1
- package/src/sources/HyperSync.res +6 -0
- package/src/sources/HyperSync.res.mjs +5 -2
- package/src/sources/HyperSync.resi +2 -0
- package/src/sources/HyperSyncClient.res +6 -0
- package/src/sources/HyperSyncSSE.res +1 -1
- package/src/sources/HyperSyncSSE.res.mjs +4 -10
- package/src/sources/RequestStat.res +8 -1
- package/src/sources/RpcSource.res +1 -0
- package/src/sources/RpcSource.res.mjs +1 -1
- package/src/sources/SimulateSource.res +1 -0
- package/src/sources/SimulateSource.res.mjs +1 -1
- package/src/sources/Source.res +11 -3
- package/src/sources/SourceManager.res +34 -13
- package/src/sources/SourceManager.res.mjs +26 -9
- package/src/sources/SourceManager.resi +2 -0
- package/src/sources/SvmHyperSyncClient.res +5 -0
- package/src/sources/SvmHyperSyncSource.res +3 -0
- package/src/sources/SvmHyperSyncSource.res.mjs +4 -2
- 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
|
@@ -6,8 +6,10 @@ import * as Utils from "./Utils.res.mjs";
|
|
|
6
6
|
import * as Logging from "./Logging.res.mjs";
|
|
7
7
|
import * as ChainState from "./ChainState.res.mjs";
|
|
8
8
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
9
|
+
import * as HistoryPolicy from "./HistoryPolicy.res.mjs";
|
|
9
10
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
10
11
|
import * as Primitive_float from "@rescript/runtime/lib/es6/Primitive_float.js";
|
|
12
|
+
import * as CheckpointSequence from "./db/CheckpointSequence.res.mjs";
|
|
11
13
|
import * as SafeCheckpointTracking from "./SafeCheckpointTracking.res.mjs";
|
|
12
14
|
|
|
13
15
|
function calculateTargetBufferSize() {
|
|
@@ -18,7 +20,7 @@ function calculateTargetBufferSize() {
|
|
|
18
20
|
}
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
function make(chainStates,
|
|
23
|
+
function make(chainStates, isRealtime, targetBufferSizeOpt) {
|
|
22
24
|
let targetBufferSize = targetBufferSizeOpt !== undefined ? targetBufferSizeOpt : (
|
|
23
25
|
Env.targetBufferSize !== undefined ? Env.targetBufferSize : 100000
|
|
24
26
|
);
|
|
@@ -27,7 +29,6 @@ function make(chainStates, isInReorgThreshold, isRealtime, targetBufferSizeOpt)
|
|
|
27
29
|
chainIds: Object.values(chainStates).map(cs => ChainState.chainConfig(cs).id),
|
|
28
30
|
isRealtime: isRealtime,
|
|
29
31
|
isCaughtUp: isRealtime,
|
|
30
|
-
isInReorgThreshold: isInReorgThreshold,
|
|
31
32
|
targetBufferSize: targetBufferSize
|
|
32
33
|
};
|
|
33
34
|
}
|
|
@@ -40,18 +41,31 @@ function isRealtime(crossChainState) {
|
|
|
40
41
|
return crossChainState.isRealtime;
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
function chainIds(crossChainState) {
|
|
45
|
+
return crossChainState.chainIds;
|
|
46
|
+
}
|
|
47
|
+
|
|
43
48
|
function isCaughtUp(crossChainState) {
|
|
44
49
|
return crossChainState.isCaughtUp;
|
|
45
50
|
}
|
|
46
51
|
|
|
47
52
|
function isInReorgThreshold(crossChainState) {
|
|
48
|
-
|
|
53
|
+
let chainStates = Object.values(crossChainState.chainStates);
|
|
54
|
+
if (Utils.$$Array.notEmpty(chainStates)) {
|
|
55
|
+
return chainStates.every(ChainState.isInReorgThreshold);
|
|
56
|
+
} else {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
49
59
|
}
|
|
50
60
|
|
|
51
61
|
function targetBufferSize(crossChainState) {
|
|
52
62
|
return crossChainState.targetBufferSize;
|
|
53
63
|
}
|
|
54
64
|
|
|
65
|
+
function shouldSaveHistory(crossChainState) {
|
|
66
|
+
return Utils.Dict.mapValues(crossChainState.chainStates, ChainState.shouldSaveHistory);
|
|
67
|
+
}
|
|
68
|
+
|
|
55
69
|
function totalReadyCount(crossChainState) {
|
|
56
70
|
let total = 0;
|
|
57
71
|
for (let i = 0, i_finish = crossChainState.chainIds.length; i < i_finish; ++i) {
|
|
@@ -65,21 +79,19 @@ function nextItemIsNone(crossChainState) {
|
|
|
65
79
|
return !Object.values(crossChainState.chainStates).some(ChainState.hasReadyItem);
|
|
66
80
|
}
|
|
67
81
|
|
|
68
|
-
function getSafeCheckpointIdByChain(crossChainState,
|
|
82
|
+
function getSafeCheckpointIdByChain(crossChainState, sequence, committedFrontier) {
|
|
69
83
|
return crossChainState.chainIds.map(chainId => {
|
|
70
84
|
let cs = crossChainState.chainStates[chainId];
|
|
71
85
|
let tracking = ChainState.safeCheckpointTracking(cs);
|
|
72
86
|
return [
|
|
73
87
|
chainId,
|
|
74
|
-
tracking !== undefined ? SafeCheckpointTracking.getSafeCheckpointId(tracking, ChainState.knownHeight(cs)) :
|
|
88
|
+
tracking !== undefined ? SafeCheckpointTracking.getSafeCheckpointId(tracking, ChainState.knownHeight(cs)) : CheckpointSequence.position(sequence, committedFrontier, chainId)
|
|
75
89
|
];
|
|
76
90
|
});
|
|
77
91
|
}
|
|
78
92
|
|
|
79
|
-
function createBatch(crossChainState,
|
|
80
|
-
return Batch.make(
|
|
81
|
-
isRollback ? 1n : 0n
|
|
82
|
-
), Utils.Dict.mapValues(crossChainState.chainStates, ChainState.toChainBeforeBatch), batchSizeTarget, crossChainState.isInReorgThreshold);
|
|
93
|
+
function createBatch(crossChainState, config, frontier, batchSizeTarget) {
|
|
94
|
+
return Batch.make(config.checkpointSequence, frontier, Utils.Dict.mapValues(crossChainState.chainStates, none => ChainState.toChainBeforeBatch(none, crossChainState.isRealtime)), batchSizeTarget, HistoryPolicy.decide(config, shouldSaveHistory(crossChainState)));
|
|
83
95
|
}
|
|
84
96
|
|
|
85
97
|
function enterReorgThreshold(crossChainState) {
|
|
@@ -87,7 +99,6 @@ function enterReorgThreshold(crossChainState) {
|
|
|
87
99
|
for (let i = 0, i_finish = crossChainState.chainIds.length; i < i_finish; ++i) {
|
|
88
100
|
ChainState.enterReorgThreshold(crossChainState.chainStates[crossChainState.chainIds[i]]);
|
|
89
101
|
}
|
|
90
|
-
crossChainState.isInReorgThreshold = true;
|
|
91
102
|
}
|
|
92
103
|
|
|
93
104
|
function applyBatchProgress(crossChainState, batch, blockTimestampName) {
|
|
@@ -101,13 +112,6 @@ function applyBatchProgress(crossChainState, batch, blockTimestampName) {
|
|
|
101
112
|
}
|
|
102
113
|
}
|
|
103
114
|
crossChainState.isCaughtUp = crossChainState.isCaughtUp || nextItemIsNone(crossChainState) && everyChainCaughtUp;
|
|
104
|
-
let allChainsReady = true;
|
|
105
|
-
for (let i$1 = 0, i_finish$1 = chainIds.length; i$1 < i_finish$1; ++i$1) {
|
|
106
|
-
if (!ChainState.isReady(crossChainState.chainStates[chainIds[i$1]])) {
|
|
107
|
-
allChainsReady = false;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
crossChainState.isRealtime = crossChainState.isRealtime || allChainsReady;
|
|
111
115
|
}
|
|
112
116
|
|
|
113
117
|
function isSettledAtHead(crossChainState) {
|
|
@@ -129,17 +133,13 @@ function markCaughtUpIfSettled(crossChainState) {
|
|
|
129
133
|
|
|
130
134
|
function markCaughtUpOnResume(crossChainState) {
|
|
131
135
|
let everyChainCaughtUp = crossChainState.chainIds.length !== 0;
|
|
132
|
-
let everyChainReady = true;
|
|
133
136
|
for (let i = 0, i_finish = crossChainState.chainIds.length; i < i_finish; ++i) {
|
|
134
137
|
let cs = crossChainState.chainStates[crossChainState.chainIds[i]];
|
|
135
138
|
if (!ChainState.isDurablyCaughtUp(cs)) {
|
|
136
139
|
everyChainCaughtUp = false;
|
|
137
140
|
}
|
|
138
|
-
if (!ChainState.isReady(cs)) {
|
|
139
|
-
everyChainReady = false;
|
|
140
|
-
}
|
|
141
141
|
}
|
|
142
|
-
if (everyChainCaughtUp && !
|
|
142
|
+
if (everyChainCaughtUp && !crossChainState.isRealtime && nextItemIsNone(crossChainState)) {
|
|
143
143
|
crossChainState.isCaughtUp = true;
|
|
144
144
|
return;
|
|
145
145
|
}
|
|
@@ -199,7 +199,7 @@ async function checkAndFetch(crossChainState, dispatchChain) {
|
|
|
199
199
|
let chainTargetItems = (
|
|
200
200
|
isCold ? Primitive_float.min(remaining.contents, minimumAdmissionBudget) : remaining.contents
|
|
201
201
|
) + ChainState.pendingBudget(cs);
|
|
202
|
-
let maxTargetBlock = alignment !== undefined && alignment[0] !== chainId ? ChainState.blockAtProgress(cs, alignment[1] + 0.
|
|
202
|
+
let maxTargetBlock = alignment !== undefined && alignment[0] !== chainId ? ChainState.blockAtProgress(cs, alignment[1] + 0.2) : undefined;
|
|
203
203
|
let action = ChainState.getNextQuery(cs, chainTargetItems, maxTargetBlock);
|
|
204
204
|
if (typeof action !== "object") {
|
|
205
205
|
if (action === "WaitingForNewBlock") {
|
|
@@ -249,9 +249,11 @@ export {
|
|
|
249
249
|
make,
|
|
250
250
|
chainStates,
|
|
251
251
|
isRealtime,
|
|
252
|
+
chainIds,
|
|
252
253
|
isCaughtUp,
|
|
253
254
|
isInReorgThreshold,
|
|
254
255
|
targetBufferSize,
|
|
256
|
+
shouldSaveHistory,
|
|
255
257
|
nextItemIsNone,
|
|
256
258
|
getSafeCheckpointIdByChain,
|
|
257
259
|
createBatch,
|
package/src/CrossChainState.resi
CHANGED
|
@@ -5,34 +5,27 @@ type t
|
|
|
5
5
|
|
|
6
6
|
let calculateTargetBufferSize: unit => int
|
|
7
7
|
|
|
8
|
-
let make: (
|
|
9
|
-
~chainStates: dict<ChainState.t>,
|
|
10
|
-
~isInReorgThreshold: bool,
|
|
11
|
-
~isRealtime: bool,
|
|
12
|
-
~targetBufferSize: int=?,
|
|
13
|
-
) => t
|
|
8
|
+
let make: (~chainStates: dict<ChainState.t>, ~isRealtime: bool, ~targetBufferSize: int=?) => t
|
|
14
9
|
|
|
15
10
|
// Accessors.
|
|
16
11
|
let chainStates: t => dict<ChainState.t>
|
|
17
12
|
let isRealtime: t => bool
|
|
13
|
+
let chainIds: t => array<ChainId.t>
|
|
18
14
|
let isCaughtUp: t => bool
|
|
19
15
|
let isInReorgThreshold: t => bool
|
|
20
16
|
let targetBufferSize: t => int
|
|
17
|
+
let shouldSaveHistory: t => dict<bool>
|
|
21
18
|
|
|
22
19
|
// Derived (pure).
|
|
23
20
|
let nextItemIsNone: t => bool
|
|
24
21
|
let getSafeCheckpointIdByChain: (
|
|
25
22
|
t,
|
|
26
|
-
~
|
|
23
|
+
~sequence: CheckpointSequence.t,
|
|
24
|
+
~committedFrontier: Frontier.t,
|
|
27
25
|
) => array<(ChainId.t, option<Internal.checkpointId>)>
|
|
28
26
|
|
|
29
27
|
// Cross-chain transitions.
|
|
30
|
-
let createBatch: (
|
|
31
|
-
t,
|
|
32
|
-
~processedCheckpointId: Internal.checkpointId,
|
|
33
|
-
~batchSizeTarget: int,
|
|
34
|
-
~isRollback: bool,
|
|
35
|
-
) => Batch.t
|
|
28
|
+
let createBatch: (t, ~config: Config.t, ~frontier: Frontier.t, ~batchSizeTarget: int) => Batch.t
|
|
36
29
|
let enterReorgThreshold: t => unit
|
|
37
30
|
let applyBatchProgress: (t, ~batch: Batch.t, ~blockTimestampName: string) => unit
|
|
38
31
|
let markCaughtUpIfSettled: t => unit
|
package/src/EffectState.res
CHANGED
|
@@ -36,15 +36,24 @@ type effectStats = {
|
|
|
36
36
|
mutable hasCache: bool,
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
// A handler output, stamped with the checkpoint that produced it on the chain
|
|
40
|
+
// whose handler ran it. A cross-chain effect's entries come from several
|
|
41
|
+
// chains, and under per-chain sequences an id only compares against its own
|
|
42
|
+
// chain's committed one.
|
|
43
|
+
type cacheEntry = {
|
|
44
|
+
output: Internal.effectOutput,
|
|
45
|
+
chainId: ChainId.t,
|
|
46
|
+
checkpointId: Internal.checkpointId,
|
|
47
|
+
}
|
|
48
|
+
|
|
39
49
|
type effectCacheInMemTable = {
|
|
40
50
|
// Cache keys whose handler output is persisted on the next write. Drained
|
|
41
51
|
// each write; eviction is driven by the per-entry checkpointId instead.
|
|
42
52
|
mutable idsToStore: array<string>,
|
|
43
53
|
mutable invalidationsCount: int,
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
mutable dict: dict<Change.t<Internal.effectOutput>>,
|
|
54
|
+
// Committed entries are dropped once persisted or re-derivable, mirroring
|
|
55
|
+
// entity changes; a db read is stamped loadedFromDbCheckpointId.
|
|
56
|
+
mutable dict: dict<cacheEntry>,
|
|
48
57
|
mutable changesCount: float,
|
|
49
58
|
effect: Internal.effect,
|
|
50
59
|
// The scope this cache is for and its resolved db table (the address). The
|
package/src/EffectState.resi
CHANGED
|
@@ -11,10 +11,16 @@ type effectRateLimitState = {
|
|
|
11
11
|
// toMetrics.
|
|
12
12
|
type effectStats
|
|
13
13
|
|
|
14
|
+
type cacheEntry = {
|
|
15
|
+
output: Internal.effectOutput,
|
|
16
|
+
chainId: ChainId.t,
|
|
17
|
+
checkpointId: Internal.checkpointId,
|
|
18
|
+
}
|
|
19
|
+
|
|
14
20
|
type effectCacheInMemTable = {
|
|
15
21
|
mutable idsToStore: array<string>,
|
|
16
22
|
mutable invalidationsCount: int,
|
|
17
|
-
mutable dict: dict<
|
|
23
|
+
mutable dict: dict<cacheEntry>,
|
|
18
24
|
mutable changesCount: float,
|
|
19
25
|
effect: Internal.effect,
|
|
20
26
|
scope: Internal.chainScope,
|
package/src/EventProcessing.res
CHANGED
|
@@ -157,9 +157,9 @@ let preloadBatchOrThrow = async (
|
|
|
157
157
|
|
|
158
158
|
for checkpointIdx in 0 to batch.checkpointIds->Array.length - 1 {
|
|
159
159
|
let checkpointId = batch.checkpointIds->Array.getUnsafe(checkpointIdx)
|
|
160
|
-
let
|
|
160
|
+
let checkpointItemsCount = batch.checkpointItemsCount->Array.getUnsafe(checkpointIdx)
|
|
161
161
|
|
|
162
|
-
for idx in 0 to
|
|
162
|
+
for idx in 0 to checkpointItemsCount - 1 {
|
|
163
163
|
let item = batch.items->Array.getUnsafe(itemIdx.contents + idx)
|
|
164
164
|
switch item {
|
|
165
165
|
| Event(_) =>
|
|
@@ -233,7 +233,7 @@ let preloadBatchOrThrow = async (
|
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
-
itemIdx := itemIdx.contents +
|
|
236
|
+
itemIdx := itemIdx.contents + checkpointItemsCount
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
let _ = await Promise.all(promises)
|
|
@@ -251,9 +251,9 @@ let runBatchHandlersOrThrow = async (
|
|
|
251
251
|
|
|
252
252
|
for checkpointIdx in 0 to batch.checkpointIds->Array.length - 1 {
|
|
253
253
|
let checkpointId = batch.checkpointIds->Array.getUnsafe(checkpointIdx)
|
|
254
|
-
let
|
|
254
|
+
let checkpointItemsCount = batch.checkpointItemsCount->Array.getUnsafe(checkpointIdx)
|
|
255
255
|
|
|
256
|
-
for idx in 0 to
|
|
256
|
+
for idx in 0 to checkpointItemsCount - 1 {
|
|
257
257
|
let item = batch.items->Array.getUnsafe(itemIdx.contents + idx)
|
|
258
258
|
|
|
259
259
|
await runHandlerOrThrow(
|
|
@@ -266,7 +266,7 @@ let runBatchHandlersOrThrow = async (
|
|
|
266
266
|
~chains,
|
|
267
267
|
)
|
|
268
268
|
}
|
|
269
|
-
itemIdx := itemIdx.contents +
|
|
269
|
+
itemIdx := itemIdx.contents + checkpointItemsCount
|
|
270
270
|
}
|
|
271
271
|
}
|
|
272
272
|
|
|
@@ -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
|
@@ -50,6 +50,22 @@ let makeSelection = (~onEventRegistrations, ~dependsOnAddresses, ~clientFiltered
|
|
|
50
50
|
startBlock: ?deriveSelectionStartBlock(onEventRegistrations),
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
// A partition's frontier never sits below the block before its selection can
|
|
54
|
+
// first match: the blocks below hold nothing for it, so they count as fetched
|
|
55
|
+
// the same way the blocks before an address's start block do. The chain's
|
|
56
|
+
// buffer frontier is its lowest partition frontier, so a partition left at the
|
|
57
|
+
// chain start would hold every other partition's events back as unprocessable
|
|
58
|
+
// and keep the chain's query target — sized from that frontier — short of
|
|
59
|
+
// anything worth asking for. A start block the chain has not reached yet leaves
|
|
60
|
+
// the partition waiting there, like an address partition does, rather than
|
|
61
|
+
// scanning empty ranges up to it; bufferBlockNumber caps the chain's frontier at
|
|
62
|
+
// the head meanwhile.
|
|
63
|
+
let floorAtSelectionStart = (latestFetchedBlock, ~selection) =>
|
|
64
|
+
switch selection.startBlock {
|
|
65
|
+
| Some(startBlock) => Pervasives.max(latestFetchedBlock, startBlock - 1)
|
|
66
|
+
| None => latestFetchedBlock
|
|
67
|
+
}
|
|
68
|
+
|
|
53
69
|
type pendingQuery = {
|
|
54
70
|
fromBlock: int,
|
|
55
71
|
toBlock: option<int>,
|
|
@@ -398,6 +414,10 @@ module OptimizedPartitions = {
|
|
|
398
414
|
~dynamicContracts: Utils.Set.t<string>,
|
|
399
415
|
~clientFilteredContracts: Utils.Set.t<string>,
|
|
400
416
|
) => {
|
|
417
|
+
let partitions = partitions->Array.map(p => {
|
|
418
|
+
let floored = p.latestFetchedBlock->floorAtSelectionStart(~selection=p.selection)
|
|
419
|
+
floored === p.latestFetchedBlock ? p : {...p, latestFetchedBlock: floored}
|
|
420
|
+
})
|
|
401
421
|
let newPartitions = []
|
|
402
422
|
let mergingPartitions = Dict.make()
|
|
403
423
|
let nextPartitionIndexRef = ref(nextPartitionIndex)
|
|
@@ -847,28 +867,17 @@ type t = {
|
|
|
847
867
|
clientFilterAddressThreshold: option<int>,
|
|
848
868
|
}
|
|
849
869
|
|
|
870
|
+
// The latest block whose items are all in the buffer: the lowest partition
|
|
871
|
+
// frontier, held back by the onBlock pointer. Without onBlock registrations the
|
|
872
|
+
// pointer tracks the known height, so this also caps the frontier at the head: a
|
|
873
|
+
// partition can sit past it, on a response that reported a block the chain
|
|
874
|
+
// hadn't heard of yet or on a start block the chain hasn't reached.
|
|
850
875
|
@inline
|
|
851
876
|
let bufferBlockNumber = ({latestOnBlockBlockNumber, optimizedPartitions}: t) => {
|
|
852
877
|
switch optimizedPartitions->OptimizedPartitions.getLatestFullyFetchedBlock {
|
|
853
878
|
| None => latestOnBlockBlockNumber
|
|
854
879
|
| Some(latestFullyFetchedBlock) =>
|
|
855
|
-
latestOnBlockBlockNumber
|
|
856
|
-
? latestOnBlockBlockNumber
|
|
857
|
-
: latestFullyFetchedBlock
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
/**
|
|
862
|
-
* Returns the latest block which is ready to be consumed
|
|
863
|
-
*/
|
|
864
|
-
@inline
|
|
865
|
-
let bufferBlock = ({optimizedPartitions, latestOnBlockBlockNumber}: t) => {
|
|
866
|
-
switch optimizedPartitions->OptimizedPartitions.getLatestFullyFetchedBlock {
|
|
867
|
-
| None => latestOnBlockBlockNumber
|
|
868
|
-
| Some(latestFullyFetchedBlock) =>
|
|
869
|
-
latestOnBlockBlockNumber < latestFullyFetchedBlock
|
|
870
|
-
? latestOnBlockBlockNumber
|
|
871
|
-
: latestFullyFetchedBlock
|
|
880
|
+
Pervasives.min(latestOnBlockBlockNumber, latestFullyFetchedBlock)
|
|
872
881
|
}
|
|
873
882
|
}
|
|
874
883
|
|
|
@@ -979,6 +988,20 @@ let compareBufferItem = (a: Internal.item, b: Internal.item): int => {
|
|
|
979
988
|
}
|
|
980
989
|
}
|
|
981
990
|
|
|
991
|
+
// Whether two adjacent buffer items came from one log routed to two
|
|
992
|
+
// registrations: everything `compareBufferItem` orders on except the
|
|
993
|
+
// registration index is equal. Only meaningful on neighbours of a sorted
|
|
994
|
+
// buffer, where such items sit next to each other.
|
|
995
|
+
let isSameLog = (a: Internal.item, b: Internal.item): bool =>
|
|
996
|
+
a->Internal.getItemKind === 0 &&
|
|
997
|
+
b->Internal.getItemKind === 0 &&
|
|
998
|
+
a->Internal.getItemBlockNumber === b->Internal.getItemBlockNumber &&
|
|
999
|
+
a->Internal.getItemLogIndex === b->Internal.getItemLogIndex &&
|
|
1000
|
+
switch (a->Internal.getItemOrderPath, b->Internal.getItemOrderPath) {
|
|
1001
|
+
| (Value(pa), Value(pb)) => comparePath(pa, pb) === 0
|
|
1002
|
+
| _ => true
|
|
1003
|
+
}
|
|
1004
|
+
|
|
982
1005
|
// Merge a maybe-unsorted `newItems` run into the already-sorted, already-deduped
|
|
983
1006
|
// `buffer`, dropping items equal on every component of `compareBufferItem`.
|
|
984
1007
|
// Single linear pass over both runs after ordering `newItems` in place; every
|
|
@@ -1124,14 +1147,20 @@ let updateInternal = (
|
|
|
1124
1147
|
// Use maxOnBlockBufferSize to get the last target item in the buffer
|
|
1125
1148
|
// (sorted, so this is the highest-block item within the buffer cap).
|
|
1126
1149
|
// All this needed to prevent OOM when adding too many block items to the queue
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
| Some(
|
|
1133
|
-
|
|
1134
|
-
|
|
1150
|
+
// Never past the head: a partition can sit there, on a start block the
|
|
1151
|
+
// chain hasn't reached, and a response is applied before the height it
|
|
1152
|
+
// reported, so its events can run past the height still known here.
|
|
1153
|
+
let maxBlockNumber = Pervasives.min(
|
|
1154
|
+
switch base->Array.get(fetchState.maxOnBlockBufferSize - 1) {
|
|
1155
|
+
| Some(item) => item->Internal.getItemBlockNumber
|
|
1156
|
+
| None =>
|
|
1157
|
+
switch optimizedPartitions->OptimizedPartitions.getLatestFullyFetchedBlock {
|
|
1158
|
+
| None => knownHeight
|
|
1159
|
+
| Some(latestFullyFetchedBlock) => latestFullyFetchedBlock
|
|
1160
|
+
}
|
|
1161
|
+
},
|
|
1162
|
+
knownHeight,
|
|
1163
|
+
)
|
|
1135
1164
|
appendOnBlockItems(
|
|
1136
1165
|
~mutItems=blockItems,
|
|
1137
1166
|
~onBlockRegistrations,
|
|
@@ -2151,27 +2180,11 @@ let walkPartitionPending = (
|
|
|
2151
2180
|
pqIdx := pqIdx.contents + 1
|
|
2152
2181
|
}
|
|
2153
2182
|
|
|
2154
|
-
// Nothing in this partition's selection can match below its earliest start
|
|
2155
|
-
// block, so forward work skips straight to it instead of scanning up to it and
|
|
2156
|
-
// discarding whole pages. Only the cursor moves — `latestFetchedBlock` still
|
|
2157
|
-
// advances solely on a response, so no block is ever reported fetched that
|
|
2158
|
-
// wasn't. Bounded by the head and the query end block: past either, the
|
|
2159
|
-
// partition would offer no candidate at all, so it queries as before rather
|
|
2160
|
-
// than going quiet until the chain reaches its start block.
|
|
2161
|
-
let cursor = switch p.selection.startBlock {
|
|
2162
|
-
| Some(startBlock) if startBlock > cursor.contents =>
|
|
2163
|
-
switch Utils.Math.minOptInt(Some(headBlockNumber), queryEndBlock) {
|
|
2164
|
-
| Some(reachable) if startBlock <= reachable => startBlock
|
|
2165
|
-
| _ => cursor.contents
|
|
2166
|
-
}
|
|
2167
|
-
| _ => cursor.contents
|
|
2168
|
-
}
|
|
2169
|
-
|
|
2170
2183
|
canContinue.contents
|
|
2171
2184
|
? Some({
|
|
2172
2185
|
partitionId,
|
|
2173
2186
|
p,
|
|
2174
|
-
cursor,
|
|
2187
|
+
cursor: cursor.contents,
|
|
2175
2188
|
chunksUsedThisCall: chunksUsedThisCall.contents,
|
|
2176
2189
|
inFlightCount,
|
|
2177
2190
|
queryEndBlock,
|
|
@@ -2766,10 +2779,17 @@ let make = (
|
|
|
2766
2779
|
// fetching, so without seeding the buffer here getNextQuery would return
|
|
2767
2780
|
// NothingToQuery and the indexer would get stuck.
|
|
2768
2781
|
let buffer = []
|
|
2769
|
-
let latestOnBlockBlockNumber =
|
|
2782
|
+
let latestOnBlockBlockNumber = switch onBlockRegistrations {
|
|
2783
|
+
// As updateInternal keeps it: with nothing to generate per block the pointer
|
|
2784
|
+
// is the head cap on the buffer frontier, and left at the progress block it
|
|
2785
|
+
// would hold the frontier there until the first height update — below a
|
|
2786
|
+
// partition that starts later, whose queries the chain sizes off that
|
|
2787
|
+
// frontier and so never reaches.
|
|
2788
|
+
| [] if knownHeight > 0 => knownHeight
|
|
2789
|
+
| onBlockRegistrations if knownHeight > 0 =>
|
|
2770
2790
|
let maxBlockNumber = switch optimizedPartitions->OptimizedPartitions.getLatestFullyFetchedBlock {
|
|
2771
2791
|
| None => knownHeight
|
|
2772
|
-
| Some(latestFullyFetchedBlock) => latestFullyFetchedBlock
|
|
2792
|
+
| Some(latestFullyFetchedBlock) => Pervasives.min(latestFullyFetchedBlock, knownHeight)
|
|
2773
2793
|
}
|
|
2774
2794
|
appendOnBlockItems(
|
|
2775
2795
|
~mutItems=buffer,
|
|
@@ -2779,8 +2799,7 @@ let make = (
|
|
|
2779
2799
|
~maxBlockNumber,
|
|
2780
2800
|
~maxOnBlockBufferSize,
|
|
2781
2801
|
)
|
|
2782
|
-
|
|
2783
|
-
progressBlockNumber
|
|
2802
|
+
| _ => progressBlockNumber
|
|
2784
2803
|
}
|
|
2785
2804
|
|
|
2786
2805
|
let fetchState = {
|