Take collection rows in one order too
The tag paths are sorted now, but two writers of model_projects still iterated in caller order: findOrCreateProject over the models it attaches, and setProjects over a model's collections. Two of either running at once could take the same rows in opposite orders — the same shape as the tag deadlock, one table across. Preventative: unlike the tag case, no failure from these was ever observed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
d2dd67c311
commit
9ce95a6521
1 changed files with 4 additions and 2 deletions
|
|
@ -450,7 +450,9 @@ async function acceptCollectionSuggestion(name, modelIds = null) {
|
|||
ORDER BY name = lower(name), name LIMIT 1), $1)
|
||||
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) {
|
||||
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
|
||||
async function setProjects(client, modelId, projectIds) {
|
||||
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(
|
||||
'INSERT INTO model_projects (model_id, project_id) VALUES ($1,$2) ON CONFLICT DO NOTHING',
|
||||
[modelId, pid]);
|
||||
|
|
|
|||
Loading…
Reference in a new issue