envio 3.15.0-subgraph → 3.16.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/README.md +40 -34
- package/evm.schema.json +3 -3
- package/fuel.schema.json +2 -2
- package/index.d.ts +3 -3
- package/licenses/README.md +1 -1
- package/package.json +9 -10
- package/src/Batch.res.mjs +5 -5
- package/src/BatchProcessing.res +1 -0
- package/src/BatchProcessing.res.mjs +1 -0
- package/src/Bin.res +0 -7
- package/src/Bin.res.mjs +0 -8
- package/src/ChainFetching.res +17 -456
- package/src/ChainFetching.res.mjs +33 -404
- package/src/ChainState.res +48 -83
- package/src/ChainState.res.mjs +83 -115
- package/src/ChainState.resi +0 -26
- package/src/Clock.res +57 -0
- package/src/Clock.res.mjs +72 -0
- package/src/Config.res +7 -16
- package/src/Config.res.mjs +4 -11
- package/src/ContractRegisterContext.res +6 -3
- package/src/ContractRegisterContext.res.mjs +2 -4
- package/src/Core.res +5 -136
- package/src/Core.res.mjs +1 -90
- package/src/CrossChainState.res +2 -8
- package/src/CrossChainState.res.mjs +3 -3
- package/src/Ecosystem.res +4 -7
- package/src/Ecosystem.res.mjs +8 -8
- package/src/EffectState.res +10 -2
- package/src/EffectState.res.mjs +8 -4
- package/src/EffectState.resi +3 -1
- package/src/EntityId.res +2 -7
- package/src/EntityId.res.mjs +1 -8
- package/src/EntityTables.res +4 -1
- package/src/EntityTables.res.mjs +1 -1
- package/src/Env.res +0 -16
- package/src/Env.res.mjs +0 -11
- package/src/EventProcessing.res +1 -38
- package/src/EventProcessing.res.mjs +1 -28
- package/src/FetchState.res +160 -319
- package/src/FetchState.res.mjs +182 -292
- package/src/FinalizeBackfill.res +2 -4
- package/src/FinalizeBackfill.res.mjs +3 -4
- package/src/HandlerLoader.res +15 -39
- package/src/HandlerLoader.res.mjs +8 -27
- package/src/HandlerRegister.res +0 -4
- package/src/HandlerRegister.res.mjs +2 -5
- package/src/HandlerRegister.resi +0 -2
- package/src/InMemoryTable.res +17 -16
- package/src/InMemoryTable.res.mjs +14 -15
- package/src/IndexerState.res +28 -4
- package/src/IndexerState.res.mjs +19 -6
- package/src/IndexerState.resi +4 -0
- package/src/Internal.res +0 -110
- package/src/Internal.res.mjs +1 -115
- package/src/LoadLayer.res +21 -47
- package/src/LoadLayer.res.mjs +47 -72
- package/src/LoadLayer.resi +0 -26
- package/src/Main.res +1 -14
- package/src/Main.res.mjs +3 -4
- package/src/Persistence.res +3 -23
- package/src/Persistence.res.mjs +3 -3
- package/src/Rollback.res +0 -1
- package/src/Rollback.res.mjs +1 -1
- package/src/RunScope.res +0 -3
- package/src/SafeCheckpointTracking.res +4 -4
- package/src/SafeCheckpointTracking.res.mjs +1 -1
- package/src/SimulateItems.res +26 -42
- package/src/SimulateItems.res.mjs +16 -40
- package/src/StagedRows.res +106 -0
- package/src/StagedRows.res.mjs +102 -0
- package/src/Staging.res +32 -14
- package/src/Staging.res.mjs +17 -20
- package/src/Storage.res +277 -998
- package/src/Storage.res.mjs +216 -731
- package/src/Supervisor.res +75 -56
- package/src/Supervisor.res.mjs +55 -26
- package/src/TestIndexer.res +22 -27
- package/src/TestIndexer.res.mjs +20 -17
- package/src/Throttler.res +15 -8
- package/src/Throttler.res.mjs +9 -6
- package/src/Throttler.resi +1 -1
- package/src/UserContext.res +46 -410
- package/src/UserContext.res.mjs +30 -318
- package/src/Utils.res +0 -23
- package/src/Utils.res.mjs +1 -17
- package/src/Writing.res +0 -1
- package/src/Writing.res.mjs +1 -1
- package/src/bindings/ClickHouse.res +0 -322
- package/src/bindings/ClickHouse.res.mjs +0 -338
- package/src/bindings/StorageClient.res +107 -175
- package/src/bindings/StorageClient.res.mjs +19 -8
- package/src/bindings/Vitest.res +0 -26
- package/src/bindings/Vitest.res.mjs +0 -3
- package/src/db/Table.res +24 -150
- package/src/db/Table.res.mjs +38 -272
- package/src/sources/AddressSet.res +0 -2
- package/src/sources/AddressStore.res +0 -3
- package/src/sources/ChainSources.res +2 -0
- package/src/sources/ChainSources.res.mjs +2 -2
- package/src/sources/EvmChain.res +4 -7
- package/src/sources/EvmChain.res.mjs +5 -4
- package/src/sources/EvmHyperSyncSource.res +2 -2
- package/src/sources/EvmHyperSyncSource.res.mjs +1 -1
- package/src/sources/EvmRpcClient.res +13 -3
- package/src/sources/EvmRpcClient.res.mjs +4 -3
- package/src/sources/EvmRpcWs.res +4 -3
- package/src/sources/EvmRpcWs.res.mjs +2 -2
- package/src/sources/HeightFeed.res +31 -10
- package/src/sources/HeightFeed.res.mjs +10 -6
- package/src/sources/HeightStream.res +32 -17
- package/src/sources/HeightStream.res.mjs +10 -10
- package/src/sources/HyperSync.res +1 -2
- package/src/sources/HyperSync.res.mjs +1 -2
- package/src/sources/HyperSyncSSE.res +4 -6
- package/src/sources/HyperSyncSSE.res.mjs +2 -2
- package/src/sources/RpcSource.res +10 -1
- package/src/sources/RpcSource.res.mjs +4 -3
- package/src/sources/Source.res +3 -0
- package/src/sources/SourceManager.res +85 -104
- package/src/sources/SourceManager.res.mjs +18 -37
- package/src/sources/SourceManager.resi +3 -5
- package/src/sources/StartBlockResolver.res +1 -0
- package/src/sources/StartBlockResolver.res.mjs +4 -3
- package/src/sources/SvmHyperSyncSource.res +2 -2
- package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
- package/svm.schema.json +3 -3
- package/src/EffectCacheLookup.res +0 -98
- package/src/EffectCacheLookup.res.mjs +0 -116
- package/src/PgWriting.res +0 -36
- package/src/PgWriting.res.mjs +0 -34
- package/src/PreloadLookahead.res +0 -184
- package/src/PreloadLookahead.res.mjs +0 -197
- package/src/SubgraphLog.res +0 -19
- package/src/SubgraphLog.res.mjs +0 -26
- package/src/SyncWrites.res +0 -101
- package/src/SyncWrites.res.mjs +0 -98
- package/src/db/IndexDefinition.res +0 -47
- package/src/db/IndexDefinition.res.mjs +0 -60
- package/src/sources/CallSource.res +0 -274
- package/src/sources/CallSource.res.mjs +0 -196
- package/src/subgraph/abi-types.ts +0 -84
- package/src/subgraph/aggregations.ts +0 -745
- package/src/subgraph/as-package.ts +0 -143
- package/src/subgraph/assemblyscript-regex.ts +0 -67
- package/src/subgraph/assemblyscript.ts +0 -731
- package/src/subgraph/blocks.ts +0 -398
- package/src/subgraph/calls-source.ts +0 -702
- package/src/subgraph/calls.ts +0 -258
- package/src/subgraph/conformance.ts +0 -106
- package/src/subgraph/errors.ts +0 -85
- package/src/subgraph/graft.ts +0 -73
- package/src/subgraph/graph-cli-worker.mjs +0 -35
- package/src/subgraph/graph-cli.ts +0 -900
- package/src/subgraph/graph-node-decimal.ts +0 -199
- package/src/subgraph/graph-ts-enums.ts +0 -28
- package/src/subgraph/graph-ts-types/VERSION +0 -2
- package/src/subgraph/graph-ts-types/chain/arweave.d.ts +0 -70
- package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +0 -327
- package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +0 -233
- package/src/subgraph/graph-ts-types/chain/near.d.ts +0 -253
- package/src/subgraph/graph-ts-types/chain/starknet.d.ts +0 -32
- package/src/subgraph/graph-ts-types/common/collections.d.ts +0 -136
- package/src/subgraph/graph-ts-types/common/conversion.d.ts +0 -11
- package/src/subgraph/graph-ts-types/common/datasource.d.ts +0 -30
- package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
- package/src/subgraph/graph-ts-types/common/json.d.ts +0 -17
- package/src/subgraph/graph-ts-types/common/numbers.d.ts +0 -120
- package/src/subgraph/graph-ts-types/common/value.d.ts +0 -120
- package/src/subgraph/graph-ts-types/common/yaml.d.ts +0 -90
- package/src/subgraph/graph-ts-types/global/global.d.ts +0 -194
- package/src/subgraph/graph-ts-types/helper-functions.d.ts +0 -22
- package/src/subgraph/graph-ts-types/index.d.ts +0 -102
- package/src/subgraph/graph-ts.ts +0 -4280
- package/src/subgraph/hosts.ts +0 -554
- package/src/subgraph/log.ts +0 -28
- package/src/subgraph/receipts.ts +0 -184
- package/src/subgraph/register-slots.ts +0 -93
- package/src/subgraph/rollup.ts +0 -109
- package/src/subgraph/rpc.ts +0 -337
- package/src/subgraph/runtime.ts +0 -2060
- package/src/subgraph/scope.ts +0 -177
- package/src/subgraph/stats.ts +0 -42
- package/src/subgraph/template-instances.ts +0 -66
- package/src/subgraph/toolchain.ts +0 -327
- package/src/subgraph/transient.ts +0 -176
package/src/FinalizeBackfill.res
CHANGED
|
@@ -40,7 +40,7 @@ let runOnce = async (state: IndexerState.t) => {
|
|
|
40
40
|
let storage = persistence->Persistence.getInitializedStorageOrThrow
|
|
41
41
|
let readyAt = Date.make()
|
|
42
42
|
|
|
43
|
-
await storage.finalizeBackfill(~
|
|
43
|
+
await storage.finalizeBackfill(~chainIds, ~readyAt)
|
|
44
44
|
|
|
45
45
|
// Only after the commit: in-memory readiness must never run ahead of the
|
|
46
46
|
// `ready_at` a restart would read back.
|
|
@@ -68,10 +68,8 @@ let run = (state: IndexerState.t) =>
|
|
|
68
68
|
// Best-effort and not awaited by the loop: indexing is already live and correct
|
|
69
69
|
// without the index, just slower.
|
|
70
70
|
let repairSchemaIndexes = (state: IndexerState.t) => {
|
|
71
|
-
let
|
|
72
|
-
let storage = persistence->Persistence.getInitializedStorageOrThrow
|
|
71
|
+
let storage = state->IndexerState.persistence->Persistence.getInitializedStorageOrThrow
|
|
73
72
|
storage.ensureSchemaIndexes(
|
|
74
|
-
~entities=persistence.allEntities,
|
|
75
73
|
~chainIds=state->IndexerState.crossChainState->CrossChainState.chainIds,
|
|
76
74
|
)
|
|
77
75
|
}
|
|
@@ -27,7 +27,7 @@ async function runOnce(state) {
|
|
|
27
27
|
let persistence = IndexerState.persistence(state);
|
|
28
28
|
let storage = Persistence.getInitializedStorageOrThrow(persistence);
|
|
29
29
|
let readyAt = new Date();
|
|
30
|
-
await storage.finalizeBackfill(
|
|
30
|
+
await storage.finalizeBackfill(chainIds, readyAt);
|
|
31
31
|
return IndexerState.markReady(state, readyAt);
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -42,9 +42,8 @@ function run(state) {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
function repairSchemaIndexes(state) {
|
|
45
|
-
let
|
|
46
|
-
|
|
47
|
-
return storage.ensureSchemaIndexes(persistence.allEntities, CrossChainState.chainIds(IndexerState.crossChainState(state)));
|
|
45
|
+
let storage = Persistence.getInitializedStorageOrThrow(IndexerState.persistence(state));
|
|
46
|
+
return storage.ensureSchemaIndexes(CrossChainState.chainIds(IndexerState.crossChainState(state)));
|
|
48
47
|
}
|
|
49
48
|
|
|
50
49
|
export {
|
package/src/HandlerLoader.res
CHANGED
|
@@ -54,8 +54,8 @@ let registerContractHandlers = async (~logger, ~contractName, ~handler: option<s
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
let
|
|
58
|
-
let srcPattern = `./${handlers}/**/*.{js,mjs,ts}`
|
|
57
|
+
let getAutoLoadFiles = async (~config: Config.t) => {
|
|
58
|
+
let srcPattern = `./${config.handlers}/**/*.{js,mjs,ts}`
|
|
59
59
|
try {
|
|
60
60
|
let iterator = globIterator(srcPattern)
|
|
61
61
|
let files = await iterator->Utils.Array.fromAsyncIterator
|
|
@@ -77,14 +77,6 @@ let globAutoLoadFiles = async (~handlers) => {
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
let getAutoLoadFiles = async (~config: Config.t) =>
|
|
81
|
-
switch config.subgraph {
|
|
82
|
-
// A subgraph project's `src/` holds AssemblyScript mappings, not envio
|
|
83
|
-
// handlers: auto-loading or type-checking them as TypeScript would fail.
|
|
84
|
-
| Some(_) => []
|
|
85
|
-
| None => await globAutoLoadFiles(~handlers=config.handlers)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
80
|
let typeCheck = async (~config: Config.t, ~logger, ~autoLoadFiles) => {
|
|
89
81
|
// A contract's `handler:` may also be an auto-loaded file.
|
|
90
82
|
let files =
|
|
@@ -111,16 +103,6 @@ let typeCheck = async (~config: Config.t, ~logger, ~autoLoadFiles) => {
|
|
|
111
103
|
// `HandlerRegister.finishRegistration`. This loads the user handler files
|
|
112
104
|
// (populating the global `HandlerRegister` registry as a side effect) and
|
|
113
105
|
// returns the resulting per-chain registrations.
|
|
114
|
-
// The subgraph runtime lives in this package but is never exported: it's
|
|
115
|
-
// reached only from here, when the resolved config carries a translated
|
|
116
|
-
// manifest.
|
|
117
|
-
let registerSubgraph: (
|
|
118
|
-
JSON.t,
|
|
119
|
-
~isDev: bool,
|
|
120
|
-
~logger: Logger.t,
|
|
121
|
-
) => promise<unit> = %raw(`(subgraph, isDev, logger) =>
|
|
122
|
-
import("./subgraph/runtime.ts").then((m) => m.registerSubgraph({ ...subgraph, isDev }, logger))`)
|
|
123
|
-
|
|
124
106
|
let registerAllHandlers = async (
|
|
125
107
|
~config: Config.t,
|
|
126
108
|
~logger,
|
|
@@ -129,27 +111,21 @@ let registerAllHandlers = async (
|
|
|
129
111
|
HandlerRegister.startRegistration(~config, ~logger)
|
|
130
112
|
registerTsHooks()
|
|
131
113
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
->Array.map(file => {
|
|
139
|
-
importHandler(file)->Promise.catch(exn => {
|
|
140
|
-
let cause = exn->Utils.prettifyExn->Obj.magic
|
|
141
|
-
logger->Logger.errorWithExn(`Failed to auto-load handler file: ${file}`, exn)
|
|
142
|
-
JsError.throwWithMessage(`Failed to auto-load handler file: ${file}. Cause: ${cause}`)
|
|
143
|
-
})
|
|
114
|
+
let _ = await autoLoadFiles
|
|
115
|
+
->Array.map(file => {
|
|
116
|
+
importHandler(file)->Promise.catch(exn => {
|
|
117
|
+
let cause = exn->Utils.prettifyExn->Obj.magic
|
|
118
|
+
logger->Logger.errorWithExn(`Failed to auto-load handler file: ${file}`, exn)
|
|
119
|
+
JsError.throwWithMessage(`Failed to auto-load handler file: ${file}. Cause: ${cause}`)
|
|
144
120
|
})
|
|
145
|
-
|
|
121
|
+
})
|
|
122
|
+
->Promise.all
|
|
146
123
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
124
|
+
let _ = await config.contractHandlers
|
|
125
|
+
->Array.map(({name, handler}) => {
|
|
126
|
+
registerContractHandlers(~logger, ~contractName=name, ~handler)
|
|
127
|
+
})
|
|
128
|
+
->Promise.all
|
|
153
129
|
|
|
154
130
|
HandlerRegister.finishRegistration(~config)
|
|
155
131
|
}
|
|
@@ -58,8 +58,8 @@ async function registerContractHandlers(logger, contractName, handler) {
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
async function
|
|
62
|
-
let srcPattern = `./` + handlers + `/**/*.{js,mjs,ts}`;
|
|
61
|
+
async function getAutoLoadFiles(config) {
|
|
62
|
+
let srcPattern = `./` + config.handlers + `/**/*.{js,mjs,ts}`;
|
|
63
63
|
try {
|
|
64
64
|
let iterator = Promises.glob(srcPattern);
|
|
65
65
|
let files = await Utils.$$Array.fromAsyncIterator(iterator);
|
|
@@ -70,15 +70,6 @@ async function globAutoLoadFiles(handlers) {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
async function getAutoLoadFiles(config) {
|
|
74
|
-
let match = config.subgraph;
|
|
75
|
-
if (match !== undefined) {
|
|
76
|
-
return [];
|
|
77
|
-
} else {
|
|
78
|
-
return await globAutoLoadFiles(config.handlers);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
73
|
async function typeCheck(config, logger, autoLoadFiles) {
|
|
83
74
|
let files = Array.from(new Set(autoLoadFiles.concat(Stdlib_Array.filterMap(config.contractHandlers, param => param.handler)).filter(isTypeScript).map(toAbsolutePath)));
|
|
84
75
|
if (files.length === 0) {
|
|
@@ -94,23 +85,15 @@ async function typeCheck(config, logger, autoLoadFiles) {
|
|
|
94
85
|
}
|
|
95
86
|
}
|
|
96
87
|
|
|
97
|
-
let registerSubgraph = ((subgraph, isDev, logger) =>
|
|
98
|
-
import("./subgraph/runtime.ts").then((m) => m.registerSubgraph({ ...subgraph, isDev }, logger)));
|
|
99
|
-
|
|
100
88
|
async function registerAllHandlers(config, logger, autoLoadFiles) {
|
|
101
89
|
HandlerRegister.startRegistration(config, logger);
|
|
102
90
|
registerTsHooks();
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
Logger.errorWithExn(logger, `Failed to auto-load handler file: ` + file, exn);
|
|
110
|
-
return Stdlib_JsError.throwWithMessage(`Failed to auto-load handler file: ` + file + `. Cause: ` + cause);
|
|
111
|
-
})));
|
|
112
|
-
await Promise.all(config.contractHandlers.map(param => registerContractHandlers(logger, param.name, param.handler)));
|
|
113
|
-
}
|
|
91
|
+
await Promise.all(autoLoadFiles.map(file => Stdlib_Promise.$$catch(importHandler(file), exn => {
|
|
92
|
+
let cause = Utils.prettifyExn(exn);
|
|
93
|
+
Logger.errorWithExn(logger, `Failed to auto-load handler file: ` + file, exn);
|
|
94
|
+
return Stdlib_JsError.throwWithMessage(`Failed to auto-load handler file: ` + file + `. Cause: ` + cause);
|
|
95
|
+
})));
|
|
96
|
+
await Promise.all(config.contractHandlers.map(param => registerContractHandlers(logger, param.name, param.handler)));
|
|
114
97
|
return HandlerRegister.finishRegistration(config);
|
|
115
98
|
}
|
|
116
99
|
|
|
@@ -121,10 +104,8 @@ export {
|
|
|
121
104
|
toAbsolutePath,
|
|
122
105
|
importHandler,
|
|
123
106
|
registerContractHandlers,
|
|
124
|
-
globAutoLoadFiles,
|
|
125
107
|
getAutoLoadFiles,
|
|
126
108
|
typeCheck,
|
|
127
|
-
registerSubgraph,
|
|
128
109
|
registerAllHandlers,
|
|
129
110
|
}
|
|
130
111
|
/* url Not a pure module */
|
package/src/HandlerRegister.res
CHANGED
|
@@ -699,8 +699,6 @@ let registerOnBlock = (
|
|
|
699
699
|
~where: unknown,
|
|
700
700
|
~fields: unknown,
|
|
701
701
|
~handler: Internal.onBlockArgs => promise<unit>,
|
|
702
|
-
~runsFirst=false,
|
|
703
|
-
~contractRegister=?,
|
|
704
702
|
~getChainsObject: Config.t => dict<unknown>,
|
|
705
703
|
) => {
|
|
706
704
|
withRegistration(registration => {
|
|
@@ -794,8 +792,6 @@ let registerOnBlock = (
|
|
|
794
792
|
interval: range._every,
|
|
795
793
|
chainId,
|
|
796
794
|
handler,
|
|
797
|
-
runsFirst,
|
|
798
|
-
?contractRegister,
|
|
799
795
|
blockFieldMask,
|
|
800
796
|
}: Internal.onBlockRegistration
|
|
801
797
|
),
|
|
@@ -440,8 +440,7 @@ function extractRange(filter, name, ecosystem) {
|
|
|
440
440
|
}
|
|
441
441
|
}
|
|
442
442
|
|
|
443
|
-
function registerOnBlock(name, where, fields, handler,
|
|
444
|
-
let runsFirst = runsFirstOpt !== undefined ? runsFirstOpt : false;
|
|
443
|
+
function registerOnBlock(name, where, fields, handler, getChainsObject) {
|
|
445
444
|
withRegistration(registration => {
|
|
446
445
|
let config = registration.config;
|
|
447
446
|
let ecosystem = config.ecosystem;
|
|
@@ -498,9 +497,7 @@ function registerOnBlock(name, where, fields, handler, runsFirstOpt, contractReg
|
|
|
498
497
|
endBlock: range._lte,
|
|
499
498
|
interval: range._every,
|
|
500
499
|
handler: handler,
|
|
501
|
-
blockFieldMask: blockFieldMask
|
|
502
|
-
runsFirst: runsFirst,
|
|
503
|
-
contractRegister: contractRegister
|
|
500
|
+
blockFieldMask: blockFieldMask
|
|
504
501
|
});
|
|
505
502
|
});
|
|
506
503
|
if (!matchedAny.contents) {
|
package/src/HandlerRegister.resi
CHANGED
|
@@ -46,7 +46,5 @@ let registerOnBlock: (
|
|
|
46
46
|
~where: unknown,
|
|
47
47
|
~fields: unknown,
|
|
48
48
|
~handler: Internal.onBlockArgs => promise<unit>,
|
|
49
|
-
~runsFirst: bool=?,
|
|
50
|
-
~contractRegister: Internal.onBlockContractRegisterArgs => promise<unit>=?,
|
|
51
49
|
~getChainsObject: Config.t => dict<unknown>,
|
|
52
50
|
) => unit
|
package/src/InMemoryTable.res
CHANGED
|
@@ -22,6 +22,8 @@ module Entity = {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
type t = {
|
|
25
|
+
// Keys every id dict and Set below; see Table.table.
|
|
26
|
+
entityIdToKey: EntityId.t => string,
|
|
25
27
|
latestEntityChangeById: dict<Change.t<Internal.entity>>,
|
|
26
28
|
// Recorded changes (new latest ids + prevEntityChanges pushes), tracked
|
|
27
29
|
// manually so InMemoryStore can gauge size without scanning every dict.
|
|
@@ -45,12 +47,9 @@ module Entity = {
|
|
|
45
47
|
mutable hasIndexes: bool,
|
|
46
48
|
}
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
// string/int/bigint, so it's stringified to a stable key for in-memory
|
|
50
|
-
// indexing.
|
|
51
|
-
let getEntityIdUnsafe = (entity: Internal.entity): string =>
|
|
50
|
+
let getEntityKeyUnsafe = (self: t, entity: Internal.entity): string =>
|
|
52
51
|
switch (entity->(Utils.magic: Internal.entity => {"id": option<EntityId.t>}))["id"] {
|
|
53
|
-
| Some(id) => id
|
|
52
|
+
| Some(id) => self.entityIdToKey(id)
|
|
54
53
|
| None => JsError.throwWithMessage("Property 'id' does not exist on expected entity object")
|
|
55
54
|
}
|
|
56
55
|
|
|
@@ -62,7 +61,8 @@ module Entity = {
|
|
|
62
61
|
}
|
|
63
62
|
}
|
|
64
63
|
|
|
65
|
-
let make = (): t => {
|
|
64
|
+
let make = (~entityIdToKey): t => {
|
|
65
|
+
entityIdToKey,
|
|
66
66
|
latestEntityChangeById: Dict.make(),
|
|
67
67
|
changesCount: 0.,
|
|
68
68
|
dirtyIds: Utils.Set.make(),
|
|
@@ -141,10 +141,8 @@ module Entity = {
|
|
|
141
141
|
self.hasIndexes = false
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
let updateIndexes = (self: t, ~entity: Internal.entity) =>
|
|
144
|
+
let updateIndexes = (self: t, ~entityId: string, ~entity: Internal.entity) =>
|
|
145
145
|
if self.hasIndexes {
|
|
146
|
-
let entityId = entity->getEntityIdUnsafe
|
|
147
|
-
|
|
148
146
|
switch self.indexesByEntityId->Utils.Dict.dangerouslyGetNonOption(entityId) {
|
|
149
147
|
| None => ()
|
|
150
148
|
| Some(indexes) =>
|
|
@@ -185,7 +183,7 @@ module Entity = {
|
|
|
185
183
|
}
|
|
186
184
|
|
|
187
185
|
let set = (inMemTable: t, ~committedCheckpointId, change: Change.t<Internal.entity>) => {
|
|
188
|
-
let entityKey = change->Change.getEntityId
|
|
186
|
+
let entityKey = inMemTable.entityIdToKey(change->Change.getEntityId)
|
|
189
187
|
switch inMemTable.latestEntityChangeById->Utils.Dict.dangerouslyGetNonOption(entityKey) {
|
|
190
188
|
| Some(prev) =>
|
|
191
189
|
let prevCheckpointId = prev->Change.getCheckpointId
|
|
@@ -200,8 +198,8 @@ module Entity = {
|
|
|
200
198
|
}
|
|
201
199
|
|
|
202
200
|
switch change {
|
|
203
|
-
| Set({entity}) => inMemTable->updateIndexes(~entity)
|
|
204
|
-
| Delete(
|
|
201
|
+
| Set({entity}) => inMemTable->updateIndexes(~entityId=entityKey, ~entity)
|
|
202
|
+
| Delete(_) => inMemTable->deleteEntityFromIndexes(~entityId=entityKey)
|
|
205
203
|
}
|
|
206
204
|
inMemTable.latestEntityChangeById->Dict.set(entityKey, change)
|
|
207
205
|
if change->Change.getCheckpointId > committedCheckpointId {
|
|
@@ -214,11 +212,14 @@ module Entity = {
|
|
|
214
212
|
let initValue = (
|
|
215
213
|
inMemTable: t,
|
|
216
214
|
~committedCheckpointId,
|
|
217
|
-
~
|
|
215
|
+
~entityId: EntityId.t,
|
|
218
216
|
~entity: option<Internal.entity>,
|
|
219
217
|
) =>
|
|
220
|
-
if
|
|
221
|
-
|
|
218
|
+
if (
|
|
219
|
+
inMemTable.latestEntityChangeById
|
|
220
|
+
->Utils.Dict.dangerouslyGetNonOption(inMemTable.entityIdToKey(entityId))
|
|
221
|
+
->Option.isNone
|
|
222
|
+
) {
|
|
222
223
|
let change: Change.t<Internal.entity> = switch entity {
|
|
223
224
|
| Some(entity) => Set({entityId, entity, checkpointId: Internal.loadedFromDbCheckpointId})
|
|
224
225
|
| None => Delete({entityId, checkpointId: Internal.loadedFromDbCheckpointId})
|
|
@@ -312,7 +313,7 @@ module Entity = {
|
|
|
312
313
|
switch change->mapChangeToEntity {
|
|
313
314
|
| Some(entity) =>
|
|
314
315
|
if index.matcher(entity) {
|
|
315
|
-
inMemTable->addToIndex(~index, ~entityId=entity
|
|
316
|
+
inMemTable->addToIndex(~index, ~entityId=inMemTable->getEntityKeyUnsafe(entity))
|
|
316
317
|
}
|
|
317
318
|
| None => ()
|
|
318
319
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Utils from "./Utils.res.mjs";
|
|
4
|
-
import * as EntityId from "./EntityId.res.mjs";
|
|
5
4
|
import * as Internal from "./Internal.res.mjs";
|
|
6
5
|
import * as EntityFilter from "./db/EntityFilter.res.mjs";
|
|
7
6
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
@@ -9,10 +8,10 @@ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
|
9
8
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
10
9
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
11
10
|
|
|
12
|
-
function
|
|
11
|
+
function getEntityKeyUnsafe(self, entity) {
|
|
13
12
|
let id = entity.id;
|
|
14
13
|
if (id !== undefined) {
|
|
15
|
-
return
|
|
14
|
+
return self.entityIdToKey(Primitive_option.valFromOption(id));
|
|
16
15
|
} else {
|
|
17
16
|
return Stdlib_JsError.throwWithMessage("Property 'id' does not exist on expected entity object");
|
|
18
17
|
}
|
|
@@ -28,8 +27,9 @@ function addToIndex(self, index, entityId) {
|
|
|
28
27
|
}
|
|
29
28
|
}
|
|
30
29
|
|
|
31
|
-
function make() {
|
|
30
|
+
function make(entityIdToKey) {
|
|
32
31
|
return {
|
|
32
|
+
entityIdToKey: entityIdToKey,
|
|
33
33
|
latestEntityChangeById: {},
|
|
34
34
|
changesCount: 0,
|
|
35
35
|
dirtyIds: new Set(),
|
|
@@ -99,11 +99,10 @@ function dropCommittedChanges(self, committedCheckpointId, keepLoadedFromDb) {
|
|
|
99
99
|
self.hasIndexes = false;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
function updateIndexes(self, entity) {
|
|
102
|
+
function updateIndexes(self, entityId, entity) {
|
|
103
103
|
if (!self.hasIndexes) {
|
|
104
104
|
return;
|
|
105
105
|
}
|
|
106
|
-
let entityId = getEntityIdUnsafe(entity);
|
|
107
106
|
let indexes = self.indexesByEntityId[entityId];
|
|
108
107
|
if (indexes !== undefined) {
|
|
109
108
|
let indexes$1 = Primitive_option.valFromOption(indexes);
|
|
@@ -144,7 +143,7 @@ function deleteEntityFromIndexes(self, entityId) {
|
|
|
144
143
|
}
|
|
145
144
|
|
|
146
145
|
function set(inMemTable, committedCheckpointId, change) {
|
|
147
|
-
let entityKey =
|
|
146
|
+
let entityKey = inMemTable.entityIdToKey(change.entityId);
|
|
148
147
|
let prev = inMemTable.latestEntityChangeById[entityKey];
|
|
149
148
|
if (prev !== undefined) {
|
|
150
149
|
let prevCheckpointId = prev.checkpointId;
|
|
@@ -156,9 +155,9 @@ function set(inMemTable, committedCheckpointId, change) {
|
|
|
156
155
|
inMemTable.changesCount = inMemTable.changesCount + 1;
|
|
157
156
|
}
|
|
158
157
|
if (change.type === "SET") {
|
|
159
|
-
updateIndexes(inMemTable, change.entity);
|
|
158
|
+
updateIndexes(inMemTable, entityKey, change.entity);
|
|
160
159
|
} else {
|
|
161
|
-
deleteEntityFromIndexes(inMemTable,
|
|
160
|
+
deleteEntityFromIndexes(inMemTable, entityKey);
|
|
162
161
|
}
|
|
163
162
|
inMemTable.latestEntityChangeById[entityKey] = change;
|
|
164
163
|
if (change.checkpointId > committedCheckpointId) {
|
|
@@ -167,18 +166,18 @@ function set(inMemTable, committedCheckpointId, change) {
|
|
|
167
166
|
}
|
|
168
167
|
}
|
|
169
168
|
|
|
170
|
-
function initValue(inMemTable, committedCheckpointId,
|
|
171
|
-
if (!Stdlib_Option.isNone(inMemTable.latestEntityChangeById[
|
|
169
|
+
function initValue(inMemTable, committedCheckpointId, entityId, entity) {
|
|
170
|
+
if (!Stdlib_Option.isNone(inMemTable.latestEntityChangeById[inMemTable.entityIdToKey(entityId)])) {
|
|
172
171
|
return;
|
|
173
172
|
}
|
|
174
173
|
let change = entity !== undefined ? ({
|
|
175
174
|
type: "SET",
|
|
176
|
-
entityId:
|
|
175
|
+
entityId: entityId,
|
|
177
176
|
entity: entity,
|
|
178
177
|
checkpointId: Internal.loadedFromDbCheckpointId
|
|
179
178
|
}) : ({
|
|
180
179
|
type: "DELETE",
|
|
181
|
-
entityId:
|
|
180
|
+
entityId: entityId,
|
|
182
181
|
checkpointId: Internal.loadedFromDbCheckpointId
|
|
183
182
|
});
|
|
184
183
|
set(inMemTable, committedCheckpointId, change);
|
|
@@ -285,7 +284,7 @@ function addEmptyIndex(inMemTable, filter, table) {
|
|
|
285
284
|
Utils.Dict.forEach(inMemTable.latestEntityChangeById, change => {
|
|
286
285
|
let entity = mapChangeToEntity(change);
|
|
287
286
|
if (entity !== undefined && index_matcher(entity)) {
|
|
288
|
-
return addToIndex(inMemTable, index,
|
|
287
|
+
return addToIndex(inMemTable, index, getEntityKeyUnsafe(inMemTable, entity));
|
|
289
288
|
}
|
|
290
289
|
});
|
|
291
290
|
}
|
|
@@ -321,7 +320,7 @@ function tryIndexFromLoadedValues(inMemTable, filter, table) {
|
|
|
321
320
|
}
|
|
322
321
|
|
|
323
322
|
let Entity = {
|
|
324
|
-
|
|
323
|
+
getEntityKeyUnsafe: getEntityKeyUnsafe,
|
|
325
324
|
addToIndex: addToIndex,
|
|
326
325
|
make: make,
|
|
327
326
|
snapshotChanges: snapshotChanges,
|
package/src/IndexerState.res
CHANGED
|
@@ -108,6 +108,12 @@ type t = {
|
|
|
108
108
|
// in-process test runner injects a callback that resolves its run promise
|
|
109
109
|
// instead, so a caught-up run doesn't kill the test process.
|
|
110
110
|
onExit: option<unit => unit>,
|
|
111
|
+
// Told, in the processing pass that gets it there, that a run holding its
|
|
112
|
+
// realtime transitions has gone as far as it can on its own. The test
|
|
113
|
+
// runner's stand-in supervisor releases from it, so the release lands at a
|
|
114
|
+
// point in the indexer's own progress rather than on a timer.
|
|
115
|
+
onArrivedAtHead: option<unit => unit>,
|
|
116
|
+
mutable reportedArrivalAtHead: bool,
|
|
111
117
|
// Set once on any fatal error. Every loop checks it to stop iterating and
|
|
112
118
|
// every launch skips when it's set, so a single failure quiesces the indexer.
|
|
113
119
|
mutable isStopped: bool,
|
|
@@ -157,10 +163,13 @@ let make = (
|
|
|
157
163
|
~exitAfterFirstEventBlock=false,
|
|
158
164
|
~onError: ErrorHandling.t => unit,
|
|
159
165
|
~onExit=?,
|
|
166
|
+
~onArrivedAtHead=?,
|
|
167
|
+
~clock=Clock.real,
|
|
160
168
|
) => {
|
|
161
169
|
let chainMetaThrottler = {
|
|
162
170
|
let intervalMillis = Env.ThrottleWrites.chainMetadataIntervalMillis
|
|
163
171
|
Throttler.make(
|
|
172
|
+
~clock,
|
|
164
173
|
~intervalMillis,
|
|
165
174
|
~logger=logger->Logger.withFields({
|
|
166
175
|
"context": "Throttler for chain metadata writes",
|
|
@@ -175,7 +184,7 @@ let make = (
|
|
|
175
184
|
persistence,
|
|
176
185
|
allEntities: persistence.allEntities,
|
|
177
186
|
entities: EntityTables.make(persistence.allEntities->EntityTables.crossChain),
|
|
178
|
-
effectState: EffectState.make(),
|
|
187
|
+
effectState: EffectState.make(~clock, ()),
|
|
179
188
|
rollback: None,
|
|
180
189
|
committedFrontier,
|
|
181
190
|
processedFrontier: committedFrontier->Frontier.copy,
|
|
@@ -205,6 +214,8 @@ let make = (
|
|
|
205
214
|
exitAfterFirstEventBlock,
|
|
206
215
|
onError,
|
|
207
216
|
onExit,
|
|
217
|
+
onArrivedAtHead,
|
|
218
|
+
reportedArrivalAtHead: false,
|
|
208
219
|
isStopped: false,
|
|
209
220
|
epoch: 0,
|
|
210
221
|
simulateDeadInputTracker: SimulateDeadInputTracker.makeFromConfig(config),
|
|
@@ -225,12 +236,13 @@ let make = (
|
|
|
225
236
|
}
|
|
226
237
|
|
|
227
238
|
// Check if progress is past the reorg threshold (safe block).
|
|
228
|
-
// A chain is in reorg threshold
|
|
229
|
-
// This matches the
|
|
239
|
+
// A chain is in reorg threshold once its progress passes the safe block,
|
|
240
|
+
// sourceBlockNumber - maxReorgDepth - 1. This matches the reorg checkpoints
|
|
241
|
+
// query in packages/cli/src/postgres/internal.rs.
|
|
230
242
|
let isProgressInReorgThreshold = (~progressBlockNumber, ~sourceBlockNumber, ~maxReorgDepth) => {
|
|
231
243
|
maxReorgDepth > 0 &&
|
|
232
244
|
sourceBlockNumber > 0 &&
|
|
233
|
-
progressBlockNumber > sourceBlockNumber - maxReorgDepth
|
|
245
|
+
progressBlockNumber > sourceBlockNumber - maxReorgDepth - 1
|
|
234
246
|
}
|
|
235
247
|
|
|
236
248
|
let makeFromDbState = (
|
|
@@ -249,6 +261,7 @@ let makeFromDbState = (
|
|
|
249
261
|
~holdRealtime=false,
|
|
250
262
|
~onError,
|
|
251
263
|
~onExit=?,
|
|
264
|
+
~onArrivedAtHead=?,
|
|
252
265
|
) => {
|
|
253
266
|
let isInReorgThreshold = if initialState.cleanRun {
|
|
254
267
|
false
|
|
@@ -303,6 +316,8 @@ let makeFromDbState = (
|
|
|
303
316
|
~exitAfterFirstEventBlock,
|
|
304
317
|
~onError,
|
|
305
318
|
~onExit?,
|
|
319
|
+
~onArrivedAtHead?,
|
|
320
|
+
~clock=?sourceTiming->Option.flatMap(timing => timing.clock),
|
|
306
321
|
)
|
|
307
322
|
state.crossChainState->CrossChainState.markCaughtUpOnResume
|
|
308
323
|
initialState.cache->Utils.Dict.forEach(({effectName, count, scope}) => {
|
|
@@ -559,6 +574,15 @@ let isHoldingRealtime = (state: t) => state.crossChainState->CrossChainState.isH
|
|
|
559
574
|
|
|
560
575
|
let hasArrivedAtHead = (state: t) => state.crossChainState->CrossChainState.hasArrivedAtHead
|
|
561
576
|
|
|
577
|
+
let reportArrivalAtHead = (state: t) =>
|
|
578
|
+
switch state.onArrivedAtHead {
|
|
579
|
+
| Some(onArrivedAtHead)
|
|
580
|
+
if !state.reportedArrivalAtHead && state->isHoldingRealtime && state->hasArrivedAtHead =>
|
|
581
|
+
state.reportedArrivalAtHead = true
|
|
582
|
+
onArrivedAtHead()
|
|
583
|
+
| _ => ()
|
|
584
|
+
}
|
|
585
|
+
|
|
562
586
|
let releaseRealtime = (state: t) => {
|
|
563
587
|
state.crossChainState->CrossChainState.releaseRealtime
|
|
564
588
|
// Every chain is parked at the head with no batch coming, so nothing would
|
package/src/IndexerState.res.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Env from "./Env.res.mjs";
|
|
4
4
|
import * as Batch from "./Batch.res.mjs";
|
|
5
|
+
import * as Clock from "./Clock.res.mjs";
|
|
5
6
|
import * as Utils from "./Utils.res.mjs";
|
|
6
7
|
import * as Config from "./Config.res.mjs";
|
|
7
8
|
import * as Logger from "./Logger.res.mjs";
|
|
@@ -26,25 +27,26 @@ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js
|
|
|
26
27
|
import * as CheckpointSequence from "./db/CheckpointSequence.res.mjs";
|
|
27
28
|
import * as SimulateDeadInputTracker from "./SimulateDeadInputTracker.res.mjs";
|
|
28
29
|
|
|
29
|
-
function make(config, logger, persistence, chainStates, isRealtime, targetBufferSizeOpt, holdRealtimeOpt, committedFrontierOpt, isDevelopmentModeOpt, shouldUseTuiOpt, exitAfterFirstEventBlockOpt, onError, onExit) {
|
|
30
|
+
function make(config, logger, persistence, chainStates, isRealtime, targetBufferSizeOpt, holdRealtimeOpt, committedFrontierOpt, isDevelopmentModeOpt, shouldUseTuiOpt, exitAfterFirstEventBlockOpt, onError, onExit, onArrivedAtHead, clockOpt) {
|
|
30
31
|
let targetBufferSize = targetBufferSizeOpt !== undefined ? targetBufferSizeOpt : CrossChainState.calculateTargetBufferSize();
|
|
31
32
|
let holdRealtime = holdRealtimeOpt !== undefined ? holdRealtimeOpt : false;
|
|
32
33
|
let committedFrontier = committedFrontierOpt !== undefined ? committedFrontierOpt : Frontier.empty();
|
|
33
34
|
let isDevelopmentMode = isDevelopmentModeOpt !== undefined ? isDevelopmentModeOpt : false;
|
|
34
35
|
let shouldUseTui = shouldUseTuiOpt !== undefined ? shouldUseTuiOpt : false;
|
|
35
36
|
let exitAfterFirstEventBlock = exitAfterFirstEventBlockOpt !== undefined ? exitAfterFirstEventBlockOpt : false;
|
|
37
|
+
let clock = clockOpt !== undefined ? clockOpt : Clock.real;
|
|
36
38
|
let intervalMillis = Env.ThrottleWrites.chainMetadataIntervalMillis;
|
|
37
39
|
let chainMetaThrottler = Throttler.make(intervalMillis, Logger.withFields(logger, {
|
|
38
40
|
context: "Throttler for chain metadata writes",
|
|
39
41
|
intervalMillis: intervalMillis
|
|
40
|
-
}));
|
|
42
|
+
}), clock);
|
|
41
43
|
return {
|
|
42
44
|
config: config,
|
|
43
45
|
logger: logger,
|
|
44
46
|
persistence: persistence,
|
|
45
47
|
allEntities: persistence.allEntities,
|
|
46
48
|
entities: EntityTables.make(EntityTables.crossChain(persistence.allEntities)),
|
|
47
|
-
effectState: EffectState.make(),
|
|
49
|
+
effectState: EffectState.make(clock, undefined),
|
|
48
50
|
rollback: undefined,
|
|
49
51
|
committedFrontier: committedFrontier,
|
|
50
52
|
processedFrontier: Frontier.copy(committedFrontier),
|
|
@@ -68,6 +70,8 @@ function make(config, logger, persistence, chainStates, isRealtime, targetBuffer
|
|
|
68
70
|
exitAfterFirstEventBlock: exitAfterFirstEventBlock,
|
|
69
71
|
onError: onError,
|
|
70
72
|
onExit: onExit,
|
|
73
|
+
onArrivedAtHead: onArrivedAtHead,
|
|
74
|
+
reportedArrivalAtHead: false,
|
|
71
75
|
isStopped: false,
|
|
72
76
|
epoch: 0,
|
|
73
77
|
scheduleProcessing: () => {},
|
|
@@ -88,7 +92,7 @@ function make(config, logger, persistence, chainStates, isRealtime, targetBuffer
|
|
|
88
92
|
};
|
|
89
93
|
}
|
|
90
94
|
|
|
91
|
-
function makeFromDbState(config, logger, persistence, initialState, registrationsByChainId, isDevelopmentModeOpt, shouldUseTuiOpt, exitAfterFirstEventBlockOpt, sourceTiming, targetBufferSizeOpt, holdRealtimeOpt, onError, onExit) {
|
|
95
|
+
function makeFromDbState(config, logger, persistence, initialState, registrationsByChainId, isDevelopmentModeOpt, shouldUseTuiOpt, exitAfterFirstEventBlockOpt, sourceTiming, targetBufferSizeOpt, holdRealtimeOpt, onError, onExit, onArrivedAtHead) {
|
|
92
96
|
let isDevelopmentMode = isDevelopmentModeOpt !== undefined ? isDevelopmentModeOpt : false;
|
|
93
97
|
let shouldUseTui = shouldUseTuiOpt !== undefined ? shouldUseTuiOpt : false;
|
|
94
98
|
let exitAfterFirstEventBlock = exitAfterFirstEventBlockOpt !== undefined ? exitAfterFirstEventBlockOpt : false;
|
|
@@ -99,7 +103,7 @@ function makeFromDbState(config, logger, persistence, initialState, registration
|
|
|
99
103
|
let sourceBlockNumber = resumedChainState.sourceBlockNumber;
|
|
100
104
|
let maxReorgDepth = resumedChainState.maxReorgDepth;
|
|
101
105
|
if (maxReorgDepth > 0 && sourceBlockNumber > 0) {
|
|
102
|
-
return progressBlockNumber > (sourceBlockNumber - maxReorgDepth | 0);
|
|
106
|
+
return progressBlockNumber > ((sourceBlockNumber - maxReorgDepth | 0) - 1 | 0);
|
|
103
107
|
} else {
|
|
104
108
|
return false;
|
|
105
109
|
}
|
|
@@ -111,7 +115,7 @@ function makeFromDbState(config, logger, persistence, initialState, registration
|
|
|
111
115
|
let chainConfig = ChainMap.get(config.chainMap, chainId);
|
|
112
116
|
chainStates[resumedChainState.id] = ChainState.makeFromDbState(chainConfig, resumedChainState, initialState.reorgCheckpoints, isInReorgThreshold, isRealtime, config, initialState.contractMapping, registrationsByChainId, logger, sourceTiming);
|
|
113
117
|
});
|
|
114
|
-
let state = make(config, logger, persistence, chainStates, isRealtime, targetBufferSize, holdRealtime, initialState.checkpointFrontier, isDevelopmentMode, shouldUseTui, exitAfterFirstEventBlock, onError, onExit);
|
|
118
|
+
let state = make(config, logger, persistence, chainStates, isRealtime, targetBufferSize, holdRealtime, initialState.checkpointFrontier, isDevelopmentMode, shouldUseTui, exitAfterFirstEventBlock, onError, onExit, onArrivedAtHead, Stdlib_Option.flatMap(sourceTiming, timing => timing.clock));
|
|
115
119
|
CrossChainState.markCaughtUpOnResume(state.crossChainState);
|
|
116
120
|
Utils.Dict.forEach(initialState.cache, param => {
|
|
117
121
|
let count = param.count;
|
|
@@ -401,6 +405,14 @@ function hasArrivedAtHead(state) {
|
|
|
401
405
|
return CrossChainState.hasArrivedAtHead(state.crossChainState);
|
|
402
406
|
}
|
|
403
407
|
|
|
408
|
+
function reportArrivalAtHead(state) {
|
|
409
|
+
let onArrivedAtHead = state.onArrivedAtHead;
|
|
410
|
+
if (onArrivedAtHead !== undefined && !state.reportedArrivalAtHead && CrossChainState.isHoldingRealtime(state.crossChainState) && CrossChainState.hasArrivedAtHead(state.crossChainState)) {
|
|
411
|
+
state.reportedArrivalAtHead = true;
|
|
412
|
+
return onArrivedAtHead();
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
404
416
|
function releaseRealtime(state) {
|
|
405
417
|
CrossChainState.releaseRealtime(state.crossChainState);
|
|
406
418
|
state.scheduleProcessing();
|
|
@@ -917,6 +929,7 @@ export {
|
|
|
917
929
|
bindScheduleProcessing,
|
|
918
930
|
isHoldingRealtime,
|
|
919
931
|
hasArrivedAtHead,
|
|
932
|
+
reportArrivalAtHead,
|
|
920
933
|
releaseRealtime,
|
|
921
934
|
markReady,
|
|
922
935
|
reportFinished,
|
package/src/IndexerState.resi
CHANGED
|
@@ -24,6 +24,8 @@ let make: (
|
|
|
24
24
|
~exitAfterFirstEventBlock: bool=?,
|
|
25
25
|
~onError: ErrorHandling.t => unit,
|
|
26
26
|
~onExit: unit => unit=?,
|
|
27
|
+
~onArrivedAtHead: unit => unit=?,
|
|
28
|
+
~clock: Clock.t=?,
|
|
27
29
|
) => t
|
|
28
30
|
|
|
29
31
|
let makeFromDbState: (
|
|
@@ -40,6 +42,7 @@ let makeFromDbState: (
|
|
|
40
42
|
~holdRealtime: bool=?,
|
|
41
43
|
~onError: ErrorHandling.t => unit,
|
|
42
44
|
~onExit: unit => unit=?,
|
|
45
|
+
~onArrivedAtHead: unit => unit=?,
|
|
43
46
|
) => t
|
|
44
47
|
|
|
45
48
|
let unexpectedErrorMsg: string
|
|
@@ -106,6 +109,7 @@ let shouldFinalizeIndexes: t => bool
|
|
|
106
109
|
let bindScheduleProcessing: (t, unit => unit) => unit
|
|
107
110
|
let isHoldingRealtime: t => bool
|
|
108
111
|
let hasArrivedAtHead: t => bool
|
|
112
|
+
let reportArrivalAtHead: t => unit
|
|
109
113
|
// The supervisor's go-ahead for a process driving part of a split run.
|
|
110
114
|
let releaseRealtime: t => unit
|
|
111
115
|
let markReady: (t, ~readyAt: Date.t) => unit
|