Do not queue an evaluation task if one is already in queue

So far, adding an already existing evaluation task to the queue was
wrongfully accepted and this created an evaluation build up.

Check if a repository is already in the evaluation queue before adding
it.

Change-Id: I8d4d8a225eb51eb7f20298500fca33b50ab3a2ce
diff --git a/src/main/java/com/ericsson/gerrit/plugins/gcconductor/EvaluationTask.java b/src/main/java/com/ericsson/gerrit/plugins/gcconductor/EvaluationTask.java
index 2bbade5..a95e9df 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/gcconductor/EvaluationTask.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/gcconductor/EvaluationTask.java
@@ -15,6 +15,7 @@
 package com.ericsson.gerrit.plugins.gcconductor;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Objects;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 import java.io.File;
@@ -84,6 +85,20 @@
     }
   }
 
+  @Override
+  public int hashCode() {
+    return Objects.hashCode(repositoryPath);
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (!(obj instanceof EvaluationTask)) {
+      return false;
+    }
+    EvaluationTask other = (EvaluationTask) obj;
+    return repositoryPath == other.repositoryPath;
+  }
+
   private boolean isAlreadyInQueue() {
     try {
       return queue.contains(repositoryPath);
diff --git a/src/main/java/com/ericsson/gerrit/plugins/gcconductor/evaluator/Evaluator.java b/src/main/java/com/ericsson/gerrit/plugins/gcconductor/evaluator/Evaluator.java
index 69e0a37..67d216f 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/gcconductor/evaluator/Evaluator.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/gcconductor/evaluator/Evaluator.java
@@ -24,7 +24,9 @@
 import com.google.inject.Singleton;
 import java.io.IOException;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
@@ -46,6 +48,8 @@
   private final EvaluationTask.Factory evaluationTaskFactory;
   private final GitRepositoryManager repoManager;
   private final Map<String, Long> timestamps;
+  private final Set<EvaluationTask> queuedEvaluationTasks =
+      Collections.newSetFromMap(new ConcurrentHashMap<>());
 
   private long expireTime;
 
@@ -92,8 +96,8 @@
   @Override
   public void onPostUpload(PackStatistics stats) {
     String repositoryPath = uploadRepositoryPath.get();
-    if (repositoryPath != null && needsCheck(repositoryPath)) {
-      executor.execute(evaluationTaskFactory.create(repositoryPath));
+    if (repositoryPath != null) {
+      queueEvaluationIfNecessary(repositoryPath);
       uploadRepositoryPath.remove();
     }
   }
@@ -104,9 +108,7 @@
     Project.NameKey projectNameKey = new Project.NameKey(projectName);
     try (Repository repository = repoManager.openRepository(projectNameKey)) {
       String repositoryPath = repository.getDirectory().getAbsolutePath();
-      if (needsCheck(repositoryPath)) {
-        executor.execute(evaluationTaskFactory.create(repositoryPath));
-      }
+      queueEvaluationIfNecessary(repositoryPath);
     } catch (RepositoryNotFoundException e) {
       log.error("Project not found {}", projectName, e);
     } catch (IOException e) {
@@ -114,7 +116,20 @@
     }
   }
 
-  private boolean needsCheck(String repositoryPath) {
+  private void queueEvaluationIfNecessary(String repositoryPath) {
+    if (lastCheckExpired(repositoryPath)) {
+      EvaluationTask evaluationTask = evaluationTaskFactory.create(repositoryPath);
+      if (queuedEvaluationTasks.add(evaluationTask)) {
+        try {
+          executor.execute(evaluationTask);
+        } finally {
+          queuedEvaluationTasks.remove(evaluationTask);
+        }
+      }
+    }
+  }
+
+  private boolean lastCheckExpired(String repositoryPath) {
     long now = System.currentTimeMillis();
     if (!timestamps.containsKey(repositoryPath)
         || now >= timestamps.get(repositoryPath) + expireTime) {