mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-12 03:56:15 -08:00
test(performance): count startup phases and SQL statements for the J1 launch journey
Implements plan item A2. With IPTVNATOR_PERF_CAPTURE=1 the main process
keeps named counters and registers a main-only performance:read-counters
IPC handler; without the flag nothing is counted and the handler does not
exist.
- debug-trace.ts owns the registry; traceStartupPhase replaces the
trace('startup', ...) sites and counts main.startupPhases.
- The database worker counts executed statements through better-sqlite3's
Statement prototype (the verbose callback expands every statement and
made bulk inserts 2-4x slower) and posts the count over its message
port, flushed before every other worker message. The main-thread shared
connection is counted through a new connection observer in the shared
database library.
- The first main window freezes main.modulesRegisteredBeforeWindow at
creation and main.sqlStatementsBeforeReadyToShow at ready-to-show.
- The journey gate drops the ready-to-show that Electron emits for the
about:blank detour, so the app sees the real document's first paint,
and taps the counters handler; the J1 record reads both counters after
the renderer probe completes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9d02f90dfe
commit
37ac72b951
38 files changed
+1817
-73
No files matched your search
@@ -28,6 +28,9 @@ import { content, categories, playlists, type Content } from '@iptvnator/shared/
|
||||
- `closeDatabase()` - Close connection
|
||||
- `getDatabasePath()` - Get database file path
|
||||
|
||||
### Connection observer (`connection-observer.ts`)
|
||||
- `setDatabaseConnectionObserver(observer | null)` - Called by `initDatabase` with each connection it opens, before any statement runs on it. The Electron main process registers one only with `IPTVNATOR_PERF_CAPTURE=1`, to count main-thread SQL statements. The module has no runtime dependencies and is also importable as `@iptvnator/shared/database/connection-observer`.
|
||||
|
||||
## Database Location
|
||||
|
||||
The SQLite database is stored at: `~/.iptvnator/databases/iptvnator.db`
|
||||
|
||||
@@ -7,3 +7,4 @@
|
||||
export * from './lib/schema';
|
||||
export * from './lib/connection';
|
||||
export * from './lib/path-utils';
|
||||
export * from './lib/connection-observer';
|
||||
@@ -0,0 +1,30 @@
|
||||
import type Database from 'better-sqlite3';
|
||||
import {
|
||||
notifyDatabaseConnectionOpened,
|
||||
setDatabaseConnectionObserver,
|
||||
} from './connection-observer';
|
||||
|
||||
describe('database connection observer', () => {
|
||||
afterEach(() => {
|
||||
setDatabaseConnectionObserver(null);
|
||||
});
|
||||
|
||||
it('does nothing when no observer is registered', () => {
|
||||
expect(() =>
|
||||
notifyDatabaseConnectionOpened({} as Database.Database)
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
it('passes each opened connection to the registered observer until removed', () => {
|
||||
const observer = jest.fn();
|
||||
const first = { name: 'first' } as unknown as Database.Database;
|
||||
const second = { name: 'second' } as unknown as Database.Database;
|
||||
|
||||
setDatabaseConnectionObserver(observer);
|
||||
notifyDatabaseConnectionOpened(first);
|
||||
setDatabaseConnectionObserver(null);
|
||||
notifyDatabaseConnectionOpened(second);
|
||||
|
||||
expect(observer.mock.calls).toEqual([[first]]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import type Database from 'better-sqlite3';
|
||||
|
||||
export type DatabaseConnectionObserver = (
|
||||
connection: Database.Database
|
||||
) => void;
|
||||
|
||||
let observer: DatabaseConnectionObserver | null = null;
|
||||
|
||||
/**
|
||||
* Registers a callback that `initDatabase` calls with each connection it
|
||||
* opens, before any statement runs on it; `null` removes it. The Electron
|
||||
* main process uses it with IPTVNATOR_PERF_CAPTURE=1 to count main-thread
|
||||
* SQL statements. This module has no runtime dependencies, so registering
|
||||
* the observer does not load better-sqlite3.
|
||||
*/
|
||||
export function setDatabaseConnectionObserver(
|
||||
next: DatabaseConnectionObserver | null
|
||||
): void {
|
||||
observer = next;
|
||||
}
|
||||
|
||||
export function notifyDatabaseConnectionOpened(
|
||||
connection: Database.Database
|
||||
): void {
|
||||
observer?.(connection);
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
} from '@iptvnator/shared/logging';
|
||||
import * as schema from './schema';
|
||||
import { getIptvnatorDatabasePath } from './path-utils';
|
||||
import { notifyDatabaseConnectionOpened } from './connection-observer';
|
||||
|
||||
export type DatabaseInstance = BetterSQLite3Database<typeof schema>;
|
||||
|
||||
@@ -1228,6 +1229,7 @@ export async function initDatabase(
|
||||
? (message?: unknown) => traceSqlStatement(message)
|
||||
: undefined,
|
||||
});
|
||||
notifyDatabaseConnectionOpened(sqlite);
|
||||
|
||||
if (isSqlTraceEnabled()) {
|
||||
traceSql('sql-main', 'open', {
|
||||
|
||||
Reference in new issue
Block a user