From 12a5eb406233bee7873a4ae6d608ec898c78fde4 Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 1 Jun 2021 06:34:45 -0700 Subject: [PATCH] Allow maintenance scripts to write synthetic events to the push log that act as repository updates Summary: Ref T13614. When a script holds the write lock but modifies the repository directly (rather than by pushing), the repository version won't change when the script releases the write lock. Thus, the writes may not propagate to other nodes (it depends which node lucks out and accepts the next write). To guarantee that writes propagate, allow these scripts to pretend they pushed the repository. These are bare-bones valid events flagged as "Maintenance". Test Plan: - Wrote a script to hold the write lock, wait (or pretend to do something), then release the write lock. - Applied patches, modified script to use new APIs ("newMaintenanceEvent()"). - Ran script, saw repository verison bump and relevant push logs: {F8814923} Maniphest Tasks: T13614 Differential Revision: https://secure.phabricator.com/D21670 --- .../engine/DiffusionCommitHookEngine.php | 8 +--- .../DiffusionRepositoryClusterEngine.php | 37 +++++++++++++++++++ .../PhabricatorRepositoryPushEvent.php | 15 ++++++++ .../storage/PhabricatorRepositoryPushLog.php | 3 ++ 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/applications/diffusion/engine/DiffusionCommitHookEngine.php b/src/applications/diffusion/engine/DiffusionCommitHookEngine.php index 0f6b05b578..c172f27466 100644 --- a/src/applications/diffusion/engine/DiffusionCommitHookEngine.php +++ b/src/applications/diffusion/engine/DiffusionCommitHookEngine.php @@ -216,13 +216,7 @@ final class DiffusionCommitHookEngine extends Phobject { $event->setRejectCode($this->rejectCode); $event->setRejectDetails($this->rejectDetails); - $event->openTransaction(); - $event->save(); - foreach ($all_updates as $update) { - $update->setPushEventPHID($event->getPHID()); - $update->save(); - } - $event->saveTransaction(); + $event->saveWithLogs($all_updates); if ($caught) { throw $caught; diff --git a/src/applications/diffusion/protocol/DiffusionRepositoryClusterEngine.php b/src/applications/diffusion/protocol/DiffusionRepositoryClusterEngine.php index a364828397..0372e44f4b 100644 --- a/src/applications/diffusion/protocol/DiffusionRepositoryClusterEngine.php +++ b/src/applications/diffusion/protocol/DiffusionRepositoryClusterEngine.php @@ -901,4 +901,41 @@ final class DiffusionRepositoryClusterEngine extends Phobject { new PhutilNumber($duration))); } + public function newMaintenanceEvent() { + $viewer = $this->getViewer(); + $repository = $this->getRepository(); + $now = PhabricatorTime::getNow(); + + $event = PhabricatorRepositoryPushEvent::initializeNewEvent($viewer) + ->setRepositoryPHID($repository->getPHID()) + ->setEpoch($now) + ->setPusherPHID($this->getEffectiveActingAsPHID()) + ->setRejectCode(PhabricatorRepositoryPushLog::REJECT_ACCEPT); + + return $event; + } + + public function newMaintenanceLog() { + $viewer = $this->getViewer(); + $repository = $this->getRepository(); + $now = PhabricatorTime::getNow(); + + $device = AlmanacKeys::getLiveDevice(); + if ($device) { + $device_phid = $device->getPHID(); + } else { + $device_phid = null; + } + + return PhabricatorRepositoryPushLog::initializeNewLog($viewer) + ->setDevicePHID($device_phid) + ->setRepositoryPHID($repository->getPHID()) + ->attachRepository($repository) + ->setEpoch($now) + ->setPusherPHID($this->getEffectiveActingAsPHID()) + ->setChangeFlags(PhabricatorRepositoryPushLog::CHANGEFLAG_MAINTENANCE) + ->setRefType(PhabricatorRepositoryPushLog::REFTYPE_MAINTENANCE) + ->setRefNew(''); + } + } diff --git a/src/applications/repository/storage/PhabricatorRepositoryPushEvent.php b/src/applications/repository/storage/PhabricatorRepositoryPushEvent.php index ac97aa2bcf..c0936e9c6e 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryPushEvent.php +++ b/src/applications/repository/storage/PhabricatorRepositoryPushEvent.php @@ -81,6 +81,21 @@ final class PhabricatorRepositoryPushEvent return $this->assertAttached($this->logs); } + public function saveWithLogs(array $logs) { + assert_instances_of($logs, 'PhabricatorRepositoryPushLog'); + + $this->openTransaction(); + $this->save(); + foreach ($logs as $log) { + $log->setPushEventPHID($this->getPHID()); + $log->save(); + } + $this->saveTransaction(); + + $this->attachLogs($logs); + + return $this; + } /* -( PhabricatorPolicyInterface )----------------------------------------- */ diff --git a/src/applications/repository/storage/PhabricatorRepositoryPushLog.php b/src/applications/repository/storage/PhabricatorRepositoryPushLog.php index 095c227994..d9892b2dff 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryPushLog.php +++ b/src/applications/repository/storage/PhabricatorRepositoryPushLog.php @@ -18,6 +18,7 @@ final class PhabricatorRepositoryPushLog const REFTYPE_BOOKMARK = 'bookmark'; const REFTYPE_COMMIT = 'commit'; const REFTYPE_REF = 'ref'; + const REFTYPE_MAINTENANCE = 'maintenance'; const CHANGEFLAG_ADD = 1; const CHANGEFLAG_DELETE = 2; @@ -27,6 +28,7 @@ final class PhabricatorRepositoryPushLog const CHANGEFLAG_ENORMOUS = 32; const CHANGEFLAG_OVERSIZED = 64; const CHANGEFLAG_TOUCHES = 128; + const CHANGEFLAG_MAINTENANCE = 256; const REJECT_ACCEPT = 0; const REJECT_DANGEROUS = 1; @@ -70,6 +72,7 @@ final class PhabricatorRepositoryPushLog self::CHANGEFLAG_ENORMOUS => pht('Enormous'), self::CHANGEFLAG_OVERSIZED => pht('Oversized'), self::CHANGEFLAG_TOUCHES => pht('Touches Too Many Paths'), + self::CHANGEFLAG_MAINTENANCE => pht('Maintenance'), ); }