@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Provide an ad-hoc maintenance lock for clustered repositories

Summary: Ref T13614. Provide "bin/repository lock" to temporarily lock repositories for manual maintenance.

Test Plan:
- Read instructions.
- Used `bin/repository lock` according to the instructions.
- Saw Storage tab in Diffusion report lock held during maintenance, released after it completes.
- Saw "maintenance" push log generated and repository version bump.
- Tried to lock some invalid repositories.

Maniphest Tasks: T13614

Differential Revision: https://secure.phabricator.com/D21671

+222
+2
src/__phutil_library_map__.php
··· 4613 4613 'PhabricatorRepositoryManagementImportingWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementImportingWorkflow.php', 4614 4614 'PhabricatorRepositoryManagementListPathsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListPathsWorkflow.php', 4615 4615 'PhabricatorRepositoryManagementListWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListWorkflow.php', 4616 + 'PhabricatorRepositoryManagementLockWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementLockWorkflow.php', 4616 4617 'PhabricatorRepositoryManagementMaintenanceWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMaintenanceWorkflow.php', 4617 4618 'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMarkImportedWorkflow.php', 4618 4619 'PhabricatorRepositoryManagementMarkReachableWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMarkReachableWorkflow.php', ··· 11382 11383 'PhabricatorRepositoryManagementImportingWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 11383 11384 'PhabricatorRepositoryManagementListPathsWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 11384 11385 'PhabricatorRepositoryManagementListWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 11386 + 'PhabricatorRepositoryManagementLockWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 11385 11387 'PhabricatorRepositoryManagementMaintenanceWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 11386 11388 'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 11387 11389 'PhabricatorRepositoryManagementMarkReachableWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
+139
src/applications/repository/management/PhabricatorRepositoryManagementLockWorkflow.php
··· 1 + <?php 2 + 3 + final class PhabricatorRepositoryManagementLockWorkflow 4 + extends PhabricatorRepositoryManagementWorkflow { 5 + 6 + protected function didConstruct() { 7 + $this 8 + ->setName('lock') 9 + ->setExamples('**lock** [options] __repository__ ...') 10 + ->setSynopsis( 11 + pht( 12 + 'Temporarily lock clustered repositories to perform maintenance.')) 13 + ->setArguments( 14 + array( 15 + array( 16 + 'name' => 'repositories', 17 + 'wildcard' => true, 18 + ), 19 + )); 20 + } 21 + 22 + public function execute(PhutilArgumentParser $args) { 23 + $viewer = $this->getViewer(); 24 + 25 + $repositories = $this->loadRepositories($args, 'repositories'); 26 + if (!$repositories) { 27 + throw new PhutilArgumentUsageException( 28 + pht('Specify one or more repositories to lock.')); 29 + } 30 + 31 + foreach ($repositories as $repository) { 32 + $display_name = $repository->getDisplayName(); 33 + 34 + if (!$repository->isHosted()) { 35 + throw new PhutilArgumentUsageException( 36 + pht( 37 + 'Unable to lock repository "%s": only hosted repositories may be '. 38 + 'locked.', 39 + $display_name)); 40 + } 41 + 42 + if (!$repository->supportsSynchronization()) { 43 + throw new PhutilArgumentUsageException( 44 + pht( 45 + 'Unable to lock repository "%s": only repositories that support '. 46 + 'clustering may be locked.', 47 + $display_name)); 48 + } 49 + 50 + if (!$repository->getAlmanacServicePHID()) { 51 + throw new PhutilArgumentUsageException( 52 + pht( 53 + 'Unable to lock repository "%s": only clustered repositories '. 54 + 'may be locked.', 55 + $display_name)); 56 + } 57 + } 58 + 59 + $diffusion_phid = id(new PhabricatorDiffusionApplication()) 60 + ->getPHID(); 61 + 62 + $locks = array(); 63 + foreach ($repositories as $repository) { 64 + $engine = id(new DiffusionRepositoryClusterEngine()) 65 + ->setViewer($viewer) 66 + ->setActingAsPHID($diffusion_phid) 67 + ->setRepository($repository); 68 + 69 + $event = $engine->newMaintenanceEvent(); 70 + 71 + $logs = array(); 72 + $logs[] = $engine->newMaintenanceLog(); 73 + 74 + $locks[] = array( 75 + 'repository' => $repository, 76 + 'engine' => $engine, 77 + 'event' => $event, 78 + 'logs' => $logs, 79 + ); 80 + } 81 + 82 + $display_list = new PhutilConsoleList(); 83 + foreach ($repositories as $repository) { 84 + $display_list->addItem( 85 + pht( 86 + '%s %s', 87 + $repository->getMonogram(), 88 + $repository->getName())); 89 + } 90 + 91 + echo tsprintf( 92 + "%s\n\n%B\n", 93 + pht('These repositories will be locked:'), 94 + $display_list->drawConsoleString()); 95 + 96 + echo tsprintf( 97 + "%s\n", 98 + pht( 99 + 'While the lock is held: users will be unable to write to this '. 100 + 'repository, and you may safely perform working copy maintenance '. 101 + 'on this node in another terminal window.')); 102 + 103 + $query = pht('Lock repositories and begin maintenance?'); 104 + if (!phutil_console_confirm($query)) { 105 + throw new ArcanistUserAbortException(); 106 + } 107 + 108 + foreach ($locks as $key => $lock) { 109 + $engine = $lock['engine']; 110 + $engine->synchronizeWorkingCopyBeforeWrite(); 111 + } 112 + 113 + echo tsprintf( 114 + "%s\n", 115 + pht( 116 + 'Repositories are now locked. You may begin maintenance in '. 117 + 'another terminal window. Keep this process running until '. 118 + 'you complete the maintenance, then confirm that you are ready to '. 119 + 'release the locks.')); 120 + 121 + while (!phutil_console_confirm('Ready to release the locks?')) { 122 + // Wait for the user to confirm that they're ready. 123 + } 124 + 125 + foreach ($locks as $key => $lock) { 126 + $lock['event']->saveWithLogs($lock['logs']); 127 + 128 + $engine = $lock['engine']; 129 + $engine->synchronizeWorkingCopyAfterWrite(); 130 + } 131 + 132 + echo tsprintf( 133 + "%s\n", 134 + pht('Done.')); 135 + 136 + return 0; 137 + } 138 + 139 + }
+81
src/docs/user/cluster/cluster_repositories.diviner
··· 523 523 data more easily in a wider range of disaster situations. 524 524 525 525 526 + Ad-Hoc Maintenance Locks 527 + ======================== 528 + 529 + Occasionally, you may want to perform maintenance to a clustered repository 530 + which requires you modify the actual content of the repository. 531 + 532 + For example: you might want to delete a large number of old or temporary 533 + branches; or you might want to merge a very large number of commits from 534 + another source. 535 + 536 + These operations may be prohibitively slow or complex to perform using normal 537 + pushes. In cases where you would prefer to directly modify a working copy, you 538 + can use a maintenance lock to safely make a working copy mutable. 539 + 540 + If you simply perform this kind of content-modifying maintenance by directly 541 + modifying the repository on disk with commands like `git update-ref`, your 542 + changes may either encounter conflicts or encounter problems with change 543 + propagation. 544 + 545 + You can encounter conflicts because directly modifying the working copy on disk 546 + won't prevent users or Phabricator itself from performing writes to the same 547 + working copy at the same time. Phabricator does not compromise the lower-level 548 + locks provided by the VCS so this is theoretically safe -- and this rarely 549 + causes any significant problems in practice -- but doesn't make things any 550 + simpler or easier. 551 + 552 + Your changes may fail to propagate because writing directly to the repository 553 + doesn't turn it into the new cluster leader after your writes complete. If 554 + another node accepts the next push, it will become the new leader -- without 555 + your changes -- and all other nodes will synchronize from it. 556 + 557 + Note that some maintenance operations (like `git gc`, `git prune`, or 558 + `git repack`) do not modify repository content. In theory, these operations do 559 + not require a maintenance lock: lower-level Git locks should protect 560 + them from conflicts, and they can not be affected by propagation issues because 561 + they do not propagate. In practice, these operations are not conflict-free in 562 + all circumstances. Using a maintenance lock may be overkill, but it's probably 563 + still a good idea. 564 + 565 + To use a maintenance lock: 566 + 567 + - Open two terminal windows. You'll use one window to hold the lock and a 568 + second window to perform maintenance. 569 + - Run `bin/repository lock <repository> ...` in one terminal. 570 + - When the process reports that repositories are locked, switch to the second 571 + terminal and perform maintenance. The `repository lock` process should 572 + still be running in your first terminal. 573 + - After maintenance completes, switch back to the first terminal and answer 574 + the prompt to confirm maintenance is complete. 575 + 576 + The workflow looks something like this: 577 + 578 + ``` 579 + $ ./bin/repository lock R2 580 + 581 + These repositories will be locked: 582 + 583 + - R2 Git Test Repository 584 + 585 + While the lock is held: users will be unable to write to this repository, 586 + and you may safely perform working copy maintenance on this node in another 587 + terminal window. 588 + 589 + Lock repositories and begin maintenance? [y/N] y 590 + 591 + Repositories are now locked. You may begin maintenance in another terminal 592 + window. Keep this process running until you complete the maintenance, then 593 + confirm that you are ready to release the locks. 594 + 595 + Ready to release the locks? [y/N] y 596 + 597 + Done. 598 + ``` 599 + 600 + As maintenance completes, the push log for the repository will be updated to 601 + reflect that you performed maintenance. 602 + 603 + If the lock is interrupted, you may encounter a "Write Interruptions" condition 604 + described earlier in this document. See that section for details. In most 605 + cases, you can resolve this issue by demoting the node you are working on. 606 + 526 607 Next Steps 527 608 ========== 528 609