Merge one lock order for collection rows
All checks were successful
build-and-push / docker (push) Successful in 21s

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
dlawler489 2026-09-16 17:44:05 +10:00
commit 27e1caf1a6

View file

@ -450,7 +450,9 @@ async function acceptCollectionSuggestion(name, modelIds = null) {
ORDER BY name = lower(name), name LIMIT 1), $1) ORDER BY name = lower(name), name LIMIT 1), $1)
RETURNING *`, [name])); RETURNING *`, [name]));
} }
const ids = waiting.map((w) => w.model_id); // Sorted, so two of these at once take the model_projects rows in the same
// order rather than deadlocking on each other.
const ids = waiting.map((w) => w.model_id).sort((a, b) => a - b);
for (const id of ids) { for (const id of ids) {
await client.query('INSERT INTO model_projects (model_id, project_id) VALUES ($1, $2) ON CONFLICT DO NOTHING', [id, project.id]); await client.query('INSERT INTO model_projects (model_id, project_id) VALUES ($1, $2) ON CONFLICT DO NOTHING', [id, project.id]);
} }
@ -485,7 +487,7 @@ async function getAllTags() {
// ---------------------------------------------------------------- projects // ---------------------------------------------------------------- projects
async function setProjects(client, modelId, projectIds) { async function setProjects(client, modelId, projectIds) {
await client.query('DELETE FROM model_projects WHERE model_id = $1', [modelId]); await client.query('DELETE FROM model_projects WHERE model_id = $1', [modelId]);
for (const pid of projectIds) { for (const pid of [...projectIds].sort((a, b) => a - b)) { // one lock order, always
await client.query( await client.query(
'INSERT INTO model_projects (model_id, project_id) VALUES ($1,$2) ON CONFLICT DO NOTHING', 'INSERT INTO model_projects (model_id, project_id) VALUES ($1,$2) ON CONFLICT DO NOTHING',
[modelId, pid]); [modelId, pid]);