envio 3.15.0 → 3.16.0-subgraph
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 +11 -2
- package/fuel.schema.json +10 -1
- package/index.d.ts +6 -0
- package/licenses/README.md +1 -1
- package/package.json +10 -9
- package/src/Batch.res.mjs +5 -5
- package/src/BatchProcessing.res +1 -0
- package/src/BatchProcessing.res.mjs +1 -0
- package/src/Bin.res +7 -0
- package/src/Bin.res.mjs +8 -0
- package/src/ChainFetching.res +450 -16
- package/src/ChainFetching.res.mjs +403 -32
- package/src/ChainState.res +124 -7
- package/src/ChainState.res.mjs +128 -67
- package/src/ChainState.resi +26 -0
- package/src/Clock.res +57 -0
- package/src/Clock.res.mjs +72 -0
- package/src/Config.res +31 -3
- package/src/Config.res.mjs +15 -4
- package/src/ContractRegisterContext.res +3 -6
- package/src/ContractRegisterContext.res.mjs +4 -2
- package/src/Core.res +95 -36
- package/src/Core.res.mjs +90 -1
- package/src/CrossChainState.res +12 -2
- package/src/CrossChainState.res.mjs +3 -3
- package/src/Ecosystem.res +7 -4
- package/src/Ecosystem.res.mjs +8 -8
- package/src/EffectCacheLookup.res +98 -0
- package/src/EffectCacheLookup.res.mjs +116 -0
- 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 +20 -0
- package/src/Env.res.mjs +16 -0
- package/src/EventProcessing.res +38 -1
- package/src/EventProcessing.res.mjs +28 -1
- package/src/FetchState.res +408 -73
- package/src/FetchState.res.mjs +361 -91
- package/src/FinalizeBackfill.res +2 -4
- package/src/FinalizeBackfill.res.mjs +3 -4
- package/src/HandlerLoader.res +39 -15
- package/src/HandlerLoader.res.mjs +27 -8
- package/src/HandlerRegister.res +4 -0
- package/src/HandlerRegister.res.mjs +5 -2
- package/src/HandlerRegister.resi +2 -0
- 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 +61 -49
- package/src/Internal.res.mjs +36 -80
- package/src/LoadLayer.res +54 -15
- package/src/LoadLayer.res.mjs +75 -45
- package/src/LoadLayer.resi +26 -0
- package/src/Main.res +14 -1
- package/src/Main.res.mjs +4 -3
- package/src/Persistence.res +3 -23
- package/src/Persistence.res.mjs +3 -3
- package/src/PreloadLookahead.res +202 -0
- package/src/PreloadLookahead.res.mjs +218 -0
- package/src/Rollback.res +0 -1
- package/src/Rollback.res.mjs +1 -1
- package/src/RunScope.res +3 -0
- package/src/SafeCheckpointTracking.res +4 -4
- package/src/SafeCheckpointTracking.res.mjs +1 -1
- package/src/SimulateItems.res +42 -26
- package/src/SimulateItems.res.mjs +40 -16
- 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 +303 -948
- package/src/Storage.res.mjs +229 -708
- package/src/SubgraphLog.res +19 -0
- package/src/SubgraphLog.res.mjs +26 -0
- package/src/Supervisor.res +75 -56
- package/src/Supervisor.res.mjs +55 -26
- package/src/SyncWrites.res +107 -0
- package/src/SyncWrites.res.mjs +98 -0
- 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 +419 -46
- package/src/UserContext.res.mjs +318 -30
- package/src/Utils.res +17 -6
- package/src/Utils.res.mjs +12 -6
- 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 +108 -174
- 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 +2 -0
- package/src/sources/AddressStore.res +3 -0
- package/src/sources/CallSource.res +274 -0
- package/src/sources/CallSource.res.mjs +196 -0
- package/src/sources/ChainSources.res +2 -0
- package/src/sources/ChainSources.res.mjs +2 -2
- package/src/sources/EvmChain.res +10 -1
- package/src/sources/EvmChain.res.mjs +6 -3
- 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 +2 -1
- package/src/sources/HyperSync.res.mjs +2 -1
- 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 +84 -77
- package/src/sources/SourceManager.res.mjs +17 -20
- package/src/sources/SourceManager.resi +3 -4
- package/src/sources/StartBlockResolver.res +1 -0
- package/src/sources/StartBlockResolver.res.mjs +3 -2
- package/src/sources/SvmHyperSyncSource.res +2 -2
- package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
- package/src/subgraph/abi-types.ts +84 -0
- package/src/subgraph/aggregations.ts +745 -0
- package/src/subgraph/as-package.ts +143 -0
- package/src/subgraph/assemblyscript-regex.ts +67 -0
- package/src/subgraph/assemblyscript.ts +731 -0
- package/src/subgraph/blocks.ts +398 -0
- package/src/subgraph/calls-source.ts +702 -0
- package/src/subgraph/calls.ts +258 -0
- package/src/subgraph/conformance.ts +106 -0
- package/src/subgraph/errors.ts +85 -0
- package/src/subgraph/graft.ts +73 -0
- package/src/subgraph/graph-cli-worker.mjs +35 -0
- package/src/subgraph/graph-cli.ts +900 -0
- package/src/subgraph/graph-node-decimal.ts +199 -0
- package/src/subgraph/graph-ts-enums.ts +28 -0
- package/src/subgraph/graph-ts-types/VERSION +2 -0
- package/src/subgraph/graph-ts-types/chain/arweave.d.ts +70 -0
- package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +327 -0
- package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +233 -0
- package/src/subgraph/graph-ts-types/chain/near.d.ts +253 -0
- package/src/subgraph/graph-ts-types/chain/starknet.d.ts +32 -0
- package/src/subgraph/graph-ts-types/common/collections.d.ts +136 -0
- package/src/subgraph/graph-ts-types/common/conversion.d.ts +11 -0
- package/src/subgraph/graph-ts-types/common/datasource.d.ts +30 -0
- package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
- package/src/subgraph/graph-ts-types/common/json.d.ts +17 -0
- package/src/subgraph/graph-ts-types/common/numbers.d.ts +120 -0
- package/src/subgraph/graph-ts-types/common/value.d.ts +120 -0
- package/src/subgraph/graph-ts-types/common/yaml.d.ts +90 -0
- package/src/subgraph/graph-ts-types/global/global.d.ts +194 -0
- package/src/subgraph/graph-ts-types/helper-functions.d.ts +22 -0
- package/src/subgraph/graph-ts-types/index.d.ts +102 -0
- package/src/subgraph/graph-ts.ts +4339 -0
- package/src/subgraph/hosts.ts +554 -0
- package/src/subgraph/log.ts +28 -0
- package/src/subgraph/receipts.ts +184 -0
- package/src/subgraph/register-slots.ts +93 -0
- package/src/subgraph/rollup.ts +109 -0
- package/src/subgraph/rpc.ts +337 -0
- package/src/subgraph/runtime.ts +2059 -0
- package/src/subgraph/scope.ts +176 -0
- package/src/subgraph/stats.ts +42 -0
- package/src/subgraph/template-instances.ts +66 -0
- package/src/subgraph/toolchain.ts +327 -0
- package/src/subgraph/transient.ts +176 -0
- package/svm.schema.json +11 -2
- package/src/PgWriting.res +0 -36
- package/src/PgWriting.res.mjs +0 -34
- package/src/db/IndexDefinition.res +0 -47
- package/src/db/IndexDefinition.res.mjs +0 -67
|
@@ -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 = `./${
|
|
57
|
+
let globAutoLoadFiles = async (~handlers) => {
|
|
58
|
+
let srcPattern = `./${handlers}/**/*.{js,mjs,ts}`
|
|
59
59
|
try {
|
|
60
60
|
let iterator = globIterator(srcPattern)
|
|
61
61
|
let files = await iterator->Utils.Array.fromAsyncIterator
|
|
@@ -77,6 +77,14 @@ let getAutoLoadFiles = async (~config: Config.t) => {
|
|
|
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
|
+
|
|
80
88
|
let typeCheck = async (~config: Config.t, ~logger, ~autoLoadFiles) => {
|
|
81
89
|
// A contract's `handler:` may also be an auto-loaded file.
|
|
82
90
|
let files =
|
|
@@ -103,6 +111,16 @@ let typeCheck = async (~config: Config.t, ~logger, ~autoLoadFiles) => {
|
|
|
103
111
|
// `HandlerRegister.finishRegistration`. This loads the user handler files
|
|
104
112
|
// (populating the global `HandlerRegister` registry as a side effect) and
|
|
105
113
|
// 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
|
+
|
|
106
124
|
let registerAllHandlers = async (
|
|
107
125
|
~config: Config.t,
|
|
108
126
|
~logger,
|
|
@@ -111,21 +129,27 @@ let registerAllHandlers = async (
|
|
|
111
129
|
HandlerRegister.startRegistration(~config, ~logger)
|
|
112
130
|
registerTsHooks()
|
|
113
131
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
132
|
+
switch config.subgraph {
|
|
133
|
+
// Registered after the TypeScript hooks, so the subgraph runtime's own hooks
|
|
134
|
+
// see a mapping first.
|
|
135
|
+
| Some(subgraph) => await registerSubgraph(subgraph, ~isDev=config.isDev, ~logger)
|
|
136
|
+
| None =>
|
|
137
|
+
let _ = await autoLoadFiles
|
|
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
|
+
})
|
|
120
144
|
})
|
|
121
|
-
|
|
122
|
-
->Promise.all
|
|
145
|
+
->Promise.all
|
|
123
146
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
147
|
+
let _ = await config.contractHandlers
|
|
148
|
+
->Array.map(({name, handler}) => {
|
|
149
|
+
registerContractHandlers(~logger, ~contractName=name, ~handler)
|
|
150
|
+
})
|
|
151
|
+
->Promise.all
|
|
152
|
+
}
|
|
129
153
|
|
|
130
154
|
HandlerRegister.finishRegistration(~config)
|
|
131
155
|
}
|
|
@@ -58,8 +58,8 @@ async function registerContractHandlers(logger, contractName, handler) {
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
async function
|
|
62
|
-
let srcPattern = `./` +
|
|
61
|
+
async function globAutoLoadFiles(handlers) {
|
|
62
|
+
let srcPattern = `./` + handlers + `/**/*.{js,mjs,ts}`;
|
|
63
63
|
try {
|
|
64
64
|
let iterator = Promises.glob(srcPattern);
|
|
65
65
|
let files = await Utils.$$Array.fromAsyncIterator(iterator);
|
|
@@ -70,6 +70,15 @@ async function getAutoLoadFiles(config) {
|
|
|
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
|
+
|
|
73
82
|
async function typeCheck(config, logger, autoLoadFiles) {
|
|
74
83
|
let files = Array.from(new Set(autoLoadFiles.concat(Stdlib_Array.filterMap(config.contractHandlers, param => param.handler)).filter(isTypeScript).map(toAbsolutePath)));
|
|
75
84
|
if (files.length === 0) {
|
|
@@ -85,15 +94,23 @@ async function typeCheck(config, logger, autoLoadFiles) {
|
|
|
85
94
|
}
|
|
86
95
|
}
|
|
87
96
|
|
|
97
|
+
let registerSubgraph = ((subgraph, isDev, logger) =>
|
|
98
|
+
import("./subgraph/runtime.ts").then((m) => m.registerSubgraph({ ...subgraph, isDev }, logger)));
|
|
99
|
+
|
|
88
100
|
async function registerAllHandlers(config, logger, autoLoadFiles) {
|
|
89
101
|
HandlerRegister.startRegistration(config, logger);
|
|
90
102
|
registerTsHooks();
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
103
|
+
let subgraph = config.subgraph;
|
|
104
|
+
if (subgraph !== undefined) {
|
|
105
|
+
await registerSubgraph(subgraph, config.isDev, logger);
|
|
106
|
+
} else {
|
|
107
|
+
await Promise.all(autoLoadFiles.map(file => Stdlib_Promise.$$catch(importHandler(file), exn => {
|
|
108
|
+
let cause = Utils.prettifyExn(exn);
|
|
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
|
+
}
|
|
97
114
|
return HandlerRegister.finishRegistration(config);
|
|
98
115
|
}
|
|
99
116
|
|
|
@@ -104,8 +121,10 @@ export {
|
|
|
104
121
|
toAbsolutePath,
|
|
105
122
|
importHandler,
|
|
106
123
|
registerContractHandlers,
|
|
124
|
+
globAutoLoadFiles,
|
|
107
125
|
getAutoLoadFiles,
|
|
108
126
|
typeCheck,
|
|
127
|
+
registerSubgraph,
|
|
109
128
|
registerAllHandlers,
|
|
110
129
|
}
|
|
111
130
|
/* url Not a pure module */
|
package/src/HandlerRegister.res
CHANGED
|
@@ -699,6 +699,8 @@ let registerOnBlock = (
|
|
|
699
699
|
~where: unknown,
|
|
700
700
|
~fields: unknown,
|
|
701
701
|
~handler: Internal.onBlockArgs => promise<unit>,
|
|
702
|
+
~runsFirst=false,
|
|
703
|
+
~contractRegister=?,
|
|
702
704
|
~getChainsObject: Config.t => dict<unknown>,
|
|
703
705
|
) => {
|
|
704
706
|
withRegistration(registration => {
|
|
@@ -792,6 +794,8 @@ let registerOnBlock = (
|
|
|
792
794
|
interval: range._every,
|
|
793
795
|
chainId,
|
|
794
796
|
handler,
|
|
797
|
+
runsFirst,
|
|
798
|
+
?contractRegister,
|
|
795
799
|
blockFieldMask,
|
|
796
800
|
}: Internal.onBlockRegistration
|
|
797
801
|
),
|
|
@@ -440,7 +440,8 @@ function extractRange(filter, name, ecosystem) {
|
|
|
440
440
|
}
|
|
441
441
|
}
|
|
442
442
|
|
|
443
|
-
function registerOnBlock(name, where, fields, handler, getChainsObject) {
|
|
443
|
+
function registerOnBlock(name, where, fields, handler, runsFirstOpt, contractRegister, getChainsObject) {
|
|
444
|
+
let runsFirst = runsFirstOpt !== undefined ? runsFirstOpt : false;
|
|
444
445
|
withRegistration(registration => {
|
|
445
446
|
let config = registration.config;
|
|
446
447
|
let ecosystem = config.ecosystem;
|
|
@@ -497,7 +498,9 @@ function registerOnBlock(name, where, fields, handler, getChainsObject) {
|
|
|
497
498
|
endBlock: range._lte,
|
|
498
499
|
interval: range._every,
|
|
499
500
|
handler: handler,
|
|
500
|
-
blockFieldMask: blockFieldMask
|
|
501
|
+
blockFieldMask: blockFieldMask,
|
|
502
|
+
runsFirst: runsFirst,
|
|
503
|
+
contractRegister: contractRegister
|
|
501
504
|
});
|
|
502
505
|
});
|
|
503
506
|
if (!matchedAny.contents) {
|
package/src/HandlerRegister.resi
CHANGED
|
@@ -46,5 +46,7 @@ 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>=?,
|
|
49
51
|
~getChainsObject: Config.t => dict<unknown>,
|
|
50
52
|
) => 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
|