mirror of
https://github.com/screentinker/screentinker.git
synced 2026-08-16 23:33:10 -06:00
fix(#146) P1.1: resolveIdentity short-circuits on device_id (zero-lookup hot path)
resolveIdentity runs on every register (block + flap gates). It already returned on device_id before any DB access; memoized the device_fingerprints statement (prepared once, lazily) and documented the invariant. Test asserts a device_id-present resolve prepares/runs ZERO device_fingerprints queries; a device_id-absent resolve does. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
317754376c
commit
d4b2532c9a
|
|
@ -19,9 +19,21 @@ const { db } = require('../db/database');
|
||||||
|
|
||||||
const ANON_KEY = 'anon:global';
|
const ANON_KEY = 'anon:global';
|
||||||
|
|
||||||
|
// Memoized statement — prepared once, lazily (safe on a partially-migrated DB).
|
||||||
|
let _fpStmt = null;
|
||||||
|
function fpStmt() {
|
||||||
|
if (!_fpStmt) { try { _fpStmt = db.prepare('SELECT device_id FROM device_fingerprints WHERE fingerprint = ?'); } catch (_) { return null; } }
|
||||||
|
return _fpStmt;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns { key, kind, deviceId } — `key` is stable for keying; `deviceId` is the
|
// Returns { key, kind, deviceId } — `key` is stable for keying; `deviceId` is the
|
||||||
// resolved device id when the chain produced one (device_id directly or via
|
// resolved device id when the chain produced one (device_id directly or via
|
||||||
// fingerprint), else null.
|
// fingerprint), else null.
|
||||||
|
//
|
||||||
|
// #146 P1: SHORT-CIRCUITS on device_id — the common case (a device that sends its
|
||||||
|
// device_id) returns immediately with ZERO DB lookups. The device_fingerprints SELECT
|
||||||
|
// runs ONLY when device_id is absent. Called on every register (block + flap gates), so
|
||||||
|
// the hot path must stay lookup-free.
|
||||||
function resolveIdentity(payload = {}) {
|
function resolveIdentity(payload = {}) {
|
||||||
const { device_id, fingerprint, device_token } = payload;
|
const { device_id, fingerprint, device_token } = payload;
|
||||||
|
|
||||||
|
|
@ -30,7 +42,8 @@ function resolveIdentity(payload = {}) {
|
||||||
if (fingerprint) {
|
if (fingerprint) {
|
||||||
let mapped = null;
|
let mapped = null;
|
||||||
try {
|
try {
|
||||||
const row = db.prepare('SELECT device_id FROM device_fingerprints WHERE fingerprint = ?').get(fingerprint);
|
const st = fpStmt();
|
||||||
|
const row = st && st.get(fingerprint);
|
||||||
mapped = row && row.device_id ? row.device_id : null;
|
mapped = row && row.device_id ? row.device_id : null;
|
||||||
} catch (_) { /* table may not exist on a partially-migrated DB */ }
|
} catch (_) { /* table may not exist on a partially-migrated DB */ }
|
||||||
if (mapped) return { key: 'd:' + mapped, kind: 'fingerprint->device_id', deviceId: mapped };
|
if (mapped) return { key: 'd:' + mapped, kind: 'fingerprint->device_id', deviceId: mapped };
|
||||||
|
|
|
||||||
45
server/test/identity-resolver.test.js
Normal file
45
server/test/identity-resolver.test.js
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// #146 P1.1 — resolveIdentity() runs on EVERY register. It must SHORT-CIRCUIT on
|
||||||
|
// device_id (the common case) and query device_fingerprints ONLY when device_id is
|
||||||
|
// absent — zero extra DB lookups for a device that sends its id.
|
||||||
|
|
||||||
|
const os = require('node:os');
|
||||||
|
const path = require('node:path');
|
||||||
|
const crypto = require('node:crypto');
|
||||||
|
process.env.DATA_DIR = path.join(os.tmpdir(), 'st-ident-' + crypto.randomBytes(4).toString('hex'));
|
||||||
|
|
||||||
|
const { test } = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const { db } = require('../db/database');
|
||||||
|
const { resolveIdentity } = require('../lib/device-identity');
|
||||||
|
|
||||||
|
// Spy on db.prepare to record whether the device_fingerprints query is ever prepared/run.
|
||||||
|
function withPrepareSpy(fn) {
|
||||||
|
const real = db.prepare.bind(db);
|
||||||
|
const prepared = [];
|
||||||
|
db.prepare = (sql) => { prepared.push(sql); return real(sql); };
|
||||||
|
try { fn(); } finally { db.prepare = real; }
|
||||||
|
return prepared;
|
||||||
|
}
|
||||||
|
|
||||||
|
test('a device_id-present resolve does ZERO fingerprint lookups', () => {
|
||||||
|
// warm the memoized statement first so a lazy prepare doesn't confuse the spy
|
||||||
|
resolveIdentity({ fingerprint: 'warm' });
|
||||||
|
const prepared = withPrepareSpy(() => {
|
||||||
|
const r = resolveIdentity({ device_id: 'dev-1', fingerprint: 'fp', device_token: 'tok' });
|
||||||
|
assert.equal(r.kind, 'device_id');
|
||||||
|
assert.equal(r.deviceId, 'dev-1');
|
||||||
|
});
|
||||||
|
assert.equal(prepared.filter((s) => /device_fingerprints/.test(s)).length, 0,
|
||||||
|
'no device_fingerprints query when device_id is present');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('a device_id-absent resolve DOES query device_fingerprints (only then)', () => {
|
||||||
|
db.pragma('foreign_keys = OFF');
|
||||||
|
db.prepare("INSERT OR REPLACE INTO device_fingerprints (fingerprint, device_id) VALUES ('fp-x', 'dev-x')").run();
|
||||||
|
db.pragma('foreign_keys = ON');
|
||||||
|
const r = resolveIdentity({ fingerprint: 'fp-x' });
|
||||||
|
assert.equal(r.kind, 'fingerprint->device_id');
|
||||||
|
assert.equal(r.deviceId, 'dev-x');
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue