Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14036257
D14819.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
13 KB
Referenced Files
None
Subscribers
None
D14819.diff
View Options
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
@@ -883,6 +883,7 @@
'DrydockLeasePHIDType' => 'applications/drydock/phid/DrydockLeasePHIDType.php',
'DrydockLeaseQuery' => 'applications/drydock/query/DrydockLeaseQuery.php',
'DrydockLeaseQueuedLogType' => 'applications/drydock/logtype/DrydockLeaseQueuedLogType.php',
+ 'DrydockLeaseReclaimLogType' => 'applications/drydock/logtype/DrydockLeaseReclaimLogType.php',
'DrydockLeaseReleaseController' => 'applications/drydock/controller/DrydockLeaseReleaseController.php',
'DrydockLeaseReleasedLogType' => 'applications/drydock/logtype/DrydockLeaseReleasedLogType.php',
'DrydockLeaseSearchEngine' => 'applications/drydock/query/DrydockLeaseSearchEngine.php',
@@ -900,6 +901,7 @@
'DrydockLogType' => 'applications/drydock/logtype/DrydockLogType.php',
'DrydockManagementCommandWorkflow' => 'applications/drydock/management/DrydockManagementCommandWorkflow.php',
'DrydockManagementLeaseWorkflow' => 'applications/drydock/management/DrydockManagementLeaseWorkflow.php',
+ 'DrydockManagementReclaimWorkflow' => 'applications/drydock/management/DrydockManagementReclaimWorkflow.php',
'DrydockManagementReleaseLeaseWorkflow' => 'applications/drydock/management/DrydockManagementReleaseLeaseWorkflow.php',
'DrydockManagementReleaseResourceWorkflow' => 'applications/drydock/management/DrydockManagementReleaseResourceWorkflow.php',
'DrydockManagementUpdateLeaseWorkflow' => 'applications/drydock/management/DrydockManagementUpdateLeaseWorkflow.php',
@@ -926,6 +928,7 @@
'DrydockResourceListView' => 'applications/drydock/view/DrydockResourceListView.php',
'DrydockResourcePHIDType' => 'applications/drydock/phid/DrydockResourcePHIDType.php',
'DrydockResourceQuery' => 'applications/drydock/query/DrydockResourceQuery.php',
+ 'DrydockResourceReclaimLogType' => 'applications/drydock/logtype/DrydockResourceReclaimLogType.php',
'DrydockResourceReleaseController' => 'applications/drydock/controller/DrydockResourceReleaseController.php',
'DrydockResourceSearchEngine' => 'applications/drydock/query/DrydockResourceSearchEngine.php',
'DrydockResourceStatus' => 'applications/drydock/constants/DrydockResourceStatus.php',
@@ -4819,6 +4822,7 @@
'DrydockLeasePHIDType' => 'PhabricatorPHIDType',
'DrydockLeaseQuery' => 'DrydockQuery',
'DrydockLeaseQueuedLogType' => 'DrydockLogType',
+ 'DrydockLeaseReclaimLogType' => 'DrydockLogType',
'DrydockLeaseReleaseController' => 'DrydockLeaseController',
'DrydockLeaseReleasedLogType' => 'DrydockLogType',
'DrydockLeaseSearchEngine' => 'PhabricatorApplicationSearchEngine',
@@ -4839,6 +4843,7 @@
'DrydockLogType' => 'Phobject',
'DrydockManagementCommandWorkflow' => 'DrydockManagementWorkflow',
'DrydockManagementLeaseWorkflow' => 'DrydockManagementWorkflow',
+ 'DrydockManagementReclaimWorkflow' => 'DrydockManagementWorkflow',
'DrydockManagementReleaseLeaseWorkflow' => 'DrydockManagementWorkflow',
'DrydockManagementReleaseResourceWorkflow' => 'DrydockManagementWorkflow',
'DrydockManagementUpdateLeaseWorkflow' => 'DrydockManagementWorkflow',
@@ -4871,6 +4876,7 @@
'DrydockResourceListView' => 'AphrontView',
'DrydockResourcePHIDType' => 'PhabricatorPHIDType',
'DrydockResourceQuery' => 'DrydockQuery',
+ 'DrydockResourceReclaimLogType' => 'DrydockLogType',
'DrydockResourceReleaseController' => 'DrydockResourceController',
'DrydockResourceSearchEngine' => 'PhabricatorApplicationSearchEngine',
'DrydockResourceStatus' => 'DrydockConstants',
diff --git a/src/applications/drydock/logtype/DrydockLeaseReclaimLogType.php b/src/applications/drydock/logtype/DrydockLeaseReclaimLogType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/drydock/logtype/DrydockLeaseReclaimLogType.php
@@ -0,0 +1,25 @@
+<?php
+
+final class DrydockLeaseReclaimLogType extends DrydockLogType {
+
+ const LOGCONST = 'core.lease.reclaim';
+
+ public function getLogTypeName() {
+ return pht('Reclaimed Resources');
+ }
+
+ public function getLogTypeIcon(array $data) {
+ return 'fa-refresh yellow';
+ }
+
+ public function renderLog(array $data) {
+ $viewer = $this->getViewer();
+
+ $resource_phids = idx($data, 'resourcePHIDs', array());
+
+ return pht(
+ 'Reclaimed resource %s.',
+ $viewer->renderHandleList($resource_phids)->render());
+ }
+
+}
diff --git a/src/applications/drydock/logtype/DrydockResourceReclaimLogType.php b/src/applications/drydock/logtype/DrydockResourceReclaimLogType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/drydock/logtype/DrydockResourceReclaimLogType.php
@@ -0,0 +1,24 @@
+<?php
+
+final class DrydockResourceReclaimLogType extends DrydockLogType {
+
+ const LOGCONST = 'core.resource.reclaim';
+
+ public function getLogTypeName() {
+ return pht('Reclaimed');
+ }
+
+ public function getLogTypeIcon(array $data) {
+ return 'fa-refresh red';
+ }
+
+ public function renderLog(array $data) {
+ $viewer = $this->getViewer();
+ $reclaimer_phid = idx($data, 'reclaimerPHID');
+
+ return pht(
+ 'Resource reclaimed by %s.',
+ $viewer->renderHandle($reclaimer_phid)->render());
+ }
+
+}
diff --git a/src/applications/drydock/management/DrydockManagementReclaimWorkflow.php b/src/applications/drydock/management/DrydockManagementReclaimWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/drydock/management/DrydockManagementReclaimWorkflow.php
@@ -0,0 +1,63 @@
+<?php
+
+final class DrydockManagementReclaimWorkflow
+ extends DrydockManagementWorkflow {
+
+ protected function didConstruct() {
+ $this
+ ->setName('reclaim')
+ ->setSynopsis(pht('Reclaim unused resources.'))
+ ->setArguments(array());
+ }
+
+ public function execute(PhutilArgumentParser $args) {
+ $viewer = $this->getViewer();
+ $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID();
+
+ PhabricatorWorker::setRunAllTasksInProcess(true);
+
+ $resources = id(new DrydockResourceQuery())
+ ->setViewer($viewer)
+ ->withStatuses(
+ array(
+ DrydockResourceStatus::STATUS_ACTIVE,
+ ))
+ ->execute();
+ foreach ($resources as $resource) {
+ $command = DrydockCommand::initializeNewCommand($viewer)
+ ->setTargetPHID($resource->getPHID())
+ ->setAuthorPHID($drydock_phid)
+ ->setCommand(DrydockCommand::COMMAND_RECLAIM)
+ ->save();
+
+ $resource->scheduleUpdate();
+
+ $resource = $resource->reload();
+
+ $name = pht(
+ 'Resource %d: %s',
+ $resource->getID(),
+ $resource->getResourceName());
+
+ switch ($resource->getStatus()) {
+ case DrydockResourceStatus::STATUS_RELEASED:
+ case DrydockResourceStatus::STATUS_DESTROYED:
+ echo tsprintf(
+ "%s\n",
+ pht(
+ 'Resource "%s" was reclaimed.',
+ $name));
+ break;
+ default:
+ echo tsprintf(
+ "%s\n",
+ pht(
+ 'Resource "%s" could not be reclaimed.',
+ $name));
+ break;
+ }
+ }
+
+ }
+
+}
diff --git a/src/applications/drydock/storage/DrydockCommand.php b/src/applications/drydock/storage/DrydockCommand.php
--- a/src/applications/drydock/storage/DrydockCommand.php
+++ b/src/applications/drydock/storage/DrydockCommand.php
@@ -5,6 +5,7 @@
implements PhabricatorPolicyInterface {
const COMMAND_RELEASE = 'release';
+ const COMMAND_RECLAIM = 'reclaim';
protected $authorPHID;
protected $targetPHID;
diff --git a/src/applications/drydock/worker/DrydockLeaseUpdateWorker.php b/src/applications/drydock/worker/DrydockLeaseUpdateWorker.php
--- a/src/applications/drydock/worker/DrydockLeaseUpdateWorker.php
+++ b/src/applications/drydock/worker/DrydockLeaseUpdateWorker.php
@@ -179,6 +179,23 @@
// satisfy the lease, just not right now. This is a temporary failure,
// and we expect allocation to succeed eventually.
if (!$usable_blueprints) {
+ $blueprints = $this->rankBlueprints($blueprints, $lease);
+
+ // Try to actively reclaim unused resources. If we succeed, jump back
+ // into the queue in an effort to claim it.
+ foreach ($blueprints as $blueprint) {
+ $reclaimed = $this->reclaimResources($blueprint, $lease);
+ if ($reclaimed) {
+ $lease->logEvent(
+ DrydockLeaseReclaimLogType::LOGCONST,
+ array(
+ 'resourcePHIDs' => array($reclaimed->getPHID()),
+ ));
+
+ throw new PhabricatorWorkerYieldException(15);
+ }
+ }
+
$lease->logEvent(
DrydockLeaseWaitingForResourcesLogType::LOGCONST,
array(
@@ -439,6 +456,7 @@
assert_instances_of($blueprints, 'DrydockBlueprint');
$keep = array();
+
foreach ($blueprints as $key => $blueprint) {
if (!$blueprint->canAllocateResourceForLease($lease)) {
continue;
@@ -573,6 +591,35 @@
}
}
+ private function reclaimResources(
+ DrydockBlueprint $blueprint,
+ DrydockLease $lease) {
+ $viewer = $this->getViewer();
+
+ $resources = id(new DrydockResourceQuery())
+ ->setViewer($viewer)
+ ->withBlueprintPHIDs(array($blueprint->getPHID()))
+ ->withStatuses(
+ array(
+ DrydockResourceStatus::STATUS_ACTIVE,
+ ))
+ ->execute();
+
+ // TODO: We could be much smarter about this and try to release long-unused
+ // resources, resources with many similar copies, old resources, resources
+ // that are cheap to rebuild, etc.
+ shuffle($resources);
+
+ foreach ($resources as $resource) {
+ if ($this->canReclaimResource($resource)) {
+ $this->reclaimResource($resource, $lease);
+ return $resource;
+ }
+ }
+
+ return null;
+ }
+
/* -( Acquiring Leases )--------------------------------------------------- */
diff --git a/src/applications/drydock/worker/DrydockResourceUpdateWorker.php b/src/applications/drydock/worker/DrydockResourceUpdateWorker.php
--- a/src/applications/drydock/worker/DrydockResourceUpdateWorker.php
+++ b/src/applications/drydock/worker/DrydockResourceUpdateWorker.php
@@ -143,7 +143,11 @@
switch ($command->getCommand()) {
case DrydockCommand::COMMAND_RELEASE:
- $this->releaseResource($resource);
+ $this->releaseResource($resource, null);
+ break;
+ case DrydockCommand::COMMAND_RECLAIM:
+ $reclaimer_phid = $command->getAuthorPHID();
+ $this->releaseResource($resource, $reclaimer_phid);
break;
}
}
@@ -188,7 +192,22 @@
/**
* @task release
*/
- private function releaseResource(DrydockResource $resource) {
+ private function releaseResource(
+ DrydockResource $resource,
+ $reclaimer_phid) {
+
+ if ($reclaimer_phid) {
+ if (!$this->canReclaimResource($resource)) {
+ return;
+ }
+
+ $resource->logEvent(
+ DrydockResourceReclaimLogType::LOGCONST,
+ array(
+ 'reclaimerPHID' => $reclaimer_phid,
+ ));
+ }
+
$viewer = $this->getViewer();
$drydock_phid = id(new PhabricatorDrydockApplication())->getPHID();
diff --git a/src/applications/drydock/worker/DrydockWorker.php b/src/applications/drydock/worker/DrydockWorker.php
--- a/src/applications/drydock/worker/DrydockWorker.php
+++ b/src/applications/drydock/worker/DrydockWorker.php
@@ -195,5 +195,61 @@
return $this;
}
+ protected function canReclaimResource(DrydockResource $resource) {
+ $viewer = $this->getViewer();
+
+ // Don't reclaim a resource if it has been updated recently. If two
+ // leases are fighting, we don't want them to keep reclaming resources
+ // from one another forever without making progress, so make resources
+ // immune to reclamation for a little while after they activate or update.
+
+ // TODO: It would be nice to use a more narrow time here, like "last
+ // activation or lease release", but we don't currently store that
+ // anywhere.
+
+ $updated = $resource->getDateModified();
+ $now = PhabricatorTime::getNow();
+ $ago = ($now - $updated);
+ if ($ago < phutil_units('3 minutes in seconds')) {
+ return false;
+ }
+
+ $statuses = array(
+ DrydockLeaseStatus::STATUS_PENDING,
+ DrydockLeaseStatus::STATUS_ACQUIRED,
+ DrydockLeaseStatus::STATUS_ACTIVE,
+ DrydockLeaseStatus::STATUS_RELEASED,
+ DrydockLeaseStatus::STATUS_BROKEN,
+ );
+
+ // Don't reclaim resources that have any active leases.
+ $leases = id(new DrydockLeaseQuery())
+ ->setViewer($viewer)
+ ->withResourcePHIDs(array($resource->getPHID()))
+ ->withStatuses($statuses)
+ ->setLimit(1)
+ ->execute();
+ if ($leases) {
+ return false;
+ }
+
+ return true;
+ }
+
+ protected function reclaimResource(
+ DrydockResource $resource,
+ DrydockLease $lease) {
+ $viewer = $this->getViewer();
+
+ $command = DrydockCommand::initializeNewCommand($viewer)
+ ->setTargetPHID($resource->getPHID())
+ ->setAuthorPHID($lease->getPHID())
+ ->setCommand(DrydockCommand::COMMAND_RECLAIM)
+ ->save();
+
+ $resource->scheduleUpdate();
+
+ return $this;
+ }
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Nov 11, 9:23 AM (3 d, 3 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6740016
Default Alt Text
D14819.diff (13 KB)
Attached To
Mode
D14819: Make Drydock reclaim unused resources when it reaches a resource limit
Attached
Detach File
Event Timeline
Log In to Comment