/hudson-core/src/main/java/hudson/model/ResourceController.java

http://github.com/hudson/hudson · Java · 136 lines · 54 code · 13 blank · 69 comment · 2 complexity · abd9125c68698632e4a3bdf92dd86e27 MD5 · raw file

  1. /*
  2. * The MIT License
  3. *
  4. * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. package hudson.model;
  25. import hudson.util.AdaptedIterator;
  26. import java.util.Set;
  27. import java.util.HashSet;
  28. import java.util.Collection;
  29. import java.util.AbstractCollection;
  30. import java.util.Iterator;
  31. /**
  32. * Controls mutual exclusion of {@link ResourceList}.
  33. * @author Kohsuke Kawaguchi
  34. */
  35. public class ResourceController {
  36. /**
  37. * {@link ResourceList}s that are used by activities that are in progress.
  38. */
  39. private final Set<ResourceActivity> inProgress = new HashSet<ResourceActivity>();
  40. /**
  41. * View of {@link #inProgress} that exposes its {@link ResourceList}.
  42. */
  43. private final Collection<ResourceList> resourceView = new AbstractCollection<ResourceList>() {
  44. public Iterator<ResourceList> iterator() {
  45. return new AdaptedIterator<ResourceActivity,ResourceList>(inProgress.iterator()) {
  46. protected ResourceList adapt(ResourceActivity item) {
  47. return item.getResourceList();
  48. }
  49. };
  50. }
  51. public int size() {
  52. return inProgress.size();
  53. }
  54. };
  55. /**
  56. * Union of all {@link Resource}s that are currently in use.
  57. * Updated as a task starts/completes executing.
  58. */
  59. private ResourceList inUse = ResourceList.EMPTY;
  60. /**
  61. * Performs the task that requires the given list of resources.
  62. *
  63. * <p>
  64. * The execution is blocked until the resource is available.
  65. *
  66. * @throws InterruptedException
  67. * the thread can be interrupted while waiting for the available resources.
  68. */
  69. public void execute( Runnable task, ResourceActivity activity ) throws InterruptedException {
  70. ResourceList resources = activity.getResourceList();
  71. synchronized(this) {
  72. while(inUse.isCollidingWith(resources))
  73. wait();
  74. // we have a go
  75. inProgress.add(activity);
  76. inUse = ResourceList.union(inUse,resources);
  77. }
  78. try {
  79. task.run();
  80. } finally {
  81. synchronized(this) {
  82. inProgress.remove(activity);
  83. inUse = ResourceList.union(resourceView);
  84. notifyAll();
  85. }
  86. }
  87. }
  88. /**
  89. * Checks if an activity that requires the given resource list
  90. * can run immediately.
  91. *
  92. * <p>
  93. * This method is really only useful as a hint, since
  94. * another activity might acquire resources before the caller
  95. * gets to call {@link #execute(Runnable, ResourceActivity)}.
  96. */
  97. public synchronized boolean canRun(ResourceList resources) {
  98. return !inUse.isCollidingWith(resources);
  99. }
  100. /**
  101. * Of the resource in the given resource list, return the one that's
  102. * currently in use.
  103. *
  104. * <p>
  105. * If more than one such resource exists, one is chosen and returned.
  106. * This method is used for reporting what's causing the blockage.
  107. */
  108. public synchronized Resource getMissingResource(ResourceList resources) {
  109. return resources.getConflict(inUse);
  110. }
  111. /**
  112. * Of the activities that are in progress, return one that's blocking
  113. * the given activity, or null if it's not blocked (and thus the
  114. * given activity can be executed immediately.)
  115. */
  116. public synchronized ResourceActivity getBlockingActivity(ResourceActivity activity) {
  117. ResourceList res = activity.getResourceList();
  118. for (ResourceActivity a : inProgress)
  119. if(res.isCollidingWith(a.getResourceList()))
  120. return a;
  121. return null;
  122. }
  123. }