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

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc.
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.slaves;
25
26 import hudson.FilePath;
27 import hudson.Functions;
28 import hudson.model.Computer;
29
30 import java.util.Date;
31 import java.util.HashMap;
32 import java.util.Map;
33 import java.util.logging.Level;
34 import java.util.logging.Logger;
35
36 /**
37 * Used by {@link Computer} to keep track of workspaces that are actively in use.
38 *
39 * @author Kohsuke Kawaguchi
40 * @since 1.319
41 * @see Computer#getWorkspaceList()
42 */
43 public final class WorkspaceList {
44 /**
45 * Book keeping for workspace allocation.
46 */
47 public static final class Entry {
48 /**
49 * Who acquired this workspace?
50 */
51 public final Thread holder = Thread.currentThread();
52
53 /**
54 * When?
55 */
56 public final long time = System.currentTimeMillis();
57
58 /**
59 * From where?
60 */
61 public final Exception source = new Exception();
62
63 /**
64 * True makes the caller of {@link WorkspaceList#allocate(FilePath)} wait
65 * for this workspace.
66 */
67 public final boolean quick;
68
69 public final FilePath path;
70
71 /**
72 * Multiple threads can acquire the same lock if they share the same context object.
73 */
74 public final Object context;
75
76 public int lockCount=1;
77
78 private Entry(FilePath path, boolean quick) {
79 this(path,quick,new Object()); // unique context
80 }
81
82 private Entry(FilePath path, boolean quick, Object context) {
83 this.path = path;
84 this.quick = quick;
85 this.context = context;
86 }
87
88 @Override
89 public String toString() {
90 String s = path+" owned by "+holder.getName()+" from "+new Date(time);
91 if(quick) s+=" (quick)";
92 s+="\n"+Functions.printThrowable(source);
93 return s;
94 }
95 }
96
97 /**
98 * Represents a leased workspace that needs to be returned later.
99 */
100 public static abstract class Lease {
101 public final FilePath path;
102
103 protected Lease(FilePath path) {
104 this.path = path;
105 }
106
107 /**
108 * Releases this lease.
109 */
110 public abstract void release();
111
112 /**
113 * Creates a dummy {@link Lease} object that does no-op in the release.
114 */
115 public static Lease createDummyLease(FilePath p) {
116 return new Lease(p) {
117 public void release() {
118 // noop
119 }
120 };
121 }
122
123 /**
124 * Creates a {@link Lease} object that points to the specified path, but the lock
125 * is controlled by the given parent lease object.
126 */
127 public static Lease createLinkedDummyLease(FilePath p, final Lease parent) {
128 return new Lease(p) {
129 public void release() {
130 parent.release();
131 }
132 };
133 }
134 }
135
136 private final Map<FilePath,Entry> inUse = new HashMap<FilePath,Entry>();
137
138 public WorkspaceList() {
139 }
140
141 /**
142 * Allocates a workspace by adding some variation to the given base to make it unique.
143 *
144 * <p>
145 * This method doesn't block prolonged amount of time. Whenever a desired workspace
146 * is in use, the unique variation is added.
147 */
148 public synchronized Lease allocate(FilePath base) throws InterruptedException {
149 return allocate(base,new Object());
150 }
151
152 /**
153 * See {@link #allocate(FilePath)}
154 *
155 * @param context
156 * Threads that share the same context can re-acquire the same lock (which will just increment the lock count.)
157 * This allows related executors to share the same workspace.
158 */
159 public synchronized Lease allocate(FilePath base, Object context) throws InterruptedException {
160 for (int i=1; ; i++) {
161 FilePath candidate = i==1 ? base : base.withSuffix(COMBINATOR+i);
162 Entry e = inUse.get(candidate);
163 if(e!=null && !e.quick && e.context!=context)
164 continue;
165 return acquire(candidate,false,context);
166 }
167 }
168
169 /**
170 * Just record that this workspace is being used, without paying any attention to the synchronization support.
171 */
172 public synchronized Lease record(FilePath p) {
173 log("recorded "+p);
174 Entry old = inUse.put(p, new Entry(p, false));
175 if (old!=null)
176 throw new AssertionError("Tried to record a workspace already owned: "+old);
177 return lease(p);
178 }
179
180 /**
181 * Releases an allocated or acquired workspace.
182 */
183 private synchronized void _release(FilePath p) {
184 Entry old = inUse.get(p);
185 if (old==null)
186 throw new AssertionError("Releasing unallocated workspace "+p);
187 old.lockCount--;
188 if (old.lockCount==0)
189 inUse.remove(p);
190 notifyAll();
191 }
192
193 /**
194 * Acquires the given workspace. If necessary, this method blocks until it's made available.
195 *
196 * @return
197 * The same {@link FilePath} as given to this method.
198 */
199 public synchronized Lease acquire(FilePath p) throws InterruptedException {
200 return acquire(p,false);
201 }
202
203 /**
204 * See {@link #acquire(FilePath)}
205 *
206 * @param quick
207 * If true, indicates that the acquired workspace will be returned quickly.
208 * This makes other calls to {@link #allocate(FilePath)} to wait for the release of this workspace.
209 */
210 public synchronized Lease acquire(FilePath p, boolean quick) throws InterruptedException {
211 return acquire(p,quick,new Object());
212 }
213
214 /**
215 * See {@link #acquire(FilePath,boolean)}
216 *
217 * @param context
218 * Threads that share the same context can re-acquire the same lock (which will just increment the lock count.)
219 * This allows related executors to share the same workspace.
220 */
221 public synchronized Lease acquire(FilePath p, boolean quick, Object context) throws InterruptedException {
222 Entry e;
223
224 Thread t = Thread.currentThread();
225 String oldName = t.getName();
226 t.setName("Waiting to acquire "+p+" : "+t.getName());
227 try {
228 while (true) {
229 e = inUse.get(p);
230 if (e==null || e.context==context)
231 break;
232 wait();
233 }
234 } finally {
235 t.setName(oldName);
236 }
237 log("acquired "+p);
238
239 if (e!=null) e.lockCount++;
240 else inUse.put(p,new Entry(p,quick,context));
241 return lease(p);
242 }
243
244 /**
245 * Wraps a path into a valid lease.
246 */
247 private Lease lease(FilePath p) {
248 return new Lease(p) {
249 public void release() {
250 _release(path);
251 }
252 };
253 }
254
255 private void log(String msg) {
256 if (LOGGER.isLoggable(Level.FINE))
257 LOGGER.fine(Thread.currentThread().getName() + " " + msg);
258 }
259
260 private static final Logger LOGGER = Logger.getLogger(WorkspaceList.class.getName());
261
262 /**
263 * The token that combines the project name and unique number to create unique workspace directory.
264 */
265 private static final String COMBINATOR = System.getProperty(WorkspaceList.class.getName(),"@");
266 }
267