mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-21 23:05:46 +00:00
fix(analysis): native library backfill coordinator for advanced strategy (#881)
* feat(analysis): native library backfill coordinator for advanced strategy Move advanced analytics scheduling from the webview loop into a Rust background worker (configure + spawn_blocking batch/enqueue), matching cover backfill. Scan hash+BPM gap tracks instead of the full library; suppress low-priority analysis UI events; limit loudness refresh IPC to the playback window. * fix(analysis): flat backfill configure IPC and restore probe track-perf Use flattened Tauri args like cover backfill so release/prod invoke works; keep emitting analysis:track-perf for library low-priority work so Performance Probe tpm/last-track stats update while waveform/enrichment UI events stay suppressed. * chore(analysis): fix clippy and drop duplicate TS backfill policy Allow too_many_arguments on library_analysis_backfill_configure for CI; remove unused frontend batch API and TS watermark helpers now owned in Rust; clarify analysis_emits_ui_events comment for low-priority track-perf. * docs: CHANGELOG and credits for PR #881 native analysis backfill
This commit is contained in:
@@ -1,48 +0,0 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import {
|
||||
computeLibraryBackfillTargetDepth,
|
||||
libraryBackfillNeedsTopUp,
|
||||
libraryBackfillPipelineBacklog,
|
||||
libraryBackfillTopUpLimit,
|
||||
} from './libraryAnalysisBackfillPolicy';
|
||||
|
||||
describe('libraryAnalysisBackfillPolicy', () => {
|
||||
it('targets workers × 3 with floor and cap', () => {
|
||||
expect(computeLibraryBackfillTargetDepth(1)).toBe(8);
|
||||
expect(computeLibraryBackfillTargetDepth(4)).toBe(12);
|
||||
expect(computeLibraryBackfillTargetDepth(8)).toBe(24);
|
||||
expect(computeLibraryBackfillTargetDepth(100)).toBe(240);
|
||||
});
|
||||
|
||||
const zeroCpu = { cpuQueued: 0, cpuDecodeActive: 0 };
|
||||
|
||||
it('measures backlog as HTTP plus CPU seed pipeline load', () => {
|
||||
expect(
|
||||
libraryBackfillPipelineBacklog({
|
||||
httpQueued: 5,
|
||||
httpDownloadActive: 3,
|
||||
...zeroCpu,
|
||||
}),
|
||||
).toBe(8);
|
||||
expect(
|
||||
libraryBackfillPipelineBacklog({
|
||||
httpQueued: 0,
|
||||
httpDownloadActive: 0,
|
||||
cpuQueued: 4,
|
||||
cpuDecodeActive: 2,
|
||||
}),
|
||||
).toBe(6);
|
||||
});
|
||||
|
||||
it('requests top-up while backlog stays below target', () => {
|
||||
const stats = { httpQueued: 2, httpDownloadActive: 1, ...zeroCpu };
|
||||
expect(libraryBackfillNeedsTopUp(stats, 8)).toBe(true);
|
||||
expect(libraryBackfillTopUpLimit(stats, 8)).toBe(20);
|
||||
});
|
||||
|
||||
it('stops top-up when backlog meets target', () => {
|
||||
const stats = { httpQueued: 20, httpDownloadActive: 4, ...zeroCpu };
|
||||
expect(libraryBackfillNeedsTopUp(stats, 8)).toBe(false);
|
||||
expect(libraryBackfillTopUpLimit(stats, 8)).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -1,41 +0,0 @@
|
||||
import type { AnalysisPipelineQueueStatsDto } from '../../api/analysis';
|
||||
import { LIBRARY_ANALYSIS_BACKFILL_BATCH_SIZE } from '../../api/analysis';
|
||||
|
||||
/** Target backlog ≈ workers × multiplier (min floor, max cap). */
|
||||
export const LIBRARY_BACKLOG_DEPTH_MULTIPLIER = 3;
|
||||
export const LIBRARY_BACKLOG_MIN = 8;
|
||||
export const LIBRARY_BACKLOG_MAX = 240;
|
||||
|
||||
export function computeLibraryBackfillTargetDepth(workers: number): number {
|
||||
const w = Math.max(1, Math.round(workers));
|
||||
return Math.min(
|
||||
LIBRARY_BACKLOG_MAX,
|
||||
Math.max(LIBRARY_BACKLOG_MIN, w * LIBRARY_BACKLOG_DEPTH_MULTIPLIER),
|
||||
);
|
||||
}
|
||||
|
||||
type PipelineBacklogStats = Pick<
|
||||
AnalysisPipelineQueueStatsDto,
|
||||
'httpQueued' | 'httpDownloadActive' | 'cpuQueued' | 'cpuDecodeActive'
|
||||
>;
|
||||
|
||||
/** HTTP + in-flight CPU seed jobs (decode backpressure must not look like an empty pipeline). */
|
||||
export function libraryBackfillPipelineBacklog(stats: PipelineBacklogStats): number {
|
||||
return (
|
||||
stats.httpQueued
|
||||
+ stats.httpDownloadActive
|
||||
+ stats.cpuQueued
|
||||
+ stats.cpuDecodeActive
|
||||
);
|
||||
}
|
||||
|
||||
export function libraryBackfillNeedsTopUp(stats: PipelineBacklogStats, workers: number): boolean {
|
||||
return libraryBackfillPipelineBacklog(stats) < computeLibraryBackfillTargetDepth(workers);
|
||||
}
|
||||
|
||||
export function libraryBackfillTopUpLimit(stats: PipelineBacklogStats, workers: number): number {
|
||||
const target = computeLibraryBackfillTargetDepth(workers);
|
||||
const deficit = target - libraryBackfillPipelineBacklog(stats);
|
||||
if (deficit <= 0) return 0;
|
||||
return Math.min(LIBRARY_ANALYSIS_BACKFILL_BATCH_SIZE, deficit);
|
||||
}
|
||||
Reference in New Issue
Block a user