@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.

Record lock timing information on PushEvents

Summary:
Depends on D19249. Ref T13109. Add timing information to the `PushEvent`:

- `writeWait`: Time spent waiting for a write lock.
- `readWait`: Time spent waiting for a read lock.
- `hostWait`: Roughly, total time spent on the leaf node.

The primary goal here is to see if `readWait` is meaningful in the wild. If it is, that motivates smarter routing, and the value of smarter routing can be demonstrated by looking for a reduction in read wait times.

Test Plan: Pushed some stuff, saw reasonable timing values in the table. Saw timing information in "Export Data".

Maniphest Tasks: T13109

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

+111 -17
+8
resources/sql/autopatches/20180322.lock.02.wait.sql
··· 1 + ALTER TABLE {$NAMESPACE}_repository.repository_pushevent 2 + ADD writeWait BIGINT UNSIGNED; 3 + 4 + ALTER TABLE {$NAMESPACE}_repository.repository_pushevent 5 + ADD readWait BIGINT UNSIGNED; 6 + 7 + ALTER TABLE {$NAMESPACE}_repository.repository_pushevent 8 + ADD hostWait BIGINT UNSIGNED;
+14
src/applications/diffusion/protocol/DiffusionRepositoryClusterEngine.php
··· 315 315 316 316 $lock_wait = phutil_units('2 minutes in seconds'); 317 317 try { 318 + $write_wait_start = microtime(true); 319 + 318 320 $start = PhabricatorTime::getNow(); 319 321 $step_wait = 1; 320 322 321 323 while (true) { 322 324 try { 323 325 $write_lock->lock((int)floor($step_wait)); 326 + $write_wait_end = microtime(true); 324 327 break; 325 328 } catch (PhutilLockException $ex) { 326 329 $waited = (PhabricatorTime::getNow() - $start); ··· 370 373 'documentation for instructions.')); 371 374 } 372 375 376 + $read_wait_start = microtime(true); 373 377 try { 374 378 $max_version = $this->synchronizeWorkingCopyBeforeRead(); 375 379 } catch (Exception $ex) { 376 380 $write_lock->unlock(); 377 381 throw $ex; 378 382 } 383 + $read_wait_end = microtime(true); 379 384 380 385 $pid = getmypid(); 381 386 $hash = Filesystem::readRandomCharacters(12); ··· 394 399 395 400 $this->clusterWriteVersion = $max_version; 396 401 $this->clusterWriteLock = $write_lock; 402 + 403 + $write_wait = ($write_wait_end - $write_wait_start); 404 + $read_wait = ($read_wait_end - $read_wait_start); 405 + 406 + $log = $this->logger; 407 + if ($log) { 408 + $log->writeClusterEngineLogProperty('readWait', $read_wait); 409 + $log->writeClusterEngineLogProperty('writeWait', $write_wait); 410 + } 397 411 } 398 412 399 413
+1
src/applications/diffusion/protocol/DiffusionRepositoryClusterEngineLogInterface.php
··· 3 3 interface DiffusionRepositoryClusterEngineLogInterface { 4 4 5 5 public function writeClusterEngineLogMessage($message); 6 + public function writeClusterEngineLogProperty($key, $value); 6 7 7 8 }
+43
src/applications/diffusion/ssh/DiffusionGitReceivePackSSHWorkflow.php
··· 14 14 } 15 15 16 16 protected function executeRepositoryOperations() { 17 + $host_wait_start = microtime(true); 18 + 17 19 $repository = $this->getRepository(); 18 20 $viewer = $this->getSSHUser(); 19 21 $device = AlmanacKeys::getLiveDevice(); ··· 71 73 PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE, 72 74 PhabricatorRepositoryStatusMessage::CODE_OKAY); 73 75 $this->waitForGitClient(); 76 + 77 + $host_wait_end = microtime(true); 78 + 79 + $this->updatePushLogWithTimingInformation( 80 + $this->getClusterEngineLogProperty('writeWait'), 81 + $this->getClusterEngineLogProperty('readWait'), 82 + ($host_wait_end - $host_wait_start)); 83 + 74 84 } 75 85 76 86 return $err; ··· 87 97 ->setIOChannel($this->getIOChannel()) 88 98 ->setCommandChannelFromExecFuture($future) 89 99 ->execute(); 100 + } 101 + 102 + private function updatePushLogWithTimingInformation( 103 + $write_wait, 104 + $read_wait, 105 + $host_wait) { 106 + 107 + if ($write_wait !== null) { 108 + $write_wait = (int)(1000000 * $write_wait); 109 + } 110 + 111 + if ($read_wait !== null) { 112 + $read_wait = (int)(1000000 * $read_wait); 113 + } 114 + 115 + if ($host_wait !== null) { 116 + $host_wait = (int)(1000000 * $host_wait); 117 + } 118 + 119 + $identifier = $this->getRequestIdentifier(); 120 + 121 + $event = new PhabricatorRepositoryPushEvent(); 122 + $conn = $event->establishConnection('w'); 123 + 124 + queryfx( 125 + $conn, 126 + 'UPDATE %T SET writeWait = %nd, readWait = %nd, hostWait = %nd 127 + WHERE requestIdentifier = %s', 128 + $event->getTableName(), 129 + $write_wait, 130 + $read_wait, 131 + $host_wait, 132 + $identifier); 90 133 } 91 134 92 135 }
+10
src/applications/diffusion/ssh/DiffusionGitSSHWorkflow.php
··· 4 4 extends DiffusionSSHWorkflow 5 5 implements DiffusionRepositoryClusterEngineLogInterface { 6 6 7 + private $engineLogProperties = array(); 8 + 7 9 protected function writeError($message) { 8 10 // Git assumes we'll add our own newlines. 9 11 return parent::writeError($message."\n"); ··· 12 14 public function writeClusterEngineLogMessage($message) { 13 15 parent::writeError($message); 14 16 $this->getErrorChannel()->update(); 17 + } 18 + 19 + public function writeClusterEngineLogProperty($key, $value) { 20 + $this->engineLogProperties[$key] = $value; 21 + } 22 + 23 + protected function getClusterEngineLogProperty($key, $default = null) { 24 + return idx($this->engineLogProperties, $key, $default); 15 25 } 16 26 17 27 protected function identifyRepository() {
+29 -17
src/applications/repository/query/PhabricatorRepositoryPushLogSearchEngine.php
··· 98 98 $viewer = $this->requireViewer(); 99 99 100 100 $fields = array( 101 - $fields[] = id(new PhabricatorIDExportField()) 101 + id(new PhabricatorIDExportField()) 102 102 ->setKey('pushID') 103 103 ->setLabel(pht('Push ID')), 104 - $fields[] = id(new PhabricatorStringExportField()) 104 + id(new PhabricatorStringExportField()) 105 105 ->setKey('unique') 106 106 ->setLabel(pht('Unique')), 107 - $fields[] = id(new PhabricatorStringExportField()) 107 + id(new PhabricatorStringExportField()) 108 108 ->setKey('protocol') 109 109 ->setLabel(pht('Protocol')), 110 - $fields[] = id(new PhabricatorPHIDExportField()) 110 + id(new PhabricatorPHIDExportField()) 111 111 ->setKey('repositoryPHID') 112 112 ->setLabel(pht('Repository PHID')), 113 - $fields[] = id(new PhabricatorStringExportField()) 113 + id(new PhabricatorStringExportField()) 114 114 ->setKey('repository') 115 115 ->setLabel(pht('Repository')), 116 - $fields[] = id(new PhabricatorPHIDExportField()) 116 + id(new PhabricatorPHIDExportField()) 117 117 ->setKey('pusherPHID') 118 118 ->setLabel(pht('Pusher PHID')), 119 - $fields[] = id(new PhabricatorStringExportField()) 119 + id(new PhabricatorStringExportField()) 120 120 ->setKey('pusher') 121 121 ->setLabel(pht('Pusher')), 122 - $fields[] = id(new PhabricatorPHIDExportField()) 122 + id(new PhabricatorPHIDExportField()) 123 123 ->setKey('devicePHID') 124 124 ->setLabel(pht('Device PHID')), 125 - $fields[] = id(new PhabricatorStringExportField()) 125 + id(new PhabricatorStringExportField()) 126 126 ->setKey('device') 127 127 ->setLabel(pht('Device')), 128 - $fields[] = id(new PhabricatorStringExportField()) 128 + id(new PhabricatorStringExportField()) 129 129 ->setKey('type') 130 130 ->setLabel(pht('Ref Type')), 131 - $fields[] = id(new PhabricatorStringExportField()) 131 + id(new PhabricatorStringExportField()) 132 132 ->setKey('name') 133 133 ->setLabel(pht('Ref Name')), 134 - $fields[] = id(new PhabricatorStringExportField()) 134 + id(new PhabricatorStringExportField()) 135 135 ->setKey('old') 136 136 ->setLabel(pht('Ref Old')), 137 - $fields[] = id(new PhabricatorStringExportField()) 137 + id(new PhabricatorStringExportField()) 138 138 ->setKey('new') 139 139 ->setLabel(pht('Ref New')), 140 - $fields[] = id(new PhabricatorIntExportField()) 140 + id(new PhabricatorIntExportField()) 141 141 ->setKey('flags') 142 142 ->setLabel(pht('Flags')), 143 - $fields[] = id(new PhabricatorStringListExportField()) 143 + id(new PhabricatorStringListExportField()) 144 144 ->setKey('flagNames') 145 145 ->setLabel(pht('Flag Names')), 146 - $fields[] = id(new PhabricatorIntExportField()) 146 + id(new PhabricatorIntExportField()) 147 147 ->setKey('result') 148 148 ->setLabel(pht('Result')), 149 - $fields[] = id(new PhabricatorStringExportField()) 149 + id(new PhabricatorStringExportField()) 150 150 ->setKey('resultName') 151 151 ->setLabel(pht('Result Name')), 152 + id(new PhabricatorIntExportField()) 153 + ->setKey('writeWait') 154 + ->setLabel(pht('Write Wait (us)')), 155 + id(new PhabricatorIntExportField()) 156 + ->setKey('readWait') 157 + ->setLabel(pht('Read Wait (us)')), 158 + id(new PhabricatorIntExportField()) 159 + ->setKey('hostWait') 160 + ->setLabel(pht('Host Wait (us)')), 152 161 ); 153 162 154 163 if ($viewer->getIsAdmin()) { ··· 228 237 'flagNames' => $flag_names, 229 238 'result' => $result, 230 239 'resultName' => $result_name, 240 + 'writeWait' => $event->getWriteWait(), 241 + 'readWait' => $event->getReadWait(), 242 + 'hostWait' => $event->getHostWait(), 231 243 ); 232 244 233 245 if ($viewer->getIsAdmin()) {
+6
src/applications/repository/storage/PhabricatorRepositoryPushEvent.php
··· 16 16 protected $remoteProtocol; 17 17 protected $rejectCode; 18 18 protected $rejectDetails; 19 + protected $writeWait; 20 + protected $readWait; 21 + protected $hostWait; 19 22 20 23 private $repository = self::ATTACHABLE; 21 24 private $logs = self::ATTACHABLE; ··· 35 38 'remoteProtocol' => 'text32?', 36 39 'rejectCode' => 'uint32', 37 40 'rejectDetails' => 'text64?', 41 + 'writeWait' => 'uint64?', 42 + 'readWait' => 'uint64?', 43 + 'hostWait' => 'uint64?', 38 44 ), 39 45 self::CONFIG_KEY_SCHEMA => array( 40 46 'key_repository' => array(