envio 2.31.0-alpha.0 → 2.31.0-alpha.2

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/src/PgStorage.res CHANGED
@@ -65,7 +65,7 @@ let makeInitializeTransaction = (
65
65
  let generalTables = [
66
66
  InternalTable.Chains.table,
67
67
  InternalTable.PersistedState.table,
68
- InternalTable.EndOfBlockRangeScannedData.table,
68
+ InternalTable.Checkpoints.table,
69
69
  InternalTable.RawEvents.table,
70
70
  ]
71
71
 
@@ -116,13 +116,8 @@ GRANT ALL ON SCHEMA "${pgSchema}" TO public;`,
116
116
  }
117
117
  })
118
118
 
119
- let functionsQuery = ref("")
120
-
121
119
  // Add derived indices
122
120
  entities->Js.Array2.forEach((entity: Internal.entityConfig) => {
123
- functionsQuery :=
124
- functionsQuery.contents ++ "\n" ++ entity.entityHistory.makeInsertFnQuery(~pgSchema)
125
-
126
121
  entity.table
127
122
  ->Table.getDerivedFromFields
128
123
  ->Js.Array2.forEach(derivedFromField => {
@@ -149,10 +144,8 @@ GRANT ALL ON SCHEMA "${pgSchema}" TO public;`,
149
144
  | None => ()
150
145
  }
151
146
 
152
- // Add cache row count function
153
- functionsQuery :=
154
- functionsQuery.contents ++
155
- "\n" ++
147
+ [
148
+ query.contents,
156
149
  `CREATE OR REPLACE FUNCTION ${getCacheRowCountFnName}(table_name text)
157
150
  RETURNS integer AS $$
158
151
  DECLARE
@@ -161,11 +154,8 @@ BEGIN
161
154
  EXECUTE format('SELECT COUNT(*) FROM "${pgSchema}".%I', table_name) INTO result;
162
155
  RETURN result;
163
156
  END;
164
- $$ LANGUAGE plpgsql;`
165
-
166
- [query.contents]->Js.Array2.concat(
167
- functionsQuery.contents !== "" ? [functionsQuery.contents] : [],
168
- )
157
+ $$ LANGUAGE plpgsql;`,
158
+ ]
169
159
  }
170
160
 
171
161
  let makeLoadByIdQuery = (~pgSchema, ~tableName) => {
@@ -270,6 +260,11 @@ let makeTableBatchSetQuery = (~pgSchema, ~table: Table.table, ~itemSchema: S.t<'
270
260
  // FIXME what about Fuel params?
271
261
  let isRawEvents = table.tableName === InternalTable.RawEvents.table.tableName
272
262
 
263
+ // Currently history update table uses S.object with transformation for schema,
264
+ // which is being lossed during conversion to dbSchema.
265
+ // So use simple insert values for now.
266
+ let isHistoryUpdate = table.tableName->Js.String2.startsWith("envio_history_")
267
+
273
268
  // Should experiment how much it'll affect performance
274
269
  // Although, it should be fine not to perform the validation check,
275
270
  // since the values are validated by type system.
@@ -277,7 +272,7 @@ let makeTableBatchSetQuery = (~pgSchema, ~table: Table.table, ~itemSchema: S.t<'
277
272
  // db write fails to show a better user error.
278
273
  let typeValidation = false
279
274
 
280
- if isRawEvents || !hasArrayField {
275
+ if (isRawEvents || !hasArrayField) && !isHistoryUpdate {
281
276
  {
282
277
  "query": makeInsertUnnestSetQuery(~pgSchema, ~table, ~itemSchema, ~isRawEvents),
283
278
  "convertOrThrow": S.compile(
@@ -325,7 +320,7 @@ let chunkArray = (arr: array<'a>, ~chunkSize) => {
325
320
  let removeInvalidUtf8InPlace = entities =>
326
321
  entities->Js.Array2.forEach(item => {
327
322
  let dict = item->(Utils.magic: 'a => dict<unknown>)
328
- dict->Utils.Dict.forEachWithKey((key, value) => {
323
+ dict->Utils.Dict.forEachWithKey((value, key) => {
329
324
  if value->Js.typeof === "string" {
330
325
  let value = value->(Utils.magic: unknown => string)
331
326
  // We mutate here, since we don't care
@@ -414,44 +409,6 @@ let setOrThrow = async (sql, ~items, ~table: Table.table, ~itemSchema, ~pgSchema
414
409
  }
415
410
  }
416
411
 
417
- let setEntityHistoryOrThrow = (
418
- sql,
419
- ~entityHistory: EntityHistory.t<'entity>,
420
- ~rows: array<EntityHistory.historyRow<'entity>>,
421
- ~shouldCopyCurrentEntity=?,
422
- ~shouldRemoveInvalidUtf8=false,
423
- ) => {
424
- rows->Belt.Array.map(historyRow => {
425
- let row = historyRow->S.reverseConvertToJsonOrThrow(entityHistory.schema)
426
- if shouldRemoveInvalidUtf8 {
427
- [row]->removeInvalidUtf8InPlace
428
- }
429
- entityHistory.insertFn(
430
- sql,
431
- row,
432
- ~shouldCopyCurrentEntity=switch shouldCopyCurrentEntity {
433
- | Some(v) => v
434
- | None => {
435
- let containsRollbackDiffChange =
436
- historyRow.containsRollbackDiffChange->Belt.Option.getWithDefault(false)
437
- !containsRollbackDiffChange
438
- }
439
- },
440
- )->Promise.catch(exn => {
441
- let reason = exn->Utils.prettifyExn
442
- let detail = %raw(`reason?.detail || ""`)
443
- raise(
444
- Persistence.StorageError({
445
- message: `Failed to insert history item into table "${entityHistory.table.tableName}".${detail !== ""
446
- ? ` Details: ${detail}`
447
- : ""}`,
448
- reason,
449
- }),
450
- )
451
- })
452
- })
453
- }
454
-
455
412
  type schemaTableName = {
456
413
  @as("table_name")
457
414
  tableName: string,
@@ -707,7 +664,19 @@ let make = (
707
664
  {
708
665
  cleanRun: true,
709
666
  cache,
710
- chains: chainConfigs->Js.Array2.map(InternalTable.Chains.initialFromConfig),
667
+ reorgCheckpoints: [],
668
+ chains: chainConfigs->Js.Array2.map((chainConfig): Persistence.initialChainState => {
669
+ id: chainConfig.id,
670
+ startBlock: chainConfig.startBlock,
671
+ endBlock: chainConfig.endBlock,
672
+ maxReorgDepth: chainConfig.maxReorgDepth,
673
+ progressBlockNumber: -1,
674
+ numEventsProcessed: 0,
675
+ firstEventBlockNumber: None,
676
+ timestampCaughtUpToHeadOrEndblock: None,
677
+ dynamicContracts: [],
678
+ }),
679
+ checkpointId: InternalTable.Checkpoints.initialCheckpointId,
711
680
  }
712
681
  }
713
682
 
@@ -895,19 +864,38 @@ let make = (
895
864
  }
896
865
 
897
866
  let resumeInitialState = async (): Persistence.initialState => {
898
- let (cache, chains) = await Promise.all2((
867
+ let (cache, chains, checkpointIdResult, reorgCheckpoints) = await Promise.all4((
899
868
  restoreEffectCache(~withUpload=false),
869
+ InternalTable.Chains.getInitialState(
870
+ sql,
871
+ ~pgSchema,
872
+ )->Promise.thenResolve(rawInitialStates => {
873
+ rawInitialStates->Belt.Array.map((rawInitialState): Persistence.initialChainState => {
874
+ id: rawInitialState.id,
875
+ startBlock: rawInitialState.startBlock,
876
+ endBlock: rawInitialState.endBlock->Js.Null.toOption,
877
+ maxReorgDepth: rawInitialState.maxReorgDepth,
878
+ firstEventBlockNumber: rawInitialState.firstEventBlockNumber->Js.Null.toOption,
879
+ timestampCaughtUpToHeadOrEndblock: rawInitialState.timestampCaughtUpToHeadOrEndblock->Js.Null.toOption,
880
+ numEventsProcessed: rawInitialState.numEventsProcessed,
881
+ progressBlockNumber: rawInitialState.progressBlockNumber,
882
+ dynamicContracts: rawInitialState.dynamicContracts,
883
+ })
884
+ }),
900
885
  sql
901
- ->Postgres.unsafe(
902
- makeLoadAllQuery(~pgSchema, ~tableName=InternalTable.Chains.table.tableName),
903
- )
904
- ->(Utils.magic: promise<array<unknown>> => promise<array<InternalTable.Chains.t>>),
886
+ ->Postgres.unsafe(InternalTable.Checkpoints.makeCommitedCheckpointIdQuery(~pgSchema))
887
+ ->(Utils.magic: promise<array<unknown>> => promise<array<{"id": int}>>),
888
+ sql
889
+ ->Postgres.unsafe(InternalTable.Checkpoints.makeGetReorgCheckpointsQuery(~pgSchema))
890
+ ->(Utils.magic: promise<array<unknown>> => promise<array<Internal.reorgCheckpoint>>),
905
891
  ))
906
892
 
907
893
  {
908
894
  cleanRun: false,
895
+ reorgCheckpoints,
909
896
  cache,
910
897
  chains,
898
+ checkpointId: (checkpointIdResult->Belt.Array.getUnsafe(0))["id"],
911
899
  }
912
900
  }
913
901
 
@@ -13,7 +13,6 @@ var Logging = require("./Logging.res.js");
13
13
  var $$Promise = require("./bindings/Promise.res.js");
14
14
  var Internal = require("./Internal.res.js");
15
15
  var Belt_Array = require("rescript/lib/js/belt_Array.js");
16
- var Belt_Option = require("rescript/lib/js/belt_Option.js");
17
16
  var Caml_option = require("rescript/lib/js/caml_option.js");
18
17
  var Persistence = require("./Persistence.res.js");
19
18
  var InternalTable = require("./db/InternalTable.res.js");
@@ -51,7 +50,7 @@ function makeCreateTableQuery(table, pgSchema) {
51
50
  var fieldType = field.fieldType;
52
51
  var fieldName = Table.getDbFieldName(field);
53
52
  var tmp;
54
- tmp = fieldType === "TIMESTAMP" || fieldType === "TIMESTAMP WITH TIME ZONE" || fieldType === "JSONB" || fieldType === "SERIAL" || fieldType === "TEXT" || fieldType === "DOUBLE PRECISION" || fieldType === "NUMERIC" || fieldType === "BOOLEAN" || fieldType === "INTEGER" || fieldType === "TIMESTAMP WITH TIME ZONE NULL" || fieldType.startsWith("NUMERIC(") ? fieldType : "\"" + pgSchema + "\"." + fieldType;
53
+ tmp = fieldType === "TIMESTAMP" || fieldType === "TIMESTAMP WITH TIME ZONE" || fieldType === "JSONB" || fieldType === "SERIAL" || fieldType === "TEXT" || fieldType === "DOUBLE PRECISION" || fieldType === "NUMERIC" || fieldType === "BOOLEAN" || fieldType === "BIGINT" || fieldType === "INTEGER" || fieldType === "TIMESTAMP WITH TIME ZONE NULL" || fieldType.startsWith("NUMERIC(") ? fieldType : "\"" + pgSchema + "\"." + fieldType;
55
54
  return "\"" + fieldName + "\" " + tmp + (
56
55
  field.isArray ? "[]" : ""
57
56
  ) + (
@@ -77,7 +76,7 @@ function makeInitializeTransaction(pgSchema, pgUser, chainConfigsOpt, entitiesOp
77
76
  var generalTables = [
78
77
  InternalTable.Chains.table,
79
78
  InternalTable.PersistedState.table,
80
- InternalTable.EndOfBlockRangeScannedData.table,
79
+ InternalTable.Checkpoints.table,
81
80
  InternalTable.RawEvents.table
82
81
  ];
83
82
  var allTables = $$Array.copy(generalTables);
@@ -110,11 +109,7 @@ function makeInitializeTransaction(pgSchema, pgUser, chainConfigsOpt, entitiesOp
110
109
  }
111
110
 
112
111
  });
113
- var functionsQuery = {
114
- contents: ""
115
- };
116
112
  entities.forEach(function (entity) {
117
- functionsQuery.contents = functionsQuery.contents + "\n" + entity.entityHistory.makeInsertFnQuery(pgSchema);
118
113
  Table.getDerivedFromFields(entity.table).forEach(function (derivedFromField) {
119
114
  var indexField = Utils.unwrapResultExn(Schema.getDerivedFromFieldName(derivedSchema, derivedFromField));
120
115
  query.contents = query.contents + "\n" + makeCreateIndexQuery(derivedFromField.derivedFromEntity, [indexField], pgSchema);
@@ -126,8 +121,10 @@ function makeInitializeTransaction(pgSchema, pgUser, chainConfigsOpt, entitiesOp
126
121
  if (initialChainsValuesQuery !== undefined) {
127
122
  query.contents = query.contents + "\n" + initialChainsValuesQuery;
128
123
  }
129
- functionsQuery.contents = functionsQuery.contents + "\n" + ("CREATE OR REPLACE FUNCTION " + getCacheRowCountFnName + "(table_name text) \nRETURNS integer AS $$\nDECLARE\n result integer;\nBEGIN\n EXECUTE format('SELECT COUNT(*) FROM \"" + pgSchema + "\".%I', table_name) INTO result;\n RETURN result;\nEND;\n$$ LANGUAGE plpgsql;");
130
- return [query.contents].concat(functionsQuery.contents !== "" ? [functionsQuery.contents] : []);
124
+ return [
125
+ query.contents,
126
+ "CREATE OR REPLACE FUNCTION " + getCacheRowCountFnName + "(table_name text) \nRETURNS integer AS $$\nDECLARE\n result integer;\nBEGIN\n EXECUTE format('SELECT COUNT(*) FROM \"" + pgSchema + "\".%I', table_name) INTO result;\n RETURN result;\nEND;\n$$ LANGUAGE plpgsql;"
127
+ ];
131
128
  }
132
129
 
133
130
  function makeLoadByIdQuery(pgSchema, tableName) {
@@ -197,7 +194,8 @@ function makeInsertValuesSetQuery(pgSchema, table, itemSchema, itemsCount) {
197
194
  function makeTableBatchSetQuery(pgSchema, table, itemSchema) {
198
195
  var match = Table.toSqlParams(table, itemSchema, pgSchema);
199
196
  var isRawEvents = table.tableName === InternalTable.RawEvents.table.tableName;
200
- if (isRawEvents || !match.hasArrayField) {
197
+ var isHistoryUpdate = table.tableName.startsWith("envio_history_");
198
+ if ((isRawEvents || !match.hasArrayField) && !isHistoryUpdate) {
201
199
  return {
202
200
  query: makeInsertUnnestSetQuery(pgSchema, table, itemSchema, isRawEvents),
203
201
  convertOrThrow: S$RescriptSchema.compile(S$RescriptSchema.unnest(match.dbSchema), "Output", "Input", "Sync", false),
@@ -231,7 +229,7 @@ function chunkArray(arr, chunkSize) {
231
229
 
232
230
  function removeInvalidUtf8InPlace(entities) {
233
231
  entities.forEach(function (item) {
234
- Utils.Dict.forEachWithKey(item, (function (key, value) {
232
+ Utils.Dict.forEachWithKey(item, (function (value, key) {
235
233
  if (typeof value === "string") {
236
234
  item[key] = value.replaceAll("\x00", "");
237
235
  return ;
@@ -296,28 +294,6 @@ async function setOrThrow(sql, items, table, itemSchema, pgSchema) {
296
294
  }
297
295
  }
298
296
 
299
- function setEntityHistoryOrThrow(sql, entityHistory, rows, shouldCopyCurrentEntity, shouldRemoveInvalidUtf8Opt) {
300
- var shouldRemoveInvalidUtf8 = shouldRemoveInvalidUtf8Opt !== undefined ? shouldRemoveInvalidUtf8Opt : false;
301
- return Belt_Array.map(rows, (function (historyRow) {
302
- var row = S$RescriptSchema.reverseConvertToJsonOrThrow(historyRow, entityHistory.schema);
303
- if (shouldRemoveInvalidUtf8) {
304
- removeInvalidUtf8InPlace([row]);
305
- }
306
- return $$Promise.$$catch(entityHistory.insertFn(sql, row, shouldCopyCurrentEntity !== undefined ? shouldCopyCurrentEntity : !Belt_Option.getWithDefault(historyRow.containsRollbackDiffChange, false)), (function (exn) {
307
- var reason = Utils.prettifyExn(exn);
308
- var detail = (reason?.detail || "");
309
- throw {
310
- RE_EXN_ID: Persistence.StorageError,
311
- message: "Failed to insert history item into table \"" + entityHistory.table.tableName + "\"." + (
312
- detail !== "" ? " Details: " + detail : ""
313
- ),
314
- reason: reason,
315
- Error: new Error()
316
- };
317
- }));
318
- }));
319
- }
320
-
321
297
  function makeSchemaTableNamesQuery(pgSchema) {
322
298
  return "SELECT table_name FROM information_schema.tables WHERE table_schema = '" + pgSchema + "';";
323
299
  }
@@ -498,7 +474,21 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, onI
498
474
  return {
499
475
  cleanRun: true,
500
476
  cache: cache,
501
- chains: chainConfigs.map(InternalTable.Chains.initialFromConfig)
477
+ chains: chainConfigs.map(function (chainConfig) {
478
+ return {
479
+ id: chainConfig.id,
480
+ startBlock: chainConfig.startBlock,
481
+ endBlock: chainConfig.endBlock,
482
+ maxReorgDepth: chainConfig.maxReorgDepth,
483
+ progressBlockNumber: -1,
484
+ numEventsProcessed: 0,
485
+ firstEventBlockNumber: undefined,
486
+ timestampCaughtUpToHeadOrEndblock: undefined,
487
+ dynamicContracts: []
488
+ };
489
+ }),
490
+ checkpointId: InternalTable.Checkpoints.initialCheckpointId,
491
+ reorgCheckpoints: []
502
492
  };
503
493
  };
504
494
  var loadByIdsOrThrow = async function (ids, table, rowsSchema) {
@@ -636,12 +626,30 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, onI
636
626
  var resumeInitialState = async function () {
637
627
  var match = await Promise.all([
638
628
  restoreEffectCache(false),
639
- sql.unsafe(makeLoadAllQuery(pgSchema, InternalTable.Chains.table.tableName))
629
+ InternalTable.Chains.getInitialState(sql, pgSchema).then(function (rawInitialStates) {
630
+ return Belt_Array.map(rawInitialStates, (function (rawInitialState) {
631
+ return {
632
+ id: rawInitialState.id,
633
+ startBlock: rawInitialState.startBlock,
634
+ endBlock: Caml_option.null_to_opt(rawInitialState.endBlock),
635
+ maxReorgDepth: rawInitialState.maxReorgDepth,
636
+ progressBlockNumber: rawInitialState.progressBlockNumber,
637
+ numEventsProcessed: rawInitialState.numEventsProcessed,
638
+ firstEventBlockNumber: Caml_option.null_to_opt(rawInitialState.firstEventBlockNumber),
639
+ timestampCaughtUpToHeadOrEndblock: Caml_option.null_to_opt(rawInitialState.timestampCaughtUpToHeadOrEndblock),
640
+ dynamicContracts: rawInitialState.dynamicContracts
641
+ };
642
+ }));
643
+ }),
644
+ sql.unsafe(InternalTable.Checkpoints.makeCommitedCheckpointIdQuery(pgSchema)),
645
+ sql.unsafe(InternalTable.Checkpoints.makeGetReorgCheckpointsQuery(pgSchema))
640
646
  ]);
641
647
  return {
642
648
  cleanRun: false,
643
649
  cache: match[0],
644
- chains: match[1]
650
+ chains: match[1],
651
+ checkpointId: match[2][0].id,
652
+ reorgCheckpoints: match[3]
645
653
  };
646
654
  };
647
655
  return {
@@ -677,7 +685,6 @@ exports.pgErrorMessageSchema = pgErrorMessageSchema;
677
685
  exports.PgEncodingError = PgEncodingError;
678
686
  exports.setQueryCache = setQueryCache;
679
687
  exports.setOrThrow = setOrThrow;
680
- exports.setEntityHistoryOrThrow = setEntityHistoryOrThrow;
681
688
  exports.makeSchemaTableNamesQuery = makeSchemaTableNamesQuery;
682
689
  exports.cacheTablePrefixLength = cacheTablePrefixLength;
683
690
  exports.makeSchemaCacheTableInfoQuery = makeSchemaCacheTableInfoQuery;
@@ -477,9 +477,15 @@ module RollbackSuccess = {
477
477
  "help": "Number of successful rollbacks on reorg",
478
478
  })
479
479
 
480
- let increment = (~timeMillis: Hrtime.milliseconds) => {
480
+ let eventsCounter = PromClient.Counter.makeCounter({
481
+ "name": "envio_rollback_events_count",
482
+ "help": "Number of events rollbacked on reorg",
483
+ })
484
+
485
+ let increment = (~timeMillis: Hrtime.milliseconds, ~rollbackedProcessedEvents) => {
481
486
  timeCounter->PromClient.Counter.incMany(timeMillis->Hrtime.intFromMillis)
482
487
  counter->PromClient.Counter.inc
488
+ eventsCounter->PromClient.Counter.incMany(rollbackedProcessedEvents)
483
489
  }
484
490
  }
485
491
 
@@ -579,14 +579,21 @@ var counter$3 = new PromClient.Counter({
579
579
  help: "Number of successful rollbacks on reorg"
580
580
  });
581
581
 
582
- function increment$3(timeMillis) {
582
+ var eventsCounter = new PromClient.Counter({
583
+ name: "envio_rollback_events_count",
584
+ help: "Number of events rollbacked on reorg"
585
+ });
586
+
587
+ function increment$3(timeMillis, rollbackedProcessedEvents) {
583
588
  timeCounter.inc(Hrtime.intFromMillis(timeMillis));
584
589
  counter$3.inc();
590
+ eventsCounter.inc(rollbackedProcessedEvents);
585
591
  }
586
592
 
587
593
  var RollbackSuccess = {
588
594
  timeCounter: timeCounter,
589
595
  counter: counter$3,
596
+ eventsCounter: eventsCounter,
590
597
  increment: increment$3
591
598
  };
592
599