envio 3.5.0-alpha.3 → 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 +17 -7
- package/src/BatchProcessing.res.mjs +8 -4
- 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 +35 -20
- package/src/ChainState.res.mjs +34 -11
- package/src/ChainState.resi +2 -0
- package/src/Config.res +41 -24
- package/src/Config.res.mjs +17 -14
- package/src/ContractRegisterContext.res +1 -1
- package/src/ContractRegisterContext.res.mjs +1 -1
- package/src/Core.res +1 -0
- package/src/CrossChainState.res +61 -16
- package/src/CrossChainState.res.mjs +37 -13
- package/src/CrossChainState.resi +3 -2
- 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 +261 -89
- package/src/FetchState.res.mjs +187 -63
- package/src/FinalizeBackfill.res +33 -6
- package/src/FinalizeBackfill.res.mjs +19 -1
- 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/IndexerLoop.res +9 -2
- package/src/IndexerLoop.res.mjs +8 -1
- package/src/IndexerState.res +41 -24
- package/src/IndexerState.res.mjs +36 -17
- package/src/IndexerState.resi +9 -7
- package/src/Internal.res +19 -17
- package/src/Internal.res.mjs +18 -9
- package/src/LoadLayer.res +1 -1
- package/src/LoadLayer.res.mjs +2 -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 +15 -7
- package/src/PgStorage.res +284 -258
- package/src/PgStorage.res.mjs +181 -208
- 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 +11 -14
- package/src/TestIndexer.res.mjs +14 -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/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 +50 -26
- package/src/db/InternalTable.res.mjs +32 -24
- package/src/db/Table.res +11 -1
- package/src/db/Table.res.mjs +9 -4
- 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/db/IndexRegistry.res +0 -219
- package/src/db/IndexRegistry.res.mjs +0 -195
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,14 +17,16 @@ 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
|
-
import * as IndexRegistry from "./db/IndexRegistry.res.mjs";
|
|
22
24
|
import * as InternalTable from "./db/InternalTable.res.mjs";
|
|
23
25
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
24
26
|
import * as Child_process from "child_process";
|
|
25
27
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
26
28
|
import * as Stdlib_Promise from "@rescript/runtime/lib/es6/Stdlib_Promise.js";
|
|
29
|
+
import * as IndexDefinition from "./db/IndexDefinition.res.mjs";
|
|
27
30
|
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
28
31
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
29
32
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
@@ -45,108 +48,33 @@ function makeClient() {
|
|
|
45
48
|
});
|
|
46
49
|
}
|
|
47
50
|
|
|
48
|
-
function makeCreateIndexQuery(tableName, indexFields, pgSchema) {
|
|
49
|
-
let indexName = tableName + "_" + indexFields.join("_");
|
|
50
|
-
let index = indexFields.map(idx => `"` + idx + `"`).join(", ");
|
|
51
|
-
return `CREATE INDEX IF NOT EXISTS "` + indexName + `" ON "` + pgSchema + `"."` + tableName + `"(` + index + `);`;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function directionToSql(direction) {
|
|
55
|
-
if (direction === "Asc") {
|
|
56
|
-
return "";
|
|
57
|
-
} else {
|
|
58
|
-
return " DESC";
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function directionToIndexName(direction) {
|
|
63
|
-
if (direction === "Asc") {
|
|
64
|
-
return "";
|
|
65
|
-
} else {
|
|
66
|
-
return "_desc";
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function makeCreateCompositeIndexQuery(tableName, indexFields, pgSchema) {
|
|
71
|
-
let indexName = tableName + "_" + indexFields.map(f => f.fieldName + directionToIndexName(f.direction)).join("_");
|
|
72
|
-
let index = indexFields.map(f => `"` + f.fieldName + `"` + directionToSql(f.direction)).join(", ");
|
|
73
|
-
return `CREATE INDEX IF NOT EXISTS "` + indexName + `" ON "` + pgSchema + `"."` + tableName + `"(` + index + `);`;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function makeCreateTableIndexesQuery(table, pgSchema) {
|
|
77
|
-
let tableName = table.tableName;
|
|
78
|
-
let createIndex = indexField => makeCreateIndexQuery(tableName, [indexField], pgSchema);
|
|
79
|
-
let createCompositeIndex = indexFields => makeCreateCompositeIndexQuery(tableName, indexFields, pgSchema);
|
|
80
|
-
let singleIndexes = Table.getSingleIndexes(table);
|
|
81
|
-
let compositeIndexes = Table.getCompositeIndexes(table);
|
|
82
|
-
return singleIndexes.map(createIndex).join("\n") + compositeIndexes.map(createCompositeIndex).join("\n");
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function schemaIndexDescription(param) {
|
|
86
|
-
return param.tableName + "_" + param.indexFields.map(f => f.fieldName + directionToIndexName(f.direction)).join("_");
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function schemaIndexName(schemaIndex) {
|
|
90
|
-
return IndexRegistry.truncateIndexName(schemaIndexDescription(schemaIndex));
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function schemaIndexKey(param) {
|
|
94
|
-
return IndexRegistry.makeKey(param.tableName, IndexRegistry.fromIndexFields(param.indexFields), IndexRegistry.btree);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function makeCreateSchemaIndexQuery(schemaIndex, pgSchema) {
|
|
98
|
-
let columns = schemaIndex.indexFields.map(f => `"` + f.fieldName + `"` + directionToSql(f.direction)).join(", ");
|
|
99
|
-
return `CREATE INDEX IF NOT EXISTS "` + IndexRegistry.truncateIndexName(schemaIndexDescription(schemaIndex)) + `" ON "` + pgSchema + `"."` + schemaIndex.tableName + `"(` + columns + `);`;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
51
|
function formatSeconds(timeRef) {
|
|
103
52
|
return (Math.round(Performance.secondsSince(timeRef) * 100) / 100).toString();
|
|
104
53
|
}
|
|
105
54
|
|
|
106
55
|
let slowOnLargeDatabaseNotice = "This can take a long time on a large database.";
|
|
107
56
|
|
|
108
|
-
function makeReindexQuery(pgSchema, indexName) {
|
|
109
|
-
return `REINDEX INDEX "` + pgSchema + `"."` + indexName + `";`;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function nameCollisionError(indexName, pgSchema) {
|
|
113
|
-
return new Error(`Cannot create the index "` + indexName + `" in schema "` + pgSchema + `". An index of that name already exists and PostgreSQL reports it as invalid, but it isn't one the indexer created — it covers different columns, or it is a unique or partial index — so it is left untouched. Drop or repair it by hand, then restart the indexer.`);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function makeSingleColumnSchemaIndex(tableName, column) {
|
|
117
|
-
return {
|
|
118
|
-
tableName: tableName,
|
|
119
|
-
indexFields: [{
|
|
120
|
-
fieldName: column,
|
|
121
|
-
direction: "Asc"
|
|
122
|
-
}]
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
57
|
function getSchemaIndexes(entities) {
|
|
127
58
|
let derivedSchema = Schema.make(entities.map(e => e.table));
|
|
128
59
|
let all = [];
|
|
129
60
|
entities.forEach(param => {
|
|
130
61
|
let table = param.table;
|
|
131
62
|
Table.getSingleIndexes(table).forEach(column => {
|
|
132
|
-
all.push(
|
|
63
|
+
all.push(IndexDefinition.single(table.tableName, column));
|
|
133
64
|
});
|
|
134
65
|
Table.getCompositeIndexes(table).forEach(indexFields => {
|
|
135
|
-
all.push(
|
|
136
|
-
tableName: table.tableName,
|
|
137
|
-
indexFields: indexFields
|
|
138
|
-
});
|
|
66
|
+
all.push(IndexDefinition.fromIndexFields(table.tableName, indexFields));
|
|
139
67
|
});
|
|
140
68
|
});
|
|
141
69
|
entities.forEach(param => {
|
|
142
70
|
Table.getDerivedFromFields(param.table).forEach(derivedFromField => {
|
|
143
71
|
let column = Utils.unwrapResultExn(Schema.getDerivedFromPgFieldName(derivedSchema, derivedFromField));
|
|
144
|
-
all.push(
|
|
72
|
+
all.push(IndexDefinition.single(derivedFromField.derivedFromEntity, column));
|
|
145
73
|
});
|
|
146
74
|
});
|
|
147
75
|
let seen = new Set();
|
|
148
|
-
return all.filter(
|
|
149
|
-
let key =
|
|
76
|
+
return all.filter(definition => {
|
|
77
|
+
let key = IndexDefinition.key(definition);
|
|
150
78
|
if (seen.has(key)) {
|
|
151
79
|
return false;
|
|
152
80
|
} else {
|
|
@@ -156,12 +84,13 @@ function getSchemaIndexes(entities) {
|
|
|
156
84
|
});
|
|
157
85
|
}
|
|
158
86
|
|
|
159
|
-
function makeCreateTableQuery(table, pgSchema, isNumericArrayAsText) {
|
|
87
|
+
function makeCreateTableQuery(table, pgSchema, isNumericArrayAsText, chainIdModeOpt) {
|
|
88
|
+
let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
|
|
160
89
|
let fieldsMapped = Table.getFields(table).map(field => {
|
|
161
90
|
let defaultValue = field.defaultValue;
|
|
162
91
|
let isNullable = field.isNullable;
|
|
163
92
|
let fieldName = Table.getPgDbFieldName(field);
|
|
164
|
-
return `"` + fieldName + `" ` + Table.getPgFieldType(field.fieldType, pgSchema, field.isArray, isNumericArrayAsText, isNullable) + (
|
|
93
|
+
return `"` + fieldName + `" ` + Table.getPgFieldType(field.fieldType, pgSchema, field.isArray, isNumericArrayAsText, isNullable, chainIdMode) + (
|
|
165
94
|
defaultValue !== undefined ? ` DEFAULT ` + defaultValue : (
|
|
166
95
|
isNullable ? `` : ` NOT NULL`
|
|
167
96
|
)
|
|
@@ -244,12 +173,13 @@ function getEntityHistory(entityConfig) {
|
|
|
244
173
|
return cache$1;
|
|
245
174
|
}
|
|
246
175
|
|
|
247
|
-
function makeInitializeTransaction(pgSchema, pgUser, isHasuraEnabled, chainConfigsOpt, entitiesOpt, enumsOpt, isEmptyPgSchemaOpt, deferSchemaIndexesOpt) {
|
|
176
|
+
function makeInitializeTransaction(pgSchema, pgUser, isHasuraEnabled, chainConfigsOpt, entitiesOpt, enumsOpt, isEmptyPgSchemaOpt, deferSchemaIndexesOpt, chainIdModeOpt) {
|
|
248
177
|
let chainConfigs = chainConfigsOpt !== undefined ? chainConfigsOpt : [];
|
|
249
178
|
let entities = entitiesOpt !== undefined ? entitiesOpt : [];
|
|
250
179
|
let enums = enumsOpt !== undefined ? enumsOpt : [];
|
|
251
180
|
let isEmptyPgSchema = isEmptyPgSchemaOpt !== undefined ? isEmptyPgSchemaOpt : false;
|
|
252
181
|
let deferSchemaIndexes = deferSchemaIndexesOpt !== undefined ? deferSchemaIndexesOpt : false;
|
|
182
|
+
let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
|
|
253
183
|
let generalTables = [
|
|
254
184
|
InternalTable.Chains.table,
|
|
255
185
|
InternalTable.EnvioInfo.table,
|
|
@@ -262,7 +192,6 @@ function makeInitializeTransaction(pgSchema, pgUser, isHasuraEnabled, chainConfi
|
|
|
262
192
|
allTables.push(getEntityHistory(entityConfig).table);
|
|
263
193
|
});
|
|
264
194
|
let schemaIndexes = getSchemaIndexes(entities);
|
|
265
|
-
IndexRegistry.validateIndexNamesOrThrow(schemaIndexes.map(schemaIndexDescription));
|
|
266
195
|
let query = {
|
|
267
196
|
contents: (
|
|
268
197
|
isEmptyPgSchema && pgSchema === "public" ? `CREATE SCHEMA IF NOT EXISTS "` + pgSchema + `";\n` : `DROP SCHEMA IF EXISTS "` + pgSchema + `" CASCADE;
|
|
@@ -275,11 +204,11 @@ GRANT ALL ON SCHEMA "` + pgSchema + `" TO public;`)
|
|
|
275
204
|
query.contents = query.contents + "\n" + enumCreateQuery;
|
|
276
205
|
});
|
|
277
206
|
allTables.forEach(table => {
|
|
278
|
-
query.contents = query.contents + "\n" + makeCreateTableQuery(table, pgSchema, isHasuraEnabled);
|
|
207
|
+
query.contents = query.contents + "\n" + makeCreateTableQuery(table, pgSchema, isHasuraEnabled, chainIdMode);
|
|
279
208
|
});
|
|
280
209
|
if (!deferSchemaIndexes) {
|
|
281
|
-
schemaIndexes.forEach(
|
|
282
|
-
query.contents = query.contents + "\n" +
|
|
210
|
+
schemaIndexes.forEach(definition => {
|
|
211
|
+
query.contents = query.contents + "\n" + IndexDefinition.makeCreateQuery(definition, pgSchema);
|
|
283
212
|
});
|
|
284
213
|
}
|
|
285
214
|
query.contents = query.contents + "\n" + InternalTable.Views.makeMetaViewQuery(pgSchema);
|
|
@@ -368,8 +297,9 @@ function makeLoadAllQuery(pgSchema, tableName) {
|
|
|
368
297
|
return `SELECT * FROM "` + pgSchema + `"."` + tableName + `";`;
|
|
369
298
|
}
|
|
370
299
|
|
|
371
|
-
function makeInsertUnnestSetQuery(pgSchema, table, itemSchema, isRawEvents) {
|
|
372
|
-
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);
|
|
373
303
|
let quotedNonPrimaryFieldNames = match.quotedNonPrimaryFieldNames;
|
|
374
304
|
let primaryKeyFieldNames = Table.getPgPrimaryKeyFieldNames(table);
|
|
375
305
|
return `INSERT INTO "` + pgSchema + `"."` + table.tableName + `" (` + match.quotedFieldNames.join(", ") + `)
|
|
@@ -380,8 +310,9 @@ SELECT * FROM unnest(` + match.arrayFieldTypes.map((arrayFieldType, idx) => `$`
|
|
|
380
310
|
) + ";";
|
|
381
311
|
}
|
|
382
312
|
|
|
383
|
-
function makeInsertValuesSetQuery(pgSchema, table, itemSchema, itemsCount) {
|
|
384
|
-
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);
|
|
385
316
|
let quotedNonPrimaryFieldNames = match.quotedNonPrimaryFieldNames;
|
|
386
317
|
let quotedFieldNames = match.quotedFieldNames;
|
|
387
318
|
let primaryKeyFieldNames = Table.getPgPrimaryKeyFieldNames(table);
|
|
@@ -408,19 +339,20 @@ VALUES` + placeholders + (
|
|
|
408
339
|
) + ";";
|
|
409
340
|
}
|
|
410
341
|
|
|
411
|
-
function makeTableBatchSetQuery(pgSchema, table, itemSchema) {
|
|
412
|
-
let
|
|
342
|
+
function makeTableBatchSetQuery(pgSchema, table, itemSchema, chainIdModeOpt) {
|
|
343
|
+
let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
|
|
344
|
+
let match = Table.toSqlParams(table, itemSchema, pgSchema, chainIdMode);
|
|
413
345
|
let isRawEvents = table.tableName === InternalTable.RawEvents.table.tableName;
|
|
414
346
|
let isHistoryUpdate = table.tableName.startsWith(EntityHistory.historyTablePrefix);
|
|
415
347
|
if ((isRawEvents || !match.hasArrayField) && !isHistoryUpdate) {
|
|
416
348
|
return {
|
|
417
|
-
query: makeInsertUnnestSetQuery(pgSchema, table, itemSchema, isRawEvents),
|
|
349
|
+
query: makeInsertUnnestSetQuery(pgSchema, table, itemSchema, isRawEvents, chainIdMode),
|
|
418
350
|
convertOrThrow: S$RescriptSchema.compile(S$RescriptSchema.unnest(match.dbSchema), "Output", "Input", "Sync", false),
|
|
419
351
|
isInsertValues: false
|
|
420
352
|
};
|
|
421
353
|
} else {
|
|
422
354
|
return {
|
|
423
|
-
query: makeInsertValuesSetQuery(pgSchema, table, itemSchema, 500),
|
|
355
|
+
query: makeInsertValuesSetQuery(pgSchema, table, itemSchema, 500, chainIdMode),
|
|
424
356
|
convertOrThrow: S$RescriptSchema.compile(S$RescriptSchema.preprocess(S$RescriptSchema.unnest(itemSchema), param => ({
|
|
425
357
|
s: prim => prim.flat(1)
|
|
426
358
|
})), "Output", "Input", "Sync", false),
|
|
@@ -496,7 +428,8 @@ function classifyWriteError(specificError, table, exn) {
|
|
|
496
428
|
|
|
497
429
|
let setQueryCache = new WeakMap();
|
|
498
430
|
|
|
499
|
-
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";
|
|
500
433
|
if (items.length === 0) {
|
|
501
434
|
return;
|
|
502
435
|
}
|
|
@@ -505,7 +438,7 @@ async function setOrThrow(sql, items, table, itemSchema, pgSchema) {
|
|
|
505
438
|
if (cached !== undefined) {
|
|
506
439
|
data = Primitive_option.valFromOption(cached);
|
|
507
440
|
} else {
|
|
508
|
-
let newQuery = makeTableBatchSetQuery(pgSchema, table, itemSchema);
|
|
441
|
+
let newQuery = makeTableBatchSetQuery(pgSchema, table, itemSchema, chainIdMode);
|
|
509
442
|
setQueryCache.set(table, newQuery);
|
|
510
443
|
data = newQuery;
|
|
511
444
|
}
|
|
@@ -519,7 +452,7 @@ async function setOrThrow(sql, items, table, itemSchema, pgSchema) {
|
|
|
519
452
|
let chunkSize = chunk.length;
|
|
520
453
|
let isFullChunk = chunkSize === 500;
|
|
521
454
|
let params = data.convertOrThrow(chunk);
|
|
522
|
-
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);
|
|
523
456
|
responses.push(response);
|
|
524
457
|
});
|
|
525
458
|
await Promise.all(responses);
|
|
@@ -654,7 +587,7 @@ function makeInsertDeleteUpdatesQuery(entityConfig, pgSchema) {
|
|
|
654
587
|
}
|
|
655
588
|
});
|
|
656
589
|
let selectPartsStr = selectParts.join(", ");
|
|
657
|
-
let checkpointIdPgType = Table.getPgFieldType(EntityHistory.checkpointIdFieldType, pgSchema, false, false, false);
|
|
590
|
+
let checkpointIdPgType = Table.getPgFieldType(EntityHistory.checkpointIdFieldType, pgSchema, false, false, false, undefined);
|
|
658
591
|
let idPgType = Table.getIdPgFieldType(entityConfig.table, pgSchema);
|
|
659
592
|
return `INSERT INTO "` + pgSchema + `"."` + historyTableName + `" (` + allHistoryFieldNamesStr + `)
|
|
660
593
|
SELECT ` + selectPartsStr + `
|
|
@@ -671,6 +604,7 @@ function executeSet(sql, items, dbFunction) {
|
|
|
671
604
|
|
|
672
605
|
async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, config, allEntities, setEffectCacheOrThrow, updatedEffectsCache, updatedEntities, sinkPromise, chainMetaData, escapeTables) {
|
|
673
606
|
try {
|
|
607
|
+
let chainIdMode = config.chainIdMode;
|
|
674
608
|
let shouldSaveHistory = Config.shouldSaveHistory(config, isInReorgThreshold);
|
|
675
609
|
let specificError = {
|
|
676
610
|
contents: undefined
|
|
@@ -682,7 +616,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
682
616
|
if (item.kind !== 0) {
|
|
683
617
|
return;
|
|
684
618
|
}
|
|
685
|
-
let coordinate = Internal.getItemChainId(item)
|
|
619
|
+
let coordinate = ChainId.toString(Internal.getItemChainId(item)) + `-` + item.blockNumber.toString() + `-` + item.logIndex.toString();
|
|
686
620
|
if (seenLogCoordinates.has(coordinate)) {
|
|
687
621
|
return;
|
|
688
622
|
} else {
|
|
@@ -699,7 +633,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
699
633
|
}
|
|
700
634
|
let setRawEvents = async sql => {
|
|
701
635
|
try {
|
|
702
|
-
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));
|
|
703
637
|
} catch (raw_exn) {
|
|
704
638
|
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
705
639
|
return classifyWriteError(specificError, InternalTable.RawEvents.table, exn);
|
|
@@ -776,14 +710,14 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
776
710
|
}));
|
|
777
711
|
}
|
|
778
712
|
let entityHistory = getEntityHistory(entityConfig);
|
|
779
|
-
promises.push(setOrThrow(sql, batchSetUpdates, entityHistory.table, entityHistory.setChangeSchema, pgSchema));
|
|
713
|
+
promises.push(setOrThrow(sql, batchSetUpdates, entityHistory.table, entityHistory.setChangeSchema, pgSchema, chainIdMode));
|
|
780
714
|
}
|
|
781
715
|
}
|
|
782
716
|
if (Utils.$$Array.notEmpty(entitiesToSet)) {
|
|
783
717
|
if (shouldRemoveInvalidUtf8) {
|
|
784
718
|
removeInvalidUtf8InPlace(entitiesToSet);
|
|
785
719
|
}
|
|
786
|
-
promises.push(setOrThrow(sql, entitiesToSet, entityConfig.table, entityConfig.schema, pgSchema));
|
|
720
|
+
promises.push(setOrThrow(sql, entitiesToSet, entityConfig.table, entityConfig.schema, pgSchema, chainIdMode));
|
|
787
721
|
}
|
|
788
722
|
if (Utils.$$Array.notEmpty(idsToDelete)) {
|
|
789
723
|
promises.push(deleteByIdsOrThrow(sql, pgSchema, idsToDelete, entityConfig.table));
|
|
@@ -800,7 +734,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
800
734
|
if (rollback !== undefined) {
|
|
801
735
|
let rollbackTargetCheckpointId = rollback.targetCheckpointId;
|
|
802
736
|
rollbackTables = sql => {
|
|
803
|
-
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));
|
|
804
738
|
promises.push(InternalTable.Checkpoints.rollback(sql, pgSchema, rollbackTargetCheckpointId));
|
|
805
739
|
return Promise.all(promises);
|
|
806
740
|
};
|
|
@@ -826,7 +760,7 @@ async function writeBatch(sql, batch, pgSchema, rollback, isInReorgThreshold, co
|
|
|
826
760
|
setOperations.push(sql => InternalTable.Chains.setMeta(sql, pgSchema, chainMetaData));
|
|
827
761
|
}
|
|
828
762
|
if (shouldSaveHistory) {
|
|
829
|
-
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));
|
|
830
764
|
}
|
|
831
765
|
await Promise.all(setOperations.map(dbFunc => dbFunc(sql)));
|
|
832
766
|
if (sinkPromise === undefined) {
|
|
@@ -901,7 +835,8 @@ let rollbackRowStateSchema = Utils.$$WeakMap.memoize(table => S$RescriptSchema.o
|
|
|
901
835
|
|
|
902
836
|
let rollbackRemovedIdsSchema = Utils.$$WeakMap.memoize(table => S$RescriptSchema.array(S$RescriptSchema.object(s => s.f(Table.idFieldName, Table.getIdSchema(table)))));
|
|
903
837
|
|
|
904
|
-
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";
|
|
905
840
|
let containerName = "envio-postgres";
|
|
906
841
|
let psqlExecOptions_env = Object.fromEntries([
|
|
907
842
|
[
|
|
@@ -918,20 +853,25 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
918
853
|
};
|
|
919
854
|
let cacheDirPath = Path.resolve(".envio", "cache");
|
|
920
855
|
let storageName = "postgres";
|
|
921
|
-
let
|
|
922
|
-
let
|
|
923
|
-
|
|
924
|
-
let
|
|
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);
|
|
925
865
|
if (invalidIndexNames.length !== 0) {
|
|
926
866
|
Logging.warn({
|
|
927
867
|
storage: storageName,
|
|
928
|
-
msg: `Ignoring invalid PostgreSQL indexes in schema "` + pgSchema + `". They
|
|
868
|
+
msg: `Ignoring invalid PostgreSQL indexes in schema "` + pgSchema + `". They can't serve queries, so the indexer builds its own alongside them.`,
|
|
929
869
|
indexes: invalidIndexNames
|
|
930
870
|
});
|
|
931
871
|
}
|
|
932
872
|
return Logging.info({
|
|
933
873
|
storage: storageName,
|
|
934
|
-
msg: `Found ` +
|
|
874
|
+
msg: `Found ` + IndexCatalog.size(catalog).toString() + ` existing indexes in the indexer schema.`
|
|
935
875
|
});
|
|
936
876
|
};
|
|
937
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 + `');`));
|
|
@@ -950,21 +890,23 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
950
890
|
let subEntries = await Fs.promises.readdir(entryPath);
|
|
951
891
|
let tsvs = subEntries.filter(sub => sub.endsWith(".tsv"));
|
|
952
892
|
let chainId = Internal.EffectCache.parseChainId(entry);
|
|
953
|
-
if (chainId
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
Path.join(entryPath, sub)
|
|
960
|
-
]);
|
|
961
|
-
});
|
|
962
|
-
return;
|
|
963
|
-
} else if (Utils.$$Array.notEmpty(tsvs)) {
|
|
964
|
-
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(", ") + `.`);
|
|
965
|
-
} else {
|
|
966
|
-
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
|
+
}
|
|
967
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;
|
|
968
910
|
}
|
|
969
911
|
if (!entry.endsWith(".tsv")) {
|
|
970
912
|
return;
|
|
@@ -999,7 +941,7 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
999
941
|
await Promise.all(entries.map(param => {
|
|
1000
942
|
let inputFile = param[1];
|
|
1001
943
|
let table = param[0];
|
|
1002
|
-
return sql.unsafe(makeCreateTableQuery(table, pgSchema, false)).then(() => {
|
|
944
|
+
return sql.unsafe(makeCreateTableQuery(table, pgSchema, false, undefined)).then(() => {
|
|
1003
945
|
let command = psqlExec$1 + ` -c 'COPY "` + pgSchema + `"."` + table.tableName + `" FROM STDIN WITH (FORMAT text, HEADER);' < ` + inputFile;
|
|
1004
946
|
return new Promise((resolve, reject) => {
|
|
1005
947
|
Child_process.exec(command, psqlExecOptions, (error, stdout, param) => {
|
|
@@ -1053,7 +995,7 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1053
995
|
if (sink !== undefined) {
|
|
1054
996
|
await sink.initialize(chainConfigs, chEntities, enums);
|
|
1055
997
|
}
|
|
1056
|
-
let queries = makeInitializeTransaction(pgSchema, pgUser, isHasuraEnabled, chainConfigs, pgEntities, enums, Utils.$$Array.isEmpty(schemaTableNames), true);
|
|
998
|
+
let queries = makeInitializeTransaction(pgSchema, pgUser, isHasuraEnabled, chainConfigs, pgEntities, enums, Utils.$$Array.isEmpty(schemaTableNames), true, chainIdMode);
|
|
1057
999
|
await sql.begin(async sql => {
|
|
1058
1000
|
await Promise.all(queries.map(query => sql.unsafe(query)));
|
|
1059
1001
|
return await InternalTable.EnvioInfo.write(sql, pgSchema, envioInfo);
|
|
@@ -1071,15 +1013,16 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1071
1013
|
});
|
|
1072
1014
|
});
|
|
1073
1015
|
if (ids.length !== 0) {
|
|
1016
|
+
let addrChainIdArrayType = Table.getPgFieldType("ChainId", pgSchema, true, false, false, chainIdMode);
|
|
1074
1017
|
await sql.unsafe(`INSERT INTO "` + pgSchema + `"."` + Config.EnvioAddresses.table.tableName + `" ("id", "chain_id", "registration_block", "registration_log_index", "contract_name")
|
|
1075
|
-
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);`, [
|
|
1076
1019
|
ids,
|
|
1077
1020
|
addrChainIds,
|
|
1078
1021
|
addrContractNames
|
|
1079
1022
|
]);
|
|
1080
1023
|
}
|
|
1081
1024
|
let cache = await restoreEffectCache(true);
|
|
1082
|
-
await
|
|
1025
|
+
await reloadIndexCatalog();
|
|
1083
1026
|
if (onInitialize !== undefined) {
|
|
1084
1027
|
await onInitialize();
|
|
1085
1028
|
}
|
|
@@ -1153,73 +1096,102 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
|
|
|
1153
1096
|
filters.forEach(collect);
|
|
1154
1097
|
return columns;
|
|
1155
1098
|
};
|
|
1156
|
-
let
|
|
1157
|
-
let
|
|
1158
|
-
|
|
1159
|
-
if (match === undefined) {
|
|
1160
|
-
return makeCreateSchemaIndexQuery(schemaIndex, pgSchema);
|
|
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]);
|
|
1161
1102
|
}
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
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
|
+
});
|
|
1167
1117
|
}
|
|
1168
|
-
|
|
1118
|
+
return IndexManager.resync(indexManager, name, rows);
|
|
1169
1119
|
};
|
|
1170
|
-
let isRepair = schemaIndex => Stdlib_Option.isSome(IndexRegistry.getInvalid(indexRegistry, IndexRegistry.truncateIndexName(schemaIndexDescription(schemaIndex))));
|
|
1171
1120
|
let ensureQueryIndexes = async (table, filters) => {
|
|
1172
|
-
let
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
storage: storageName,
|
|
1195
|
-
msg: `Index "` + indexName + `" is ready after ` + formatSeconds(timeRef) + `s. Resuming indexing.`
|
|
1196
|
-
});
|
|
1197
|
-
}).catch(exn => Logging.warn({
|
|
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({
|
|
1198
1143
|
storage: storageName,
|
|
1199
|
-
msg: `Failed to create
|
|
1144
|
+
msg: `Failed to create an index on "` + table.tableName + `"("` + column + `") for a getWhere query. The query runs without it.`,
|
|
1200
1145
|
err: Utils.prettifyExn(exn)
|
|
1201
|
-
})
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
}
|
|
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
|
+
})));
|
|
1205
1178
|
};
|
|
1206
1179
|
let finalizeBackfill = async (entities, chainIds, readyAt) => {
|
|
1207
1180
|
let schemaIndexes = getSchemaIndexes(entities.filter(e => e.storage.postgres));
|
|
1208
|
-
|
|
1209
|
-
let
|
|
1210
|
-
|
|
1211
|
-
if (Utils.$$Array.notEmpty(repaired)) {
|
|
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) {
|
|
1212
1184
|
Logging.warn({
|
|
1213
1185
|
storage: storageName,
|
|
1214
|
-
msg: `PostgreSQL reports ` +
|
|
1215
|
-
indexes:
|
|
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)
|
|
1216
1188
|
});
|
|
1217
1189
|
}
|
|
1218
1190
|
if (missing.length !== 0) {
|
|
1219
1191
|
Logging.info({
|
|
1220
1192
|
storage: storageName,
|
|
1221
1193
|
msg: `Creating the ` + missing.length.toString() + ` remaining schema indexes before the indexer reports ready. Writes are paused until they are committed. ` + slowOnLargeDatabaseNotice,
|
|
1222
|
-
indexes: missing.map(
|
|
1194
|
+
indexes: missing.map(prepared => prepared.name)
|
|
1223
1195
|
});
|
|
1224
1196
|
} else {
|
|
1225
1197
|
Logging.info({
|
|
@@ -1227,28 +1199,40 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
|
|
|
1227
1199
|
msg: `All ` + schemaIndexes.length.toString() + ` schema indexes are already in place. Marking the indexer ready.`
|
|
1228
1200
|
});
|
|
1229
1201
|
}
|
|
1230
|
-
let indexQueries = missing.map(makeEnsureIndexQuery);
|
|
1231
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);
|
|
1232
1219
|
await sql.begin(async sql => {
|
|
1233
|
-
for (let idx = 0, idx_finish =
|
|
1234
|
-
await sql.unsafe(
|
|
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});
|
|
1235
1225
|
}
|
|
1236
|
-
return await sql.unsafe(InternalTable.Chains.makeSetReadyAtQuery(pgSchema), [
|
|
1237
|
-
readyAt,
|
|
1238
|
-
chainIds
|
|
1239
|
-
], {prepare: true});
|
|
1240
1226
|
});
|
|
1241
|
-
missing.forEach(schemaIndex => IndexRegistry.add(indexRegistry, schemaIndexKey(schemaIndex)));
|
|
1242
|
-
repaired.forEach(schemaIndex => IndexRegistry.clearInvalidName(indexRegistry, IndexRegistry.truncateIndexName(schemaIndexDescription(schemaIndex))));
|
|
1243
1227
|
return Logging.info({
|
|
1244
1228
|
storage: storageName,
|
|
1245
1229
|
msg: `Committed ` + missing.length.toString() + ` schema indexes and the ready timestamp in ` + formatSeconds(timeRef) + `s.`
|
|
1246
1230
|
});
|
|
1247
1231
|
};
|
|
1248
|
-
let setOrThrow$1 = (items, table, itemSchema) => setOrThrow(sql, items, table, itemSchema, pgSchema);
|
|
1232
|
+
let setOrThrow$1 = (items, table, itemSchema) => setOrThrow(sql, items, table, itemSchema, pgSchema, undefined);
|
|
1249
1233
|
let setEffectCacheOrThrow = async (table, itemSchema, items, initialize) => {
|
|
1250
1234
|
if (initialize) {
|
|
1251
|
-
await sql.unsafe(makeCreateTableQuery(table, pgSchema, false));
|
|
1235
|
+
await sql.unsafe(makeCreateTableQuery(table, pgSchema, false, undefined));
|
|
1252
1236
|
if (onNewTables !== undefined) {
|
|
1253
1237
|
await onNewTables([table.tableName]);
|
|
1254
1238
|
}
|
|
@@ -1321,11 +1305,11 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
|
|
|
1321
1305
|
sql.unsafe(InternalTable.Checkpoints.makeGetReorgCheckpointsQuery(pgSchema)),
|
|
1322
1306
|
InternalTable.EnvioInfo.read(sql, pgSchema)
|
|
1323
1307
|
]);
|
|
1324
|
-
await
|
|
1308
|
+
await reloadIndexCatalog();
|
|
1325
1309
|
let checkpointId = BigInt(match[2][0].id);
|
|
1326
1310
|
let reorgCheckpoints = match[3].map(raw => ({
|
|
1327
1311
|
id: BigInt(raw.id),
|
|
1328
|
-
chain_id: raw.chain_id,
|
|
1312
|
+
chain_id: ChainId.normalizeOrThrow(raw.chain_id),
|
|
1329
1313
|
block_number: raw.block_number,
|
|
1330
1314
|
block_hash: raw.block_hash
|
|
1331
1315
|
}));
|
|
@@ -1404,6 +1388,7 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
|
|
|
1404
1388
|
resumeInitialState: resumeInitialState,
|
|
1405
1389
|
loadOrThrow: loadOrThrow,
|
|
1406
1390
|
ensureQueryIndexes: ensureQueryIndexes,
|
|
1391
|
+
ensureSchemaIndexes: ensureSchemaIndexes,
|
|
1407
1392
|
finalizeBackfill: finalizeBackfill,
|
|
1408
1393
|
dumpEffectCache: dumpEffectCache,
|
|
1409
1394
|
reset: reset,
|
|
@@ -1444,11 +1429,11 @@ function makeStorageFromEnv(config, sqlOpt, pgSchemaOpt, isHasuraEnabledOpt) {
|
|
|
1444
1429
|
if (missing.length !== 0) {
|
|
1445
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.`);
|
|
1446
1431
|
}
|
|
1447
|
-
tmp = Sink.makeClickHouse(host, database, username, password);
|
|
1432
|
+
tmp = Sink.makeClickHouse(host, database, username, password, config.chainIdMode);
|
|
1448
1433
|
} else {
|
|
1449
1434
|
tmp = undefined;
|
|
1450
1435
|
}
|
|
1451
|
-
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, {
|
|
1452
1437
|
role: Env.Hasura.role,
|
|
1453
1438
|
secret: Env.Hasura.secret
|
|
1454
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, {
|
|
@@ -1470,20 +1455,8 @@ let maxItemsPerQuery = 500;
|
|
|
1470
1455
|
|
|
1471
1456
|
export {
|
|
1472
1457
|
makeClient,
|
|
1473
|
-
makeCreateIndexQuery,
|
|
1474
|
-
directionToSql,
|
|
1475
|
-
directionToIndexName,
|
|
1476
|
-
makeCreateCompositeIndexQuery,
|
|
1477
|
-
makeCreateTableIndexesQuery,
|
|
1478
|
-
schemaIndexDescription,
|
|
1479
|
-
schemaIndexName,
|
|
1480
|
-
schemaIndexKey,
|
|
1481
|
-
makeCreateSchemaIndexQuery,
|
|
1482
1458
|
formatSeconds,
|
|
1483
1459
|
slowOnLargeDatabaseNotice,
|
|
1484
|
-
makeReindexQuery,
|
|
1485
|
-
nameCollisionError,
|
|
1486
|
-
makeSingleColumnSchemaIndex,
|
|
1487
1460
|
getSchemaIndexes,
|
|
1488
1461
|
makeCreateTableQuery,
|
|
1489
1462
|
entityHistoryCache,
|