envio 3.5.0-alpha.2 → 3.5.0-rc.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/package.json +6 -6
- package/src/Batch.res +8 -8
- package/src/Batch.res.mjs +4 -3
- package/src/BatchProcessing.res +24 -0
- package/src/BatchProcessing.res.mjs +12 -0
- package/src/ChainFetching.res +20 -19
- package/src/ChainFetching.res.mjs +14 -14
- package/src/ChainId.res +58 -0
- package/src/ChainId.res.mjs +49 -0
- package/src/ChainId.resi +27 -0
- package/src/ChainMap.res +12 -26
- package/src/ChainMap.res.mjs +5 -41
- package/src/ChainMap.resi +5 -20
- package/src/ChainMetadata.res +1 -1
- package/src/ChainMetadata.res.mjs +3 -2
- package/src/ChainState.res +45 -24
- package/src/ChainState.res.mjs +40 -16
- package/src/ChainState.resi +3 -1
- package/src/Config.res +43 -26
- package/src/Config.res.mjs +19 -16
- package/src/ContractRegisterContext.res +1 -1
- package/src/ContractRegisterContext.res.mjs +1 -1
- package/src/Core.res +1 -0
- package/src/CrossChainState.res +90 -22
- package/src/CrossChainState.res.mjs +55 -16
- package/src/CrossChainState.resi +5 -1
- package/src/Env.res +0 -3
- package/src/Env.res.mjs +0 -3
- package/src/EventConfigBuilder.res +1 -1
- package/src/EventProcessing.res +4 -4
- package/src/EventProcessing.res.mjs +5 -5
- package/src/FetchState.res +489 -153
- package/src/FetchState.res.mjs +399 -129
- package/src/FinalizeBackfill.res +61 -0
- package/src/FinalizeBackfill.res.mjs +44 -0
- package/src/HandlerRegister.res +8 -8
- package/src/HandlerRegister.res.mjs +5 -4
- package/src/HandlerRegister.resi +1 -1
- package/src/InMemoryStore.res +4 -0
- package/src/InMemoryStore.res.mjs +1 -1
- package/src/InMemoryTable.res +15 -15
- package/src/InMemoryTable.res.mjs +14 -14
- package/src/IndexerLoop.res +9 -2
- package/src/IndexerLoop.res.mjs +8 -1
- package/src/IndexerState.res +52 -23
- package/src/IndexerState.res.mjs +52 -14
- package/src/IndexerState.resi +11 -6
- package/src/Internal.res +19 -17
- package/src/Internal.res.mjs +18 -9
- package/src/LoadLayer.res +10 -2
- package/src/LoadLayer.res.mjs +3 -1
- package/src/LogSelection.res +2 -2
- package/src/Main.res +7 -11
- package/src/Main.res.mjs +4 -6
- package/src/Metrics.res +6 -6
- package/src/Metrics.res.mjs +4 -3
- package/src/Persistence.res +23 -4
- package/src/PgStorage.res +447 -100
- package/src/PgStorage.res.mjs +285 -99
- package/src/RawEvent.res +1 -2
- package/src/RawEvent.res.mjs +1 -1
- package/src/Rollback.res +18 -20
- package/src/Rollback.res.mjs +9 -9
- package/src/RollbackCommit.res +2 -2
- package/src/RollbackCommit.res.mjs +3 -3
- package/src/SafeCheckpointTracking.res +2 -2
- package/src/SimulateDeadInputTracker.res +17 -21
- package/src/SimulateDeadInputTracker.res.mjs +9 -8
- package/src/SimulateItems.res +8 -10
- package/src/SimulateItems.res.mjs +9 -10
- package/src/Sink.res +2 -2
- package/src/Sink.res.mjs +3 -2
- package/src/TestIndexer.res +14 -14
- package/src/TestIndexer.res.mjs +16 -10
- package/src/UserContext.res +2 -2
- package/src/UserContext.res.mjs +2 -1
- package/src/Utils.res +0 -4
- package/src/Utils.res.mjs +1 -6
- package/src/bindings/ClickHouse.res +20 -2
- package/src/bindings/ClickHouse.res.mjs +25 -14
- package/src/db/EntityFilter.res +0 -4
- package/src/db/EntityFilter.res.mjs +1 -8
- package/src/db/EntityHistory.res +1 -1
- package/src/db/IndexCatalog.res +248 -0
- package/src/db/IndexCatalog.res.mjs +222 -0
- package/src/db/IndexDefinition.res +131 -0
- package/src/db/IndexDefinition.res.mjs +138 -0
- package/src/db/IndexManager.res +145 -0
- package/src/db/IndexManager.res.mjs +130 -0
- package/src/db/InternalTable.res +54 -23
- package/src/db/InternalTable.res.mjs +38 -23
- package/src/db/Table.res +24 -14
- package/src/db/Table.res.mjs +21 -16
- package/src/sources/AddressSet.res +5 -4
- package/src/sources/AddressStore.res +25 -14
- package/src/sources/AddressStore.res.mjs +10 -12
- package/src/sources/Evm.res +2 -2
- package/src/sources/Evm.res.mjs +1 -1
- package/src/sources/EvmChain.res +3 -3
- package/src/sources/EvmChain.res.mjs +3 -3
- package/src/sources/EvmHyperSyncSource.res +7 -7
- package/src/sources/EvmHyperSyncSource.res.mjs +6 -6
- package/src/sources/Fuel.res +2 -2
- package/src/sources/Fuel.res.mjs +1 -1
- package/src/sources/FuelHyperSyncClient.res +3 -0
- package/src/sources/FuelHyperSyncClient.res.mjs +1 -0
- package/src/sources/FuelHyperSyncSource.res +5 -7
- package/src/sources/FuelHyperSyncSource.res.mjs +5 -5
- package/src/sources/HyperSync.resi +2 -2
- package/src/sources/HyperSyncClient.res +5 -0
- package/src/sources/HyperSyncClient.res.mjs +1 -0
- package/src/sources/RpcSource.res +13 -14
- package/src/sources/RpcSource.res.mjs +13 -12
- package/src/sources/SimulateSource.res +42 -15
- package/src/sources/SimulateSource.res.mjs +27 -9
- package/src/sources/Source.res +1 -5
- package/src/sources/SourceManager.res +12 -12
- package/src/sources/SourceManager.res.mjs +11 -10
- package/src/sources/SourceManager.resi +2 -2
- package/src/sources/Svm.res +4 -5
- package/src/sources/Svm.res.mjs +5 -4
- package/src/sources/SvmHyperSyncClient.res +3 -0
- package/src/sources/SvmHyperSyncClient.res.mjs +1 -0
- package/src/sources/SvmHyperSyncSource.res +4 -4
- package/src/sources/SvmHyperSyncSource.res.mjs +3 -3
- package/src/tui/Tui.res +1 -1
- package/src/tui/Tui.res.mjs +2 -1
- package/src/tui/components/CustomHooks.res +5 -4
- package/src/tui/components/CustomHooks.res.mjs +4 -2
package/src/PgStorage.res.mjs
CHANGED
|
@@ -9,6 +9,7 @@ import * as Utils from "./Utils.res.mjs";
|
|
|
9
9
|
import * as Config from "./Config.res.mjs";
|
|
10
10
|
import * as Hasura from "./Hasura.res.mjs";
|
|
11
11
|
import * as Schema from "./db/Schema.res.mjs";
|
|
12
|
+
import * as ChainId from "./ChainId.res.mjs";
|
|
12
13
|
import * as Logging from "./Logging.res.mjs";
|
|
13
14
|
import * as EntityId from "./EntityId.res.mjs";
|
|
14
15
|
import * as Internal from "./Internal.res.mjs";
|
|
@@ -16,6 +17,8 @@ import Postgres from "postgres";
|
|
|
16
17
|
import * as ChainState from "./ChainState.res.mjs";
|
|
17
18
|
import * as Performance from "./bindings/Performance.res.mjs";
|
|
18
19
|
import * as Persistence from "./Persistence.res.mjs";
|
|
20
|
+
import * as IndexCatalog from "./db/IndexCatalog.res.mjs";
|
|
21
|
+
import * as IndexManager from "./db/IndexManager.res.mjs";
|
|
19
22
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
20
23
|
import * as EntityHistory from "./db/EntityHistory.res.mjs";
|
|
21
24
|
import * as InternalTable from "./db/InternalTable.res.mjs";
|
|
@@ -23,6 +26,7 @@ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
|
23
26
|
import * as Child_process from "child_process";
|
|
24
27
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
25
28
|
import * as Stdlib_Promise from "@rescript/runtime/lib/es6/Stdlib_Promise.js";
|
|
29
|
+
import * as IndexDefinition from "./db/IndexDefinition.res.mjs";
|
|
26
30
|
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
27
31
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
28
32
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
@@ -44,49 +48,49 @@ function makeClient() {
|
|
|
44
48
|
});
|
|
45
49
|
}
|
|
46
50
|
|
|
47
|
-
function
|
|
48
|
-
|
|
49
|
-
let index = indexFields.map(idx => `"` + idx + `"`).join(", ");
|
|
50
|
-
return `CREATE INDEX IF NOT EXISTS "` + indexName + `" ON "` + pgSchema + `"."` + tableName + `"(` + index + `);`;
|
|
51
|
+
function formatSeconds(timeRef) {
|
|
52
|
+
return (Math.round(Performance.secondsSince(timeRef) * 100) / 100).toString();
|
|
51
53
|
}
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
if (direction === "Asc") {
|
|
55
|
-
return "";
|
|
56
|
-
} else {
|
|
57
|
-
return " DESC";
|
|
58
|
-
}
|
|
59
|
-
}
|
|
55
|
+
let slowOnLargeDatabaseNotice = "This can take a long time on a large database.";
|
|
60
56
|
|
|
61
|
-
function
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
let
|
|
80
|
-
|
|
81
|
-
|
|
57
|
+
function getSchemaIndexes(entities) {
|
|
58
|
+
let derivedSchema = Schema.make(entities.map(e => e.table));
|
|
59
|
+
let all = [];
|
|
60
|
+
entities.forEach(param => {
|
|
61
|
+
let table = param.table;
|
|
62
|
+
Table.getSingleIndexes(table).forEach(column => {
|
|
63
|
+
all.push(IndexDefinition.single(table.tableName, column));
|
|
64
|
+
});
|
|
65
|
+
Table.getCompositeIndexes(table).forEach(indexFields => {
|
|
66
|
+
all.push(IndexDefinition.fromIndexFields(table.tableName, indexFields));
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
entities.forEach(param => {
|
|
70
|
+
Table.getDerivedFromFields(param.table).forEach(derivedFromField => {
|
|
71
|
+
let column = Utils.unwrapResultExn(Schema.getDerivedFromPgFieldName(derivedSchema, derivedFromField));
|
|
72
|
+
all.push(IndexDefinition.single(derivedFromField.derivedFromEntity, column));
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
let seen = new Set();
|
|
76
|
+
return all.filter(definition => {
|
|
77
|
+
let key = IndexDefinition.key(definition);
|
|
78
|
+
if (seen.has(key)) {
|
|
79
|
+
return false;
|
|
80
|
+
} else {
|
|
81
|
+
seen.add(key);
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
82
85
|
}
|
|
83
86
|
|
|
84
|
-
function makeCreateTableQuery(table, pgSchema, isNumericArrayAsText) {
|
|
87
|
+
function makeCreateTableQuery(table, pgSchema, isNumericArrayAsText, chainIdModeOpt) {
|
|
88
|
+
let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
|
|
85
89
|
let fieldsMapped = Table.getFields(table).map(field => {
|
|
86
90
|
let defaultValue = field.defaultValue;
|
|
87
91
|
let isNullable = field.isNullable;
|
|
88
92
|
let fieldName = Table.getPgDbFieldName(field);
|
|
89
|
-
return `"` + fieldName + `" ` + Table.getPgFieldType(field.fieldType, pgSchema, field.isArray, isNumericArrayAsText, isNullable) + (
|
|
93
|
+
return `"` + fieldName + `" ` + Table.getPgFieldType(field.fieldType, pgSchema, field.isArray, isNumericArrayAsText, isNullable, chainIdMode) + (
|
|
90
94
|
defaultValue !== undefined ? ` DEFAULT ` + defaultValue : (
|
|
91
95
|
isNullable ? `` : ` NOT NULL`
|
|
92
96
|
)
|
|
@@ -169,11 +173,13 @@ function getEntityHistory(entityConfig) {
|
|
|
169
173
|
return cache$1;
|
|
170
174
|
}
|
|
171
175
|
|
|
172
|
-
function makeInitializeTransaction(pgSchema, pgUser, isHasuraEnabled, chainConfigsOpt, entitiesOpt, enumsOpt, isEmptyPgSchemaOpt) {
|
|
176
|
+
function makeInitializeTransaction(pgSchema, pgUser, isHasuraEnabled, chainConfigsOpt, entitiesOpt, enumsOpt, isEmptyPgSchemaOpt, deferSchemaIndexesOpt, chainIdModeOpt) {
|
|
173
177
|
let chainConfigs = chainConfigsOpt !== undefined ? chainConfigsOpt : [];
|
|
174
178
|
let entities = entitiesOpt !== undefined ? entitiesOpt : [];
|
|
175
179
|
let enums = enumsOpt !== undefined ? enumsOpt : [];
|
|
176
180
|
let isEmptyPgSchema = isEmptyPgSchemaOpt !== undefined ? isEmptyPgSchemaOpt : false;
|
|
181
|
+
let deferSchemaIndexes = deferSchemaIndexesOpt !== undefined ? deferSchemaIndexesOpt : false;
|
|
182
|
+
let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
|
|
177
183
|
let generalTables = [
|
|
178
184
|
InternalTable.Chains.table,
|
|
179
185
|
InternalTable.EnvioInfo.table,
|
|
@@ -181,13 +187,11 @@ function makeInitializeTransaction(pgSchema, pgUser, isHasuraEnabled, chainConfi
|
|
|
181
187
|
InternalTable.RawEvents.table
|
|
182
188
|
];
|
|
183
189
|
let allTables = generalTables.slice();
|
|
184
|
-
let allEntityTables = [];
|
|
185
190
|
entities.forEach(entityConfig => {
|
|
186
|
-
allEntityTables.push(entityConfig.table);
|
|
187
191
|
allTables.push(entityConfig.table);
|
|
188
192
|
allTables.push(getEntityHistory(entityConfig).table);
|
|
189
193
|
});
|
|
190
|
-
let
|
|
194
|
+
let schemaIndexes = getSchemaIndexes(entities);
|
|
191
195
|
let query = {
|
|
192
196
|
contents: (
|
|
193
197
|
isEmptyPgSchema && pgSchema === "public" ? `CREATE SCHEMA IF NOT EXISTS "` + pgSchema + `";\n` : `DROP SCHEMA IF EXISTS "` + pgSchema + `" CASCADE;
|
|
@@ -200,21 +204,13 @@ GRANT ALL ON SCHEMA "` + pgSchema + `" TO public;`)
|
|
|
200
204
|
query.contents = query.contents + "\n" + enumCreateQuery;
|
|
201
205
|
});
|
|
202
206
|
allTables.forEach(table => {
|
|
203
|
-
query.contents = query.contents + "\n" + makeCreateTableQuery(table, pgSchema, isHasuraEnabled);
|
|
204
|
-
});
|
|
205
|
-
allTables.forEach(table => {
|
|
206
|
-
let indices = makeCreateTableIndicesQuery(table, pgSchema);
|
|
207
|
-
if (indices !== "") {
|
|
208
|
-
query.contents = query.contents + "\n" + indices;
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
207
|
+
query.contents = query.contents + "\n" + makeCreateTableQuery(table, pgSchema, isHasuraEnabled, chainIdMode);
|
|
211
208
|
});
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
query.contents = query.contents + "\n" + makeCreateIndexQuery(derivedFromField.derivedFromEntity, [indexField], pgSchema);
|
|
209
|
+
if (!deferSchemaIndexes) {
|
|
210
|
+
schemaIndexes.forEach(definition => {
|
|
211
|
+
query.contents = query.contents + "\n" + IndexDefinition.makeCreateQuery(definition, pgSchema);
|
|
216
212
|
});
|
|
217
|
-
}
|
|
213
|
+
}
|
|
218
214
|
query.contents = query.contents + "\n" + InternalTable.Views.makeMetaViewQuery(pgSchema);
|
|
219
215
|
query.contents = query.contents + "\n" + InternalTable.Views.makeChainMetadataViewQuery(pgSchema);
|
|
220
216
|
let initialChainsValuesQuery = InternalTable.Chains.makeInitialValuesQuery(pgSchema, chainConfigs);
|
|
@@ -301,8 +297,9 @@ function makeLoadAllQuery(pgSchema, tableName) {
|
|
|
301
297
|
return `SELECT * FROM "` + pgSchema + `"."` + tableName + `";`;
|
|
302
298
|
}
|
|
303
299
|
|
|
304
|
-
function makeInsertUnnestSetQuery(pgSchema, table, itemSchema, isRawEvents) {
|
|
305
|
-
let
|
|
300
|
+
function makeInsertUnnestSetQuery(pgSchema, table, itemSchema, isRawEvents, chainIdModeOpt) {
|
|
301
|
+
let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
|
|
302
|
+
let match = Table.toSqlParams(table, itemSchema, pgSchema, chainIdMode);
|
|
306
303
|
let quotedNonPrimaryFieldNames = match.quotedNonPrimaryFieldNames;
|
|
307
304
|
let primaryKeyFieldNames = Table.getPgPrimaryKeyFieldNames(table);
|
|
308
305
|
return `INSERT INTO "` + pgSchema + `"."` + table.tableName + `" (` + match.quotedFieldNames.join(", ") + `)
|
|
@@ -313,8 +310,9 @@ SELECT * FROM unnest(` + match.arrayFieldTypes.map((arrayFieldType, idx) => `$`
|
|
|
313
310
|
) + ";";
|
|
314
311
|
}
|
|
315
312
|
|
|
316
|
-
function makeInsertValuesSetQuery(pgSchema, table, itemSchema, itemsCount) {
|
|
317
|
-
let
|
|
313
|
+
function makeInsertValuesSetQuery(pgSchema, table, itemSchema, itemsCount, chainIdModeOpt) {
|
|
314
|
+
let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
|
|
315
|
+
let match = Table.toSqlParams(table, itemSchema, pgSchema, chainIdMode);
|
|
318
316
|
let quotedNonPrimaryFieldNames = match.quotedNonPrimaryFieldNames;
|
|
319
317
|
let quotedFieldNames = match.quotedFieldNames;
|
|
320
318
|
let primaryKeyFieldNames = Table.getPgPrimaryKeyFieldNames(table);
|
|
@@ -341,19 +339,20 @@ VALUES` + placeholders + (
|
|
|
341
339
|
) + ";";
|
|
342
340
|
}
|
|
343
341
|
|
|
344
|
-
function makeTableBatchSetQuery(pgSchema, table, itemSchema) {
|
|
345
|
-
let
|
|
342
|
+
function makeTableBatchSetQuery(pgSchema, table, itemSchema, chainIdModeOpt) {
|
|
343
|
+
let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
|
|
344
|
+
let match = Table.toSqlParams(table, itemSchema, pgSchema, chainIdMode);
|
|
346
345
|
let isRawEvents = table.tableName === InternalTable.RawEvents.table.tableName;
|
|
347
346
|
let isHistoryUpdate = table.tableName.startsWith(EntityHistory.historyTablePrefix);
|
|
348
347
|
if ((isRawEvents || !match.hasArrayField) && !isHistoryUpdate) {
|
|
349
348
|
return {
|
|
350
|
-
query: makeInsertUnnestSetQuery(pgSchema, table, itemSchema, isRawEvents),
|
|
349
|
+
query: makeInsertUnnestSetQuery(pgSchema, table, itemSchema, isRawEvents, chainIdMode),
|
|
351
350
|
convertOrThrow: S$RescriptSchema.compile(S$RescriptSchema.unnest(match.dbSchema), "Output", "Input", "Sync", false),
|
|
352
351
|
isInsertValues: false
|
|
353
352
|
};
|
|
354
353
|
} else {
|
|
355
354
|
return {
|
|
356
|
-
query: makeInsertValuesSetQuery(pgSchema, table, itemSchema, 500),
|
|
355
|
+
query: makeInsertValuesSetQuery(pgSchema, table, itemSchema, 500, chainIdMode),
|
|
357
356
|
convertOrThrow: S$RescriptSchema.compile(S$RescriptSchema.preprocess(S$RescriptSchema.unnest(itemSchema), param => ({
|
|
358
357
|
s: prim => prim.flat(1)
|
|
359
358
|
})), "Output", "Input", "Sync", false),
|
|
@@ -429,7 +428,8 @@ function classifyWriteError(specificError, table, exn) {
|
|
|
429
428
|
|
|
430
429
|
let setQueryCache = new WeakMap();
|
|
431
430
|
|
|
432
|
-
async function setOrThrow(sql, items, table, itemSchema, pgSchema) {
|
|
431
|
+
async function setOrThrow(sql, items, table, itemSchema, pgSchema, chainIdModeOpt) {
|
|
432
|
+
let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
|
|
433
433
|
if (items.length === 0) {
|
|
434
434
|
return;
|
|
435
435
|
}
|
|
@@ -438,7 +438,7 @@ async function setOrThrow(sql, items, table, itemSchema, pgSchema) {
|
|
|
438
438
|
if (cached !== undefined) {
|
|
439
439
|
data = Primitive_option.valFromOption(cached);
|
|
440
440
|
} else {
|
|
441
|
-
let newQuery = makeTableBatchSetQuery(pgSchema, table, itemSchema);
|
|
441
|
+
let newQuery = makeTableBatchSetQuery(pgSchema, table, itemSchema, chainIdMode);
|
|
442
442
|
setQueryCache.set(table, newQuery);
|
|
443
443
|
data = newQuery;
|
|
444
444
|
}
|
|
@@ -452,7 +452,7 @@ async function setOrThrow(sql, items, table, itemSchema, pgSchema) {
|
|
|
452
452
|
let chunkSize = chunk.length;
|
|
453
453
|
let isFullChunk = chunkSize === 500;
|
|
454
454
|
let params = data.convertOrThrow(chunk);
|
|
455
|
-
let response = isFullChunk ? sql.unsafe(data.query, params, {prepare: true}) : sql.unsafe(makeInsertValuesSetQuery(pgSchema, table, itemSchema, chunkSize), params);
|
|
455
|
+
let response = isFullChunk ? sql.unsafe(data.query, params, {prepare: true}) : sql.unsafe(makeInsertValuesSetQuery(pgSchema, table, itemSchema, chunkSize, chainIdMode), params);
|
|
456
456
|
responses.push(response);
|
|
457
457
|
});
|
|
458
458
|
await Promise.all(responses);
|
|
@@ -587,7 +587,7 @@ function makeInsertDeleteUpdatesQuery(entityConfig, pgSchema) {
|
|
|
587
587
|
}
|
|
588
588
|
});
|
|
589
589
|
let selectPartsStr = selectParts.join(", ");
|
|
590
|
-
let checkpointIdPgType = Table.getPgFieldType(EntityHistory.checkpointIdFieldType, pgSchema, false, false, false);
|
|
590
|
+
let checkpointIdPgType = Table.getPgFieldType(EntityHistory.checkpointIdFieldType, pgSchema, false, false, false, undefined);
|
|
591
591
|
let idPgType = Table.getIdPgFieldType(entityConfig.table, pgSchema);
|
|
592
592
|
return `INSERT INTO "` + pgSchema + `"."` + historyTableName + `" (` + allHistoryFieldNamesStr + `)
|
|
593
593
|
SELECT ` + selectPartsStr + `
|
|
@@ -604,6 +604,7 @@ function executeSet(sql, items, dbFunction) {
|
|
|
604
604
|
|
|
605
605
|
async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, config, allEntities, setEffectCacheOrThrow, updatedEffectsCache, updatedEntities, sinkPromise, chainMetaData, escapeTables) {
|
|
606
606
|
try {
|
|
607
|
+
let chainIdMode = config.chainIdMode;
|
|
607
608
|
let shouldSaveHistory = Config.shouldSaveHistory(config, isInReorgThreshold);
|
|
608
609
|
let specificError = {
|
|
609
610
|
contents: undefined
|
|
@@ -615,7 +616,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
615
616
|
if (item.kind !== 0) {
|
|
616
617
|
return;
|
|
617
618
|
}
|
|
618
|
-
let coordinate = Internal.getItemChainId(item)
|
|
619
|
+
let coordinate = ChainId.toString(Internal.getItemChainId(item)) + `-` + item.blockNumber.toString() + `-` + item.logIndex.toString();
|
|
619
620
|
if (seenLogCoordinates.has(coordinate)) {
|
|
620
621
|
return;
|
|
621
622
|
} else {
|
|
@@ -632,7 +633,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
632
633
|
}
|
|
633
634
|
let setRawEvents = async sql => {
|
|
634
635
|
try {
|
|
635
|
-
return await executeSet(sql, rawEvents, (sql, items) => setOrThrow(sql, items, InternalTable.RawEvents.table, InternalTable.RawEvents.schema, pgSchema));
|
|
636
|
+
return await executeSet(sql, rawEvents, (sql, items) => setOrThrow(sql, items, InternalTable.RawEvents.table, InternalTable.RawEvents.schema, pgSchema, chainIdMode));
|
|
636
637
|
} catch (raw_exn) {
|
|
637
638
|
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
638
639
|
return classifyWriteError(specificError, InternalTable.RawEvents.table, exn);
|
|
@@ -709,14 +710,14 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
709
710
|
}));
|
|
710
711
|
}
|
|
711
712
|
let entityHistory = getEntityHistory(entityConfig);
|
|
712
|
-
promises.push(setOrThrow(sql, batchSetUpdates, entityHistory.table, entityHistory.setChangeSchema, pgSchema));
|
|
713
|
+
promises.push(setOrThrow(sql, batchSetUpdates, entityHistory.table, entityHistory.setChangeSchema, pgSchema, chainIdMode));
|
|
713
714
|
}
|
|
714
715
|
}
|
|
715
716
|
if (Utils.$$Array.notEmpty(entitiesToSet)) {
|
|
716
717
|
if (shouldRemoveInvalidUtf8) {
|
|
717
718
|
removeInvalidUtf8InPlace(entitiesToSet);
|
|
718
719
|
}
|
|
719
|
-
promises.push(setOrThrow(sql, entitiesToSet, entityConfig.table, entityConfig.schema, pgSchema));
|
|
720
|
+
promises.push(setOrThrow(sql, entitiesToSet, entityConfig.table, entityConfig.schema, pgSchema, chainIdMode));
|
|
720
721
|
}
|
|
721
722
|
if (Utils.$$Array.notEmpty(idsToDelete)) {
|
|
722
723
|
promises.push(deleteByIdsOrThrow(sql, pgSchema, idsToDelete, entityConfig.table));
|
|
@@ -733,7 +734,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
733
734
|
if (rollback !== undefined) {
|
|
734
735
|
let rollbackTargetCheckpointId = rollback.targetCheckpointId;
|
|
735
736
|
rollbackTables = sql => {
|
|
736
|
-
let promises = allEntities.map(entityConfig => EntityHistory.rollback(sql, pgSchema, entityConfig.name, entityConfig.index, rollbackTargetCheckpointId));
|
|
737
|
+
let promises = allEntities.filter(entityConfig => entityConfig.storage.postgres).map(entityConfig => EntityHistory.rollback(sql, pgSchema, entityConfig.name, entityConfig.index, rollbackTargetCheckpointId));
|
|
737
738
|
promises.push(InternalTable.Checkpoints.rollback(sql, pgSchema, rollbackTargetCheckpointId));
|
|
738
739
|
return Promise.all(promises);
|
|
739
740
|
};
|
|
@@ -759,7 +760,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
759
760
|
setOperations.push(sql => InternalTable.Chains.setMeta(sql, pgSchema, chainMetaData));
|
|
760
761
|
}
|
|
761
762
|
if (shouldSaveHistory) {
|
|
762
|
-
setOperations.push(sql => InternalTable.Checkpoints.insert(sql, pgSchema, batch.checkpointIds, batch.checkpointChainIds, batch.checkpointBlockNumbers, batch.checkpointBlockHashes, batch.checkpointEventsProcessed));
|
|
763
|
+
setOperations.push(sql => InternalTable.Checkpoints.insert(sql, pgSchema, batch.checkpointIds, batch.checkpointChainIds, batch.checkpointBlockNumbers, batch.checkpointBlockHashes, batch.checkpointEventsProcessed, chainIdMode));
|
|
763
764
|
}
|
|
764
765
|
await Promise.all(setOperations.map(dbFunc => dbFunc(sql)));
|
|
765
766
|
if (sinkPromise === undefined) {
|
|
@@ -834,7 +835,8 @@ let rollbackRowStateSchema = Utils.$$WeakMap.memoize(table => S$RescriptSchema.o
|
|
|
834
835
|
|
|
835
836
|
let rollbackRemovedIdsSchema = Utils.$$WeakMap.memoize(table => S$RescriptSchema.array(S$RescriptSchema.object(s => s.f(Table.idFieldName, Table.getIdSchema(table)))));
|
|
836
837
|
|
|
837
|
-
function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isHasuraEnabled, sink, onInitialize, onNewTables) {
|
|
838
|
+
function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isHasuraEnabled, chainIdModeOpt, sink, onInitialize, onNewTables) {
|
|
839
|
+
let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
|
|
838
840
|
let containerName = "envio-postgres";
|
|
839
841
|
let psqlExecOptions_env = Object.fromEntries([
|
|
840
842
|
[
|
|
@@ -850,6 +852,28 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
850
852
|
env: psqlExecOptions_env
|
|
851
853
|
};
|
|
852
854
|
let cacheDirPath = Path.resolve(".envio", "cache");
|
|
855
|
+
let storageName = "postgres";
|
|
856
|
+
let indexManager = IndexManager.make();
|
|
857
|
+
let loadCatalogRows = (sql, indexName) => sql.unsafe(IndexCatalog.makeQuery(pgSchema, indexName)).then(rows => S$RescriptSchema.parseOrThrow(rows, IndexCatalog.rowsSchema));
|
|
858
|
+
let refreshIndexCatalog = async () => {
|
|
859
|
+
let rows = await loadCatalogRows(sql, undefined);
|
|
860
|
+
return IndexManager.reload(indexManager, rows);
|
|
861
|
+
};
|
|
862
|
+
let reloadIndexCatalog = async () => {
|
|
863
|
+
let catalog = await refreshIndexCatalog();
|
|
864
|
+
let invalidIndexNames = IndexCatalog.invalidNames(catalog);
|
|
865
|
+
if (invalidIndexNames.length !== 0) {
|
|
866
|
+
Logging.warn({
|
|
867
|
+
storage: storageName,
|
|
868
|
+
msg: `Ignoring invalid PostgreSQL indexes in schema "` + pgSchema + `". They can't serve queries, so the indexer builds its own alongside them.`,
|
|
869
|
+
indexes: invalidIndexNames
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
return Logging.info({
|
|
873
|
+
storage: storageName,
|
|
874
|
+
msg: `Found ` + IndexCatalog.size(catalog).toString() + ` existing indexes in the indexer schema.`
|
|
875
|
+
});
|
|
876
|
+
};
|
|
853
877
|
let isInitialized = async () => Utils.$$Array.notEmpty(await sql.unsafe(`SELECT table_schema FROM information_schema.tables WHERE table_schema = '` + pgSchema + `' AND (table_name = '` + "event_sync_state" + `' OR table_name = '` + InternalTable.Chains.table.tableName + `');`));
|
|
854
878
|
let scanCacheDir = async () => {
|
|
855
879
|
let topEntries;
|
|
@@ -866,21 +890,23 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
866
890
|
let subEntries = await Fs.promises.readdir(entryPath);
|
|
867
891
|
let tsvs = subEntries.filter(sub => sub.endsWith(".tsv"));
|
|
868
892
|
let chainId = Internal.EffectCache.parseChainId(entry);
|
|
869
|
-
if (chainId
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
Path.join(entryPath, sub)
|
|
876
|
-
]);
|
|
877
|
-
});
|
|
878
|
-
return;
|
|
879
|
-
} else if (Utils.$$Array.notEmpty(tsvs)) {
|
|
880
|
-
return Stdlib_JsError.throwWithMessage(`Invalid effect cache directory ".envio/cache/` + entry + `". Chain cache directories must be named by a numeric chain id (e.g. "1"). Found cache files: ` + tsvs.join(", ") + `.`);
|
|
881
|
-
} else {
|
|
882
|
-
return;
|
|
893
|
+
if (chainId === undefined) {
|
|
894
|
+
if (Utils.$$Array.notEmpty(tsvs)) {
|
|
895
|
+
return Stdlib_JsError.throwWithMessage(`Invalid effect cache directory ".envio/cache/` + entry + `". Chain cache directories must be named by a numeric chain id (e.g. "1"). Found cache files: ` + tsvs.join(", ") + `.`);
|
|
896
|
+
} else {
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
883
899
|
}
|
|
900
|
+
let chainId$1 = Primitive_option.valFromOption(chainId);
|
|
901
|
+
tsvs.forEach(sub => {
|
|
902
|
+
let effectName = sub.slice(0, -4);
|
|
903
|
+
let table = Internal.makeCacheTable(effectName, chainId$1);
|
|
904
|
+
result.push([
|
|
905
|
+
table,
|
|
906
|
+
Path.join(entryPath, sub)
|
|
907
|
+
]);
|
|
908
|
+
});
|
|
909
|
+
return;
|
|
884
910
|
}
|
|
885
911
|
if (!entry.endsWith(".tsv")) {
|
|
886
912
|
return;
|
|
@@ -915,7 +941,7 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
915
941
|
await Promise.all(entries.map(param => {
|
|
916
942
|
let inputFile = param[1];
|
|
917
943
|
let table = param[0];
|
|
918
|
-
return sql.unsafe(makeCreateTableQuery(table, pgSchema, false)).then(() => {
|
|
944
|
+
return sql.unsafe(makeCreateTableQuery(table, pgSchema, false, undefined)).then(() => {
|
|
919
945
|
let command = psqlExec$1 + ` -c 'COPY "` + pgSchema + `"."` + table.tableName + `" FROM STDIN WITH (FORMAT text, HEADER);' < ` + inputFile;
|
|
920
946
|
return new Promise((resolve, reject) => {
|
|
921
947
|
Child_process.exec(command, psqlExecOptions, (error, stdout, param) => {
|
|
@@ -969,7 +995,7 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
969
995
|
if (sink !== undefined) {
|
|
970
996
|
await sink.initialize(chainConfigs, chEntities, enums);
|
|
971
997
|
}
|
|
972
|
-
let queries = makeInitializeTransaction(pgSchema, pgUser, isHasuraEnabled, chainConfigs, pgEntities, enums, Utils.$$Array.isEmpty(schemaTableNames));
|
|
998
|
+
let queries = makeInitializeTransaction(pgSchema, pgUser, isHasuraEnabled, chainConfigs, pgEntities, enums, Utils.$$Array.isEmpty(schemaTableNames), true, chainIdMode);
|
|
973
999
|
await sql.begin(async sql => {
|
|
974
1000
|
await Promise.all(queries.map(query => sql.unsafe(query)));
|
|
975
1001
|
return await InternalTable.EnvioInfo.write(sql, pgSchema, envioInfo);
|
|
@@ -987,14 +1013,16 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
987
1013
|
});
|
|
988
1014
|
});
|
|
989
1015
|
if (ids.length !== 0) {
|
|
1016
|
+
let addrChainIdArrayType = Table.getPgFieldType("ChainId", pgSchema, true, false, false, chainIdMode);
|
|
990
1017
|
await sql.unsafe(`INSERT INTO "` + pgSchema + `"."` + Config.EnvioAddresses.table.tableName + `" ("id", "chain_id", "registration_block", "registration_log_index", "contract_name")
|
|
991
|
-
SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2
|
|
1018
|
+
SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::` + addrChainIdArrayType + `,$3::text[]) AS t(id, chain_id, contract_name);`, [
|
|
992
1019
|
ids,
|
|
993
1020
|
addrChainIds,
|
|
994
1021
|
addrContractNames
|
|
995
1022
|
]);
|
|
996
1023
|
}
|
|
997
1024
|
let cache = await restoreEffectCache(true);
|
|
1025
|
+
await reloadIndexCatalog();
|
|
998
1026
|
if (onInitialize !== undefined) {
|
|
999
1027
|
await onInitialize();
|
|
1000
1028
|
}
|
|
@@ -1045,10 +1073,166 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
|
|
|
1045
1073
|
};
|
|
1046
1074
|
}
|
|
1047
1075
|
};
|
|
1048
|
-
let
|
|
1076
|
+
let filterColumns = (table, filters) => {
|
|
1077
|
+
let queryFields = Table.queryFields(table);
|
|
1078
|
+
let columns = [];
|
|
1079
|
+
let seen = new Set();
|
|
1080
|
+
let collect = filter => {
|
|
1081
|
+
if (filter.operator === "and") {
|
|
1082
|
+
filter.filters.forEach(collect);
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
let match = queryFields[filter.fieldName];
|
|
1086
|
+
if (match === undefined) {
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
let pgDbFieldName = match.pgDbFieldName;
|
|
1090
|
+
if (!seen.has(pgDbFieldName)) {
|
|
1091
|
+
seen.add(pgDbFieldName);
|
|
1092
|
+
columns.push(pgDbFieldName);
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
1095
|
+
};
|
|
1096
|
+
filters.forEach(collect);
|
|
1097
|
+
return columns;
|
|
1098
|
+
};
|
|
1099
|
+
let runAndVerify = async (sql, prepared) => {
|
|
1100
|
+
for (let idx = 0, idx_finish = prepared.queries.length; idx < idx_finish; ++idx) {
|
|
1101
|
+
await sql.unsafe(prepared.queries[idx]);
|
|
1102
|
+
}
|
|
1103
|
+
let rows = await loadCatalogRows(sql, prepared.name);
|
|
1104
|
+
return IndexManager.verifyOrThrow(prepared, rows, pgSchema);
|
|
1105
|
+
};
|
|
1106
|
+
let resyncIndex = async name => {
|
|
1107
|
+
let rows;
|
|
1108
|
+
try {
|
|
1109
|
+
rows = await loadCatalogRows(sql, name);
|
|
1110
|
+
} catch (raw_exn) {
|
|
1111
|
+
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
1112
|
+
return Logging.debug({
|
|
1113
|
+
storage: storageName,
|
|
1114
|
+
msg: `Could not re-read the index "` + name + `" after a failed build. The next attempt reads it again.`,
|
|
1115
|
+
err: Utils.prettifyExn(exn)
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
return IndexManager.resync(indexManager, name, rows);
|
|
1119
|
+
};
|
|
1120
|
+
let ensureQueryIndexes = async (table, filters) => {
|
|
1121
|
+
let columns = filterColumns(table, filters);
|
|
1122
|
+
await Promise.all(columns.map(column => {
|
|
1123
|
+
let definition = IndexDefinition.single(table.tableName, column);
|
|
1124
|
+
return Stdlib_Promise.$$catch(IndexManager.ensure(indexManager, definition, "LeadingColumns", async () => {
|
|
1125
|
+
let prepared = IndexManager.prepare(indexManager, definition, "LeadingColumns", pgSchema);
|
|
1126
|
+
if (prepared === undefined) {
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
let verb = prepared.isRebuild ? "Rebuilding unusable index" : "Creating index";
|
|
1130
|
+
Logging.info({
|
|
1131
|
+
storage: storageName,
|
|
1132
|
+
msg: verb + ` "` + prepared.name + `" to serve a getWhere query on "` + table.tableName + `". Writes to the table are paused until it completes. ` + slowOnLargeDatabaseNotice
|
|
1133
|
+
});
|
|
1134
|
+
let timeRef = Performance.now();
|
|
1135
|
+
let entry = await runAndVerify(sql, prepared);
|
|
1136
|
+
IndexManager.record(indexManager, entry);
|
|
1137
|
+
return Logging.info({
|
|
1138
|
+
storage: storageName,
|
|
1139
|
+
msg: `Index "` + prepared.name + `" is ready after ` + formatSeconds(timeRef) + `s. Resuming indexing.`
|
|
1140
|
+
});
|
|
1141
|
+
}), async exn => {
|
|
1142
|
+
Logging.warn({
|
|
1143
|
+
storage: storageName,
|
|
1144
|
+
msg: `Failed to create an index on "` + table.tableName + `"("` + column + `") for a getWhere query. The query runs without it.`,
|
|
1145
|
+
err: Utils.prettifyExn(exn)
|
|
1146
|
+
});
|
|
1147
|
+
return await resyncIndex(IndexDefinition.name(definition));
|
|
1148
|
+
});
|
|
1149
|
+
}));
|
|
1150
|
+
};
|
|
1151
|
+
let ensureSchemaIndexes = async entities => {
|
|
1152
|
+
let schemaIndexes = getSchemaIndexes(entities.filter(e => e.storage.postgres));
|
|
1153
|
+
await Promise.all(schemaIndexes.map(definition => Stdlib_Promise.$$catch(IndexManager.ensure(indexManager, definition, "Exact", async () => {
|
|
1154
|
+
let prepared = IndexManager.prepare(indexManager, definition, "Exact", pgSchema);
|
|
1155
|
+
if (prepared === undefined) {
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
let verb = prepared.isRebuild ? "Rebuilding unusable index" : "Creating missing index";
|
|
1159
|
+
Logging.info({
|
|
1160
|
+
storage: storageName,
|
|
1161
|
+
msg: verb + ` "` + prepared.name + `" the schema promises but the database no longer has. Writes to the table are paused until it completes. ` + slowOnLargeDatabaseNotice
|
|
1162
|
+
});
|
|
1163
|
+
let timeRef = Performance.now();
|
|
1164
|
+
let entry = await runAndVerify(sql, prepared);
|
|
1165
|
+
IndexManager.record(indexManager, entry);
|
|
1166
|
+
return Logging.info({
|
|
1167
|
+
storage: storageName,
|
|
1168
|
+
msg: `Index "` + prepared.name + `" is ready after ` + formatSeconds(timeRef) + `s.`
|
|
1169
|
+
});
|
|
1170
|
+
}), async exn => {
|
|
1171
|
+
Logging.warn({
|
|
1172
|
+
storage: storageName,
|
|
1173
|
+
msg: `Failed to restore the schema index "` + IndexDefinition.name(definition) + `". Queries relying on it run unindexed until the next restart.`,
|
|
1174
|
+
err: Utils.prettifyExn(exn)
|
|
1175
|
+
});
|
|
1176
|
+
return await resyncIndex(IndexDefinition.name(definition));
|
|
1177
|
+
})));
|
|
1178
|
+
};
|
|
1179
|
+
let finalizeBackfill = async (entities, chainIds, readyAt) => {
|
|
1180
|
+
let schemaIndexes = getSchemaIndexes(entities.filter(e => e.storage.postgres));
|
|
1181
|
+
let missing = Stdlib_Array.filterMap(schemaIndexes, definition => IndexManager.prepare(indexManager, definition, "Exact", pgSchema));
|
|
1182
|
+
let rebuilt = missing.filter(prepared => prepared.isRebuild);
|
|
1183
|
+
if (rebuilt.length !== 0) {
|
|
1184
|
+
Logging.warn({
|
|
1185
|
+
storage: storageName,
|
|
1186
|
+
msg: `PostgreSQL reports ` + rebuilt.length.toString() + ` of the indexer's own indexes as invalid, so they can't serve queries. Rebuilding them.`,
|
|
1187
|
+
indexes: rebuilt.map(prepared => prepared.name)
|
|
1188
|
+
});
|
|
1189
|
+
}
|
|
1190
|
+
if (missing.length !== 0) {
|
|
1191
|
+
Logging.info({
|
|
1192
|
+
storage: storageName,
|
|
1193
|
+
msg: `Creating the ` + missing.length.toString() + ` remaining schema indexes before the indexer reports ready. Writes are paused until they are committed. ` + slowOnLargeDatabaseNotice,
|
|
1194
|
+
indexes: missing.map(prepared => prepared.name)
|
|
1195
|
+
});
|
|
1196
|
+
} else {
|
|
1197
|
+
Logging.info({
|
|
1198
|
+
storage: storageName,
|
|
1199
|
+
msg: `All ` + schemaIndexes.length.toString() + ` schema indexes are already in place. Marking the indexer ready.`
|
|
1200
|
+
});
|
|
1201
|
+
}
|
|
1202
|
+
let timeRef = Performance.now();
|
|
1203
|
+
for (let idx = 0, idx_finish = missing.length; idx < idx_finish; ++idx) {
|
|
1204
|
+
let prepared = missing[idx];
|
|
1205
|
+
let exit = 0;
|
|
1206
|
+
let entry;
|
|
1207
|
+
try {
|
|
1208
|
+
entry = await runAndVerify(sql, prepared);
|
|
1209
|
+
exit = 1;
|
|
1210
|
+
} catch (exn) {
|
|
1211
|
+
await resyncIndex(prepared.name);
|
|
1212
|
+
throw exn;
|
|
1213
|
+
}
|
|
1214
|
+
if (exit === 1) {
|
|
1215
|
+
IndexManager.record(indexManager, entry);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
let setReadyAtQuery = InternalTable.Chains.makeSetReadyAtQuery(pgSchema);
|
|
1219
|
+
await sql.begin(async sql => {
|
|
1220
|
+
for (let idx = 0, idx_finish = chainIds.length; idx < idx_finish; ++idx) {
|
|
1221
|
+
await sql.unsafe(setReadyAtQuery, [
|
|
1222
|
+
readyAt,
|
|
1223
|
+
chainIds[idx]
|
|
1224
|
+
], {prepare: true});
|
|
1225
|
+
}
|
|
1226
|
+
});
|
|
1227
|
+
return Logging.info({
|
|
1228
|
+
storage: storageName,
|
|
1229
|
+
msg: `Committed ` + missing.length.toString() + ` schema indexes and the ready timestamp in ` + formatSeconds(timeRef) + `s.`
|
|
1230
|
+
});
|
|
1231
|
+
};
|
|
1232
|
+
let setOrThrow$1 = (items, table, itemSchema) => setOrThrow(sql, items, table, itemSchema, pgSchema, undefined);
|
|
1049
1233
|
let setEffectCacheOrThrow = async (table, itemSchema, items, initialize) => {
|
|
1050
1234
|
if (initialize) {
|
|
1051
|
-
await sql.unsafe(makeCreateTableQuery(table, pgSchema, false));
|
|
1235
|
+
await sql.unsafe(makeCreateTableQuery(table, pgSchema, false, undefined));
|
|
1052
1236
|
if (onNewTables !== undefined) {
|
|
1053
1237
|
await onNewTables([table.tableName]);
|
|
1054
1238
|
}
|
|
@@ -1121,10 +1305,11 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
|
|
|
1121
1305
|
sql.unsafe(InternalTable.Checkpoints.makeGetReorgCheckpointsQuery(pgSchema)),
|
|
1122
1306
|
InternalTable.EnvioInfo.read(sql, pgSchema)
|
|
1123
1307
|
]);
|
|
1308
|
+
await reloadIndexCatalog();
|
|
1124
1309
|
let checkpointId = BigInt(match[2][0].id);
|
|
1125
1310
|
let reorgCheckpoints = match[3].map(raw => ({
|
|
1126
1311
|
id: BigInt(raw.id),
|
|
1127
|
-
chain_id: raw.chain_id,
|
|
1312
|
+
chain_id: ChainId.normalizeOrThrow(raw.chain_id),
|
|
1128
1313
|
block_number: raw.block_number,
|
|
1129
1314
|
block_hash: raw.block_hash
|
|
1130
1315
|
}));
|
|
@@ -1193,15 +1378,18 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
|
|
|
1193
1378
|
}
|
|
1194
1379
|
let primaryTimerRef = Performance.now();
|
|
1195
1380
|
await writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, config, allEntities, setEffectCacheOrThrow, updatedEffectsCache, pgUpdates, sinkPromise, chainMetaData, undefined);
|
|
1196
|
-
return onWrite(
|
|
1381
|
+
return onWrite(storageName, Performance.secondsSince(primaryTimerRef));
|
|
1197
1382
|
};
|
|
1198
1383
|
let close = () => sql.end();
|
|
1199
1384
|
return {
|
|
1200
|
-
name:
|
|
1385
|
+
name: storageName,
|
|
1201
1386
|
isInitialized: isInitialized,
|
|
1202
1387
|
initialize: initialize,
|
|
1203
1388
|
resumeInitialState: resumeInitialState,
|
|
1204
1389
|
loadOrThrow: loadOrThrow,
|
|
1390
|
+
ensureQueryIndexes: ensureQueryIndexes,
|
|
1391
|
+
ensureSchemaIndexes: ensureSchemaIndexes,
|
|
1392
|
+
finalizeBackfill: finalizeBackfill,
|
|
1205
1393
|
dumpEffectCache: dumpEffectCache,
|
|
1206
1394
|
reset: reset,
|
|
1207
1395
|
setChainMeta: setChainMeta,
|
|
@@ -1241,11 +1429,11 @@ function makeStorageFromEnv(config, sqlOpt, pgSchemaOpt, isHasuraEnabledOpt) {
|
|
|
1241
1429
|
if (missing.length !== 0) {
|
|
1242
1430
|
Stdlib_JsError.throwWithMessage(`ClickHouse storage is enabled but required env vars are not set: ` + missing.join(", ") + `. Please set them, disable clickhouse in the \`storage\` config, or run \`envio dev\` for a pre-configured local ClickHouse.`);
|
|
1243
1431
|
}
|
|
1244
|
-
tmp = Sink.makeClickHouse(host, database, username, password);
|
|
1432
|
+
tmp = Sink.makeClickHouse(host, database, username, password, config.chainIdMode);
|
|
1245
1433
|
} else {
|
|
1246
1434
|
tmp = undefined;
|
|
1247
1435
|
}
|
|
1248
|
-
return make(sql, Env.Db.host, pgSchema, Env.Db.port, Env.Db.user, Env.Db.database, Env.Db.password, isHasuraEnabled, tmp, isHasuraEnabled ? () => Stdlib_Promise.$$catch(Hasura.trackDatabase(Env.Hasura.graphqlEndpoint, {
|
|
1436
|
+
return make(sql, Env.Db.host, pgSchema, Env.Db.port, Env.Db.user, Env.Db.database, Env.Db.password, isHasuraEnabled, config.chainIdMode, tmp, isHasuraEnabled ? () => Stdlib_Promise.$$catch(Hasura.trackDatabase(Env.Hasura.graphqlEndpoint, {
|
|
1249
1437
|
role: Env.Hasura.role,
|
|
1250
1438
|
secret: Env.Hasura.secret
|
|
1251
1439
|
}, pgSchema, Config.getPgUserEntities(config), Env.Hasura.aggregateEntities, Env.Hasura.responseLimit, Schema.make(config.allEntities.map(e => e.table))), err => Promise.resolve(Logging.errorWithExn(Utils.prettifyExn(err), `Error tracking tables`))) : undefined, isHasuraEnabled ? tableNames => Stdlib_Promise.$$catch(Hasura.trackTables(Env.Hasura.graphqlEndpoint, {
|
|
@@ -1267,11 +1455,9 @@ let maxItemsPerQuery = 500;
|
|
|
1267
1455
|
|
|
1268
1456
|
export {
|
|
1269
1457
|
makeClient,
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
makeCreateCompositeIndexQuery,
|
|
1274
|
-
makeCreateTableIndicesQuery,
|
|
1458
|
+
formatSeconds,
|
|
1459
|
+
slowOnLargeDatabaseNotice,
|
|
1460
|
+
getSchemaIndexes,
|
|
1275
1461
|
makeCreateTableQuery,
|
|
1276
1462
|
entityHistoryCache,
|
|
1277
1463
|
getEntityHistory,
|
package/src/RawEvent.res
CHANGED
|
@@ -32,9 +32,8 @@ let make = (
|
|
|
32
32
|
~blockTimestamp: int,
|
|
33
33
|
~cleanUpRawEventFieldsInPlace: JSON.t => unit,
|
|
34
34
|
): Internal.rawEvent => {
|
|
35
|
-
let {
|
|
35
|
+
let {chainId, blockNumber, logIndex} = eventItem
|
|
36
36
|
let eventConfig = eventItem.onEventRegistration.eventConfig
|
|
37
|
-
let chainId = chain->ChainMap.Chain.toChainId
|
|
38
37
|
let eventId = EventUtils.packEventIndex(~logIndex, ~blockNumber)
|
|
39
38
|
let blockFields =
|
|
40
39
|
block
|