diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1842,6 +1842,7 @@ 'PhabricatorConfigOptionType' => 'applications/config/custom/PhabricatorConfigOptionType.php', 'PhabricatorConfigPHIDModule' => 'applications/config/module/PhabricatorConfigPHIDModule.php', 'PhabricatorConfigProxySource' => 'infrastructure/env/PhabricatorConfigProxySource.php', + 'PhabricatorConfigPurgeCacheController' => 'applications/config/controller/PhabricatorConfigPurgeCacheController.php', 'PhabricatorConfigRequestExceptionHandlerModule' => 'applications/config/module/PhabricatorConfigRequestExceptionHandlerModule.php', 'PhabricatorConfigResponse' => 'applications/config/response/PhabricatorConfigResponse.php', 'PhabricatorConfigSchemaQuery' => 'applications/config/schema/PhabricatorConfigSchemaQuery.php', @@ -5748,6 +5749,7 @@ 'PhabricatorConfigOptionType' => 'Phobject', 'PhabricatorConfigPHIDModule' => 'PhabricatorConfigModule', 'PhabricatorConfigProxySource' => 'PhabricatorConfigSource', + 'PhabricatorConfigPurgeCacheController' => 'PhabricatorConfigController', 'PhabricatorConfigRequestExceptionHandlerModule' => 'PhabricatorConfigModule', 'PhabricatorConfigResponse' => 'AphrontStandaloneHTMLResponse', 'PhabricatorConfigSchemaQuery' => 'Phobject', diff --git a/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php b/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php --- a/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php +++ b/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php @@ -6,7 +6,8 @@ protected function didConstruct() { $this ->setName('purge') - ->setSynopsis(pht('Drop data from caches.')) + ->setSynopsis(pht('Drop data from caches. APC-based caches can be '. + 'purged from the web interface.')) ->setArguments( array( array( diff --git a/src/applications/cache/spec/PhabricatorCacheSpec.php b/src/applications/cache/spec/PhabricatorCacheSpec.php --- a/src/applications/cache/spec/PhabricatorCacheSpec.php +++ b/src/applications/cache/spec/PhabricatorCacheSpec.php @@ -5,6 +5,7 @@ private $name; private $isEnabled = false; private $version; + private $clearCacheCallback = null; private $issues = array(); private $usedMemory = 0; @@ -108,4 +109,12 @@ ->addPHPConfig('apc.enabled'); } + public function setClearCacheCallback($callback) { + $this->clearCacheCallback = $callback; + return $this; + } + + public function getClearCacheCallback() { + return $this->clearCacheCallback; + } } diff --git a/src/applications/cache/spec/PhabricatorDataCacheSpec.php b/src/applications/cache/spec/PhabricatorDataCacheSpec.php --- a/src/applications/cache/spec/PhabricatorDataCacheSpec.php +++ b/src/applications/cache/spec/PhabricatorDataCacheSpec.php @@ -34,7 +34,9 @@ ->setVersion(phpversion('apc')); if (ini_get('apc.enabled')) { - $this->setIsEnabled(true); + $this + ->setIsEnabled(true) + ->setClearCacheCallback('apc_clear_cache'); $this->initAPCCommonSpec(); } else { $this->setIsEnabled(false); @@ -48,7 +50,9 @@ ->setVersion(phpversion('apcu')); if (ini_get('apc.enabled')) { - $this->setIsEnabled(true); + $this + ->setIsEnabled(true) + ->setClearCacheCallback('apc_clear_cache'); $this->initAPCCommonSpec(); } else { $this->setIsEnabled(false); @@ -118,5 +122,4 @@ return $key; } - } diff --git a/src/applications/cache/spec/PhabricatorOpcodeCacheSpec.php b/src/applications/cache/spec/PhabricatorOpcodeCacheSpec.php --- a/src/applications/cache/spec/PhabricatorOpcodeCacheSpec.php +++ b/src/applications/cache/spec/PhabricatorOpcodeCacheSpec.php @@ -23,7 +23,9 @@ ->setVersion(phpversion('apc')); if (ini_get('apc.enabled')) { - $this->setIsEnabled(true); + $this + ->setIsEnabled(true) + ->setClearCacheCallback('apc_clear_cache'); $mem = apc_sma_info(); $this->setTotalMemory($mem['num_seg'] * $mem['seg_size']); @@ -109,7 +111,9 @@ ->setVersion(phpversion('Zend OPcache')); if (ini_get('opcache.enable')) { - $this->setIsEnabled(true); + $this + ->setIsEnabled(true) + ->setClearCacheCallback('opcache_reset'); $status = opcache_get_status(); $memory = $status['memory_usage']; @@ -199,5 +203,4 @@ $this->raiseInstallAPCIssue(); } } - } diff --git a/src/applications/config/application/PhabricatorConfigApplication.php b/src/applications/config/application/PhabricatorConfigApplication.php --- a/src/applications/config/application/PhabricatorConfigApplication.php +++ b/src/applications/config/application/PhabricatorConfigApplication.php @@ -55,7 +55,10 @@ '' => 'PhabricatorConfigIssueListController', '(?P[^/]+)/' => 'PhabricatorConfigIssueViewController', ), - 'cache/' => 'PhabricatorConfigCacheController', + 'cache/' => array( + '' => 'PhabricatorConfigCacheController', + 'purge/' => 'PhabricatorConfigPurgeCacheController', + ), 'module/' => array( '(?P[^/]+)/' => 'PhabricatorConfigModuleController', ), diff --git a/src/applications/config/controller/PhabricatorConfigCacheController.php b/src/applications/config/controller/PhabricatorConfigCacheController.php --- a/src/applications/config/controller/PhabricatorConfigCacheController.php +++ b/src/applications/config/controller/PhabricatorConfigCacheController.php @@ -39,8 +39,22 @@ $this->renderCommonProperties($properties, $cache); + $purge_icon = id(new PHUIIconView()) + ->setIconFont('fa-exclamation-triangle'); + + $purge_button = id(new PHUIButtonView()) + ->setText(pht('Purge Caches')) + ->setHref('/config/cache/purge/') + ->setTag('a') + ->setWorkflow(true) + ->setIcon($purge_icon); + + $header = id(new PHUIHeaderView()) + ->setHeader(pht('Opcode Cache')) + ->addActionLink($purge_button); + return id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Opcode Cache')) + ->setHeader($header) ->addPropertyList($properties); } diff --git a/src/applications/config/controller/PhabricatorConfigPurgeCacheController.php b/src/applications/config/controller/PhabricatorConfigPurgeCacheController.php new file mode 100644 --- /dev/null +++ b/src/applications/config/controller/PhabricatorConfigPurgeCacheController.php @@ -0,0 +1,62 @@ +getViewer(); + $cancel_uri = $this->getApplicationURI('cache/'); + + $opcode_cache = PhabricatorOpcodeCacheSpec::getActiveCacheSpec(); + $data_cache = PhabricatorDataCacheSpec::getActiveCacheSpec(); + + $opcode_clearable = $opcode_cache->getClearCacheCallback(); + $data_clearable = $data_cache->getClearCacheCallback(); + + if (!$opcode_clearable && !$data_clearable) { + return $this->newDialog() + ->setTitle(pht('No Caches to Reset')) + ->appendParagraph( + pht('None of the caches on this page can be cleared.')) + ->addCancelButton($cancel_uri); + } + + if ($request->isDialogFormPost()) { + if ($opcode_clearable) { + call_user_func($opcode_cache->getClearCacheCallback()); + } + + if ($data_clearable) { + call_user_func($data_cache->getClearCacheCallback()); + } + + return id(new AphrontRedirectResponse())->setURI($cancel_uri); + } + + $caches = id(new PHUIPropertyListView()) + ->setUser($viewer); + + if ($opcode_clearable) { + $caches->addProperty( + pht('Opcode'), + $opcode_cache->getName()); + } + + if ($data_clearable) { + $caches->addProperty( + pht('Data'), + $data_cache->getName()); + } + + return $this->newDialog() + ->setTitle(pht('Really Clear Cache?')) + ->setShortTitle(pht('Really Clear Cache')) + ->appendParagraph(pht('This will only affect the current web '. + 'frontend. Daemons and any other web frontends may continue '. + 'to use older, cached code from their opcache.')) + ->appendParagraph(pht('The following caches will be cleared:')) + ->appendChild($caches) + ->addSubmitButton(pht('Clear Cache')) + ->addCancelButton($cancel_uri); + } +}