@cubejs-backend/query-orchestrator 0.23.3 → 0.24.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/CHANGELOG.md +38 -0
- package/README.md +2 -2
- package/dist/src/driver/BaseDriver.d.ts +36 -0
- package/dist/src/driver/BaseDriver.d.ts.map +1 -0
- package/dist/src/driver/BaseDriver.js +175 -0
- package/dist/src/driver/BaseDriver.js.map +1 -0
- package/dist/src/driver/index.d.ts +3 -0
- package/dist/src/driver/index.d.ts.map +1 -0
- package/dist/src/driver/index.js +15 -0
- package/dist/src/driver/index.js.map +1 -0
- package/dist/src/driver/utils.d.ts +2 -0
- package/dist/src/driver/utils.d.ts.map +1 -0
- package/dist/src/driver/utils.js +17 -0
- package/dist/src/driver/utils.js.map +1 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +15 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/orchestrator/BaseQueueDriver.d.ts +4 -0
- package/dist/src/orchestrator/BaseQueueDriver.d.ts.map +1 -0
- package/dist/src/orchestrator/BaseQueueDriver.js +16 -0
- package/dist/src/orchestrator/BaseQueueDriver.js.map +1 -0
- package/dist/src/orchestrator/ContinueWaitError.d.ts +3 -0
- package/dist/src/orchestrator/ContinueWaitError.d.ts.map +1 -0
- package/dist/src/orchestrator/ContinueWaitError.js +10 -0
- package/dist/src/orchestrator/ContinueWaitError.js.map +1 -0
- package/dist/src/orchestrator/LocalCacheDriver.d.ts +8 -0
- package/dist/src/orchestrator/LocalCacheDriver.d.ts.map +1 -0
- package/dist/src/orchestrator/LocalCacheDriver.js +30 -0
- package/dist/src/orchestrator/LocalCacheDriver.js.map +1 -0
- package/dist/src/orchestrator/LocalQueueDriver.d.ts +57 -0
- package/dist/src/orchestrator/LocalQueueDriver.d.ts.map +1 -0
- package/dist/src/orchestrator/LocalQueueDriver.js +230 -0
- package/dist/src/orchestrator/LocalQueueDriver.js.map +1 -0
- package/dist/src/orchestrator/PreAggregations.d.ts +26 -0
- package/dist/src/orchestrator/PreAggregations.d.ts.map +1 -0
- package/dist/src/orchestrator/PreAggregations.js +565 -0
- package/dist/src/orchestrator/PreAggregations.js.map +1 -0
- package/dist/src/orchestrator/QueryCache.d.ts +51 -0
- package/dist/src/orchestrator/QueryCache.d.ts.map +1 -0
- package/dist/src/orchestrator/QueryCache.js +293 -0
- package/dist/src/orchestrator/QueryCache.js.map +1 -0
- package/dist/src/orchestrator/QueryOrchestrator.d.ts +27 -0
- package/dist/src/orchestrator/QueryOrchestrator.d.ts.map +1 -0
- package/dist/src/orchestrator/QueryOrchestrator.js +79 -0
- package/dist/src/orchestrator/QueryOrchestrator.js.map +1 -0
- package/dist/src/orchestrator/QueryQueue.d.ts +36 -0
- package/dist/src/orchestrator/QueryQueue.d.ts.map +1 -0
- package/dist/src/orchestrator/QueryQueue.js +351 -0
- package/dist/src/orchestrator/QueryQueue.js.map +1 -0
- package/dist/src/orchestrator/RedisCacheDriver.d.ts +12 -0
- package/dist/src/orchestrator/RedisCacheDriver.d.ts.map +1 -0
- package/dist/src/orchestrator/RedisCacheDriver.js +50 -0
- package/dist/src/orchestrator/RedisCacheDriver.js.map +1 -0
- package/dist/src/orchestrator/RedisFactory.d.ts +3 -0
- package/dist/src/orchestrator/RedisFactory.d.ts.map +1 -0
- package/dist/src/orchestrator/RedisFactory.js +45 -0
- package/dist/src/orchestrator/RedisFactory.js.map +1 -0
- package/dist/src/orchestrator/RedisPool.d.ts +10 -0
- package/dist/src/orchestrator/RedisPool.d.ts.map +1 -0
- package/dist/src/orchestrator/RedisPool.js +57 -0
- package/dist/src/orchestrator/RedisPool.js.map +1 -0
- package/dist/src/orchestrator/RedisQueueDriver.d.ts +47 -0
- package/dist/src/orchestrator/RedisQueueDriver.d.ts.map +1 -0
- package/dist/src/orchestrator/RedisQueueDriver.js +253 -0
- package/dist/src/orchestrator/RedisQueueDriver.js.map +1 -0
- package/dist/src/orchestrator/TimeoutError.d.ts +4 -0
- package/dist/src/orchestrator/TimeoutError.d.ts.map +1 -0
- package/dist/src/orchestrator/TimeoutError.js +7 -0
- package/dist/src/orchestrator/TimeoutError.js.map +1 -0
- package/dist/src/orchestrator/index.d.ts +14 -0
- package/dist/src/orchestrator/index.d.ts.map +1 -0
- package/dist/src/orchestrator/index.js +26 -0
- package/dist/src/orchestrator/index.js.map +1 -0
- package/driver/BaseDriver.js +5 -221
- package/driver/README.md +3 -0
- package/driver/utils.js +8 -12
- package/orchestrator/BaseQueueDriver.js +5 -8
- package/orchestrator/ContinueWaitError.js +6 -5
- package/orchestrator/LocalCacheDriver.js +5 -29
- package/orchestrator/LocalQueueDriver.js +5 -256
- package/orchestrator/PreAggregations.js +4 -764
- package/orchestrator/QueryCache.js +5 -381
- package/orchestrator/QueryOrchestrator.js +5 -100
- package/orchestrator/QueryQueue.js +5 -378
- package/orchestrator/README.md +3 -0
- package/orchestrator/RedisCacheDriver.js +5 -45
- package/orchestrator/RedisFactory.js +6 -46
- package/orchestrator/RedisPool.js +5 -49
- package/orchestrator/RedisQueueDriver.js +5 -283
- package/orchestrator/TimeoutError.js +6 -1
- package/package.json +29 -10
- package/test/integration/PreAggregations.test.js +0 -337
- package/test/integration/QueryQueueRedis.test.js +0 -6
- package/test/unit/QueryOrchestrator.test.js +0 -301
- package/test/unit/QueryQueue.test.js +0 -249
|
@@ -1,768 +1,8 @@
|
|
|
1
|
-
const
|
|
2
|
-
const R = require('ramda');
|
|
3
|
-
const { cancelCombinator } = require('../driver/utils');
|
|
4
|
-
const RedisCacheDriver = require('./RedisCacheDriver');
|
|
5
|
-
const LocalCacheDriver = require('./LocalCacheDriver');
|
|
1
|
+
const { PreAggregations } = require('../dist/src/orchestrator/PreAggregations');
|
|
6
2
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
function encodeTimeStamp(time) {
|
|
11
|
-
return Math.floor(time / 1000).toString(32);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function version(cacheKey, isDigestKey = false) {
|
|
15
|
-
let result = '';
|
|
16
|
-
const hashCharset = 'abcdefghijklmnopqrstuvwxyz012345';
|
|
17
|
-
let digestBuffer = Number(cacheKey);
|
|
18
|
-
if (!isDigestKey) {
|
|
19
|
-
digestBuffer = crypto.createHash('md5').update(JSON.stringify(cacheKey)).digest();
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
let residue = 0;
|
|
23
|
-
let shiftCounter = 0;
|
|
24
|
-
for (let i = 0; i < 5; i++) {
|
|
25
|
-
const byte = digestBuffer.readUInt8(i);
|
|
26
|
-
shiftCounter += 8;
|
|
27
|
-
// eslint-disable-next-line operator-assignment,no-bitwise
|
|
28
|
-
residue = (byte << (shiftCounter - 8)) | residue;
|
|
29
|
-
// eslint-disable-next-line no-bitwise
|
|
30
|
-
while (residue >> 5) {
|
|
31
|
-
result += hashCharset.charAt(residue % 32);
|
|
32
|
-
shiftCounter -= 5;
|
|
33
|
-
// eslint-disable-next-line operator-assignment,no-bitwise
|
|
34
|
-
residue = residue >> 5;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
result += hashCharset.charAt(residue % 32);
|
|
38
|
-
return result;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const tablesToVersionEntries = (schema, tables) => R.sortBy(
|
|
42
|
-
table => -table.last_updated_at,
|
|
43
|
-
tables.map(table => {
|
|
44
|
-
const match = (table.table_name || table.TABLE_NAME).match(/(.+)_(.+)_(.+)_(.+)/);
|
|
45
|
-
|
|
46
|
-
if (!match) {
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const entity = {
|
|
51
|
-
table_name: `${schema}.${match[1]}`,
|
|
52
|
-
content_version: match[2],
|
|
53
|
-
structure_version: match[3]
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
if (match[4].length < 13) {
|
|
57
|
-
entity.last_updated_at = parseInt(match[4], 32) * 1000;
|
|
58
|
-
entity.naming_version = 2;
|
|
59
|
-
} else {
|
|
60
|
-
entity.last_updated_at = parseInt(match[4], 10);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return entity;
|
|
64
|
-
}).filter(R.identity)
|
|
3
|
+
process.emitWarning(
|
|
4
|
+
'Using absolute import with @cubejs-backend/query-orchestrator is deprecated',
|
|
5
|
+
'DeprecationWarning'
|
|
65
6
|
);
|
|
66
7
|
|
|
67
|
-
class PreAggregationLoadCache {
|
|
68
|
-
constructor(redisPrefix, clientFactory, queryCache, preAggregations, options) {
|
|
69
|
-
options = options || {};
|
|
70
|
-
this.redisPrefix = redisPrefix;
|
|
71
|
-
this.driverFactory = clientFactory;
|
|
72
|
-
this.queryCache = queryCache;
|
|
73
|
-
this.preAggregations = preAggregations;
|
|
74
|
-
this.queryResults = {};
|
|
75
|
-
this.cacheDriver = preAggregations.cacheDriver;
|
|
76
|
-
this.externalDriverFactory = preAggregations.externalDriverFactory;
|
|
77
|
-
this.requestId = options.requestId;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
async tablesFromCache(preAggregation, forceRenew) {
|
|
81
|
-
let tables = forceRenew ? null : await this.cacheDriver.get(this.tablesRedisKey(preAggregation));
|
|
82
|
-
if (!tables) {
|
|
83
|
-
tables = await this.preAggregations.getLoadCacheQueue().executeInQueue(
|
|
84
|
-
'query',
|
|
85
|
-
`Fetch tables for ${preAggregation.preAggregationsSchema}`,
|
|
86
|
-
{
|
|
87
|
-
preAggregation, requestId: this.requestId
|
|
88
|
-
},
|
|
89
|
-
0,
|
|
90
|
-
{ requestId: this.requestId }
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
return tables;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
async fetchTables(preAggregation) {
|
|
97
|
-
if (preAggregation.external && !this.externalDriverFactory) {
|
|
98
|
-
throw new Error('externalDriverFactory should be set in order to use external pre-aggregations');
|
|
99
|
-
}
|
|
100
|
-
const client = preAggregation.external ?
|
|
101
|
-
await this.externalDriverFactory() :
|
|
102
|
-
await this.driverFactory();
|
|
103
|
-
const newTables = await client.getTablesQuery(preAggregation.preAggregationsSchema);
|
|
104
|
-
await this.cacheDriver.set(
|
|
105
|
-
this.tablesRedisKey(preAggregation),
|
|
106
|
-
newTables,
|
|
107
|
-
this.preAggregations.options.preAggregationsSchemaCacheExpire || 60 * 60
|
|
108
|
-
);
|
|
109
|
-
return newTables;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
tablesRedisKey(preAggregation) {
|
|
113
|
-
return `SQL_PRE_AGGREGATIONS_TABLES_${this.redisPrefix}${preAggregation.external ? '_EXT' : ''}`;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
async getTablesQuery(preAggregation) {
|
|
117
|
-
if (!this.tables) {
|
|
118
|
-
this.tables = await this.tablesFromCache(preAggregation);
|
|
119
|
-
}
|
|
120
|
-
return this.tables;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
async getVersionEntries(preAggregation) {
|
|
124
|
-
if (!this.versionEntries) {
|
|
125
|
-
this.versionEntries = tablesToVersionEntries(
|
|
126
|
-
preAggregation.preAggregationsSchema,
|
|
127
|
-
await this.getTablesQuery(preAggregation)
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
const [active, toProcess, queries] = await this.fetchQueryStageState();
|
|
131
|
-
const targetTableNamesInQueue = (Object.keys(queries))
|
|
132
|
-
// eslint-disable-next-line no-use-before-define
|
|
133
|
-
.map(q => PreAggregations.targetTableName(queries[q].query.newVersionEntry));
|
|
134
|
-
return this.versionEntries.filter(
|
|
135
|
-
// eslint-disable-next-line no-use-before-define
|
|
136
|
-
e => targetTableNamesInQueue.indexOf(PreAggregations.targetTableName(e)) === -1
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
async keyQueryResult(keyQuery, waitForRenew, priority, renewalThreshold) {
|
|
141
|
-
if (!this.queryResults[this.queryCache.queryRedisKey(keyQuery)]) {
|
|
142
|
-
this.queryResults[this.queryCache.queryRedisKey(keyQuery)] = await this.queryCache.cacheQueryResult(
|
|
143
|
-
Array.isArray(keyQuery) ? keyQuery[0] : keyQuery,
|
|
144
|
-
Array.isArray(keyQuery) ? keyQuery[1] : [],
|
|
145
|
-
keyQuery,
|
|
146
|
-
60 * 60,
|
|
147
|
-
{
|
|
148
|
-
renewalThreshold:
|
|
149
|
-
this.queryCache.options.refreshKeyRenewalThreshold ||
|
|
150
|
-
renewalThreshold ||
|
|
151
|
-
2 * 60,
|
|
152
|
-
renewalKey: keyQuery,
|
|
153
|
-
waitForRenew,
|
|
154
|
-
priority,
|
|
155
|
-
requestId: this.requestId
|
|
156
|
-
}
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
return this.queryResults[this.queryCache.queryRedisKey(keyQuery)];
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
hasKeyQueryResult(keyQuery) {
|
|
163
|
-
return !!this.queryResults[this.queryCache.queryRedisKey(keyQuery)];
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
async getQueryStage(stageQueryKey) {
|
|
167
|
-
const queue = this.preAggregations.getQueue();
|
|
168
|
-
await this.fetchQueryStageState(queue);
|
|
169
|
-
return queue.getQueryStage(stageQueryKey, undefined, this.queryStageState);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
async fetchQueryStageState(queue) {
|
|
173
|
-
queue = queue || this.preAggregations.getQueue();
|
|
174
|
-
if (!this.queryStageState) {
|
|
175
|
-
this.queryStageState = await queue.fetchQueryStageState();
|
|
176
|
-
}
|
|
177
|
-
return this.queryStageState;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
async reset(preAggregation) {
|
|
181
|
-
this.tables = undefined;
|
|
182
|
-
this.queryStageState = undefined;
|
|
183
|
-
this.versionEntries = undefined;
|
|
184
|
-
await this.cacheDriver.remove(this.tablesRedisKey(preAggregation));
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
class PreAggregationLoader {
|
|
189
|
-
constructor(
|
|
190
|
-
redisPrefix,
|
|
191
|
-
clientFactory,
|
|
192
|
-
logger,
|
|
193
|
-
queryCache,
|
|
194
|
-
preAggregations,
|
|
195
|
-
preAggregation,
|
|
196
|
-
preAggregationsTablesToTempTables,
|
|
197
|
-
loadCache,
|
|
198
|
-
options
|
|
199
|
-
) {
|
|
200
|
-
options = options || {};
|
|
201
|
-
this.redisPrefix = redisPrefix;
|
|
202
|
-
this.driverFactory = clientFactory;
|
|
203
|
-
this.logger = logger;
|
|
204
|
-
this.queryCache = queryCache;
|
|
205
|
-
this.preAggregations = preAggregations;
|
|
206
|
-
this.preAggregation = preAggregation;
|
|
207
|
-
this.preAggregationsTablesToTempTables = preAggregationsTablesToTempTables;
|
|
208
|
-
this.loadCache = loadCache;
|
|
209
|
-
this.waitForRenew = options.waitForRenew;
|
|
210
|
-
this.externalDriverFactory = preAggregations.externalDriverFactory;
|
|
211
|
-
this.requestId = options.requestId;
|
|
212
|
-
this.structureVersionPersistTime = preAggregations.structureVersionPersistTime;
|
|
213
|
-
this.externalRefresh = options.externalRefresh;
|
|
214
|
-
if (this.externalRefresh && this.waitForRenew) {
|
|
215
|
-
const message = 'Invalid configuration - when externalRefresh is true, it will not perform a renew, therefore you cannot wait for it using waitForRenew.';
|
|
216
|
-
if (['production', 'test'].includes(process.env.NODE_ENV)) {
|
|
217
|
-
throw new Error(message);
|
|
218
|
-
} else {
|
|
219
|
-
this.logger('Invalid Configuration', {
|
|
220
|
-
requestId: this.requestId,
|
|
221
|
-
warning: message,
|
|
222
|
-
});
|
|
223
|
-
this.waitForRenew = false;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
async loadPreAggregation() {
|
|
229
|
-
const notLoadedKey = (this.preAggregation.invalidateKeyQueries || [])
|
|
230
|
-
.find(keyQuery => !this.loadCache.hasKeyQueryResult(keyQuery));
|
|
231
|
-
if (notLoadedKey && !this.waitForRenew) {
|
|
232
|
-
const structureVersion = this.structureVersion();
|
|
233
|
-
|
|
234
|
-
const getVersionsStarted = new Date();
|
|
235
|
-
const versionEntries = await this.loadCache.getVersionEntries(this.preAggregation);
|
|
236
|
-
this.logger('Load PreAggregations Tables', {
|
|
237
|
-
preAggregation: this.preAggregation,
|
|
238
|
-
requestId: this.requestId,
|
|
239
|
-
duration: (new Date().getTime() - getVersionsStarted.getTime())
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
const versionEntryByStructureVersion = versionEntries.find(
|
|
243
|
-
v => v.table_name === this.preAggregation.tableName && v.structure_version === structureVersion
|
|
244
|
-
);
|
|
245
|
-
if (this.externalRefresh) {
|
|
246
|
-
if (!versionEntryByStructureVersion) {
|
|
247
|
-
throw new Error('One or more pre-aggregation tables could not be found to satisfy that query');
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// the rollups are being maintained independently of this instance of cube.js,
|
|
251
|
-
// immediately return the latest data it already has
|
|
252
|
-
return this.targetTableName(versionEntryByStructureVersion);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (versionEntryByStructureVersion) {
|
|
256
|
-
// this triggers an asyncronous/background load of the pre-aggregation but immediately
|
|
257
|
-
// returns the latest data it already has
|
|
258
|
-
this.loadPreAggregationWithKeys().catch(e => {
|
|
259
|
-
if (!(e instanceof ContinueWaitError)) {
|
|
260
|
-
this.logger('Error loading pre-aggregation', {
|
|
261
|
-
error: (e.stack || e),
|
|
262
|
-
preAggregation: this.preAggregation,
|
|
263
|
-
requestId: this.requestId
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
return this.targetTableName(versionEntryByStructureVersion);
|
|
268
|
-
} else {
|
|
269
|
-
// no rollup has been built yet - build it syncronously as part of responding to this request
|
|
270
|
-
return this.loadPreAggregationWithKeys();
|
|
271
|
-
}
|
|
272
|
-
} else {
|
|
273
|
-
// either we have no data cached for this rollup or waitForRenew is true, either way,
|
|
274
|
-
// syncronously renew what data is needed so that the most current data will be returned for the current request
|
|
275
|
-
return {
|
|
276
|
-
targetTableName: await this.loadPreAggregationWithKeys(),
|
|
277
|
-
refreshKeyValues: await this.getInvalidationKeyValues()
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
async loadPreAggregationWithKeys() {
|
|
283
|
-
const invalidationKeys = await this.getInvalidationKeyValues();
|
|
284
|
-
const contentVersion = this.contentVersion(invalidationKeys);
|
|
285
|
-
const structureVersion = this.structureVersion();
|
|
286
|
-
|
|
287
|
-
const versionEntries = await this.loadCache.getVersionEntries(this.preAggregation);
|
|
288
|
-
|
|
289
|
-
const getVersionEntryByContentVersion = (entries) => entries.find(
|
|
290
|
-
v => v.table_name === this.preAggregation.tableName && v.content_version === contentVersion
|
|
291
|
-
);
|
|
292
|
-
|
|
293
|
-
const versionEntryByContentVersion = getVersionEntryByContentVersion(versionEntries);
|
|
294
|
-
if (versionEntryByContentVersion) {
|
|
295
|
-
return this.targetTableName(versionEntryByContentVersion);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// TODO this check can be redundant due to structure version is already checked in loadPreAggregation()
|
|
299
|
-
if (
|
|
300
|
-
!this.waitForRenew &&
|
|
301
|
-
// eslint-disable-next-line no-use-before-define
|
|
302
|
-
await this.loadCache.getQueryStage(PreAggregations.preAggregationQueryCacheKey(this.preAggregation))
|
|
303
|
-
) {
|
|
304
|
-
const versionEntryByStructureVersion = versionEntries.find(
|
|
305
|
-
v => v.table_name === this.preAggregation.tableName && v.structure_version === structureVersion
|
|
306
|
-
);
|
|
307
|
-
if (versionEntryByStructureVersion) {
|
|
308
|
-
return this.targetTableName(versionEntryByStructureVersion);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
if (!versionEntries.length) {
|
|
313
|
-
const client = this.preAggregation.external ?
|
|
314
|
-
await this.externalDriverFactory() :
|
|
315
|
-
await this.driverFactory();
|
|
316
|
-
await client.createSchemaIfNotExists(this.preAggregation.preAggregationsSchema);
|
|
317
|
-
}
|
|
318
|
-
// ensure we find appropriate structure version before invalidating anything
|
|
319
|
-
const versionEntry = versionEntries.find(
|
|
320
|
-
v => v.table_name === this.preAggregation.tableName && v.structure_version === structureVersion
|
|
321
|
-
) || versionEntries.find(
|
|
322
|
-
e => e.table_name === this.preAggregation.tableName
|
|
323
|
-
);
|
|
324
|
-
|
|
325
|
-
const newVersionEntry = {
|
|
326
|
-
table_name: this.preAggregation.tableName,
|
|
327
|
-
structure_version: structureVersion,
|
|
328
|
-
content_version: contentVersion,
|
|
329
|
-
last_updated_at: new Date().getTime(),
|
|
330
|
-
naming_version: 2,
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
const mostRecentTargetTableName = async () => {
|
|
334
|
-
await this.loadCache.reset(this.preAggregation);
|
|
335
|
-
const lastVersion = getVersionEntryByContentVersion(
|
|
336
|
-
await this.loadCache.getVersionEntries(this.preAggregation)
|
|
337
|
-
);
|
|
338
|
-
if (!lastVersion) {
|
|
339
|
-
throw new Error(`Pre-aggregation table is not found for ${this.preAggregation.tableName} after it was successfully created. It usually means database silently truncates table names due to max name length.`);
|
|
340
|
-
}
|
|
341
|
-
return this.targetTableName(lastVersion);
|
|
342
|
-
};
|
|
343
|
-
|
|
344
|
-
if (versionEntry) {
|
|
345
|
-
if (versionEntry.structure_version !== newVersionEntry.structure_version) {
|
|
346
|
-
this.logger('Invalidating pre-aggregation structure', {
|
|
347
|
-
preAggregation: this.preAggregation,
|
|
348
|
-
requestId: this.requestId,
|
|
349
|
-
queryKey: this.preAggregationQueryKey(invalidationKeys),
|
|
350
|
-
newVersionEntry
|
|
351
|
-
});
|
|
352
|
-
await this.executeInQueue(invalidationKeys, this.priority(10), newVersionEntry);
|
|
353
|
-
return mostRecentTargetTableName();
|
|
354
|
-
} else if (versionEntry.content_version !== newVersionEntry.content_version) {
|
|
355
|
-
if (this.waitForRenew) {
|
|
356
|
-
this.logger('Waiting for pre-aggregation renew', {
|
|
357
|
-
preAggregation: this.preAggregation,
|
|
358
|
-
requestId: this.requestId,
|
|
359
|
-
queryKey: this.preAggregationQueryKey(invalidationKeys),
|
|
360
|
-
newVersionEntry
|
|
361
|
-
});
|
|
362
|
-
await this.executeInQueue(invalidationKeys, this.priority(0), newVersionEntry);
|
|
363
|
-
return mostRecentTargetTableName();
|
|
364
|
-
} else {
|
|
365
|
-
this.scheduleRefresh(invalidationKeys, newVersionEntry);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
} else {
|
|
369
|
-
this.logger('Creating pre-aggregation from scratch', {
|
|
370
|
-
preAggregation: this.preAggregation,
|
|
371
|
-
requestId: this.requestId,
|
|
372
|
-
queryKey: this.preAggregationQueryKey(invalidationKeys),
|
|
373
|
-
newVersionEntry
|
|
374
|
-
});
|
|
375
|
-
await this.executeInQueue(invalidationKeys, this.priority(10), newVersionEntry);
|
|
376
|
-
return mostRecentTargetTableName();
|
|
377
|
-
}
|
|
378
|
-
return this.targetTableName(versionEntry);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
contentVersion(invalidationKeys) {
|
|
382
|
-
return version(
|
|
383
|
-
this.preAggregation.indexesSql && this.preAggregation.indexesSql.length ?
|
|
384
|
-
[this.preAggregation.loadSql, this.preAggregation.indexesSql, invalidationKeys] :
|
|
385
|
-
[this.preAggregation.loadSql, invalidationKeys]
|
|
386
|
-
);
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
structureVersion() {
|
|
390
|
-
return version(
|
|
391
|
-
this.preAggregation.indexesSql && this.preAggregation.indexesSql.length ?
|
|
392
|
-
[this.preAggregation.loadSql, this.preAggregation.indexesSql] :
|
|
393
|
-
this.preAggregation.loadSql
|
|
394
|
-
);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
priority(defaultValue) {
|
|
398
|
-
return this.preAggregation.priority != null ? this.preAggregation.priority : defaultValue;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
getInvalidationKeyValues() {
|
|
402
|
-
return Promise.all(
|
|
403
|
-
(this.preAggregation.invalidateKeyQueries || [])
|
|
404
|
-
.map(
|
|
405
|
-
(keyQuery, i) => this.loadCache.keyQueryResult(
|
|
406
|
-
keyQuery,
|
|
407
|
-
this.waitForRenew,
|
|
408
|
-
this.priority(10),
|
|
409
|
-
(this.preAggregation.refreshKeyRenewalThresholds || [])[i]
|
|
410
|
-
)
|
|
411
|
-
)
|
|
412
|
-
);
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
scheduleRefresh(invalidationKeys, newVersionEntry) {
|
|
416
|
-
this.logger('Refreshing pre-aggregation content', {
|
|
417
|
-
preAggregation: this.preAggregation,
|
|
418
|
-
requestId: this.requestId,
|
|
419
|
-
queryKey: this.preAggregationQueryKey(invalidationKeys),
|
|
420
|
-
newVersionEntry
|
|
421
|
-
});
|
|
422
|
-
this.executeInQueue(invalidationKeys, this.priority(0), newVersionEntry)
|
|
423
|
-
.catch(e => {
|
|
424
|
-
if (!(e instanceof ContinueWaitError)) {
|
|
425
|
-
this.logger('Error refreshing pre-aggregation', {
|
|
426
|
-
error: (e.stack || e), preAggregation: this.preAggregation, requestId: this.requestId
|
|
427
|
-
});
|
|
428
|
-
}
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
executeInQueue(invalidationKeys, priority, newVersionEntry) {
|
|
433
|
-
return this.preAggregations.getQueue().executeInQueue(
|
|
434
|
-
'query',
|
|
435
|
-
this.preAggregationQueryKey(invalidationKeys),
|
|
436
|
-
{
|
|
437
|
-
preAggregation: this.preAggregation,
|
|
438
|
-
preAggregationsTablesToTempTables: this.preAggregationsTablesToTempTables,
|
|
439
|
-
newVersionEntry,
|
|
440
|
-
requestId: this.requestId,
|
|
441
|
-
invalidationKeys
|
|
442
|
-
},
|
|
443
|
-
priority,
|
|
444
|
-
// eslint-disable-next-line no-use-before-define
|
|
445
|
-
{ stageQueryKey: PreAggregations.preAggregationQueryCacheKey(this.preAggregation), requestId: this.requestId }
|
|
446
|
-
);
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
preAggregationQueryKey(invalidationKeys) {
|
|
450
|
-
return [this.preAggregation.loadSql, invalidationKeys];
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
targetTableName(versionEntry) {
|
|
454
|
-
// eslint-disable-next-line no-use-before-define
|
|
455
|
-
return PreAggregations.targetTableName(versionEntry);
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
refresh(newVersionEntry, invalidationKeys) {
|
|
459
|
-
return (client) => {
|
|
460
|
-
let refreshStrategy = this.refreshImplStoreInSourceStrategy;
|
|
461
|
-
if (this.preAggregation.external) {
|
|
462
|
-
const readOnly =
|
|
463
|
-
client.config && client.config.readOnly ||
|
|
464
|
-
client.readOnly && (typeof client.readOnly === 'boolean' ? client.readOnly : client.readOnly());
|
|
465
|
-
refreshStrategy = readOnly ?
|
|
466
|
-
this.refreshImplStreamExternalStrategy : this.refreshImplTempTableExternalStrategy;
|
|
467
|
-
}
|
|
468
|
-
return cancelCombinator(
|
|
469
|
-
saveCancelFn => refreshStrategy.bind(this)(client, newVersionEntry, saveCancelFn, invalidationKeys)
|
|
470
|
-
);
|
|
471
|
-
};
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
logExecutingSql(invalidationKeys, query, params, targetTableName, newVersionEntry) {
|
|
475
|
-
this.logger(
|
|
476
|
-
'Executing Load Pre Aggregation SQL',
|
|
477
|
-
this.queryOptions(invalidationKeys, query, params, targetTableName, newVersionEntry)
|
|
478
|
-
);
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
queryOptions(invalidationKeys, query, params, targetTableName, newVersionEntry) {
|
|
482
|
-
return {
|
|
483
|
-
queryKey: this.preAggregationQueryKey(invalidationKeys),
|
|
484
|
-
query,
|
|
485
|
-
values: params,
|
|
486
|
-
targetTableName,
|
|
487
|
-
requestId: this.requestId,
|
|
488
|
-
newVersionEntry,
|
|
489
|
-
};
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
async refreshImplStoreInSourceStrategy(client, newVersionEntry, saveCancelFn, invalidationKeys) {
|
|
493
|
-
const [loadSql, params] =
|
|
494
|
-
Array.isArray(this.preAggregation.loadSql) ? this.preAggregation.loadSql : [this.preAggregation.loadSql, []];
|
|
495
|
-
const targetTableName = this.targetTableName(newVersionEntry);
|
|
496
|
-
const query = QueryCache.replacePreAggregationTableNames(loadSql, this.preAggregationsTablesToTempTables)
|
|
497
|
-
.replace(
|
|
498
|
-
this.preAggregation.tableName,
|
|
499
|
-
targetTableName
|
|
500
|
-
);
|
|
501
|
-
this.logExecutingSql(invalidationKeys, query, params, targetTableName, newVersionEntry);
|
|
502
|
-
await saveCancelFn(client.loadPreAggregationIntoTable(
|
|
503
|
-
targetTableName,
|
|
504
|
-
query,
|
|
505
|
-
params,
|
|
506
|
-
this.queryOptions(invalidationKeys, query, params, targetTableName, newVersionEntry)
|
|
507
|
-
));
|
|
508
|
-
await this.createIndexes(client, newVersionEntry, saveCancelFn);
|
|
509
|
-
await this.loadCache.reset(this.preAggregation);
|
|
510
|
-
await this.dropOrphanedTables(client, targetTableName, saveCancelFn);
|
|
511
|
-
await this.loadCache.reset(this.preAggregation);
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
async refreshImplTempTableExternalStrategy(client, newVersionEntry, saveCancelFn, invalidationKeys) {
|
|
515
|
-
const [loadSql, params] =
|
|
516
|
-
Array.isArray(this.preAggregation.loadSql) ? this.preAggregation.loadSql : [this.preAggregation.loadSql, []];
|
|
517
|
-
await client.createSchemaIfNotExists(this.preAggregation.preAggregationsSchema);
|
|
518
|
-
const targetTableName = this.targetTableName(newVersionEntry);
|
|
519
|
-
const query = QueryCache.replacePreAggregationTableNames(loadSql, this.preAggregationsTablesToTempTables)
|
|
520
|
-
.replace(
|
|
521
|
-
this.preAggregation.tableName,
|
|
522
|
-
targetTableName
|
|
523
|
-
);
|
|
524
|
-
this.logExecutingSql(invalidationKeys, query, params, targetTableName, newVersionEntry);
|
|
525
|
-
await saveCancelFn(client.loadPreAggregationIntoTable(
|
|
526
|
-
targetTableName,
|
|
527
|
-
query,
|
|
528
|
-
params,
|
|
529
|
-
this.queryOptions(invalidationKeys, query, params, targetTableName, newVersionEntry)
|
|
530
|
-
));
|
|
531
|
-
const tableData = await this.downloadTempExternalPreAggregation(client, newVersionEntry, saveCancelFn);
|
|
532
|
-
await this.uploadExternalPreAggregation(tableData, newVersionEntry, saveCancelFn);
|
|
533
|
-
await this.loadCache.reset(this.preAggregation);
|
|
534
|
-
await this.dropOrphanedTables(client, targetTableName, saveCancelFn);
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
async refreshImplStreamExternalStrategy(client, newVersionEntry, saveCancelFn, invalidationKeys) {
|
|
538
|
-
const [sql, params] =
|
|
539
|
-
Array.isArray(this.preAggregation.sql) ? this.preAggregation.sql : [this.preAggregation.sql, []];
|
|
540
|
-
if (!client.downloadQueryResults) {
|
|
541
|
-
throw new Error('Can\'t load external pre-aggregation: source driver doesn\'t support downloadQueryResults()');
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
this.logExecutingSql(invalidationKeys, sql, params, this.targetTableName(newVersionEntry), newVersionEntry);
|
|
545
|
-
this.logger('Downloading external pre-aggregation via query', {
|
|
546
|
-
preAggregation: this.preAggregation,
|
|
547
|
-
requestId: this.requestId
|
|
548
|
-
});
|
|
549
|
-
const tableData = await saveCancelFn(client.downloadQueryResults(
|
|
550
|
-
sql,
|
|
551
|
-
params,
|
|
552
|
-
this.queryOptions(invalidationKeys, sql, params, this.targetTableName(newVersionEntry), newVersionEntry)
|
|
553
|
-
));
|
|
554
|
-
await this.uploadExternalPreAggregation(tableData, newVersionEntry, saveCancelFn);
|
|
555
|
-
await this.loadCache.reset(this.preAggregation);
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
async downloadTempExternalPreAggregation(client, newVersionEntry, saveCancelFn) {
|
|
559
|
-
if (!client.downloadTable) {
|
|
560
|
-
throw new Error('Can\'t load external pre-aggregation: source driver doesn\'t support downloadTable()');
|
|
561
|
-
}
|
|
562
|
-
const table = this.targetTableName(newVersionEntry);
|
|
563
|
-
this.logger('Downloading external pre-aggregation', {
|
|
564
|
-
preAggregation: this.preAggregation,
|
|
565
|
-
requestId: this.requestId
|
|
566
|
-
});
|
|
567
|
-
const tableData = await saveCancelFn(client.downloadTable(table));
|
|
568
|
-
tableData.types = await saveCancelFn(client.tableColumnTypes(table));
|
|
569
|
-
return tableData;
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
async uploadExternalPreAggregation(tableData, newVersionEntry, saveCancelFn) {
|
|
573
|
-
const table = this.targetTableName(newVersionEntry);
|
|
574
|
-
const externalDriver = await this.externalDriverFactory();
|
|
575
|
-
if (!externalDriver.uploadTable) {
|
|
576
|
-
throw new Error('Can\'t load external pre-aggregation: destination driver doesn\'t support uploadTable()');
|
|
577
|
-
}
|
|
578
|
-
this.logger('Uploading external pre-aggregation', {
|
|
579
|
-
preAggregation: this.preAggregation,
|
|
580
|
-
requestId: this.requestId
|
|
581
|
-
});
|
|
582
|
-
await saveCancelFn(externalDriver.uploadTable(table, tableData.types, tableData));
|
|
583
|
-
await this.createIndexes(externalDriver, newVersionEntry, saveCancelFn);
|
|
584
|
-
await this.loadCache.reset(this.preAggregation);
|
|
585
|
-
await this.dropOrphanedTables(externalDriver, table, saveCancelFn);
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
async createIndexes(driver, newVersionEntry, saveCancelFn) {
|
|
589
|
-
if (!this.preAggregation.indexesSql || !this.preAggregation.indexesSql.length) {
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
|
-
for (let i = 0; i < this.preAggregation.indexesSql.length; i++) {
|
|
593
|
-
const { sql, indexName } = this.preAggregation.indexesSql[i];
|
|
594
|
-
const [query, params] = sql;
|
|
595
|
-
const indexVersionEntry = {
|
|
596
|
-
...newVersionEntry,
|
|
597
|
-
table_name: indexName
|
|
598
|
-
};
|
|
599
|
-
this.logger('Creating pre-aggregation index', {
|
|
600
|
-
preAggregation: this.preAggregation,
|
|
601
|
-
requestId: this.requestId,
|
|
602
|
-
sql
|
|
603
|
-
});
|
|
604
|
-
await saveCancelFn(driver.query(
|
|
605
|
-
QueryCache.replacePreAggregationTableNames(
|
|
606
|
-
query,
|
|
607
|
-
this.preAggregationsTablesToTempTables.concat([
|
|
608
|
-
[this.preAggregation.tableName, { targetTableName: this.targetTableName(newVersionEntry) }],
|
|
609
|
-
[indexName, { targetTableName: this.targetTableName(indexVersionEntry) }]
|
|
610
|
-
])
|
|
611
|
-
),
|
|
612
|
-
params
|
|
613
|
-
));
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
async dropOrphanedTables(client, justCreatedTable, saveCancelFn) {
|
|
618
|
-
await this.preAggregations.addTableUsed(justCreatedTable);
|
|
619
|
-
const actualTables = await client.getTablesQuery(this.preAggregation.preAggregationsSchema);
|
|
620
|
-
const versionEntries = tablesToVersionEntries(this.preAggregation.preAggregationsSchema, actualTables);
|
|
621
|
-
const versionEntriesToSave = R.pipe(
|
|
622
|
-
R.groupBy(v => v.table_name),
|
|
623
|
-
R.toPairs,
|
|
624
|
-
R.map(p => p[1][0])
|
|
625
|
-
)(versionEntries);
|
|
626
|
-
|
|
627
|
-
const structureVersionsToSave = R.pipe(
|
|
628
|
-
R.filter(v => new Date().getTime() - v.last_updated_at < this.structureVersionPersistTime * 1000),
|
|
629
|
-
R.groupBy(v => `${v.table_name}_${v.structure_version}`),
|
|
630
|
-
R.toPairs,
|
|
631
|
-
R.map(p => p[1][0])
|
|
632
|
-
)(versionEntries);
|
|
633
|
-
|
|
634
|
-
const tablesToSave =
|
|
635
|
-
(await this.preAggregations.tablesUsed())
|
|
636
|
-
.concat(structureVersionsToSave.map(v => this.targetTableName(v)))
|
|
637
|
-
.concat(versionEntriesToSave.map(v => this.targetTableName(v)))
|
|
638
|
-
.concat([justCreatedTable]);
|
|
639
|
-
const toDrop = actualTables
|
|
640
|
-
.map(t => `${this.preAggregation.preAggregationsSchema}.${t.table_name || t.TABLE_NAME}`)
|
|
641
|
-
.filter(t => tablesToSave.indexOf(t) === -1);
|
|
642
|
-
this.logger('Dropping orphaned tables', {
|
|
643
|
-
tablesToDrop: JSON.stringify(toDrop),
|
|
644
|
-
requestId: this.requestId
|
|
645
|
-
});
|
|
646
|
-
await Promise.all(toDrop.map(table => saveCancelFn(client.dropTable(table))));
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
class PreAggregations {
|
|
651
|
-
constructor(redisPrefix, clientFactory, logger, queryCache, options) {
|
|
652
|
-
this.options = options || {};
|
|
653
|
-
this.redisPrefix = redisPrefix;
|
|
654
|
-
this.driverFactory = clientFactory;
|
|
655
|
-
this.logger = logger;
|
|
656
|
-
this.queryCache = queryCache;
|
|
657
|
-
this.cacheDriver = options.cacheAndQueueDriver === 'redis' ?
|
|
658
|
-
new RedisCacheDriver({ pool: options.redisPool }) :
|
|
659
|
-
new LocalCacheDriver();
|
|
660
|
-
this.externalDriverFactory = options.externalDriverFactory;
|
|
661
|
-
this.structureVersionPersistTime = options.structureVersionPersistTime || 60 * 60 * 24 * 30;
|
|
662
|
-
this.usedTablePersistTime = options.usedTablePersistTime || 600;
|
|
663
|
-
this.externalRefresh = options.externalRefresh;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
tablesUsedRedisKey(tableName) {
|
|
667
|
-
return `SQL_PRE_AGGREGATIONS_${this.redisPrefix}_TABLES_USED_${tableName}`;
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
async addTableUsed(tableName) {
|
|
671
|
-
return this.cacheDriver.set(this.tablesUsedRedisKey(tableName), true, this.usedTablePersistTime);
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
async tablesUsed() {
|
|
675
|
-
return (await this.cacheDriver.keysStartingWith(this.tablesUsedRedisKey('')))
|
|
676
|
-
.map(k => k.replace(this.tablesUsedRedisKey(''), ''));
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
loadAllPreAggregationsIfNeeded(queryBody) {
|
|
680
|
-
const preAggregations = queryBody.preAggregations || [];
|
|
681
|
-
const loadCache = new PreAggregationLoadCache(this.redisPrefix, this.driverFactory, this.queryCache, this, {
|
|
682
|
-
requestId: queryBody.requestId
|
|
683
|
-
});
|
|
684
|
-
return preAggregations.map(p => (preAggregationsTablesToTempTables) => {
|
|
685
|
-
const loader = new PreAggregationLoader(
|
|
686
|
-
this.redisPrefix,
|
|
687
|
-
this.driverFactory,
|
|
688
|
-
this.logger,
|
|
689
|
-
this.queryCache,
|
|
690
|
-
this,
|
|
691
|
-
p,
|
|
692
|
-
preAggregationsTablesToTempTables,
|
|
693
|
-
loadCache,
|
|
694
|
-
{ waitForRenew: queryBody.renewQuery, requestId: queryBody.requestId, externalRefresh: this.externalRefresh }
|
|
695
|
-
);
|
|
696
|
-
const preAggregationPromise = () => loader.loadPreAggregation().then(async targetTableName => {
|
|
697
|
-
const usedPreAggregation = typeof targetTableName === 'string' ? { targetTableName } : targetTableName;
|
|
698
|
-
await this.addTableUsed(usedPreAggregation.targetTableName);
|
|
699
|
-
return [p.tableName, usedPreAggregation];
|
|
700
|
-
});
|
|
701
|
-
return preAggregationPromise().then(res => preAggregationsTablesToTempTables.concat([res]));
|
|
702
|
-
}).reduce((promise, fn) => promise.then(fn), Promise.resolve([]));
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
getQueue() {
|
|
706
|
-
if (!this.queue) {
|
|
707
|
-
this.queue = QueryCache.createQueue(`SQL_PRE_AGGREGATIONS_${this.redisPrefix}`, this.driverFactory, (client, q) => {
|
|
708
|
-
const {
|
|
709
|
-
preAggregation, preAggregationsTablesToTempTables, newVersionEntry, requestId, invalidationKeys
|
|
710
|
-
} = q;
|
|
711
|
-
const loader = new PreAggregationLoader(
|
|
712
|
-
this.redisPrefix,
|
|
713
|
-
this.driverFactory,
|
|
714
|
-
this.logger,
|
|
715
|
-
this.queryCache,
|
|
716
|
-
this,
|
|
717
|
-
preAggregation,
|
|
718
|
-
preAggregationsTablesToTempTables,
|
|
719
|
-
new PreAggregationLoadCache(this.redisPrefix, this.driverFactory, this.queryCache, this, { requestId }),
|
|
720
|
-
{ requestId, externalRefresh: this.externalRefresh }
|
|
721
|
-
);
|
|
722
|
-
return loader.refresh(newVersionEntry, invalidationKeys)(client);
|
|
723
|
-
}, {
|
|
724
|
-
concurrency: 1,
|
|
725
|
-
logger: this.logger,
|
|
726
|
-
cacheAndQueueDriver: this.options.cacheAndQueueDriver,
|
|
727
|
-
redisPool: this.options.redisPool,
|
|
728
|
-
...this.options.queueOptions
|
|
729
|
-
});
|
|
730
|
-
}
|
|
731
|
-
return this.queue;
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
getLoadCacheQueue() {
|
|
735
|
-
if (!this.loadCacheQueue) {
|
|
736
|
-
this.loadCacheQueue = QueryCache.createQueue(`SQL_PRE_AGGREGATIONS_CACHE_${this.redisPrefix}`, () => {}, (_, q) => {
|
|
737
|
-
const {
|
|
738
|
-
preAggregation,
|
|
739
|
-
requestId
|
|
740
|
-
} = q;
|
|
741
|
-
const loadCache = new PreAggregationLoadCache(this.redisPrefix, this.driverFactory, this.queryCache, this,
|
|
742
|
-
{ requestId });
|
|
743
|
-
return loadCache.fetchTables(preAggregation);
|
|
744
|
-
}, {
|
|
745
|
-
concurrency: 4,
|
|
746
|
-
logger: this.logger,
|
|
747
|
-
cacheAndQueueDriver: this.options.cacheAndQueueDriver,
|
|
748
|
-
redisPool: this.options.redisPool,
|
|
749
|
-
...this.options.loadCacheQueueOptions
|
|
750
|
-
});
|
|
751
|
-
}
|
|
752
|
-
return this.loadCacheQueue;
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
static preAggregationQueryCacheKey(preAggregation) {
|
|
756
|
-
return preAggregation.tableName;
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
static targetTableName(versionEntry) {
|
|
760
|
-
if (versionEntry.naming_version === 2) {
|
|
761
|
-
return `${versionEntry.table_name}_${versionEntry.content_version}_${versionEntry.structure_version}_${encodeTimeStamp(versionEntry.last_updated_at)}`;
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
return `${versionEntry.table_name}_${versionEntry.content_version}_${versionEntry.structure_version}_${versionEntry.last_updated_at}`;
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
|
|
768
8
|
module.exports = PreAggregations;
|