@@ -423,16 +423,26 @@ updateProjectBranchRoot :: ProjectBranch -> Text -> (Branch IO -> Cli (Branch IO
423423updateProjectBranchRoot projectBranch reason f = do
424424 env <- ask
425425 Cli. time " updateProjectBranchRoot" do
426- old <- getProjectBranchRoot projectBranch
427- (new, result) <- f old
428- when (old /= new) do
426+ beforeUpdates <- getProjectBranchRoot projectBranch
427+ (new, result) <- f beforeUpdates
428+ when (beforeUpdates /= new) do
429429 liftIO $ Codebase. putBranch env. codebase new
430- Cli. runTransaction do
431- -- TODO: If we transactionally check that the project branch hasn't changed while we were computing the new
432- -- branch, and if it has, abort the transaction and return an error, then we can
433- -- remove the single UCM per codebase restriction.
434- causalHashId <- Q. expectCausalHashIdByCausalHash (Branch. headHash new)
435- Q. setProjectBranchHead reason projectBranch. projectId projectBranch. branchId causalHashId
430+ Cli. runTransactionWithRollback \ rollback -> do
431+ causalHashId <- Q. expectProjectBranchHead projectBranch. projectId projectBranch. branchId
432+ currentHeadHash <- Q. expectCausalHash causalHashId
433+ -- Inside the transaction we ensure that the branch from before the updates matches the current head of the
434+ -- project branch, like a check-and-set operation.
435+ -- If it doesn't, then some other process has updated the branch between when we read it and computed the
436+ -- updates. We should abort and ask the user to try again.
437+ if
438+ | (currentHeadHash == Branch. headHash new) -> do
439+ -- Someone else updated the branch, but they set it to what we wanted to anyways.
440+ pure ()
441+ | (currentHeadHash /= Branch. headHash beforeUpdates) -> do
442+ rollback Output. BranchUpdate'BranchChanged
443+ | otherwise -> do
444+ causalHashId <- Q. expectCausalHashIdByCausalHash (Branch. headHash new)
445+ Q. setProjectBranchHead reason projectBranch. projectId projectBranch. branchId causalHashId
436446 -- The input to this function isn't necessarily the *current* project branch, which is what LSP cares about. But
437447 -- it might be! There's no harm in unconditionally notifying the LSP that the current project branch may have
438448 -- changed, but it is slightly more efficient for us to just do the == comparison here (since otherwise the LSP
0 commit comments