Commit 0976caf
committed
fix(folders): recheck cycle-freedom inside the reorder transaction
Greptile P1: the route's circular-reference check reads an unlocked snapshot
of the folder tree before the transaction opens. Two concurrent reorder
requests can each move one end of what becomes an A<->B cycle -- each
request's own cycle check only sees its own proposed edge merged with a
stale snapshot of the other folder's parentId, so both can pass
independently and, once both commit, leave a genuine cycle in the tree that
the write path never re-validates.
A cycle can only newly appear through an edge this batch is writing, and
every folder whose parentId is being changed is already a `startId` that
the closure-lock query (from an earlier round's deadlock fix) walks and
locks. So the fix reuses that same locked, transaction-consistent data:
after acquiring FOR UPDATE on the closure, build a parentId map from the
locked rows (overridden by this batch's own proposed new parentIds) and
re-run the identical cycle-walk the route already does, but against data
that can no longer change out from under it. A cycle found here now rolls
back the whole transaction with the same 400/'Cannot create circular folder
reference' response the pre-check already returns for the same-request
case.
Added a regression test simulating the race: the route's pre-check snapshot
shows the target parent's parentId as still null, while the locked read
inside the transaction reflects a concurrent request that already committed
the other half of the cycle. Full local verification passed (typecheck,
full vitest suite 11437 tests, check:api-validation, lint all clean).1 parent 8ac1ab6 commit 0976caf
2 files changed
Lines changed: 76 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
426 | 426 | | |
427 | 427 | | |
428 | 428 | | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
429 | 473 | | |
430 | 474 | | |
431 | 475 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
841 | 841 | | |
842 | 842 | | |
843 | 843 | | |
| 844 | + | |
| 845 | + | |
844 | 846 | | |
845 | 847 | | |
846 | 848 | | |
| |||
954 | 956 | | |
955 | 957 | | |
956 | 958 | | |
| 959 | + | |
957 | 960 | | |
958 | 961 | | |
959 | 962 | | |
| |||
982 | 985 | | |
983 | 986 | | |
984 | 987 | | |
| 988 | + | |
| 989 | + | |
| 990 | + | |
| 991 | + | |
| 992 | + | |
| 993 | + | |
| 994 | + | |
| 995 | + | |
| 996 | + | |
| 997 | + | |
| 998 | + | |
| 999 | + | |
| 1000 | + | |
| 1001 | + | |
| 1002 | + | |
| 1003 | + | |
| 1004 | + | |
| 1005 | + | |
| 1006 | + | |
| 1007 | + | |
| 1008 | + | |
| 1009 | + | |
| 1010 | + | |
| 1011 | + | |
| 1012 | + | |
| 1013 | + | |
985 | 1014 | | |
986 | 1015 | | |
987 | 1016 | | |
| |||
1012 | 1041 | | |
1013 | 1042 | | |
1014 | 1043 | | |
| 1044 | + | |
| 1045 | + | |
| 1046 | + | |
1015 | 1047 | | |
1016 | 1048 | | |
1017 | 1049 | | |
| |||
0 commit comments