[ASTERIXDB-2494][RT] Ensure Dataset Ref Counters Are Thread-safe

- user model changes: no
- storage format changes: no
- interface changes: no

Details:
- Dataset/Index reference counters are modified concurrently by
  multiple threads and should be thread-safe. Thread-safety issues
  in these counters could result in leaving a dataset allocated
  in memory even though it can be evicted.

Change-Id: I9328df660f463bd45bfc003b1e44c9df2702cc90
Reviewed-on: https://asterix-gerrit.ics.uci.edu/3089
Sonar-Qube: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Till Westmann <tillw@apache.org>
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/context/DatasetInfo.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/context/DatasetInfo.java
index 6e2e320..4ccb0cc 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/context/DatasetInfo.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/context/DatasetInfo.java
@@ -18,6 +18,7 @@
  */
 package org.apache.asterix.common.context;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -159,8 +160,8 @@
         this.isExternal = isExternal;
     }
 
-    public Map<Long, IndexInfo> getIndexes() {
-        return indexes;
+    public synchronized Map<Long, IndexInfo> getIndexes() {
+        return Collections.unmodifiableMap(indexes);
     }
 
     public synchronized void addIndex(long resourceID, IndexInfo indexInfo) {
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/context/DatasetLifecycleManager.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/context/DatasetLifecycleManager.java
index 1dff69d..d767219 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/context/DatasetLifecycleManager.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/context/DatasetLifecycleManager.java
@@ -163,9 +163,11 @@
         dsInfo.waitForIO();
         closeIndex(iInfo);
         dsInfo.removeIndex(resourceID);
-        if (dsInfo.getReferenceCount() == 0 && dsInfo.isOpen() && dsInfo.getIndexes().isEmpty()
-                && !dsInfo.isExternal()) {
-            removeDatasetFromCache(dsInfo.getDatasetID());
+        synchronized (dsInfo) {
+            if (dsInfo.getReferenceCount() == 0 && dsInfo.isOpen() && dsInfo.getIndexes().isEmpty()
+                    && !dsInfo.isExternal()) {
+                removeDatasetFromCache(dsInfo.getDatasetID());
+            }
         }
     }
 
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/context/Info.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/context/Info.java
index 8afae0d..fa0f14c 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/context/Info.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/context/Info.java
@@ -18,25 +18,26 @@
  */
 package org.apache.asterix.common.context;
 
+import java.util.concurrent.atomic.AtomicInteger;
+
 public abstract class Info {
-    private int referenceCount;
-    private boolean isOpen;
+    private final AtomicInteger referenceCount = new AtomicInteger();
+    private volatile boolean isOpen;
 
     public Info() {
-        referenceCount = 0;
         isOpen = false;
     }
 
     public void touch() {
-        ++referenceCount;
+        referenceCount.incrementAndGet();
     }
 
     public void untouch() {
-        --referenceCount;
+        referenceCount.decrementAndGet();
     }
 
     public int getReferenceCount() {
-        return referenceCount;
+        return referenceCount.get();
     }
 
     public boolean isOpen() {