File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\hudson\model\LoadBalancer.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2010, 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
26 import hudson.model.Queue.Task;
27 import hudson.model.queue.MappingWorksheet;
28 import hudson.model.queue.MappingWorksheet.ExecutorChunk;
29 import hudson.model.queue.MappingWorksheet.Mapping;
30 import hudson.util.ConsistentHash;
31 import hudson.util.ConsistentHash.Hash;
32
33 import java.util.ArrayList;
34 import java.util.List;
35
36 /**
37 * Strategy that decides which {@link Task} gets run on which {@link Executor}.
38 *
39 * @author Kohsuke Kawaguchi
40 * @since 1.301
41 */
42 public abstract class LoadBalancer /*implements ExtensionPoint*/ {
43 /**
44 * Chooses the executor(s) to carry out the build for the given task.
45 *
46 * <p>
47 * This method is invoked from different threads, but the execution is serialized by the caller.
48 * The thread that invokes this method always holds a lock to {@link Queue}, so queue contents
49 * can be safely introspected from this method, if that information is necessary to make
50 * decisions.
51 *
52 * @param task
53 * The task whose execution is being considered. Never null.
54 * @param worksheet
55 * The work sheet that represents the matching that needs to be made.
56 * The job of this method is to determine which work units on this worksheet
57 * are executed on which executors (also on this worksheet.)
58 *
59 * @return
60 * Build up the mapping by using the given worksheet and return it.
61 * Return null if you don't want the task to be executed right now,
62 * in which case this method will be called some time later with the same task.
63 */
64 public abstract Mapping map(Task task, MappingWorksheet worksheet);
65
66 /**
67 * Uses a consistent hash for scheduling.
68 */
69 public static final LoadBalancer CONSISTENT_HASH = new LoadBalancer() {
70 @Override
71 public Mapping map(Task task, MappingWorksheet ws) {
72 // build consistent hash for each work chunk
73 List<ConsistentHash<ExecutorChunk>> hashes = new ArrayList<ConsistentHash<ExecutorChunk>>(ws.works.size());
74 for (int i=0; i<ws.works.size(); i++) {
75 ConsistentHash<ExecutorChunk> hash = new ConsistentHash<ExecutorChunk>(new Hash<ExecutorChunk>() {
76 public String hash(ExecutorChunk node) {
77 return node.getName();
78 }
79 });
80 for (ExecutorChunk ec : ws.works(i).applicableExecutorChunks())
81 hash.add(ec,ec.size()*100);
82
83 hashes.add(hash);
84 }
85
86 // do a greedy assignment
87 Mapping m = ws.new Mapping();
88 assert m.size()==ws.works.size(); // just so that you the reader of the source code don't get confused with the for loop index
89
90 if (assignGreedily(m,task,hashes,0)) {
91 assert m.isCompletelyValid();
92 return m;
93 } else
94 return null;
95 }
96
97 private boolean assignGreedily(Mapping m, Task task, List<ConsistentHash<ExecutorChunk>> hashes, int i) {
98 if (i==hashes.size()) return true; // fully assigned
99
100 String key = task.getFullDisplayName() + (i>0 ? String.valueOf(i) : "");
101
102 for (ExecutorChunk ec : hashes.get(i).list(key)) {
103 // let's attempt this assignment
104 m.assign(i,ec);
105
106 if (m.isPartiallyValid() && assignGreedily(m,task,hashes,i+1))
107 return true; // successful greedily allocation
108
109 // otherwise 'ec' wasn't a good fit for us. try next.
110 }
111
112 // every attempt failed
113 m.assign(i,null);
114 return false;
115 }
116 };
117
118 /**
119 * Traditional implementation of this.
120 *
121 * @deprecated as of 1.377
122 * The only implementation in the core now is the one based on consistent hash.
123 */
124 public static final LoadBalancer DEFAULT = CONSISTENT_HASH;
125
126
127 /**
128 * Wraps this {@link LoadBalancer} into a decorator that tests the basic sanity of the implementation.
129 * Only override this if you find some of the checks excessive, but beware that it's like driving without a seat belt.
130 */
131 protected LoadBalancer sanitize() {
132 final LoadBalancer base = this;
133 return new LoadBalancer() {
134 @Override
135 public Mapping map(Task task, MappingWorksheet worksheet) {
136 if (Queue.ifBlockedByHudsonShutdown(task)) {
137 // if we are quieting down, don't start anything new so that
138 // all executors will be eventually free.
139 return null;
140 }
141 return base.map(task, worksheet);
142 }
143
144 /**
145 * Double-sanitization is pointless.
146 */
147 @Override
148 protected LoadBalancer sanitize() {
149 return this;
150 }
151 };
152 }
153
154 }
155