Updated Branches:
  refs/heads/master b05d459b9 -> eade3b59d

ACCUMULO-1948 Tablet constructor no longer leaks this

The core Tablet constructor no longer sets this on the TabletResourceManager 
passed to it.
The TabletResourceManager instance is created now without a Tablet reference, 
but only
with its key extent and configuration, and so it can be constructed first and 
safely passed
to the Tablet constructor. This alteration in TabletResourceManager drove 
changes to several
other locations which had been expecting a tablet reference to be available. In 
most of those
places, the key extent takes its place.

However, Keith Turner pointed out that, without a tablet reference in the 
TabletStateImpl
class (memory report) used to guide minor compaction, it's possible that a 
report logged
against a tablet that was since unloaded could cause compaction to start on a 
new instance
of that tablet that had just been reloaded. In order to ensure that cannot 
happen, the
tablet reference remains, so that the same object is used to decide on 
compaction and
potentially perform compaction.

In addition, the method of working with the memory reports was changed so that 
the same
snapshot of them used to decide on compactions is used to find the tablet to 
compact later.
This change was necessary regardless of this ticket.

Finally, the unused tabletResources field was removed from 
TabletServerResourceManager,
and that class also now avoids erroneously removing the memory report for a 
reloaded tablet
if its prior incarnation is unloaded in the scenario described above.


Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/eade3b59
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/eade3b59
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/eade3b59

Branch: refs/heads/master
Commit: eade3b59ddd95732cbfc635eadf6447c6b3108d2
Parents: b05d459
Author: Bill Havanki <bhava...@cloudera.com>
Authored: Mon Jan 27 17:09:39 2014 -0500
Committer: Bill Havanki <bhava...@cloudera.com>
Committed: Tue Feb 4 14:48:14 2014 -0500

----------------------------------------------------------------------
 server/tserver/pom.xml                          |  5 ++
 .../org/apache/accumulo/tserver/Tablet.java     |  9 +--
 .../apache/accumulo/tserver/TabletServer.java   |  8 +-
 .../tserver/TabletServerResourceManager.java    | 83 ++++++++++----------
 .../tserver/TabletResourceManagerTest.java      | 49 ++++++++++++
 5 files changed, 105 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/eade3b59/server/tserver/pom.xml
----------------------------------------------------------------------
diff --git a/server/tserver/pom.xml b/server/tserver/pom.xml
index b627de0..059473f 100644
--- a/server/tserver/pom.xml
+++ b/server/tserver/pom.xml
@@ -93,6 +93,11 @@
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>org.easymock</groupId>
+      <artifactId>easymock</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
       <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/accumulo/blob/eade3b59/server/tserver/src/main/java/org/apache/accumulo/tserver/Tablet.java
----------------------------------------------------------------------
diff --git 
a/server/tserver/src/main/java/org/apache/accumulo/tserver/Tablet.java 
b/server/tserver/src/main/java/org/apache/accumulo/tserver/Tablet.java
index 7ce270b..27412db 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/Tablet.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/Tablet.java
@@ -299,7 +299,7 @@ public class Tablet {
       commitSession = new CommitSession(nextSeq, memTable);
       nextSeq += 2;
 
-      tabletResources.updateMemoryUsageStats(memTable.estimatedSizeInBytes(), 
otherMemTable.estimatedSizeInBytes());
+      tabletResources.updateMemoryUsageStats(Tablet.this, 
memTable.estimatedSizeInBytes(), otherMemTable.estimatedSizeInBytes());
 
       return oldCommitSession;
     }
@@ -335,7 +335,7 @@ public class Tablet {
 
           deletingMemTable = null;
 
-          
tabletResources.updateMemoryUsageStats(memTable.estimatedSizeInBytes(), 0);
+          tabletResources.updateMemoryUsageStats(Tablet.this, 
memTable.estimatedSizeInBytes(), 0);
         }
       }
     }
@@ -365,7 +365,7 @@ public class Tablet {
       else if (deletingMemTable != null)
         other = deletingMemTable.estimatedSizeInBytes();
 
-      tabletResources.updateMemoryUsageStats(memTable.estimatedSizeInBytes(), 
other);
+      tabletResources.updateMemoryUsageStats(Tablet.this, 
memTable.estimatedSizeInBytes(), other);
     }
 
     List<MemoryIterator> getIterators() {
@@ -405,7 +405,7 @@ public class Tablet {
   private Configuration conf;
   private VolumeManager fs;
 
-  private TableConfiguration acuTableConf;
+  private final TableConfiguration acuTableConf;
 
   private volatile boolean tableDirChecked = false;
 
@@ -1356,7 +1356,6 @@ public class Tablet {
     // Force a load of any per-table properties
     configObserver.propertiesChanged();
 
-    tabletResources.setTablet(this, acuTableConf);
     if (!logEntries.isEmpty()) {
       log.info("Starting Write-Ahead Log recovery for " + this.extent);
       final long[] count = new long[2];

http://git-wip-us.apache.org/repos/asf/accumulo/blob/eade3b59/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
----------------------------------------------------------------------
diff --git 
a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java 
b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
index 080cc20..457bd8a 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
@@ -2670,10 +2670,12 @@ public class TabletServer extends AbstractMetricsImpl 
implements org.apache.accu
     Tablet[] newTablets = new Tablet[2];
 
     Entry<KeyExtent,SplitInfo> first = tabletInfo.firstEntry();
-    newTablets[0] = new Tablet(first.getKey(), TabletServer.this, 
resourceManager.createTabletResourceManager(), first.getValue());
+    TabletResourceManager newTrm0 = 
resourceManager.createTabletResourceManager(first.getKey(), 
getTableConfiguration(first.getKey()));
+    newTablets[0] = new Tablet(first.getKey(), TabletServer.this, newTrm0, 
first.getValue());
 
     Entry<KeyExtent,SplitInfo> last = tabletInfo.lastEntry();
-    newTablets[1] = new Tablet(last.getKey(), TabletServer.this, 
resourceManager.createTabletResourceManager(), last.getValue());
+    TabletResourceManager newTrm1 = 
resourceManager.createTabletResourceManager(last.getKey(), 
getTableConfiguration(last.getKey()));
+    newTablets[1] = new Tablet(last.getKey(), TabletServer.this, newTrm1, 
last.getValue());
 
     // roll tablet stats over into tablet server's statsKeeper object as
     // historical data
@@ -2895,7 +2897,7 @@ public class TabletServer extends AbstractMetricsImpl 
implements org.apache.accu
       boolean successful = false;
 
       try {
-        TabletResourceManager trm = 
resourceManager.createTabletResourceManager();
+        TabletResourceManager trm = 
resourceManager.createTabletResourceManager(extent, 
getTableConfiguration(extent));
 
         // this opens the tablet file and fills in the endKey in the
         // extent

http://git-wip-us.apache.org/repos/asf/accumulo/blob/eade3b59/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServerResourceManager.java
----------------------------------------------------------------------
diff --git 
a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServerResourceManager.java
 
b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServerResourceManager.java
index e958437..db046e9 100644
--- 
a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServerResourceManager.java
+++ 
b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServerResourceManager.java
@@ -16,11 +16,12 @@
  */
 package org.apache.accumulo.tserver;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.SortedMap;
@@ -82,8 +83,6 @@ public class TabletServerResourceManager {
   private ExecutorService defaultReadAheadThreadPool;
   private Map<String,ExecutorService> threadPools = new 
TreeMap<String,ExecutorService>();
 
-  private HashSet<TabletResourceManager> tabletResources;
-
   private final VolumeManager fs;
 
   private FileManager fileManager;
@@ -199,8 +198,6 @@ public class TabletServerResourceManager {
     readAheadThreadPool = createEs(Property.TSERV_READ_AHEAD_MAXCONCURRENT, 
"tablet read ahead");
     defaultReadAheadThreadPool = 
createEs(Property.TSERV_METADATA_READ_AHEAD_MAXCONCURRENT, "metadata tablets 
read ahead");
 
-    tabletResources = new HashSet<TabletResourceManager>();
-
     int maxOpenFiles = acuConf.getCount(Property.TSERV_SCAN_MAX_OPENFILES);
 
     fileManager = new FileManager(conf, fs, maxOpenFiles, _dCache, _iCache);
@@ -330,12 +327,13 @@ public class TabletServerResourceManager {
       while (true) {
         MemoryManagementActions mma = null;
 
+        Map<KeyExtent,TabletStateImpl> tabletReportsCopy = null;
         try {
-          ArrayList<TabletState> tablets;
           synchronized (tabletReports) {
-            tablets = new ArrayList<TabletState>(tabletReports.values());
+            tabletReportsCopy = new 
HashMap<KeyExtent,TabletStateImpl>(tabletReports);
           }
-          mma = memoryManager.getMemoryManagementActions(tablets);
+          ArrayList<TabletState> tabletStates = new 
ArrayList<TabletState>(tabletReportsCopy.values());
+          mma = memoryManager.getMemoryManagementActions(tabletStates);
 
         } catch (Throwable t) {
           log.error("Memory manager failed " + t.getMessage(), t);
@@ -344,16 +342,27 @@ public class TabletServerResourceManager {
         try {
           if (mma != null && mma.tabletsToMinorCompact != null && 
mma.tabletsToMinorCompact.size() > 0) {
             for (KeyExtent keyExtent : mma.tabletsToMinorCompact) {
-              TabletStateImpl tabletReport = tabletReports.get(keyExtent);
+              TabletStateImpl tabletReport = tabletReportsCopy.get(keyExtent);
 
               if (tabletReport == null) {
-                log.warn("Memory manager asked to compact nonexistant tablet " 
+ keyExtent);
+                log.warn("Memory manager asked to compact nonexistent tablet " 
+ keyExtent + "; manager implementation might be misbehaving");
                 continue;
               }
-
-              if 
(!tabletReport.getTablet().initiateMinorCompaction(MinorCompactionReason.SYSTEM))
 {
-                if (tabletReport.getTablet().isClosed()) {
-                  tabletReports.remove(tabletReport.getExtent());
+              Tablet tablet = tabletReport.getTablet();
+              if 
(!tablet.initiateMinorCompaction(MinorCompactionReason.SYSTEM)) {
+                if (tablet.isClosed()) {
+                  // attempt to remove it from the current reports if still 
there
+                  synchronized(tabletReports) {
+                    TabletStateImpl latestReport = 
tabletReports.remove(keyExtent);
+                    if (latestReport != null) {
+                      if (latestReport.getTablet() != tablet) {
+                        // different tablet instance => put it back
+                        tabletReports.put(keyExtent, latestReport);
+                      } else {
+                        log.debug("Cleaned up report for closed tablet " + 
keyExtent);
+                      }
+                    }
+                  }
                   log.debug("Ignoring memory manager recommendation: not minor 
compacting closed tablet " + keyExtent);
                 } else {
                   log.info("Ignoring memory manager recommendation: not minor 
compacting " + keyExtent);
@@ -443,19 +452,11 @@ public class TabletServerResourceManager {
     }
   }
 
-  public synchronized TabletResourceManager createTabletResourceManager() {
-    TabletResourceManager trm = new TabletResourceManager();
+  public synchronized TabletResourceManager 
createTabletResourceManager(KeyExtent extent, AccumuloConfiguration conf) {
+    TabletResourceManager trm = new TabletResourceManager(extent, conf);
     return trm;
   }
 
-  synchronized private void addTabletResource(TabletResourceManager tr) {
-    tabletResources.add(tr);
-  }
-
-  synchronized private void removeTabletResource(TabletResourceManager tr) {
-    tabletResources.remove(tr);
-  }
-
   public class TabletResourceManager {
 
     private final long creationTime = System.currentTimeMillis();
@@ -464,20 +465,22 @@ public class TabletServerResourceManager {
 
     private volatile boolean closed = false;
 
-    private Tablet tablet;
-
-    private AccumuloConfiguration tableConf;
+    private final KeyExtent extent;
 
-    TabletResourceManager() {}
+    private final AccumuloConfiguration tableConf;
 
-    void setTablet(Tablet tablet, AccumuloConfiguration tableConf) {
-      this.tablet = tablet;
+    TabletResourceManager(KeyExtent extent, AccumuloConfiguration tableConf) {
+      checkNotNull(extent, "extent is null");
+      checkNotNull(tableConf, "tableConf is null");
+      this.extent = extent;
       this.tableConf = tableConf;
-      // TabletResourceManager is not really initialized until this
-      // function is called.... so do not make it publicly available
-      // until now
+    }
 
-      addTabletResource(this);
+    KeyExtent getExtent() {
+      return extent;
+    }
+    AccumuloConfiguration getTableConfiguration() {
+      return tableConf;
     }
 
     // BEGIN methods that Tablets call to manage their set of open map files
@@ -489,7 +492,7 @@ public class TabletServerResourceManager {
     synchronized ScanFileManager newScanFileManager() {
       if (closed)
         throw new IllegalStateException("closed");
-      return fileManager.newScanFileManager(tablet.getExtent());
+      return fileManager.newScanFileManager(extent);
     }
 
     // END methods that Tablets call to manage their set of open map files
@@ -500,7 +503,7 @@ public class TabletServerResourceManager {
     private AtomicLong lastReportedMincSize = new AtomicLong();
     private volatile long lastReportedCommitTime = 0;
 
-    public void updateMemoryUsageStats(long size, long mincSize) {
+    public void updateMemoryUsageStats(Tablet tablet, long size, long 
mincSize) {
 
       // do not want to update stats for every little change,
       // so only do it under certain circumstances... the reason
@@ -563,7 +566,7 @@ public class TabletServerResourceManager {
       CompactionStrategy strategy = 
Property.createInstanceFromPropertyName(tableConf, 
Property.TABLE_COMPACTION_STRATEGY, CompactionStrategy.class,
           new DefaultCompactionStrategy());
       strategy.init(Property.getCompactionStrategyOptions(tableConf));
-      MajorCompactionRequest request = new 
MajorCompactionRequest(tablet.getExtent(), reason, 
TabletServerResourceManager.this.fs, tableConf);
+      MajorCompactionRequest request = new MajorCompactionRequest(extent, 
reason, TabletServerResourceManager.this.fs, tableConf);
       request.setFiles(tabletFiles);
       try {
         return strategy.shouldCompact(request);
@@ -590,10 +593,8 @@ public class TabletServerResourceManager {
           if (openFilesReserved)
             throw new IOException("tired to close files while open files 
reserved");
 
-          TabletServerResourceManager.this.removeTabletResource(this);
-
-          memMgmt.tabletClosed(tablet.getExtent());
-          memoryManager.tabletClosed(tablet.getExtent());
+          memMgmt.tabletClosed(extent);
+          memoryManager.tabletClosed(extent);
 
           closed = true;
         }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/eade3b59/server/tserver/src/test/java/org/apache/accumulo/tserver/TabletResourceManagerTest.java
----------------------------------------------------------------------
diff --git 
a/server/tserver/src/test/java/org/apache/accumulo/tserver/TabletResourceManagerTest.java
 
b/server/tserver/src/test/java/org/apache/accumulo/tserver/TabletResourceManagerTest.java
new file mode 100644
index 0000000..9d9db6f
--- /dev/null
+++ 
b/server/tserver/src/test/java/org/apache/accumulo/tserver/TabletResourceManagerTest.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.tserver;
+
+import org.apache.accumulo.core.data.KeyExtent;
+import org.apache.accumulo.server.conf.TableConfiguration;
+import 
org.apache.accumulo.tserver.TabletServerResourceManager.TabletResourceManager;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.*;
+import org.easymock.Capture;
+import static org.easymock.EasyMock.*;
+
+public class TabletResourceManagerTest {
+  private TabletServerResourceManager tsrm;
+  private TabletResourceManager trm;
+  private Tablet tablet;
+  private KeyExtent extent;
+  private TableConfiguration conf;
+
+  @Before
+  public void setUp() throws Exception {
+    tsrm = createMock(TabletServerResourceManager.class);
+    tablet = createMock(Tablet.class);
+    extent = createMock(KeyExtent.class);
+    conf = createMock(TableConfiguration.class);
+    trm = tsrm.new TabletResourceManager(extent, conf);
+  }
+
+  @Test
+  public void testConstruction() {
+    assertEquals(extent, trm.getExtent());
+    assertEquals(conf, trm.getTableConfiguration());
+  }
+}

Reply via email to