@subsquid/batch-processor 0.2.0-portal-api.493495 → 0.2.0-portal-api.19316d

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.
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TemplateRegistry = void 0;
4
+ class HandlerTemplates {
5
+ constructor(range, registry) {
6
+ this.range = range;
7
+ this.registry = registry;
8
+ this.data = [];
9
+ }
10
+ add(key, value, blockNumber) {
11
+ this.mutate('add', key, value, blockNumber);
12
+ }
13
+ remove(key, value, blockNumber) {
14
+ this.mutate('delete', key, value, blockNumber);
15
+ }
16
+ has(key, value, blockNumber) {
17
+ return this.registry.has(key, value, blockNumber);
18
+ }
19
+ mutate(type, key, value, blockNumber) {
20
+ if (blockNumber < this.range.from) {
21
+ throw new RangeError(`blockNumber ${blockNumber} is before batch start ${this.range.from}`);
22
+ }
23
+ let mutation = { type, key, value, blockNumber };
24
+ this.registry.apply(mutation);
25
+ this.data.push(mutation);
26
+ }
27
+ }
28
+ class TemplateRegistry {
29
+ constructor() {
30
+ this.byKey = new Map();
31
+ this.baseMutations = [];
32
+ this.undoLog = [];
33
+ this.pendingTemplates = [];
34
+ }
35
+ /**
36
+ * Rebuild state from finalized mutations and optionally replay hot block
37
+ * mutations to reconstruct the undo log.
38
+ *
39
+ * Finalized mutations form the base state. Hot block mutations are stored
40
+ * in the undo log so rollbackTo() works for hot block heights after restart.
41
+ */
42
+ init(mutations, hotBlocks) {
43
+ this.baseMutations = mutations;
44
+ this.undoLog = hotBlocks ?? [];
45
+ this.pendingTemplates = [];
46
+ this.rebuild();
47
+ }
48
+ get(key) {
49
+ let m = this.byKey.get(key);
50
+ if (m == null)
51
+ return [];
52
+ let out = [];
53
+ for (let [value, ranges] of m) {
54
+ for (let range of ranges) {
55
+ out.push({ value, range });
56
+ }
57
+ }
58
+ return out;
59
+ }
60
+ has(key, value, block) {
61
+ let byVal = this.byKey.get(key);
62
+ if (byVal == null)
63
+ return false;
64
+ let ranges = byVal.get(value);
65
+ if (ranges == null)
66
+ return false;
67
+ for (let range of ranges) {
68
+ if (block >= range.from && (range.to == null || block <= range.to)) {
69
+ return true;
70
+ }
71
+ }
72
+ return false;
73
+ }
74
+ apply(mutation) {
75
+ let changed = this.applyToState(mutation);
76
+ if (changed) {
77
+ this.pendingTemplates.push(mutation);
78
+ }
79
+ return changed;
80
+ }
81
+ async transact(range, fn) {
82
+ let templates = new HandlerTemplates(range, this);
83
+ try {
84
+ await fn(templates);
85
+ }
86
+ catch (e) {
87
+ this.pendingTemplates = [];
88
+ this.rebuild();
89
+ throw e;
90
+ }
91
+ let changed = this.pendingTemplates.length > 0;
92
+ if (changed) {
93
+ this.undoLog.push({ blockNumber: range.to, templates: this.pendingTemplates });
94
+ }
95
+ this.pendingTemplates = [];
96
+ return { data: templates.data, changed };
97
+ }
98
+ rollbackTo(blockNumber) {
99
+ let splitIdx = upperBound(this.undoLog, blockNumber);
100
+ if (splitIdx >= this.undoLog.length)
101
+ return;
102
+ this.undoLog.length = splitIdx;
103
+ this.pendingTemplates = [];
104
+ this.rebuild();
105
+ }
106
+ prune(blockNumber) {
107
+ let splitIdx = upperBound(this.undoLog, blockNumber);
108
+ for (let i = 0; i < splitIdx; i++) {
109
+ this.baseMutations.push(...this.undoLog[i].templates);
110
+ }
111
+ this.undoLog = this.undoLog.slice(splitIdx);
112
+ }
113
+ applyToState({ type, key, value, blockNumber }) {
114
+ if (type === 'add') {
115
+ let byVal = this.byKey.get(key);
116
+ if (byVal == null) {
117
+ byVal = new Map();
118
+ this.byKey.set(key, byVal);
119
+ }
120
+ let ranges = byVal.get(value);
121
+ if (ranges == null) {
122
+ byVal.set(value, [{ from: blockNumber }]);
123
+ return true;
124
+ }
125
+ let last = ranges[ranges.length - 1];
126
+ if (last.to != null) {
127
+ if (blockNumber < last.to)
128
+ return false;
129
+ ranges.push({ from: blockNumber });
130
+ return true;
131
+ }
132
+ if (blockNumber >= last.from)
133
+ return false;
134
+ last.from = blockNumber;
135
+ return true;
136
+ }
137
+ else {
138
+ let byVal = this.byKey.get(key);
139
+ if (!byVal)
140
+ return false;
141
+ let ranges = byVal.get(value);
142
+ if (!ranges || ranges.length === 0)
143
+ return false;
144
+ let last = ranges[ranges.length - 1];
145
+ if (last.to != null)
146
+ return false;
147
+ if (blockNumber < last.from)
148
+ return false;
149
+ last.to = blockNumber;
150
+ return true;
151
+ }
152
+ }
153
+ rebuild() {
154
+ this.byKey.clear();
155
+ let allMutations = [...this.baseMutations];
156
+ for (let entry of this.undoLog) {
157
+ allMutations.push(...entry.templates);
158
+ }
159
+ allMutations.sort((a, b) => {
160
+ if (a.blockNumber !== b.blockNumber)
161
+ return a.blockNumber - b.blockNumber;
162
+ if (a.type !== b.type)
163
+ return a.type === 'delete' ? -1 : 1;
164
+ return 0;
165
+ });
166
+ for (let m of allMutations) {
167
+ this.applyToState(m);
168
+ }
169
+ }
170
+ }
171
+ exports.TemplateRegistry = TemplateRegistry;
172
+ function upperBound(log, target) {
173
+ let lo = 0;
174
+ let hi = log.length;
175
+ while (lo < hi) {
176
+ let mid = (lo + hi) >> 1;
177
+ if (log[mid].blockNumber > target) {
178
+ hi = mid;
179
+ }
180
+ else {
181
+ lo = mid + 1;
182
+ }
183
+ }
184
+ return lo;
185
+ }
186
+ //# sourceMappingURL=template-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-registry.js","sourceRoot":"","sources":["../src/template-registry.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@subsquid/batch-processor",
3
- "version": "0.2.0-portal-api.493495",
3
+ "version": "0.2.0-portal-api.19316d",
4
4
  "description": "ETL processor",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "repository": "git@github.com:subsquid/squid-sdk.git",
@@ -20,9 +20,10 @@
20
20
  "@subsquid/util-internal-counters": "^1.3.2",
21
21
  "@subsquid/util-internal-prometheus-server": "^1.3.0",
22
22
  "@subsquid/util-internal-range": "^0.3.0",
23
- "@subsquid/util-internal-data-source": "0.0.1-portal-api.493495"
23
+ "@subsquid/util-internal-data-source": "0.0.1-portal-api.19316d"
24
24
  },
25
25
  "devDependencies": {
26
+ "@types/mocha": "^10.0.7",
26
27
  "@types/node": "^18.18.14",
27
28
  "typescript": "~5.5.4"
28
29
  },
package/src/database.ts CHANGED
@@ -14,12 +14,22 @@ export interface FinalTxInfo {
14
14
 
15
15
  export interface FinalDatabase<S> {
16
16
  supportsHotBlocks?: false
17
+ supportsTemplates?: boolean
17
18
  connect(): Promise<FinalDatabaseState>
18
- transact(info: FinalTxInfo, cb: (store: S) => Promise<void>): Promise<void>
19
+ transact(info: FinalTxInfo, cb: (store: S) => Promise<DatabaseTransactResult | void>): Promise<void>
19
20
  }
20
21
 
21
22
 
22
- export interface FinalDatabaseState extends HashAndHeight {}
23
+ export interface DatabaseTransactResult {
24
+ templates?: TemplateMutation[]
25
+ }
26
+
27
+
28
+ export interface FinalDatabaseState {
29
+ height: number
30
+ hash: string
31
+ templates?: TemplateMutation[]
32
+ }
23
33
 
24
34
 
25
35
  export interface HotTxInfo {
@@ -31,22 +41,42 @@ export interface HotTxInfo {
31
41
 
32
42
  export interface HotDatabase<S> {
33
43
  supportsHotBlocks: true
44
+ supportsTemplates?: boolean
34
45
  connect(): Promise<HotDatabaseState>
35
- transact(info: FinalTxInfo, cb: (store: S) => Promise<void>): Promise<void>
46
+ transact(info: FinalTxInfo, cb: (store: S) => Promise<DatabaseTransactResult | void>): Promise<void>
36
47
 
37
48
  transactHot2(
38
49
  info: HotTxInfo,
39
- cb: (store: S, blockSliceStart: number, blockSliceEnd: number) => Promise<void>
50
+ cb: (store: S, blockSliceStart: number, blockSliceEnd: number) => Promise<DatabaseTransactResult | void>
40
51
  ): Promise<void>
41
52
  }
42
53
 
43
54
 
55
+ export interface HotBlock extends HashAndHeight {
56
+ templates?: TemplateMutation[]
57
+ }
58
+
59
+
44
60
  export interface HotDatabaseState extends HashAndHeight {
45
- top: HashAndHeight[]
61
+ top: HotBlock[]
62
+ templates?: TemplateMutation[]
63
+ }
64
+
65
+
66
+ export interface FinalDatabaseState extends HashAndHeight {
67
+ templates?: TemplateMutation[]
68
+ }
69
+
70
+
71
+ export interface TemplateMutation {
72
+ type: 'add' | 'delete'
73
+ key: string
74
+ value: string
75
+ blockNumber: number
46
76
  }
47
77
 
48
78
 
49
79
  export interface HashAndHeight {
50
- height: number
51
80
  hash: string
81
+ height: number
52
82
  }