public ResolveTask getOrCreateTaskResolving( final ValueRequirement valueRequirement, final ResolveTask parentTask, final Collection<FunctionExclusionGroup> functionExclusion) { final ResolveTask newTask = new ResolveTask(valueRequirement, parentTask, functionExclusion); do { ResolveTask task; final Map<ResolveTask, ResolveTask> tasks = getBuilder().getOrCreateTasks(valueRequirement); synchronized (tasks) { if (tasks.containsKey(null)) { // The cache has been flushed continue; } task = tasks.get(newTask); if (task == null) { newTask.addRef(); // Already got a reference, increment for the collection tasks.put(newTask, newTask); } else { task.addRef(); // Got the task lock, increment so we can return it } } if (task != null) { s_logger.debug("Using existing task {}", task); newTask.release(this); // Discard local allocation return task; } else { getBuilder().incrementActiveResolveTasks(); // Don't call run; we want to fork this out to a new worker thread, never call inline newTask.addRef(); // Reference held by the run queue submit(newTask); return newTask; } } while (true); }
public void discardTask(final ResolveTask task) { // TODO: Could we post "discardTask" tasks to a queue and have them done in batches by a // ContextRunnable? do { final Map<ResolveTask, ResolveTask> tasks = getBuilder().getTasks(task.getValueRequirement()); if (tasks == null) { return; } synchronized (tasks) { if (tasks.containsKey(null)) { continue; } final int rc = task.getRefCount(); if (rc == 0) { // Not referenced by us by definition return; } if (rc != 1) { if (!task.isFinished()) { // Can't discard this -- something might be waiting on a result from it?? return; } } final ResolveTask removed = tasks.remove(task); if (removed == null) { // Task has already been discarded return; } if (removed != task) { // Task has already been discarded and replaced by an equivalent; don't discard that tasks.put(removed, removed); return; } } task.release(this); getBuilder().decrementActiveResolveTasks(); } while (true); }
public ResolvedValueProducer resolveRequirement( final ValueRequirement rawRequirement, final ResolveTask dependent, final Collection<FunctionExclusionGroup> functionExclusion) { final ValueRequirement requirement = simplifyType(rawRequirement); s_logger.debug("Resolve requirement {}", requirement); if ((dependent != null) && dependent.hasParent(requirement)) { s_logger.debug("Can't introduce a ValueRequirement loop"); return null; } RequirementResolver resolver = null; final ResolveTask[] tasks = getTasksResolving(requirement); if (tasks != null) { int i = 0; int l = tasks.length; while (i < l) { final ResolveTask task = tasks[i]; if ((dependent == null) || !dependent.hasParent(task)) { if ((task.isFinished() && !task.wasRecursionDetected()) || (ObjectUtils.equals(functionExclusion, task.getFunctionExclusion()) && task.hasParentValueRequirements(dependent))) { // The task we've found has either already completed, without hitting a recursion // constraint. Or // the task is identical to the fallback task we'd create naturally. In either case, // release everything // else and use it. for (int j = 0; j < i; j++) { tasks[j].release(this); } for (int j = i + 1; j < l; j++) { tasks[j].release(this); } return task; } i++; } else { task.release(this); tasks[i] = tasks[--l]; } } // Anything left in the array is suitable for use in a RequirementResolver if (l > 0) { resolver = new RequirementResolver(requirement, dependent, functionExclusion); if (l != tasks.length) { resolver.setTasks(this, Arrays.copyOf(tasks, l)); } else { resolver.setTasks(this, tasks); } for (i = 0; i < l; i++) { tasks[i].release(this); } } } if (resolver != null) { resolver.start(this); return resolver; } else { s_logger.debug("Using direct resolution {}/{}", requirement, dependent); return getOrCreateTaskResolving(requirement, dependent, functionExclusion); } }