const { Client } = require('../../backend/node_modules/pg'); const { performance } = require('perf_hooks'); const { config, ensureDir, explainSql, explainSummary, query02Dir, query02Sql, summarizeRows, writeCsv, writeJson } = require('./query02-lib'); const { getDbConfig } = require('./benchmark-lib'); const levels = String(process.env.BENCHMARK_CONCURRENCY_LEVELS || config.concurrencyLevels.join(',')) .split(',') .map((item) => Number.parseInt(item.trim(), 10)) .filter((item) => Number.isFinite(item) && item > 0); const requestsPerLevel = Number.parseInt( process.env.BENCHMARK_CONCURRENCY_REQUESTS || config.concurrencyRequestsPerLevel, 10 ); const activeConnections = async (client) => { try { const { rows } = await client.query( "SELECT COUNT(*)::int AS active FROM pg_stat_activity WHERE datname = current_database() AND state <> 'idle'" ); return Number(rows[0]?.active || 0); } catch { return null; } }; const runPool = async (items, workers, task) => { let index = 0; const worker = async () => { while (index < items.length) { const current = items[index]; index += 1; await task(current); } }; await Promise.all(Array.from({ length: Math.min(workers, items.length) }, () => worker())); }; const runOne = async (level, repetition) => { const timestamp = new Date().toISOString(); const client = new Client(getDbConfig(level)); const connectStarted = performance.now(); await client.connect(); const connectMs = performance.now() - connectStarted; const started = performance.now(); try { const result = await client.query(explainSql(query02Sql)); const endpointTotal = performance.now() - started + connectMs; const summary = explainSummary(result.rows[0]['QUERY PLAN'][0]); const active = await activeConnections(client); return { phase: 'query02_concurrency', concurrency_level: level, query_id: 'query_02', query_name: 'Catalogo general paginado LIMIT 25', query_group: 'estructurada', repetition, timestamp, connection_acquire_ms: connectMs, endpoint_total_ms: endpointTotal, sql_ms: summary.execution_ms, planning_ms: summary.planning_ms, execution_ms: summary.execution_ms, rows_returned: summary.actual_rows, estimated_rows: summary.estimated_rows, actual_rows: summary.actual_rows, shared_hit_blocks: summary.shared_hit_blocks, shared_read_blocks: summary.shared_read_blocks, temp_read_blocks: summary.temp_read_blocks, temp_written_blocks: summary.temp_written_blocks, active_pg_connections: active, cpu_percent_process: 0, memory_rss_mb: process.memoryUsage().rss / 1024 / 1024, disk_fs_read_ops: 0, disk_fs_write_ops: 0, success: true, error_message: '' }; } catch (error) { return { phase: 'query02_concurrency', concurrency_level: level, query_id: 'query_02', query_name: 'Catalogo general paginado LIMIT 25', query_group: 'estructurada', repetition, timestamp, connection_acquire_ms: connectMs, endpoint_total_ms: performance.now() - started + connectMs, sql_ms: null, planning_ms: null, execution_ms: null, rows_returned: 0, estimated_rows: null, actual_rows: null, shared_hit_blocks: null, shared_read_blocks: null, temp_read_blocks: null, temp_written_blocks: null, active_pg_connections: null, cpu_percent_process: 0, memory_rss_mb: process.memoryUsage().rss / 1024 / 1024, disk_fs_read_ops: 0, disk_fs_write_ops: 0, success: false, error_message: String(error?.message || error) }; } finally { await client.end(); } }; const main = async () => { ensureDir(query02Dir); const raw = []; for (const level of levels) { const work = Array.from({ length: requestsPerLevel }, (_, index) => index + 1); await runPool(work, level, async (repetition) => { const row = await runOne(level, repetition); raw.push(row); process.stdout.write( `query02 concurrency=${level} ${repetition}/${requestsPerLevel} ${row.success ? 'ok' : 'fail'} ${row.endpoint_total_ms.toFixed(2)}ms\n` ); }); } raw.sort((a, b) => a.concurrency_level - b.concurrency_level || a.repetition - b.repetition); const summary = summarizeRows(raw, [ 'phase', 'concurrency_level', 'query_id', 'query_name', 'query_group' ]); writeCsv(`${query02Dir}/concurrency_raw.csv`, raw); writeCsv(`${query02Dir}/concurrency_summary.csv`, summary); writeJson(`${query02Dir}/concurrency.json`, { generatedAt: new Date().toISOString(), levels, requestsPerLevel, summary }); }; main().catch((error) => { console.error(error); process.exit(1); });