1 11 package org.eclipse.team.internal.core.subscribers; 12 13 import java.util.*; 14 15 import org.eclipse.core.resources.IResource; 16 import org.eclipse.core.runtime.*; 17 import org.eclipse.core.runtime.jobs.*; 18 import org.eclipse.team.core.TeamException; 19 import org.eclipse.team.internal.core.*; 20 21 34 public class BatchingLock { 35 36 private final static boolean DEBUG = Policy.DEBUG_THREADING; 37 38 static final ISchedulingRule NULL_SCHEDULING_RULE= new ISchedulingRule() { 40 public boolean contains(ISchedulingRule rule) { 41 return false; 42 } 43 public boolean isConflicting(ISchedulingRule rule) { 44 return false; 45 } 46 }; 47 48 public class ThreadInfo { 49 private Set changedResources = new HashSet(); 50 private IFlushOperation operation; 51 private List rules = new ArrayList(); 52 public ThreadInfo(IFlushOperation operation) { 53 this.operation = operation; 54 } 55 62 public ISchedulingRule pushRule(ISchedulingRule resource, IProgressMonitor monitor) { 63 final ISchedulingRule rule = getRuleForResoure(resource); 65 if (rule != NULL_SCHEDULING_RULE) { 66 boolean success = false; 67 try { 68 Job.getJobManager().beginRule(rule, monitor); 69 addRule(rule); 70 success = true; 71 } finally { 72 if (!success) { 73 try { 74 Job.getJobManager().endRule(rule); 79 } catch (RuntimeException e) { 80 TeamPlugin.log(IStatus.ERROR, "Failed to end scheduling rule", e); } 83 } 84 } 85 } else { 86 addRule(rule); 89 } 90 return rule; 91 } 92 102 public void popRule(ISchedulingRule rule, IProgressMonitor monitor) throws TeamException { 103 try { 104 if (isFlushRequired()) { 105 flush(monitor); 106 } 107 } finally { 108 ISchedulingRule stackedRule = removeRule(); 109 if (rule == null) { 110 rule = NULL_SCHEDULING_RULE; 111 } 112 Assert.isTrue(stackedRule.equals(rule), "end for resource '" + rule + "' does not match stacked rule '" + stackedRule + "'"); if (rule != NULL_SCHEDULING_RULE) { 114 Job.getJobManager().endRule(rule); 115 } 116 } 117 } 118 private ISchedulingRule getRuleForResoure(ISchedulingRule resourceRule) { 119 ISchedulingRule rule; 120 if (resourceRule instanceof IResource) { 121 IResource resource = (IResource)resourceRule; 122 if (resource.getType() == IResource.ROOT) { 123 rule = NULL_SCHEDULING_RULE; 125 } else if (resource.getType() == IResource.PROJECT) { 126 rule = resource; 127 } else { 128 rule = resource.getParent(); 129 } 130 } else if (resourceRule instanceof MultiRule) { 131 ISchedulingRule[] rules = ((MultiRule)resourceRule).getChildren(); 133 Set projects = new HashSet(); 134 for (int i = 0; i < rules.length; i++) { 135 ISchedulingRule childRule = rules[i]; 136 if (childRule instanceof IResource) { 137 projects.add(((IResource)childRule).getProject()); 138 } 139 } 140 if (projects.isEmpty()) { 141 rule = NULL_SCHEDULING_RULE; 142 } else if (projects.size() == 1) { 143 rule = (ISchedulingRule)projects.iterator().next(); 144 } else { 145 rule = new MultiRule((ISchedulingRule[]) projects.toArray(new ISchedulingRule[projects.size()])); 146 } 147 } else { 148 rule = NULL_SCHEDULING_RULE; 150 } 151 return rule; 152 } 153 159 public boolean isNested() { 160 return !rules.isEmpty(); 161 } 162 public void addChangedResource(IResource resource) { 163 changedResources.add(resource); 164 } 165 public boolean isEmpty() { 166 return changedResources.isEmpty(); 167 } 168 public IResource[] getChangedResources() { 169 return (IResource[]) changedResources.toArray(new IResource[changedResources.size()]); 170 } 171 public void flush(IProgressMonitor monitor) throws TeamException { 172 try { 173 operation.flush(this, monitor); 174 } catch (OutOfMemoryError e) { 175 throw e; 176 } catch (Error e) { 177 handleAbortedFlush(e); 178 throw e; 179 } catch (RuntimeException e) { 180 handleAbortedFlush(e); 181 throw e; 182 } finally { 183 changedResources.clear(); 186 } 187 } 188 private boolean isFlushRequired() { 189 return rules.size() == 1 || remainingRulesAreNull(); 190 } 191 194 private boolean remainingRulesAreNull() { 195 for (int i = 0; i < rules.size() - 1; i++) { 196 ISchedulingRule rule = (ISchedulingRule) rules.get(i); 197 if (rule != NULL_SCHEDULING_RULE) { 198 return false; 199 } 200 } 201 return true; 202 } 203 private void handleAbortedFlush(Throwable t) { 204 TeamPlugin.log(IStatus.ERROR, Messages.BatchingLock_11, t); 205 } 206 private void addRule(ISchedulingRule rule) { 207 rules.add(rule); 208 } 209 private ISchedulingRule removeRule() { 210 return (ISchedulingRule)rules.remove(rules.size() - 1); 211 } 212 public boolean ruleContains(IResource resource) { 213 for (Iterator iter = rules.iterator(); iter.hasNext();) { 214 ISchedulingRule rule = (ISchedulingRule) iter.next(); 215 if (rule != NULL_SCHEDULING_RULE && rule.contains(resource)) { 216 return true; 217 } 218 } 219 return false; 220 } 221 } 222 223 public interface IFlushOperation { 224 public void flush(ThreadInfo info, IProgressMonitor monitor) throws TeamException; 225 } 226 227 private Map infos = new HashMap(); 228 229 233 protected ThreadInfo getThreadInfo() { 234 Thread thisThread = Thread.currentThread(); 235 synchronized (infos) { 236 ThreadInfo info = (ThreadInfo)infos.get(thisThread); 237 return info; 238 } 239 } 240 241 private ThreadInfo getThreadInfo(IResource resource) { 242 synchronized (infos) { 243 for (Iterator iter = infos.values().iterator(); iter.hasNext();) { 244 ThreadInfo info = (ThreadInfo) iter.next(); 245 if (info.ruleContains(resource)) { 246 return info; 247 } 248 } 249 return null; 250 } 251 } 252 253 public ISchedulingRule acquire(ISchedulingRule resourceRule, IFlushOperation operation, IProgressMonitor monitor) { 254 ThreadInfo info = getThreadInfo(); 255 boolean added = false; 256 synchronized (infos) { 257 if (info == null) { 258 info = createThreadInfo(operation); 259 Thread thisThread = Thread.currentThread(); 260 infos.put(thisThread, info); 261 added = true; 262 if(DEBUG) System.out.println("[" + thisThread.getName() + "] acquired batching lock on " + resourceRule); } 264 } 265 try { 266 return info.pushRule(resourceRule, monitor); 267 } catch (OperationCanceledException e) { 268 if (added) { 271 synchronized (infos) { 272 infos.remove(Thread.currentThread()); 273 } 274 } 275 throw e; 276 } 277 } 278 279 286 protected ThreadInfo createThreadInfo(IFlushOperation operation) { 287 return new ThreadInfo(operation); 288 } 289 290 299 public void release(ISchedulingRule rule, IProgressMonitor monitor) throws TeamException { 300 ThreadInfo info = getThreadInfo(); 301 Assert.isNotNull(info, "Unmatched acquire/release."); Assert.isTrue(info.isNested(), "Unmatched acquire/release."); info.popRule(rule, monitor); 304 synchronized (infos) { 305 if (!info.isNested()) { 306 Thread thisThread = Thread.currentThread(); 307 if(DEBUG) System.out.println("[" + thisThread.getName() + "] released batching lock"); infos.remove(thisThread); 309 } 310 } 311 } 312 313 public void resourceChanged(IResource resource) { 314 ThreadInfo info = getThreadInfo(); 315 Assert.isNotNull(info, "Folder changed outside of resource lock"); info.addChangedResource(resource); 317 } 318 319 324 public void flush(IProgressMonitor monitor) throws TeamException { 325 ThreadInfo info = getThreadInfo(); 326 Assert.isNotNull(info, "Flush requested outside of resource lock"); info.flush(monitor); 328 } 329 330 public boolean isWithinActiveOperationScope(IResource resource) { 331 synchronized (infos) { 332 return getThreadInfo(resource) != null; 333 } 334 } 335 } 336 | Popular Tags |