mirror of
https://github.com/alexgo-io/stacks-blockchain-api.git
synced 2026-01-12 22:43:34 +08:00
fix: refresh materialized views concurrently (#1270)
* feat: refresh materialized views concurrently * fix: do not refresh concurrently on tests
This commit is contained in:
@@ -1131,7 +1131,8 @@ export class PgDataStore
|
||||
}
|
||||
|
||||
async getChainTip(
|
||||
client: ClientBase
|
||||
client: ClientBase,
|
||||
useMaterializedView = true
|
||||
): Promise<{ blockHeight: number; blockHash: string; indexBlockHash: string }> {
|
||||
const currentTipBlock = await client.query<{
|
||||
block_height: number;
|
||||
@@ -1141,7 +1142,7 @@ export class PgDataStore
|
||||
// The `chain_tip` materialized view is not available during event replay.
|
||||
// Since `getChainTip()` is used heavily during event ingestion, we'll fall back to
|
||||
// a classic query.
|
||||
this.eventReplay
|
||||
this.eventReplay || !useMaterializedView
|
||||
? `
|
||||
SELECT block_height, block_hash, index_block_hash
|
||||
FROM blocks
|
||||
@@ -1181,7 +1182,7 @@ export class PgDataStore
|
||||
// Sanity check: ensure incoming microblocks have a `parent_index_block_hash` that matches the API's
|
||||
// current known canonical chain tip. We assume this holds true so incoming microblock data is always
|
||||
// treated as being built off the current canonical anchor block.
|
||||
const chainTip = await this.getChainTip(client);
|
||||
const chainTip = await this.getChainTip(client, false);
|
||||
const nonCanonicalMicroblock = data.microblocks.find(
|
||||
mb => mb.parent_index_block_hash !== chainTip.indexBlockHash
|
||||
);
|
||||
@@ -1312,7 +1313,7 @@ export class PgDataStore
|
||||
async update(data: DataStoreBlockUpdateData): Promise<void> {
|
||||
const tokenMetadataQueueEntries: DbTokenMetadataQueueEntry[] = [];
|
||||
await this.queryTx(async client => {
|
||||
const chainTip = await this.getChainTip(client);
|
||||
const chainTip = await this.getChainTip(client, false);
|
||||
await this.handleReorg(client, data.block, chainTip.blockHeight);
|
||||
// If the incoming block is not of greater height than current chain tip, then store data as non-canonical.
|
||||
const isCanonical = data.block.block_height > chainTip.blockHeight;
|
||||
@@ -3564,7 +3565,7 @@ export class PgDataStore
|
||||
async updateMempoolTxs({ mempoolTxs: txs }: { mempoolTxs: DbMempoolTx[] }): Promise<void> {
|
||||
const updatedTxs: DbMempoolTx[] = [];
|
||||
await this.queryTx(async client => {
|
||||
const chainTip = await this.getChainTip(client);
|
||||
const chainTip = await this.getChainTip(client, false);
|
||||
for (const tx of txs) {
|
||||
const result = await client.query(
|
||||
`
|
||||
@@ -5434,7 +5435,8 @@ export class PgDataStore
|
||||
if (this.eventReplay && skipDuringEventReplay) {
|
||||
return;
|
||||
}
|
||||
await client.query(`REFRESH MATERIALIZED VIEW ${viewName}`);
|
||||
const concurrently = isProdEnv ? 'CONCURRENTLY' : '';
|
||||
await client.query(`REFRESH MATERIALIZED VIEW ${concurrently} ${viewName}`);
|
||||
}
|
||||
|
||||
async getSmartContractByTrait(args: {
|
||||
|
||||
98
src/migrations/1660595195398_materialized_view_indexes.ts
Normal file
98
src/migrations/1660595195398_materialized_view_indexes.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
import { MigrationBuilder, ColumnDefinitions } from 'node-pg-migrate';
|
||||
|
||||
export const shorthands: ColumnDefinitions | undefined = undefined;
|
||||
|
||||
export async function up(pgm: MigrationBuilder): Promise<void> {
|
||||
// Add LIMIT 1 to chain_tip view so we can add the uniqueness index for `block_height`.
|
||||
pgm.dropMaterializedView('chain_tip');
|
||||
pgm.createMaterializedView('chain_tip', {}, `
|
||||
WITH block_tip AS (
|
||||
SELECT block_height, block_hash, index_block_hash
|
||||
FROM blocks
|
||||
WHERE block_height = (SELECT MAX(block_height) FROM blocks WHERE canonical = TRUE)
|
||||
),
|
||||
microblock_tip AS (
|
||||
SELECT microblock_hash, microblock_sequence
|
||||
FROM microblocks, block_tip
|
||||
WHERE microblocks.parent_index_block_hash = block_tip.index_block_hash
|
||||
AND microblock_canonical = true AND canonical = true
|
||||
ORDER BY microblock_sequence DESC
|
||||
LIMIT 1
|
||||
),
|
||||
microblock_count AS (
|
||||
SELECT COUNT(*)::INTEGER AS microblock_count
|
||||
FROM microblocks
|
||||
WHERE canonical = TRUE AND microblock_canonical = TRUE
|
||||
),
|
||||
tx_count AS (
|
||||
SELECT COUNT(*)::INTEGER AS tx_count
|
||||
FROM txs
|
||||
WHERE canonical = TRUE AND microblock_canonical = TRUE
|
||||
AND block_height <= (SELECT MAX(block_height) FROM blocks WHERE canonical = TRUE)
|
||||
),
|
||||
tx_count_unanchored AS (
|
||||
SELECT COUNT(*)::INTEGER AS tx_count_unanchored
|
||||
FROM txs
|
||||
WHERE canonical = TRUE AND microblock_canonical = TRUE
|
||||
)
|
||||
SELECT *, block_tip.block_height AS block_count
|
||||
FROM block_tip
|
||||
LEFT JOIN microblock_tip ON TRUE
|
||||
LEFT JOIN microblock_count ON TRUE
|
||||
LEFT JOIN tx_count ON TRUE
|
||||
LEFT JOIN tx_count_unanchored ON TRUE
|
||||
LIMIT 1
|
||||
`);
|
||||
|
||||
pgm.addIndex('chain_tip', 'block_height', { unique: true });
|
||||
pgm.addIndex('mempool_digest', 'digest', { unique: true });
|
||||
pgm.addIndex('nft_custody', ['asset_identifier', 'value'], { unique: true });
|
||||
pgm.addIndex('nft_custody_unanchored', ['asset_identifier', 'value'], { unique: true });
|
||||
}
|
||||
|
||||
export async function down(pgm: MigrationBuilder): Promise<void> {
|
||||
pgm.dropIndex('chain_tip', 'block_height', { unique: true, ifExists: true });
|
||||
pgm.dropIndex('mempool_digest', 'digest', { unique: true, ifExists: true });
|
||||
pgm.dropIndex('nft_custody', ['asset_identifier', 'value'], { unique: true, ifExists: true });
|
||||
pgm.dropIndex('nft_custody_unanchored', ['asset_identifier', 'value'], { unique: true, ifExists: true });
|
||||
|
||||
pgm.dropMaterializedView('chain_tip');
|
||||
pgm.createMaterializedView('chain_tip', {}, `
|
||||
WITH block_tip AS (
|
||||
SELECT block_height, block_hash, index_block_hash
|
||||
FROM blocks
|
||||
WHERE block_height = (SELECT MAX(block_height) FROM blocks WHERE canonical = TRUE)
|
||||
),
|
||||
microblock_tip AS (
|
||||
SELECT microblock_hash, microblock_sequence
|
||||
FROM microblocks, block_tip
|
||||
WHERE microblocks.parent_index_block_hash = block_tip.index_block_hash
|
||||
AND microblock_canonical = true AND canonical = true
|
||||
ORDER BY microblock_sequence DESC
|
||||
LIMIT 1
|
||||
),
|
||||
microblock_count AS (
|
||||
SELECT COUNT(*)::INTEGER AS microblock_count
|
||||
FROM microblocks
|
||||
WHERE canonical = TRUE AND microblock_canonical = TRUE
|
||||
),
|
||||
tx_count AS (
|
||||
SELECT COUNT(*)::INTEGER AS tx_count
|
||||
FROM txs
|
||||
WHERE canonical = TRUE AND microblock_canonical = TRUE
|
||||
AND block_height <= (SELECT MAX(block_height) FROM blocks WHERE canonical = TRUE)
|
||||
),
|
||||
tx_count_unanchored AS (
|
||||
SELECT COUNT(*)::INTEGER AS tx_count_unanchored
|
||||
FROM txs
|
||||
WHERE canonical = TRUE AND microblock_canonical = TRUE
|
||||
)
|
||||
SELECT *, block_tip.block_height AS block_count
|
||||
FROM block_tip
|
||||
LEFT JOIN microblock_tip ON TRUE
|
||||
LEFT JOIN microblock_count ON TRUE
|
||||
LEFT JOIN tx_count ON TRUE
|
||||
LEFT JOIN tx_count_unanchored ON TRUE
|
||||
`);
|
||||
}
|
||||
Reference in New Issue
Block a user