accumulo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ctubb...@apache.org
Subject svn commit: r1496171 [1/3] - in /accumulo/trunk: core/src/main/java/org/apache/accumulo/core/client/admin/ core/src/main/java/org/apache/accumulo/core/client/impl/ core/src/main/java/org/apache/accumulo/core/client/mock/ core/src/main/java/org/apache/a...
Date Mon, 24 Jun 2013 19:29:41 GMT
Author: ctubbsii
Date: Mon Jun 24 19:29:39 2013
New Revision: 1496171

URL: http://svn.apache.org/r1496171
Log:
ACCUMULO-1481 Make root tablet its own table; further polishing and testing will be needed, but this changeset passes existing unit and integration build tests and most functional tests

Added:
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/master/TabletGroupWatcher.java
Removed:
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/master/RoundRobinPartitioner.java
Modified:
    accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/admin/TableOperationsImpl.java
    accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/RootTabletLocator.java
    accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TabletLocator.java
    accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TabletLocatorImpl.java
    accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TabletServerBatchWriter.java
    accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TimeoutTabletLocator.java
    accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/mock/MockAccumulo.java
    accumulo/trunk/core/src/main/java/org/apache/accumulo/core/data/KeyExtent.java
    accumulo/trunk/core/src/main/java/org/apache/accumulo/core/iterators/OptionDescriber.java
    accumulo/trunk/core/src/main/java/org/apache/accumulo/core/util/MetadataTable.java
    accumulo/trunk/core/src/main/java/org/apache/accumulo/core/util/RootTable.java
    accumulo/trunk/core/src/main/java/org/apache/accumulo/core/util/shell/commands/GetSplitsCommand.java
    accumulo/trunk/core/src/test/java/org/apache/accumulo/core/client/impl/TabletLocatorImplTest.java
    accumulo/trunk/core/src/test/java/org/apache/accumulo/core/util/MetadataTableTest.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/ServerConstants.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/gc/SimpleGarbageCollector.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/master/Master.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/master/state/MergeInfo.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/master/state/MergeStats.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/master/state/MetaDataStateStore.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/master/state/MetaDataTableScanner.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/master/state/RootTabletStateStore.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/master/state/TabletStateStore.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/master/state/ZooTabletStateStore.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/master/tableOps/CompactRange.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/master/tableOps/TableRangeOp.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/monitor/servlets/TablesServlet.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/problems/ProblemReports.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/security/SecurityOperation.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/tabletserver/Tablet.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/tabletserver/TabletServer.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/tabletserver/TabletServerResourceManager.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/util/AddFilesWithMissingEntries.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/util/FindOfflineTablets.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/util/Initialize.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/util/MetadataTable.java
    accumulo/trunk/server/src/main/java/org/apache/accumulo/server/util/OfflineMetadataScanner.java
    accumulo/trunk/server/src/test/java/org/apache/accumulo/server/master/state/MergeInfoTest.java
    accumulo/trunk/server/src/test/java/org/apache/accumulo/server/master/state/RootTabletStateStoreTest.java
    accumulo/trunk/test/src/main/java/org/apache/accumulo/test/GCLotsOfCandidatesTest.java
    accumulo/trunk/test/src/test/java/org/apache/accumulo/test/MetaSplitTest.java
    accumulo/trunk/test/src/test/java/org/apache/accumulo/test/ShellServerTest.java
    accumulo/trunk/test/system/auto/simple/readwrite.py

Modified: accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/admin/TableOperationsImpl.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/admin/TableOperationsImpl.java?rev=1496171&r1=1496170&r2=1496171&view=diff
==============================================================================
--- accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/admin/TableOperationsImpl.java (original)
+++ accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/admin/TableOperationsImpl.java Mon Jun 24 19:29:39 2013
@@ -94,6 +94,7 @@ import org.apache.accumulo.core.util.Met
 import org.apache.accumulo.core.util.NamingThreadFactory;
 import org.apache.accumulo.core.util.OpTimer;
 import org.apache.accumulo.core.util.Pair;
+import org.apache.accumulo.core.util.RootTable;
 import org.apache.accumulo.core.util.StringUtil;
 import org.apache.accumulo.core.util.TextUtil;
 import org.apache.accumulo.core.util.ThriftUtil;
@@ -154,7 +155,7 @@ public class TableOperationsImpl extends
   @Override
   public boolean exists(String tableName) {
     ArgumentChecker.notNull(tableName);
-    if (tableName.equals(MetadataTable.NAME))
+    if (tableName.equals(MetadataTable.NAME) || tableName.equals(RootTable.NAME))
       return true;
     
     OpTimer opTimer = new OpTimer(log, Level.TRACE).start("Checking if table " + tableName + "exists...");
@@ -542,6 +543,8 @@ public class TableOperationsImpl extends
     ArgumentChecker.notNull(tableName);
     
     String tableId = Tables.getTableId(instance, tableName);
+    if (RootTable.ID.equals(tableId))
+      return Collections.emptyList();
     
     SortedSet<KeyExtent> tablets = new TreeSet<KeyExtent>();
     Map<KeyExtent,String> locations = new TreeMap<KeyExtent,String>();
@@ -1203,7 +1206,6 @@ public class TableOperationsImpl extends
   @Override
   public List<DiskUsage> getDiskUsage(Set<String> tableNames) throws AccumuloException, AccumuloSecurityException, TableNotFoundException {
     
-
     List<TDiskUsage> diskUsages = null;
     while (diskUsages == null) {
       Pair<String,Client> pair = null;
@@ -1235,7 +1237,7 @@ public class TableOperationsImpl extends
           ServerClient.close(pair.getSecond());
       }
     }
-
+    
     List<DiskUsage> finalUsages = new ArrayList<DiskUsage>();
     for (TDiskUsage diskUsage : diskUsages) {
       finalUsages.add(new DiskUsage(new TreeSet<String>(diskUsage.getTables()), diskUsage.getUsage()));
@@ -1321,7 +1323,6 @@ public class TableOperationsImpl extends
       AccumuloSecurityException {
     ArgumentChecker.notNull(tableName, className, asTypeName);
     
-
     try {
       return ServerClient.executeRaw(instance, new ClientExecReturn<Boolean,ClientService.Client>() {
         @Override

Modified: accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/RootTabletLocator.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/RootTabletLocator.java?rev=1496171&r1=1496170&r2=1496171&view=diff
==============================================================================
--- accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/RootTabletLocator.java (original)
+++ accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/RootTabletLocator.java Mon Jun 24 19:29:39 2013
@@ -42,22 +42,32 @@ public class RootTabletLocator extends T
   }
   
   @Override
-  public void binMutations(List<Mutation> mutations, Map<String,TabletServerMutations> binnedMutations, List<Mutation> failures, TCredentials credentials) throws AccumuloException,
-      AccumuloSecurityException, TableNotFoundException {
-    throw new UnsupportedOperationException();
+  public void binMutations(List<Mutation> mutations, Map<String,TabletServerMutations> binnedMutations, List<Mutation> failures, TCredentials credentials)
+      throws AccumuloException, AccumuloSecurityException, TableNotFoundException {
+    String rootTabletLocation = instance.getRootTabletLocation();
+    if (rootTabletLocation != null) {
+      TabletServerMutations tsm = new TabletServerMutations();
+      for (Mutation mutation : mutations) {
+        tsm.addMutation(RootTable.EXTENT, mutation);
+      }
+      binnedMutations.put(rootTabletLocation, tsm);
+    } else {
+      failures.addAll(mutations);
+    }
   }
   
   @Override
-  public List<Range> binRanges(List<Range> ranges, Map<String,Map<KeyExtent,List<Range>>> binnedRanges, TCredentials credentials) throws AccumuloException, AccumuloSecurityException,
-      TableNotFoundException {
+  public List<Range> binRanges(List<Range> ranges, Map<String,Map<KeyExtent,List<Range>>> binnedRanges, TCredentials credentials) throws AccumuloException,
+      AccumuloSecurityException, TableNotFoundException {
     
     String rootTabletLocation = instance.getRootTabletLocation();
     if (rootTabletLocation != null) {
       for (Range range : ranges) {
-        TabletLocatorImpl.addRange(binnedRanges, rootTabletLocation, RootTable.ROOT_TABLET_EXTENT, range);
+        TabletLocatorImpl.addRange(binnedRanges, rootTabletLocation, RootTable.EXTENT, range);
       }
+      return Collections.emptyList();
     }
-    return Collections.emptyList();
+    return ranges;
   }
   
   @Override
@@ -73,14 +83,8 @@ public class RootTabletLocator extends T
   public void invalidateCache() {}
   
   @Override
-  public TabletLocation locateTablet(Text row, boolean skipRow, boolean retry, TCredentials credentials) throws AccumuloException, AccumuloSecurityException, TableNotFoundException {
-    if (skipRow) {
-      row = new Text(row);
-      row.append(new byte[] {0}, 0, 1);
-    }
-    if (!RootTable.ROOT_TABLET_EXTENT.contains(row)) {
-      throw new AccumuloException("Tried to locate row out side of root tablet " + row);
-    }
+  public TabletLocation locateTablet(Text row, boolean skipRow, boolean retry, TCredentials credentials) throws AccumuloException, AccumuloSecurityException,
+      TableNotFoundException {
     String location = instance.getRootTabletLocation();
     // Always retry when finding the root tablet
     while (retry && location == null) {
@@ -88,7 +92,7 @@ public class RootTabletLocator extends T
       location = instance.getRootTabletLocation();
     }
     if (location != null)
-      return new TabletLocation(RootTable.ROOT_TABLET_EXTENT, location);
+      return new TabletLocation(RootTable.EXTENT, location);
     return null;
   }
   

Modified: accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TabletLocator.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TabletLocator.java?rev=1496171&r1=1496170&r2=1496171&view=diff
==============================================================================
--- accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TabletLocator.java (original)
+++ accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TabletLocator.java Mon Jun 24 19:29:39 2013
@@ -34,6 +34,7 @@ import org.apache.accumulo.core.data.Ran
 import org.apache.accumulo.core.security.thrift.TCredentials;
 import org.apache.accumulo.core.util.ArgumentChecker;
 import org.apache.accumulo.core.util.MetadataTable;
+import org.apache.accumulo.core.util.RootTable;
 import org.apache.hadoop.io.Text;
 
 public abstract class TabletLocator {
@@ -90,37 +91,20 @@ public abstract class TabletLocator {
   
   private static HashMap<LocatorKey,TabletLocator> locators = new HashMap<LocatorKey,TabletLocator>();
   
-  private static final Text ROOT_TABLET_MDE = KeyExtent.getMetadataEntry(new Text(MetadataTable.ID), null);
-  
   public static synchronized TabletLocator getInstance(Instance instance, Text tableId) {
-    LocatorKey key = new LocatorKey(instance.getInstanceID(), tableId);
     
+    LocatorKey key = new LocatorKey(instance.getInstanceID(), tableId);
     TabletLocator tl = locators.get(key);
-    
     if (tl == null) {
       MetadataLocationObtainer mlo = new MetadataLocationObtainer(instance);
       
-      if (tableId.toString().equals(MetadataTable.ID)) {
-        RootTabletLocator rootTabletLocator = new RootTabletLocator(instance);
-        tl = new TabletLocatorImpl(new Text(MetadataTable.ID), rootTabletLocator, mlo) {
-          @Override
-          public TabletLocation _locateTablet(Text row, boolean skipRow, boolean retry, boolean lock, TCredentials credentials) throws AccumuloException, AccumuloSecurityException,
-              TableNotFoundException {
-            // add a special case for the root tablet itself to the cache of information in the root tablet
-            int comparison_result = row.compareTo(ROOT_TABLET_MDE);
-            
-            if ((skipRow && comparison_result < 0) || (!skipRow && comparison_result <= 0)) {
-              return parent.locateTablet(row, skipRow, retry, credentials);
-            }
-            
-            return super._locateTablet(row, skipRow, retry, lock, credentials);
-          }
-        };
+      if (tableId.toString().equals(RootTable.ID)) {
+        tl = new RootTabletLocator(instance);
+      } else if (tableId.toString().equals(MetadataTable.ID)) {
+        tl = new TabletLocatorImpl(new Text(MetadataTable.ID), getInstance(instance, new Text(RootTable.ID)), mlo);
       } else {
-        TabletLocator rootTabletCache = getInstance(instance, new Text(MetadataTable.ID));
-        tl = new TabletLocatorImpl(tableId, rootTabletCache, mlo);
+        tl = new TabletLocatorImpl(tableId, getInstance(instance, new Text(MetadataTable.ID)), mlo);
       }
-      
       locators.put(key, tl);
     }
     

Modified: accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TabletLocatorImpl.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TabletLocatorImpl.java?rev=1496171&r1=1496170&r2=1496171&view=diff
==============================================================================
--- accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TabletLocatorImpl.java (original)
+++ accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TabletLocatorImpl.java Mon Jun 24 19:29:39 2013
@@ -59,6 +59,7 @@ public class TabletLocatorImpl extends T
   
   private static class EndRowComparator implements Comparator<Text> {
     
+    @Override
     public int compare(Text o1, Text o2) {
       
       int ret;
@@ -95,10 +96,11 @@ public class TabletLocatorImpl extends T
     /**
      * @return null when unable to read information successfully
      */
-    TabletLocations lookupTablet(TabletLocation src, Text row, Text stopRow, TabletLocator parent, TCredentials credentials) throws AccumuloSecurityException, AccumuloException;
-    
-    List<TabletLocation> lookupTablets(String tserver, Map<KeyExtent,List<Range>> map, TabletLocator parent, TCredentials credentials) throws AccumuloSecurityException,
+    TabletLocations lookupTablet(TabletLocation src, Text row, Text stopRow, TabletLocator parent, TCredentials credentials) throws AccumuloSecurityException,
         AccumuloException;
+    
+    List<TabletLocation> lookupTablets(String tserver, Map<KeyExtent,List<Range>> map, TabletLocator parent, TCredentials credentials)
+        throws AccumuloSecurityException, AccumuloException;
   }
   
   public TabletLocatorImpl(Text table, TabletLocator parent, TabletLocationObtainer tlo) {
@@ -111,8 +113,8 @@ public class TabletLocatorImpl extends T
   }
   
   @Override
-  public void binMutations(List<Mutation> mutations, Map<String,TabletServerMutations> binnedMutations, List<Mutation> failures, TCredentials credentials) throws AccumuloException,
-      AccumuloSecurityException, TableNotFoundException {
+  public void binMutations(List<Mutation> mutations, Map<String,TabletServerMutations> binnedMutations, List<Mutation> failures, TCredentials credentials)
+      throws AccumuloException, AccumuloSecurityException, TableNotFoundException {
     
     OpTimer opTimer = null;
     if (log.isTraceEnabled())
@@ -146,6 +148,7 @@ public class TabletLocatorImpl extends T
     
     if (notInCache.size() > 0) {
       Collections.sort(notInCache, new Comparator<Mutation>() {
+        @Override
         public int compare(Mutation o1, Mutation o2) {
           return WritableComparator.compareBytes(o1.getRow(), 0, o1.getRow().length, o2.getRow(), 0, o2.getRow().length);
         }
@@ -193,8 +196,8 @@ public class TabletLocatorImpl extends T
     tsm.addMutation(tl.tablet_extent, mutation);
   }
   
-  private List<Range> binRanges(List<Range> ranges, Map<String,Map<KeyExtent,List<Range>>> binnedRanges, boolean useCache, TCredentials credentials) throws AccumuloException,
-      AccumuloSecurityException, TableNotFoundException {
+  private List<Range> binRanges(List<Range> ranges, Map<String,Map<KeyExtent,List<Range>>> binnedRanges, boolean useCache, TCredentials credentials)
+      throws AccumuloException, AccumuloSecurityException, TableNotFoundException {
     List<Range> failures = new ArrayList<Range>();
     List<TabletLocation> tabletLocations = new ArrayList<TabletLocation>();
     
@@ -254,8 +257,8 @@ public class TabletLocatorImpl extends T
   }
   
   @Override
-  public List<Range> binRanges(List<Range> ranges, Map<String,Map<KeyExtent,List<Range>>> binnedRanges, TCredentials credentials) throws AccumuloException, AccumuloSecurityException,
-      TableNotFoundException {
+  public List<Range> binRanges(List<Range> ranges, Map<String,Map<KeyExtent,List<Range>>> binnedRanges, TCredentials credentials) throws AccumuloException,
+      AccumuloSecurityException, TableNotFoundException {
     
     /*
      * For this to be efficient, need to avoid fine grained synchronization and fine grained logging. Therefore methods called by this are not synchronized and
@@ -520,8 +523,8 @@ public class TabletLocatorImpl extends T
     return null;
   }
   
-  protected TabletLocation _locateTablet(Text row, boolean skipRow, boolean retry, boolean lock, TCredentials credentials) throws AccumuloException, AccumuloSecurityException,
-      TableNotFoundException {
+  protected TabletLocation _locateTablet(Text row, boolean skipRow, boolean retry, boolean lock, TCredentials credentials) throws AccumuloException,
+      AccumuloSecurityException, TableNotFoundException {
     
     if (skipRow) {
       row = new Text(row);

Modified: accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TabletServerBatchWriter.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TabletServerBatchWriter.java?rev=1496171&r1=1496170&r2=1496171&view=diff
==============================================================================
--- accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TabletServerBatchWriter.java (original)
+++ accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TabletServerBatchWriter.java Mon Jun 24 19:29:39 2013
@@ -211,6 +211,7 @@ public class TabletServerBatchWriter {
     
     if (this.maxLatency != Long.MAX_VALUE) {
       jtimer.schedule(new TimerTask() {
+        @Override
         public void run() {
           try {
             synchronized (TabletServerBatchWriter.this) {
@@ -460,9 +461,9 @@ public class TabletServerBatchWriter {
       }
     }
   }
-
+  
   private void updateAuthorizationFailures(Set<KeyExtent> keySet, SecurityErrorCode code) {
-    HashMap<KeyExtent, SecurityErrorCode> map = new HashMap<KeyExtent, SecurityErrorCode>();
+    HashMap<KeyExtent,SecurityErrorCode> map = new HashMap<KeyExtent,SecurityErrorCode>();
     for (KeyExtent ke : keySet)
       map.put(ke, code);
     
@@ -543,9 +544,6 @@ public class TabletServerBatchWriter {
   
   /**
    * Add mutations that previously failed back into the mix
-   * 
-   * @param failedMutations
-   *          static final Logger log = Logger.getLogger(TabletServerBatchWriter.class);
    */
   private synchronized void addFailedMutations(MutationSet failedMutations) throws Exception {
     mutations.addAll(failedMutations);
@@ -601,11 +599,11 @@ public class TabletServerBatchWriter {
         
         if (rf != null) {
           if (log.isTraceEnabled())
-            log.trace("requeuing " + rf.size() + " failed mutations");
+            log.trace("tid=" + Thread.currentThread().getId() + "  Requeuing " + rf.size() + " failed mutations");
           addFailedMutations(rf);
         }
       } catch (Throwable t) {
-        updateUnknownErrors("Failed to requeue failed mutations " + t.getMessage(), t);
+        updateUnknownErrors("tid=" + Thread.currentThread().getId() + "  Failed to requeue failed mutations " + t.getMessage(), t);
         cancel();
       }
     }

Modified: accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TimeoutTabletLocator.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TimeoutTabletLocator.java?rev=1496171&r1=1496170&r2=1496171&view=diff
==============================================================================
--- accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TimeoutTabletLocator.java (original)
+++ accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/impl/TimeoutTabletLocator.java Mon Jun 24 19:29:39 2013
@@ -55,9 +55,10 @@ public class TimeoutTabletLocator extend
     this.locator = locator;
     this.timeout = timeout;
   }
-
+  
   @Override
-  public TabletLocation locateTablet(Text row, boolean skipRow, boolean retry, TCredentials credentials) throws AccumuloException, AccumuloSecurityException, TableNotFoundException {
+  public TabletLocation locateTablet(Text row, boolean skipRow, boolean retry, TCredentials credentials) throws AccumuloException, AccumuloSecurityException,
+      TableNotFoundException {
     
     try {
       TabletLocation ret = locator.locateTablet(row, skipRow, retry, credentials);
@@ -75,16 +76,16 @@ public class TimeoutTabletLocator extend
   }
   
   @Override
-  public void binMutations(List<Mutation> mutations, Map<String,TabletServerMutations> binnedMutations, List<Mutation> failures, TCredentials credentials) throws AccumuloException,
-      AccumuloSecurityException, TableNotFoundException {
+  public void binMutations(List<Mutation> mutations, Map<String,TabletServerMutations> binnedMutations, List<Mutation> failures, TCredentials credentials)
+      throws AccumuloException, AccumuloSecurityException, TableNotFoundException {
     try {
       locator.binMutations(mutations, binnedMutations, failures, credentials);
-
+      
       if (failures.size() == mutations.size())
         failed();
       else
         succeeded();
-
+      
     } catch (AccumuloException ae) {
       failed();
       throw ae;
@@ -94,10 +95,10 @@ public class TimeoutTabletLocator extend
   /**
    * 
    */
-
+  
   @Override
-  public List<Range> binRanges(List<Range> ranges, Map<String,Map<KeyExtent,List<Range>>> binnedRanges, TCredentials credentials) throws AccumuloException, AccumuloSecurityException,
-      TableNotFoundException {
+  public List<Range> binRanges(List<Range> ranges, Map<String,Map<KeyExtent,List<Range>>> binnedRanges, TCredentials credentials) throws AccumuloException,
+      AccumuloSecurityException, TableNotFoundException {
     
     try {
       List<Range> ret = locator.binRanges(ranges, binnedRanges, credentials);

Modified: accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/mock/MockAccumulo.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/mock/MockAccumulo.java?rev=1496171&r1=1496170&r2=1496171&view=diff
==============================================================================
--- accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/mock/MockAccumulo.java (original)
+++ accumulo/trunk/core/src/main/java/org/apache/accumulo/core/client/mock/MockAccumulo.java Mon Jun 24 19:29:39 2013
@@ -30,6 +30,7 @@ import org.apache.accumulo.core.security
 import org.apache.accumulo.core.security.SystemPermission;
 import org.apache.accumulo.core.security.TablePermission;
 import org.apache.accumulo.core.util.MetadataTable;
+import org.apache.accumulo.core.util.RootTable;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.io.Text;
 
@@ -47,6 +48,7 @@ public class MockAccumulo {
     MockUser root = new MockUser("root", new PasswordToken(new byte[0]), Authorizations.EMPTY);
     root.permissions.add(SystemPermission.SYSTEM);
     users.put(root.name, root);
+    createTable("root", RootTable.NAME, true, TimeType.LOGICAL);
     createTable("root", MetadataTable.NAME, true, TimeType.LOGICAL);
   }
   

Modified: accumulo/trunk/core/src/main/java/org/apache/accumulo/core/data/KeyExtent.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/core/src/main/java/org/apache/accumulo/core/data/KeyExtent.java?rev=1496171&r1=1496170&r2=1496171&view=diff
==============================================================================
--- accumulo/trunk/core/src/main/java/org/apache/accumulo/core/data/KeyExtent.java (original)
+++ accumulo/trunk/core/src/main/java/org/apache/accumulo/core/data/KeyExtent.java Mon Jun 24 19:29:39 2013
@@ -251,6 +251,7 @@ public class KeyExtent implements Writab
    * Populates the extents data fields from a DataInput object
    * 
    */
+  @Override
   public void readFields(DataInput in) throws IOException {
     Text tid = new Text();
     tid.readFields(in);
@@ -280,6 +281,7 @@ public class KeyExtent implements Writab
    * Writes this extent's data fields to a DataOutput object
    * 
    */
+  @Override
   public void write(DataOutput out) throws IOException {
     getTableId().write(out);
     if (getEndRow() != null) {
@@ -404,6 +406,7 @@ public class KeyExtent implements Writab
    * Compares extents based on rows
    * 
    */
+  @Override
   public int compareTo(KeyExtent other) {
     
     int result = getTableId().compareTo(other.getTableId());
@@ -755,9 +758,6 @@ public class KeyExtent implements Writab
         : TextUtil.getByteBuffer(textPrevEndRow));
   }
   
-  /**
-   * @param prevExtent
-   */
   public boolean isPreviousExtent(KeyExtent prevExtent) {
     if (prevExtent == null)
       return getPrevEndRow() == null;
@@ -775,10 +775,10 @@ public class KeyExtent implements Writab
   }
   
   public boolean isMeta() {
-    return getTableId().toString().equals(MetadataTable.ID);
+    return getTableId().toString().equals(MetadataTable.ID) || isRootTablet();
   }
   
   public boolean isRootTablet() {
-    return this.compareTo(RootTable.ROOT_TABLET_EXTENT) == 0;
+    return getTableId().toString().equals(RootTable.ID);
   }
 }

Modified: accumulo/trunk/core/src/main/java/org/apache/accumulo/core/iterators/OptionDescriber.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/core/src/main/java/org/apache/accumulo/core/iterators/OptionDescriber.java?rev=1496171&r1=1496170&r2=1496171&view=diff
==============================================================================
--- accumulo/trunk/core/src/main/java/org/apache/accumulo/core/iterators/OptionDescriber.java (original)
+++ accumulo/trunk/core/src/main/java/org/apache/accumulo/core/iterators/OptionDescriber.java Mon Jun 24 19:29:39 2013
@@ -51,7 +51,7 @@ public interface OptionDescriber {
      *          is a list of descriptions of additional options that don't have fixed names (null if unused). The descriptions are intended to describe a
      *          category, and the user will provide parameter names and values in that category; e.g., the FilteringIterator needs a list of Filters intended to
      *          be named by their priority numbers, so its unnamedOptionDescriptions =
-     *          Collections.singletonList("<filterPriorityNumber> <ageoff|regex|filterClass>")
+     *          Collections.singletonList("&lt;filterPriorityNumber&gt; &lt;ageoff|regex|filterClass&gt;")
      */
     public IteratorOptions(String name, String description, Map<String,String> namedOptions, List<String> unnamedOptionDescriptions) {
       this.name = name;

Modified: accumulo/trunk/core/src/main/java/org/apache/accumulo/core/util/MetadataTable.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/core/src/main/java/org/apache/accumulo/core/util/MetadataTable.java?rev=1496171&r1=1496170&r2=1496171&view=diff
==============================================================================
--- accumulo/trunk/core/src/main/java/org/apache/accumulo/core/util/MetadataTable.java (original)
+++ accumulo/trunk/core/src/main/java/org/apache/accumulo/core/util/MetadataTable.java Mon Jun 24 19:29:39 2013
@@ -55,9 +55,10 @@ public class MetadataTable {
   /**
    * Reserved keyspace is any row that begins with a tilde '~' character
    */
-  public static final Key RESERVED_KEYSPACE_START_KEY = new Key(new Text(new byte[] {'~'}));
-  public static final String DELETE_FLAG_PREFIX = "~del";
-  public static final Range DELETES_KEYSPACE = new Range(new Key(new Text(DELETE_FLAG_PREFIX)), true, new Key(new Text("~dem")), false);
+  public static final Key RESERVED_RANGE_START_KEY = new Key(new Text(new byte[] {'~'}));
+  public static final Range NON_ROOT_KEYSPACE = new Range(null, false, RESERVED_RANGE_START_KEY, false);
+  public static final Range KEYSPACE = new Range(new Key(new Text(ID)), true, RESERVED_RANGE_START_KEY, false);
+  public static final Range DELETED_RANGE = new Range(new Key(new Text("~del")), true, new Key(new Text("~dem")), false);
   public static final String BLIP_FLAG_PREFIX = "~blip"; // BLIP = bulk load in progress
   public static final Range BLIP_KEYSPACE = new Range(new Key(new Text(BLIP_FLAG_PREFIX)), true, new Key(new Text("~bliq")), false);
   
@@ -101,10 +102,6 @@ public class MetadataTable {
   public static final Text CHOPPED_COLUMN_FAMILY = new Text("chopped");
   public static final ColumnFQ CHOPPED_COLUMN = new ColumnFQ(CHOPPED_COLUMN_FAMILY, new Text("chopped"));
   
-  public static final Range NON_ROOT_KEYSPACE = new Range(new Key(KeyExtent.getMetadataEntry(new Text(ID), null)).followingKey(PartialKey.ROW), true,
-      RESERVED_KEYSPACE_START_KEY, false);
-  public static final Range KEYSPACE = new Range(new Key(new Text(ID)), true, RESERVED_KEYSPACE_START_KEY, false);
-  
   public static class DataFileValue {
     private long size;
     private long numEntries;
@@ -270,7 +267,9 @@ public class MetadataTable {
       SortedSet<KeyExtent> tablets) throws AccumuloException, AccumuloSecurityException, TableNotFoundException {
     String tableId = isTid ? table : Tables.getNameToIdMap(instance).get(table);
     
-    Scanner scanner = instance.getConnector(credentials.getPrincipal(), CredentialHelper.extractToken(credentials)).createScanner(NAME, Authorizations.EMPTY);
+    String systemTableToRead = tableId.equals(ID) ? RootTable.NAME : NAME;
+    Scanner scanner = instance.getConnector(credentials.getPrincipal(), CredentialHelper.extractToken(credentials)).createScanner(systemTableToRead,
+        Authorizations.EMPTY);
     
     PREV_ROW_COLUMN.fetch(scanner);
     scanner.fetchColumnFamily(CURRENT_LOCATION_COLUMN_FAMILY);

Modified: accumulo/trunk/core/src/main/java/org/apache/accumulo/core/util/RootTable.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/core/src/main/java/org/apache/accumulo/core/util/RootTable.java?rev=1496171&r1=1496170&r2=1496171&view=diff
==============================================================================
--- accumulo/trunk/core/src/main/java/org/apache/accumulo/core/util/RootTable.java (original)
+++ accumulo/trunk/core/src/main/java/org/apache/accumulo/core/util/RootTable.java Mon Jun 24 19:29:39 2013
@@ -16,7 +16,6 @@
  */
 package org.apache.accumulo.core.util;
 
-import org.apache.accumulo.core.data.Key;
 import org.apache.accumulo.core.data.KeyExtent;
 import org.apache.accumulo.core.data.Range;
 import org.apache.hadoop.io.Text;
@@ -29,17 +28,15 @@ public class RootTable {
   public static final String ID = "!!R";
   public static final String NAME = "!!ROOT";
   
-  public static final String ZROOT_TABLET = "/root_tablet";
+  public static final String ROOT_TABLET_LOCATION = "/root_tablet";
+  
+  public static final String ZROOT_TABLET = ROOT_TABLET_LOCATION;
   public static final String ZROOT_TABLET_LOCATION = ZROOT_TABLET + "/location";
   public static final String ZROOT_TABLET_FUTURE_LOCATION = ZROOT_TABLET + "/future_location";
   public static final String ZROOT_TABLET_LAST_LOCATION = ZROOT_TABLET + "/lastlocation";
   public static final String ZROOT_TABLET_WALOGS = ZROOT_TABLET + "/walogs";
   
-  public static final String DELETE_FLAG_PREFIX = "!!" + MetadataTable.DELETE_FLAG_PREFIX;
-  public static final Range DELETES_KEYSPACE = new Range(new Key(new Text(DELETE_FLAG_PREFIX)), true, new Key(new Text("!!~dem")), false);
-  public static final KeyExtent ROOT_TABLET_EXTENT = new KeyExtent(new Text(MetadataTable.ID), KeyExtent.getMetadataEntry(new Text(MetadataTable.ID), null),
-      null);
-  public static final Range KEYSPACE = new Range(ROOT_TABLET_EXTENT.getMetadataEntry(), false, KeyExtent.getMetadataEntry(new Text(
-      MetadataTable.ID), null), true);
+  public static final KeyExtent EXTENT = new KeyExtent(new Text(ID), null, null);
+  public static final Range METADATA_TABLETS_RANGE = new Range(null, false, MetadataTable.RESERVED_RANGE_START_KEY, false);
   
 }

Modified: accumulo/trunk/core/src/main/java/org/apache/accumulo/core/util/shell/commands/GetSplitsCommand.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/core/src/main/java/org/apache/accumulo/core/util/shell/commands/GetSplitsCommand.java?rev=1496171&r1=1496170&r2=1496171&view=diff
==============================================================================
--- accumulo/trunk/core/src/main/java/org/apache/accumulo/core/util/shell/commands/GetSplitsCommand.java (original)
+++ accumulo/trunk/core/src/main/java/org/apache/accumulo/core/util/shell/commands/GetSplitsCommand.java Mon Jun 24 19:29:39 2013
@@ -32,6 +32,7 @@ import org.apache.accumulo.core.data.Ran
 import org.apache.accumulo.core.data.Value;
 import org.apache.accumulo.core.security.Authorizations;
 import org.apache.accumulo.core.util.MetadataTable;
+import org.apache.accumulo.core.util.RootTable;
 import org.apache.accumulo.core.util.TextUtil;
 import org.apache.accumulo.core.util.format.BinaryFormatter;
 import org.apache.accumulo.core.util.shell.Shell;
@@ -69,7 +70,8 @@ public class GetSplitsCommand extends Co
           p.print(encode(encode, row));
         }
       } else {
-        final Scanner scanner = shellState.getConnector().createScanner(MetadataTable.NAME, Authorizations.EMPTY);
+        String systemTableToCheck = MetadataTable.NAME.equals(tableName) ? RootTable.NAME : MetadataTable.NAME;
+        final Scanner scanner = shellState.getConnector().createScanner(systemTableToCheck, Authorizations.EMPTY);
         MetadataTable.PREV_ROW_COLUMN.fetch(scanner);
         final Text start = new Text(shellState.getConnector().tableOperations().tableIdMap().get(tableName));
         final Text end = new Text(start);

Modified: accumulo/trunk/core/src/test/java/org/apache/accumulo/core/client/impl/TabletLocatorImplTest.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/core/src/test/java/org/apache/accumulo/core/client/impl/TabletLocatorImplTest.java?rev=1496171&r1=1496170&r2=1496171&view=diff
==============================================================================
--- accumulo/trunk/core/src/test/java/org/apache/accumulo/core/client/impl/TabletLocatorImplTest.java (original)
+++ accumulo/trunk/core/src/test/java/org/apache/accumulo/core/client/impl/TabletLocatorImplTest.java Mon Jun 24 19:29:39 2013
@@ -55,7 +55,7 @@ import org.apache.hadoop.io.Text;
 
 public class TabletLocatorImplTest extends TestCase {
   
-  private static final KeyExtent RTE = RootTable.ROOT_TABLET_EXTENT;
+  private static final KeyExtent RTE = RootTable.EXTENT;
   private static final KeyExtent MTE = new KeyExtent(new Text(MetadataTable.ID), null, RTE.getEndRow());
   private static TCredentials credential = null;
   

Modified: accumulo/trunk/core/src/test/java/org/apache/accumulo/core/util/MetadataTableTest.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/core/src/test/java/org/apache/accumulo/core/util/MetadataTableTest.java?rev=1496171&r1=1496170&r2=1496171&view=diff
==============================================================================
--- accumulo/trunk/core/src/test/java/org/apache/accumulo/core/util/MetadataTableTest.java (original)
+++ accumulo/trunk/core/src/test/java/org/apache/accumulo/core/util/MetadataTableTest.java Mon Jun 24 19:29:39 2013
@@ -16,15 +16,24 @@
  */
 package org.apache.accumulo.core.util;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
 import java.util.SortedSet;
 import java.util.TreeSet;
 
-import junit.framework.TestCase;
-
 import org.apache.accumulo.core.data.KeyExtent;
 import org.apache.hadoop.io.Text;
+import org.junit.Test;
 
-public class MetadataTableTest extends TestCase {
+public class MetadataTableTest {
+  
+  @Test
+  public void checkSystemTableIdentifiers() {
+    assertNotEquals(RootTable.ID, MetadataTable.ID);
+    assertNotEquals(RootTable.NAME, MetadataTable.NAME);
+  }
   
   private KeyExtent createKeyExtent(String tname, String er, String per) {
     return new KeyExtent(new Text(tname), er == null ? null : new Text(er), per == null ? null : new Text(per));
@@ -90,6 +99,7 @@ public class MetadataTableTest extends T
     
   }
   
+  @Test
   public void testICR1() {
     runTest(null, null);
     runTest(null, "r4");

Modified: accumulo/trunk/server/src/main/java/org/apache/accumulo/server/ServerConstants.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/server/src/main/java/org/apache/accumulo/server/ServerConstants.java?rev=1496171&r1=1496170&r2=1496171&view=diff
==============================================================================
--- accumulo/trunk/server/src/main/java/org/apache/accumulo/server/ServerConstants.java (original)
+++ accumulo/trunk/server/src/main/java/org/apache/accumulo/server/ServerConstants.java Mon Jun 24 19:29:39 2013
@@ -38,13 +38,13 @@ public class ServerConstants {
     if (ns == null || ns.isEmpty()) {
       Configuration hadoopConfig = CachedConfiguration.getInstance();
       String fullPath = hadoopConfig.get("fs.default.name") + singleNamespace;
-      return new String[] { fullPath };
+      return new String[] {fullPath};
     }
     String namespaces[] = ns.split(",");
     if (namespaces.length < 2) {
       Configuration hadoopConfig = CachedConfiguration.getInstance();
       String fullPath = hadoopConfig.get("fs.default.name") + singleNamespace;
-      return new String[] { fullPath };
+      return new String[] {fullPath};
     }
     return prefix(namespaces, singleNamespace);
   }
@@ -83,11 +83,15 @@ public class ServerConstants {
     return new Path(getBaseDirs()[0], "version");
   }
   
+  public static String[] getRootTableDirs() {
+    return prefix(getTablesDirs(), RootTable.ID);
+  }
+  
   public static String[] getMetadataTableDirs() {
     return prefix(getTablesDirs(), MetadataTable.ID);
   }
   
   public static String getRootTabletDir() {
-    return prefix(getMetadataTableDirs(), RootTable.ZROOT_TABLET)[0];
+    return prefix(getRootTableDirs(), RootTable.ZROOT_TABLET)[0];
   }
 }

Modified: accumulo/trunk/server/src/main/java/org/apache/accumulo/server/gc/SimpleGarbageCollector.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/server/src/main/java/org/apache/accumulo/server/gc/SimpleGarbageCollector.java?rev=1496171&r1=1496170&r2=1496171&view=diff
==============================================================================
--- accumulo/trunk/server/src/main/java/org/apache/accumulo/server/gc/SimpleGarbageCollector.java (original)
+++ accumulo/trunk/server/src/main/java/org/apache/accumulo/server/gc/SimpleGarbageCollector.java Mon Jun 24 19:29:39 2013
@@ -67,7 +67,6 @@ import org.apache.accumulo.core.security
 import org.apache.accumulo.core.security.thrift.TCredentials;
 import org.apache.accumulo.core.util.MetadataTable;
 import org.apache.accumulo.core.util.NamingThreadFactory;
-import org.apache.accumulo.core.util.RootTable;
 import org.apache.accumulo.core.util.ServerServices;
 import org.apache.accumulo.core.util.ServerServices.Service;
 import org.apache.accumulo.core.util.UtilWaitThread;
@@ -366,17 +365,17 @@ public class SimpleGarbageCollector impl
         try {
           tabletDirs = fs.listStatus(new Path(dir + "/" + delTableId));
         } catch (FileNotFoundException ex) {
-          // ignored 
+          // ignored
         }
         if (tabletDirs == null)
           continue;
         
         if (tabletDirs.length == 0) {
           Path p = new Path(dir + "/" + delTableId);
-          if (!moveToTrash(p)) 
+          if (!moveToTrash(p))
             fs.delete(p);
         }
-      } 
+      }
     }
   }
   
@@ -453,13 +452,13 @@ public class SimpleGarbageCollector impl
     }
     
     checkForBulkProcessingFiles = false;
-    Range range = RootTable.DELETES_KEYSPACE;
-    candidates.addAll(getBatch(RootTable.DELETE_FLAG_PREFIX, range));
+    Range range = MetadataTable.DELETED_RANGE;
+    candidates.addAll(getBatch(MetadataTable.DELETED_RANGE.getStartKey().getRow().toString(), range));
     if (candidateMemExceeded)
       return candidates;
     
-    range = MetadataTable.DELETES_KEYSPACE;
-    candidates.addAll(getBatch(MetadataTable.DELETE_FLAG_PREFIX, range));
+    range = MetadataTable.DELETED_RANGE;
+    candidates.addAll(getBatch(MetadataTable.DELETED_RANGE.getStartKey().getRow().toString(), range));
     return candidates;
   }
   
@@ -475,8 +474,8 @@ public class SimpleGarbageCollector impl
       continueKey = null;
     }
     
-    Scanner scanner = instance.getConnector(credentials.getPrincipal(), CredentialHelper.extractToken(credentials)).createScanner(
-        MetadataTable.NAME, Authorizations.EMPTY);
+    Scanner scanner = instance.getConnector(credentials.getPrincipal(), CredentialHelper.extractToken(credentials)).createScanner(MetadataTable.NAME,
+        Authorizations.EMPTY);
     scanner.setRange(range);
     List<String> result = new ArrayList<String>();
     // find candidates for deletion; chop off the prefix
@@ -510,11 +509,11 @@ public class SimpleGarbageCollector impl
     if (offline) {
       // TODO
       throw new RuntimeException("Offline scanner no longer supported");
-//      try {
-//        scanner = new OfflineMetadataScanner(instance.getConfiguration(), fs);
-//      } catch (IOException e) {
-//        throw new IllegalStateException("Unable to create offline metadata scanner", e);
-//      }
+      // try {
+      // scanner = new OfflineMetadataScanner(instance.getConfiguration(), fs);
+      // } catch (IOException e) {
+      // throw new IllegalStateException("Unable to create offline metadata scanner", e);
+      // }
     } else {
       try {
         scanner = new IsolatedScanner(instance.getConnector(credentials.getPrincipal(), CredentialHelper.extractToken(credentials)).createScanner(
@@ -607,11 +606,11 @@ public class SimpleGarbageCollector impl
   
   private static void putMarkerDeleteMutation(final String delete, final BatchWriter writer, final BatchWriter rootWriter) throws MutationsRejectedException {
     if (delete.contains(METADATA_TABLE_DIR)) {
-      Mutation m = new Mutation(new Text(RootTable.DELETE_FLAG_PREFIX + delete));
+      Mutation m = new Mutation(new Text(MetadataTable.DELETED_RANGE.getStartKey().getRow().toString() + delete));
       m.putDelete(EMPTY_TEXT, EMPTY_TEXT);
       rootWriter.addMutation(m);
     } else {
-      Mutation m = new Mutation(new Text(MetadataTable.DELETE_FLAG_PREFIX + delete));
+      Mutation m = new Mutation(new Text(MetadataTable.DELETED_RANGE.getStartKey().getRow().toString() + delete));
       m.putDelete(EMPTY_TEXT, EMPTY_TEXT);
       writer.addMutation(m);
     }
@@ -674,7 +673,7 @@ public class SimpleGarbageCollector impl
           
           try {
             Path fullPath;
-
+            
             if (delete.contains(":"))
               fullPath = new Path(delete);
             else

Modified: accumulo/trunk/server/src/main/java/org/apache/accumulo/server/master/Master.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/server/src/main/java/org/apache/accumulo/server/master/Master.java?rev=1496171&r1=1496170&r2=1496171&view=diff
==============================================================================
--- accumulo/trunk/server/src/main/java/org/apache/accumulo/server/master/Master.java (original)
+++ accumulo/trunk/server/src/main/java/org/apache/accumulo/server/master/Master.java Mon Jun 24 19:29:39 2013
@@ -16,8 +16,6 @@
  */
 package org.apache.accumulo.server.master;
 
-import static java.lang.Math.min;
-
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.nio.ByteBuffer;
@@ -33,20 +31,16 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
-import java.util.TreeSet;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.accumulo.core.Constants;
 import org.apache.accumulo.core.client.AccumuloException;
 import org.apache.accumulo.core.client.AccumuloSecurityException;
-import org.apache.accumulo.core.client.BatchWriter;
-import org.apache.accumulo.core.client.BatchWriterConfig;
 import org.apache.accumulo.core.client.Connector;
 import org.apache.accumulo.core.client.Instance;
 import org.apache.accumulo.core.client.IsolatedScanner;
 import org.apache.accumulo.core.client.IteratorSetting;
-import org.apache.accumulo.core.client.MutationsRejectedException;
 import org.apache.accumulo.core.client.RowIterator;
 import org.apache.accumulo.core.client.Scanner;
 import org.apache.accumulo.core.client.TableNotFoundException;
@@ -61,9 +55,6 @@ import org.apache.accumulo.core.conf.Acc
 import org.apache.accumulo.core.conf.Property;
 import org.apache.accumulo.core.data.Key;
 import org.apache.accumulo.core.data.KeyExtent;
-import org.apache.accumulo.core.data.Mutation;
-import org.apache.accumulo.core.data.PartialKey;
-import org.apache.accumulo.core.data.Range;
 import org.apache.accumulo.core.data.Value;
 import org.apache.accumulo.core.data.thrift.TKeyExtent;
 import org.apache.accumulo.core.iterators.IteratorUtil;
@@ -81,7 +72,6 @@ import org.apache.accumulo.core.master.t
 import org.apache.accumulo.core.security.Authorizations;
 import org.apache.accumulo.core.security.SecurityUtil;
 import org.apache.accumulo.core.security.thrift.TCredentials;
-import org.apache.accumulo.core.tabletserver.thrift.NotServingTabletException;
 import org.apache.accumulo.core.util.ByteBufferUtil;
 import org.apache.accumulo.core.util.Daemon;
 import org.apache.accumulo.core.util.RootTable;
@@ -99,30 +89,24 @@ import org.apache.accumulo.server.Accumu
 import org.apache.accumulo.server.ServerConstants;
 import org.apache.accumulo.server.client.HdfsZooInstance;
 import org.apache.accumulo.server.conf.ServerConfiguration;
-import org.apache.accumulo.server.fs.FileRef;
 import org.apache.accumulo.server.fs.VolumeManager;
 import org.apache.accumulo.server.fs.VolumeManagerImpl;
 import org.apache.accumulo.server.master.LiveTServerSet.TServerConnection;
 import org.apache.accumulo.server.master.balancer.DefaultLoadBalancer;
 import org.apache.accumulo.server.master.balancer.TabletBalancer;
 import org.apache.accumulo.server.master.recovery.RecoveryManager;
-import org.apache.accumulo.server.master.state.Assignment;
 import org.apache.accumulo.server.master.state.CurrentState;
 import org.apache.accumulo.server.master.state.DeadServerList;
-import org.apache.accumulo.server.master.state.DistributedStoreException;
 import org.apache.accumulo.server.master.state.MergeInfo;
 import org.apache.accumulo.server.master.state.MergeState;
-import org.apache.accumulo.server.master.state.MergeStats;
 import org.apache.accumulo.server.master.state.MetaDataStateStore;
 import org.apache.accumulo.server.master.state.RootTabletStateStore;
 import org.apache.accumulo.server.master.state.TServerInstance;
 import org.apache.accumulo.server.master.state.TableCounts;
-import org.apache.accumulo.server.master.state.TableStats;
 import org.apache.accumulo.server.master.state.TabletLocationState;
 import org.apache.accumulo.server.master.state.TabletMigration;
 import org.apache.accumulo.server.master.state.TabletServerState;
 import org.apache.accumulo.server.master.state.TabletState;
-import org.apache.accumulo.server.master.state.TabletStateStore;
 import org.apache.accumulo.server.master.state.ZooStore;
 import org.apache.accumulo.server.master.state.ZooTabletStateStore;
 import org.apache.accumulo.server.master.state.tables.TableManager;
@@ -144,7 +128,6 @@ import org.apache.accumulo.server.monito
 import org.apache.accumulo.server.security.AuditedSecurityOperation;
 import org.apache.accumulo.server.security.SecurityConstants;
 import org.apache.accumulo.server.security.SecurityOperation;
-import org.apache.accumulo.server.tabletserver.TabletTime;
 import org.apache.accumulo.server.util.AddressUtil;
 import org.apache.accumulo.server.util.DefaultMap;
 import org.apache.accumulo.server.util.Halt;
@@ -179,42 +162,41 @@ import org.apache.zookeeper.data.Stat;
  */
 public class Master implements LiveTServerSet.Listener, TableObserver, CurrentState {
   
-  final private static Logger log = Logger.getLogger(Master.class);
+  final static Logger log = Logger.getLogger(Master.class);
   
   final private static int ONE_SECOND = 1000;
   final private static Text METADATA_TABLE_ID = new Text(MetadataTable.ID);
-  final private static long TIME_TO_WAIT_BETWEEN_SCANS = 60 * ONE_SECOND;
+  final static long TIME_TO_WAIT_BETWEEN_SCANS = 60 * ONE_SECOND;
   final private static long TIME_BETWEEN_MIGRATION_CLEANUPS = 5 * 60 * ONE_SECOND;
-  final private static long WAIT_BETWEEN_ERRORS = ONE_SECOND;
+  final static long WAIT_BETWEEN_ERRORS = ONE_SECOND;
   final private static long DEFAULT_WAIT_FOR_WATCHER = 10 * ONE_SECOND;
-  final private static int MAX_CLEANUP_WAIT_TIME = 1000;
-  final private static int TIME_TO_WAIT_BETWEEN_LOCK_CHECKS = 1000;
-  final private static int MAX_TSERVER_WORK_CHUNK = 5000;
+  final private static int MAX_CLEANUP_WAIT_TIME = ONE_SECOND;
+  final private static int TIME_TO_WAIT_BETWEEN_LOCK_CHECKS = ONE_SECOND;
+  final static int MAX_TSERVER_WORK_CHUNK = 5 * ONE_SECOND;
   final private static int MAX_BAD_STATUS_COUNT = 3;
   
-  final private VolumeManager fs;
+  final VolumeManager fs;
   final private Instance instance;
   final private String hostname;
-  final private LiveTServerSet tserverSet;
+  final LiveTServerSet tserverSet;
   final private List<TabletGroupWatcher> watchers = new ArrayList<TabletGroupWatcher>();
   final private SecurityOperation security;
   final private Map<TServerInstance,AtomicInteger> badServers = Collections.synchronizedMap(new DefaultMap<TServerInstance,AtomicInteger>(new AtomicInteger()));
-  final private Set<TServerInstance> serversToShutdown = Collections.synchronizedSet(new HashSet<TServerInstance>());
-  final private SortedMap<KeyExtent,TServerInstance> migrations = Collections.synchronizedSortedMap(new TreeMap<KeyExtent,TServerInstance>());
-  final private EventCoordinator nextEvent = new EventCoordinator();
+  final Set<TServerInstance> serversToShutdown = Collections.synchronizedSet(new HashSet<TServerInstance>());
+  final SortedMap<KeyExtent,TServerInstance> migrations = Collections.synchronizedSortedMap(new TreeMap<KeyExtent,TServerInstance>());
+  final EventCoordinator nextEvent = new EventCoordinator();
   final private Object mergeLock = new Object();
-  private RecoveryManager recoveryManager = null;
+  RecoveryManager recoveryManager = null;
   
-  private ZooLock masterLock = null;
+  ZooLock masterLock = null;
   private TServer clientService = null;
-  private TabletBalancer tabletBalancer;
+  TabletBalancer tabletBalancer;
   
   private MasterState state = MasterState.INITIAL;
   
   private Fate<Master> fate;
   
-  volatile private SortedMap<TServerInstance,TabletServerStatus> tserverStatus = Collections
-      .unmodifiableSortedMap(new TreeMap<TServerInstance,TabletServerStatus>());
+  volatile SortedMap<TServerInstance,TabletServerStatus> tserverStatus = Collections.unmodifiableSortedMap(new TreeMap<TServerInstance,TabletServerStatus>());
   
   private final Set<String> recoveriesInProgress = Collections.synchronizedSet(new HashSet<String>());
   
@@ -346,7 +328,7 @@ public class Master implements LiveTServ
   }
   
   private int nonMetaDataTabletsAssignedOrHosted() {
-    return totalAssignedOrHosted() - assignedOrHosted(new Text(MetadataTable.ID));
+    return totalAssignedOrHosted() - assignedOrHosted(new Text(MetadataTable.ID)) - assignedOrHosted(new Text(RootTable.ID));
   }
   
   private int notHosted() {
@@ -917,13 +899,9 @@ public class Master implements LiveTServ
           Text startRow = ByteBufferUtil.toText(arguments.get(1));
           Text endRow = ByteBufferUtil.toText(arguments.get(2));
           final String tableId = checkTableId(tableName, TableOperation.MERGE);
-          if (tableName.equals(MetadataTable.NAME)) {
-            if (startRow.compareTo(new Text("0")) < 0) {
-              startRow = new Text("0");
-              if (endRow.getLength() != 0 && endRow.compareTo(startRow) < 0)
-                throw new ThriftTableOperationException(null, tableName, TableOperation.MERGE, TableOperationExceptionType.OTHER,
-                    "end-row specification is in the root tablet, which cannot be merged or split");
-            }
+          if (tableId.equals(RootTable.ID)) {
+            throw new ThriftTableOperationException(null, tableName, TableOperation.MERGE, TableOperationExceptionType.OTHER,
+                "cannot merge or split the root table");
           }
           log.debug("Creating merge op: " + tableId + " " + startRow + " " + endRow);
           
@@ -1078,7 +1056,7 @@ public class Master implements LiveTServ
   
   public void setMergeState(MergeInfo info, MergeState state) throws IOException, KeeperException, InterruptedException {
     synchronized (mergeLock) {
-      String path = ZooUtil.getRoot(instance.getInstanceID()) + Constants.ZTABLES + "/" + info.getRange().getTableId().toString() + "/merge";
+      String path = ZooUtil.getRoot(instance.getInstanceID()) + Constants.ZTABLES + "/" + info.getExtent().getTableId().toString() + "/merge";
       info.setState(state);
       if (state.equals(MergeState.NONE)) {
         ZooReaderWriter.getInstance().recursiveDelete(path, NodeMissingPolicy.SKIP);
@@ -1094,7 +1072,7 @@ public class Master implements LiveTServ
       }
       mergeLock.notifyAll();
     }
-    nextEvent.event("Merge state of %s set to %s", info.getRange(), state);
+    nextEvent.event("Merge state of %s set to %s", info.getExtent(), state);
   }
   
   public void clearMergeState(Text tableId) throws IOException, KeeperException, InterruptedException {
@@ -1180,9 +1158,9 @@ public class Master implements LiveTServ
         return TabletGoalState.UNASSIGNED;
       case STOP:
         return TabletGoalState.UNASSIGNED;
+      default:
+        throw new IllegalStateException("Unknown Master State");
     }
-    // unreachable
-    return TabletGoalState.HOSTED;
   }
   
   TabletGoalState getTableGoalState(KeyExtent extent) {
@@ -1209,7 +1187,7 @@ public class Master implements LiveTServ
         return TabletGoalState.UNASSIGNED;
       }
       // Handle merge transitions
-      if (mergeInfo.getRange() != null) {
+      if (mergeInfo.getExtent() != null) {
         log.debug("mergeInfo overlaps: " + extent + " " + mergeInfo.overlaps(extent));
         if (mergeInfo.overlaps(extent)) {
           switch (mergeInfo.getState()) {
@@ -1249,580 +1227,6 @@ public class Master implements LiveTServ
     return state;
   }
   
-  private class TabletGroupWatcher extends Daemon {
-    
-    final TabletStateStore store;
-    final TabletGroupWatcher dependentWatcher;
-    
-    final TableStats stats = new TableStats();
-    
-    TabletGroupWatcher(TabletStateStore store, TabletGroupWatcher dependentWatcher) {
-      this.store = store;
-      this.dependentWatcher = dependentWatcher;
-    }
-    
-    Map<Text,TableCounts> getStats() {
-      return stats.getLast();
-    }
-    
-    TableCounts getStats(Text tableId) {
-      return stats.getLast(tableId);
-    }
-    
-    @Override
-    public void run() {
-      
-      Thread.currentThread().setName("Watching " + store.name());
-      int[] oldCounts = new int[TabletState.values().length];
-      EventCoordinator.Listener eventListener = nextEvent.getListener();
-      
-      while (stillMaster()) {
-        int totalUnloaded = 0;
-        int unloaded = 0;
-        try {
-          Map<Text,MergeStats> mergeStatsCache = new HashMap<Text,MergeStats>();
-          
-          // Get the current status for the current list of tservers
-          SortedMap<TServerInstance,TabletServerStatus> currentTServers = new TreeMap<TServerInstance,TabletServerStatus>();
-          for (TServerInstance entry : tserverSet.getCurrentServers()) {
-            currentTServers.put(entry, tserverStatus.get(entry));
-          }
-          
-          if (currentTServers.size() == 0) {
-            eventListener.waitForEvents(TIME_TO_WAIT_BETWEEN_SCANS);
-            continue;
-          }
-          
-          // Don't move tablets to servers that are shutting down
-          SortedMap<TServerInstance,TabletServerStatus> destinations = new TreeMap<TServerInstance,TabletServerStatus>(currentTServers);
-          destinations.keySet().removeAll(serversToShutdown);
-          
-          List<Assignment> assignments = new ArrayList<Assignment>();
-          List<Assignment> assigned = new ArrayList<Assignment>();
-          List<TabletLocationState> assignedToDeadServers = new ArrayList<TabletLocationState>();
-          Map<KeyExtent,TServerInstance> unassigned = new HashMap<KeyExtent,TServerInstance>();
-          
-          int[] counts = new int[TabletState.values().length];
-          stats.begin();
-          // Walk through the tablets in our store, and work tablets
-          // towards their goal
-          for (TabletLocationState tls : store) {
-            if (tls == null) {
-              continue;
-            }
-            // ignore entries for tables that do not exist in zookeeper
-            if (TableManager.getInstance().getTableState(tls.extent.getTableId().toString()) == null)
-              continue;
-            
-            // Don't overwhelm the tablet servers with work
-            if (unassigned.size() + unloaded > MAX_TSERVER_WORK_CHUNK * currentTServers.size()) {
-              flushChanges(destinations, assignments, assigned, assignedToDeadServers, unassigned);
-              assignments.clear();
-              assigned.clear();
-              assignedToDeadServers.clear();
-              unassigned.clear();
-              unloaded = 0;
-              eventListener.waitForEvents(TIME_TO_WAIT_BETWEEN_SCANS);
-            }
-            Text tableId = tls.extent.getTableId();
-            MergeStats mergeStats = mergeStatsCache.get(tableId);
-            if (mergeStats == null) {
-              mergeStatsCache.put(tableId, mergeStats = new MergeStats(getMergeInfo(tls.extent)));
-            }
-            TabletGoalState goal = getGoalState(tls, mergeStats.getMergeInfo());
-            TServerInstance server = tls.getServer();
-            TabletState state = tls.getState(currentTServers.keySet());
-            stats.update(tableId, state);
-            mergeStats.update(tls.extent, state, tls.chopped, !tls.walogs.isEmpty());
-            sendChopRequest(mergeStats.getMergeInfo(), state, tls);
-            sendSplitRequest(mergeStats.getMergeInfo(), state, tls);
-            
-            // Always follow through with assignments
-            if (state == TabletState.ASSIGNED) {
-              goal = TabletGoalState.HOSTED;
-            }
-            
-            // if we are shutting down all the tabletservers, we have to do it in order
-            if (goal == TabletGoalState.UNASSIGNED && state == TabletState.HOSTED) {
-              if (serversToShutdown.equals(currentTServers.keySet())) {
-                if (dependentWatcher != null && dependentWatcher.assignedOrHosted() > 0) {
-                  goal = TabletGoalState.HOSTED;
-                }
-              }
-            }
-            
-            if (goal == TabletGoalState.HOSTED) {
-              if (state != TabletState.HOSTED && !tls.walogs.isEmpty()) {
-                if (recoveryManager.recoverLogs(tls.extent, tls.walogs))
-                  continue;
-              }
-              switch (state) {
-                case HOSTED:
-                  if (server.equals(migrations.get(tls.extent)))
-                    migrations.remove(tls.extent);
-                  break;
-                case ASSIGNED_TO_DEAD_SERVER:
-                  assignedToDeadServers.add(tls);
-                  if (server.equals(migrations.get(tls.extent)))
-                    migrations.remove(tls.extent);
-                  // log.info("Current servers " + currentTServers.keySet());
-                  break;
-                case UNASSIGNED:
-                  // maybe it's a finishing migration
-                  TServerInstance dest = migrations.get(tls.extent);
-                  if (dest != null) {
-                    // if destination is still good, assign it
-                    if (destinations.keySet().contains(dest)) {
-                      assignments.add(new Assignment(tls.extent, dest));
-                    } else {
-                      // get rid of this migration
-                      migrations.remove(tls.extent);
-                      unassigned.put(tls.extent, server);
-                    }
-                  } else {
-                    unassigned.put(tls.extent, server);
-                  }
-                  break;
-                case ASSIGNED:
-                  // Send another reminder
-                  assigned.add(new Assignment(tls.extent, tls.future));
-                  break;
-              }
-            } else {
-              switch (state) {
-                case UNASSIGNED:
-                  break;
-                case ASSIGNED_TO_DEAD_SERVER:
-                  assignedToDeadServers.add(tls);
-                  // log.info("Current servers " + currentTServers.keySet());
-                  break;
-                case HOSTED:
-                  TServerConnection conn = tserverSet.getConnection(server);
-                  if (conn != null) {
-                    conn.unloadTablet(masterLock, tls.extent, goal != TabletGoalState.DELETED);
-                    unloaded++;
-                    totalUnloaded++;
-                  } else {
-                    log.warn("Could not connect to server " + server);
-                  }
-                  break;
-                case ASSIGNED:
-                  break;
-              }
-            }
-            counts[state.ordinal()]++;
-          }
-          
-          flushChanges(destinations, assignments, assigned, assignedToDeadServers, unassigned);
-          
-          // provide stats after flushing changes to avoid race conditions w/ delete table
-          stats.end();
-          
-          // Report changes
-          for (TabletState state : TabletState.values()) {
-            int i = state.ordinal();
-            if (counts[i] > 0 && counts[i] != oldCounts[i]) {
-              nextEvent.event("[%s]: %d tablets are %s", store.name(), counts[i], state.name());
-            }
-          }
-          log.debug(String.format("[%s]: scan time %.2f seconds", store.name(), stats.getScanTime() / 1000.));
-          oldCounts = counts;
-          if (totalUnloaded > 0) {
-            nextEvent.event("[%s]: %d tablets unloaded", store.name(), totalUnloaded);
-          }
-          
-          updateMergeState(mergeStatsCache);
-          
-          log.debug(String.format("[%s] sleeping for %.2f seconds", store.name(), TIME_TO_WAIT_BETWEEN_SCANS / 1000.));
-          eventListener.waitForEvents(TIME_TO_WAIT_BETWEEN_SCANS);
-        } catch (Exception ex) {
-          log.error("Error processing table state for store " + store.name(), ex);
-          UtilWaitThread.sleep(WAIT_BETWEEN_ERRORS);
-        }
-      }
-    }
-    
-    private int assignedOrHosted() {
-      int result = 0;
-      for (TableCounts counts : stats.getLast().values()) {
-        result += counts.assigned() + counts.hosted();
-      }
-      return result;
-    }
-    
-    private void sendSplitRequest(MergeInfo info, TabletState state, TabletLocationState tls) {
-      // Already split?
-      if (!info.getState().equals(MergeState.SPLITTING))
-        return;
-      // Merges don't split
-      if (!info.isDelete())
-        return;
-      // Online and ready to split?
-      if (!state.equals(TabletState.HOSTED))
-        return;
-      // Does this extent cover the end points of the delete?
-      KeyExtent range = info.getRange();
-      if (tls.extent.overlaps(range)) {
-        for (Text splitPoint : new Text[] {range.getPrevEndRow(), range.getEndRow()}) {
-          if (splitPoint == null)
-            continue;
-          if (!tls.extent.contains(splitPoint))
-            continue;
-          if (splitPoint.equals(tls.extent.getEndRow()))
-            continue;
-          if (splitPoint.equals(tls.extent.getPrevEndRow()))
-            continue;
-          try {
-            TServerConnection conn;
-            conn = tserverSet.getConnection(tls.current);
-            if (conn != null) {
-              log.info("Asking " + tls.current + " to split " + tls.extent + " at " + splitPoint);
-              conn.splitTablet(masterLock, tls.extent, splitPoint);
-            } else {
-              log.warn("Not connected to server " + tls.current);
-            }
-          } catch (NotServingTabletException e) {
-            log.debug("Error asking tablet server to split a tablet: " + e);
-          } catch (Exception e) {
-            log.warn("Error asking tablet server to split a tablet: " + e);
-          }
-        }
-      }
-    }
-    
-    private void sendChopRequest(MergeInfo info, TabletState state, TabletLocationState tls) {
-      // Don't bother if we're in the wrong state
-      if (!info.getState().equals(MergeState.WAITING_FOR_CHOPPED))
-        return;
-      // Tablet must be online
-      if (!state.equals(TabletState.HOSTED))
-        return;
-      // Tablet isn't already chopped
-      if (tls.chopped)
-        return;
-      // Tablet ranges intersect
-      if (info.needsToBeChopped(tls.extent)) {
-        TServerConnection conn;
-        try {
-          conn = tserverSet.getConnection(tls.current);
-          if (conn != null) {
-            log.info("Asking " + tls.current + " to chop " + tls.extent);
-            conn.chop(masterLock, tls.extent);
-          } else {
-            log.warn("Could not connect to server " + tls.current);
-          }
-        } catch (TException e) {
-          log.warn("Communications error asking tablet server to chop a tablet");
-        }
-      }
-    }
-    
-    private void updateMergeState(Map<Text,MergeStats> mergeStatsCache) {
-      for (MergeStats stats : mergeStatsCache.values()) {
-        try {
-          MergeState update = stats.nextMergeState(getConnector(), Master.this);
-          // when next state is MERGING, its important to persist this before
-          // starting the merge... the verification check that is done before
-          // moving into the merging state could fail if merge starts but does
-          // not finish
-          if (update == MergeState.COMPLETE)
-            update = MergeState.NONE;
-          if (update != stats.getMergeInfo().getState()) {
-            setMergeState(stats.getMergeInfo(), update);
-          }
-          
-          if (update == MergeState.MERGING) {
-            try {
-              if (stats.getMergeInfo().isDelete()) {
-                deleteTablets(stats.getMergeInfo());
-              } else {
-                mergeMetadataRecords(stats.getMergeInfo());
-              }
-              setMergeState(stats.getMergeInfo(), update = MergeState.COMPLETE);
-            } catch (Exception ex) {
-              log.error("Unable merge metadata table records", ex);
-            }
-          }
-        } catch (Exception ex) {
-          log.error("Unable to update merge state for merge " + stats.getMergeInfo().getRange(), ex);
-        }
-      }
-    }
-    
-    private void deleteTablets(MergeInfo info) throws AccumuloException {
-      KeyExtent range = info.getRange();
-      log.debug("Deleting tablets for " + range);
-      char timeType = '\0';
-      KeyExtent followingTablet = null;
-      if (range.getEndRow() != null) {
-        Key nextExtent = new Key(range.getEndRow()).followingKey(PartialKey.ROW);
-        followingTablet = getHighTablet(new KeyExtent(range.getTableId(), nextExtent.getRow(), range.getEndRow()));
-        log.debug("Found following tablet " + followingTablet);
-      }
-      try {
-        Connector conn = getConnector();
-        Text start = range.getPrevEndRow();
-        if (start == null) {
-          start = new Text();
-        }
-        log.debug("Making file deletion entries for " + range);
-        Range deleteRange = new Range(KeyExtent.getMetadataEntry(range.getTableId(), start), false, KeyExtent.getMetadataEntry(range.getTableId(),
-            range.getEndRow()), true);
-        Scanner scanner = conn.createScanner(MetadataTable.NAME, Authorizations.EMPTY);
-        scanner.setRange(deleteRange);
-        MetadataTable.DIRECTORY_COLUMN.fetch(scanner);
-        MetadataTable.TIME_COLUMN.fetch(scanner);
-        scanner.fetchColumnFamily(MetadataTable.DATAFILE_COLUMN_FAMILY);
-        scanner.fetchColumnFamily(MetadataTable.CURRENT_LOCATION_COLUMN_FAMILY);
-        Set<FileRef> datafiles = new TreeSet<FileRef>();
-        for (Entry<Key,Value> entry : scanner) {
-          Key key = entry.getKey();
-          if (key.compareColumnFamily(MetadataTable.DATAFILE_COLUMN_FAMILY) == 0) {
-            datafiles.add(new FileRef(fs, key));
-            if (datafiles.size() > 1000) {
-              MetadataTable.addDeleteEntries(range, datafiles, SecurityConstants.getSystemCredentials());
-              datafiles.clear();
-            }
-          } else if (MetadataTable.TIME_COLUMN.hasColumns(key)) {
-            timeType = entry.getValue().toString().charAt(0);
-          } else if (key.compareColumnFamily(MetadataTable.CURRENT_LOCATION_COLUMN_FAMILY) == 0) {
-            throw new IllegalStateException("Tablet " + key.getRow() + " is assigned during a merge!");
-          } else if (MetadataTable.DIRECTORY_COLUMN.hasColumns(key)) {
-            datafiles.add(new FileRef(fs, key));
-            if (datafiles.size() > 1000) {
-              MetadataTable.addDeleteEntries(range, datafiles, SecurityConstants.getSystemCredentials());
-              datafiles.clear();
-            }
-          }
-        }
-        MetadataTable.addDeleteEntries(range, datafiles, SecurityConstants.getSystemCredentials());
-        BatchWriter bw = conn.createBatchWriter(MetadataTable.NAME, new BatchWriterConfig());
-        try {
-          deleteTablets(deleteRange, bw, conn);
-        } finally {
-          bw.close();
-        }
-        
-        if (followingTablet != null) {
-          log.debug("Updating prevRow of " + followingTablet + " to " + range.getPrevEndRow());
-          bw = conn.createBatchWriter(MetadataTable.NAME, new BatchWriterConfig());
-          try {
-            Mutation m = new Mutation(followingTablet.getMetadataEntry());
-            MetadataTable.PREV_ROW_COLUMN.put(m, KeyExtent.encodePrevEndRow(range.getPrevEndRow()));
-            MetadataTable.CHOPPED_COLUMN.putDelete(m);
-            bw.addMutation(m);
-            bw.flush();
-          } finally {
-            bw.close();
-          }
-        } else {
-          // Recreate the default tablet to hold the end of the table
-          log.debug("Recreating the last tablet to point to " + range.getPrevEndRow());
-          MetadataTable.addTablet(new KeyExtent(range.getTableId(), null, range.getPrevEndRow()), Constants.DEFAULT_TABLET_LOCATION,
-              SecurityConstants.getSystemCredentials(), timeType, masterLock);
-        }
-      } catch (Exception ex) {
-        throw new AccumuloException(ex);
-      }
-    }
-    
-    private void mergeMetadataRecords(MergeInfo info) throws AccumuloException {
-      KeyExtent range = info.getRange();
-      log.debug("Merging metadata for " + range);
-      KeyExtent stop = getHighTablet(range);
-      log.debug("Highest tablet is " + stop);
-      Value firstPrevRowValue = null;
-      Text stopRow = stop.getMetadataEntry();
-      Text start = range.getPrevEndRow();
-      if (start == null) {
-        start = new Text();
-      }
-      Range scanRange = new Range(KeyExtent.getMetadataEntry(range.getTableId(), start), false, stopRow, false);
-      if (range.isMeta())
-        scanRange = scanRange.clip(RootTable.KEYSPACE);
-      
-      BatchWriter bw = null;
-      try {
-        long fileCount = 0;
-        Connector conn = getConnector();
-        // Make file entries in highest tablet
-        bw = conn.createBatchWriter(MetadataTable.NAME, new BatchWriterConfig());
-        Scanner scanner = conn.createScanner(MetadataTable.NAME, Authorizations.EMPTY);
-        scanner.setRange(scanRange);
-        MetadataTable.PREV_ROW_COLUMN.fetch(scanner);
-        MetadataTable.TIME_COLUMN.fetch(scanner);
-        MetadataTable.DIRECTORY_COLUMN.fetch(scanner);
-        scanner.fetchColumnFamily(MetadataTable.DATAFILE_COLUMN_FAMILY);
-        Mutation m = new Mutation(stopRow);
-        String maxLogicalTime = null;
-        for (Entry<Key,Value> entry : scanner) {
-          Key key = entry.getKey();
-          Value value = entry.getValue();
-          if (key.getColumnFamily().equals(MetadataTable.DATAFILE_COLUMN_FAMILY)) {
-            m.put(key.getColumnFamily(), key.getColumnQualifier(), value);
-            fileCount++;
-          } else if (MetadataTable.PREV_ROW_COLUMN.hasColumns(key) && firstPrevRowValue == null) {
-            log.debug("prevRow entry for lowest tablet is " + value);
-            firstPrevRowValue = new Value(value);
-          } else if (MetadataTable.TIME_COLUMN.hasColumns(key)) {
-            maxLogicalTime = TabletTime.maxMetadataTime(maxLogicalTime, value.toString());
-          } else if (MetadataTable.DIRECTORY_COLUMN.hasColumns(key)) {
-            if (!range.isMeta())
-              bw.addMutation(MetadataTable.createDeleteMutation(range.getTableId().toString(), entry.getValue().toString()));
-          }
-        }
-        
-        // read the logical time from the last tablet in the merge range, it is not included in
-        // the loop above
-        scanner = conn.createScanner(MetadataTable.NAME, Authorizations.EMPTY);
-        Range last = new Range(stopRow);
-        if (range.isMeta())
-          last = last.clip(RootTable.KEYSPACE);
-        scanner.setRange(last);
-        MetadataTable.TIME_COLUMN.fetch(scanner);
-        for (Entry<Key,Value> entry : scanner) {
-          if (MetadataTable.TIME_COLUMN.hasColumns(entry.getKey())) {
-            maxLogicalTime = TabletTime.maxMetadataTime(maxLogicalTime, entry.getValue().toString());
-          }
-        }
-        
-        if (maxLogicalTime != null)
-          MetadataTable.TIME_COLUMN.put(m, new Value(maxLogicalTime.getBytes()));
-        
-        if (!m.getUpdates().isEmpty()) {
-          bw.addMutation(m);
-        }
-        
-        bw.flush();
-        
-        log.debug("Moved " + fileCount + " files to " + stop);
-        
-        if (firstPrevRowValue == null) {
-          log.debug("tablet already merged");
-          return;
-        }
-        
-        stop.setPrevEndRow(KeyExtent.decodePrevEndRow(firstPrevRowValue));
-        Mutation updatePrevRow = stop.getPrevRowUpdateMutation();
-        log.debug("Setting the prevRow for last tablet: " + stop);
-        bw.addMutation(updatePrevRow);
-        bw.flush();
-        
-        deleteTablets(scanRange, bw, conn);
-        
-        // Clean-up the last chopped marker
-        m = new Mutation(stopRow);
-        MetadataTable.CHOPPED_COLUMN.putDelete(m);
-        bw.addMutation(m);
-        bw.flush();
-        
-      } catch (Exception ex) {
-        throw new AccumuloException(ex);
-      } finally {
-        if (bw != null)
-          try {
-            bw.close();
-          } catch (Exception ex) {
-            throw new AccumuloException(ex);
-          }
-      }
-    }
-    
-    private void deleteTablets(Range scanRange, BatchWriter bw, Connector conn) throws TableNotFoundException, MutationsRejectedException {
-      Scanner scanner;
-      Mutation m;
-      // Delete everything in the other tablets
-      // group all deletes into tablet into one mutation, this makes tablets
-      // either disappear entirely or not all.. this is important for the case
-      // where the process terminates in the loop below...
-      scanner = conn.createScanner(MetadataTable.NAME, Authorizations.EMPTY);
-      log.debug("Deleting range " + scanRange);
-      scanner.setRange(scanRange);
-      RowIterator rowIter = new RowIterator(scanner);
-      while (rowIter.hasNext()) {
-        Iterator<Entry<Key,Value>> row = rowIter.next();
-        m = null;
-        while (row.hasNext()) {
-          Entry<Key,Value> entry = row.next();
-          Key key = entry.getKey();
-          
-          if (m == null)
-            m = new Mutation(key.getRow());
-          
-          m.putDelete(key.getColumnFamily(), key.getColumnQualifier());
-          log.debug("deleting entry " + key);
-        }
-        bw.addMutation(m);
-      }
-      
-      bw.flush();
-    }
-    
-    private KeyExtent getHighTablet(KeyExtent range) throws AccumuloException {
-      try {
-        Connector conn = getConnector();
-        Scanner scanner = conn.createScanner(MetadataTable.NAME, Authorizations.EMPTY);
-        MetadataTable.PREV_ROW_COLUMN.fetch(scanner);
-        KeyExtent start = new KeyExtent(range.getTableId(), range.getEndRow(), null);
-        scanner.setRange(new Range(start.getMetadataEntry(), null));
-        Iterator<Entry<Key,Value>> iterator = scanner.iterator();
-        if (!iterator.hasNext()) {
-          throw new AccumuloException("No last tablet for a merge " + range);
-        }
-        Entry<Key,Value> entry = iterator.next();
-        KeyExtent highTablet = new KeyExtent(entry.getKey().getRow(), KeyExtent.decodePrevEndRow(entry.getValue()));
-        if (highTablet.getTableId() != range.getTableId()) {
-          throw new AccumuloException("No last tablet for merge " + range + " " + highTablet);
-        }
-        return highTablet;
-      } catch (Exception ex) {
-        throw new AccumuloException("Unexpected failure finding the last tablet for a merge " + range, ex);
-      }
-    }
-    
-    private void flushChanges(SortedMap<TServerInstance,TabletServerStatus> currentTServers, List<Assignment> assignments, List<Assignment> assigned,
-        List<TabletLocationState> assignedToDeadServers, Map<KeyExtent,TServerInstance> unassigned) throws DistributedStoreException, TException {
-      if (!assignedToDeadServers.isEmpty()) {
-        int maxServersToShow = min(assignedToDeadServers.size(), 100);
-        log.debug(assignedToDeadServers.size() + " assigned to dead servers: " + assignedToDeadServers.subList(0, maxServersToShow) + "...");
-        store.unassign(assignedToDeadServers);
-        nextEvent.event("Marked %d tablets as unassigned because they don't have current servers", assignedToDeadServers.size());
-      }
-      
-      if (!currentTServers.isEmpty()) {
-        Map<KeyExtent,TServerInstance> assignedOut = new HashMap<KeyExtent,TServerInstance>();
-        tabletBalancer.getAssignments(Collections.unmodifiableSortedMap(currentTServers), Collections.unmodifiableMap(unassigned), assignedOut);
-        for (Entry<KeyExtent,TServerInstance> assignment : assignedOut.entrySet()) {
-          if (unassigned.containsKey(assignment.getKey())) {
-            if (assignment.getValue() != null) {
-              log.debug(store.name() + " assigning tablet " + assignment);
-              assignments.add(new Assignment(assignment.getKey(), assignment.getValue()));
-            }
-          } else {
-            log.warn(store.name() + " load balancer assigning tablet that was not nominated for assignment " + assignment.getKey());
-          }
-        }
-        if (!unassigned.isEmpty() && assignedOut.isEmpty())
-          log.warn("Load balancer failed to assign any tablets");
-      }
-      
-      if (assignments.size() > 0) {
-        log.info(String.format("Assigning %d tablets", assignments.size()));
-        store.setFutureLocations(assignments);
-      }
-      assignments.addAll(assigned);
-      for (Assignment a : assignments) {
-        TServerConnection conn = tserverSet.getConnection(a.server);
-        if (conn != null) {
-          conn.assignTablet(masterLock, a.tablet);
-        } else {
-          log.warn("Could not connect to server " + a.server);
-        }
-      }
-    }
-    
-  }
-  
   private class MigrationCleanupThread extends Daemon {
     
     @Override
@@ -1894,6 +1298,7 @@ public class Master implements LiveTServ
                   break;
                 case UNLOAD_METADATA_TABLETS:
                   count = assignedOrHosted(METADATA_TABLE_ID);
+                  count += assignedOrHosted(new Text(RootTable.ID));
                   log.debug(String.format("There are %d metadata tablets assigned or hosted", count));
                   // Assumes last tablet hosted is the root tablet;
                   // it's possible
@@ -1903,6 +1308,7 @@ public class Master implements LiveTServ
                   break;
                 case UNLOAD_ROOT_TABLET:
                   count = assignedOrHosted(METADATA_TABLE_ID);
+                  count += assignedOrHosted(new Text(RootTable.ID));
                   if (count > 0)
                     log.debug(String.format("The root tablet is still assigned or hosted"));
                   if (count == 0) {
@@ -2101,11 +1507,9 @@ public class Master implements LiveTServ
     });
     
     TCredentials systemAuths = SecurityConstants.getSystemCredentials();
-    final TabletStateStore stores[] = {new ZooTabletStateStore(new ZooStore(zroot)), new RootTabletStateStore(instance, systemAuths, this),
-        new MetaDataStateStore(instance, systemAuths, this)};
-    watchers.add(new TabletGroupWatcher(stores[2], null));
-    watchers.add(new TabletGroupWatcher(stores[1], watchers.get(0)));
-    watchers.add(new TabletGroupWatcher(stores[0], watchers.get(1)));
+    watchers.add(new TabletGroupWatcher(this, new MetaDataStateStore(instance, systemAuths, this), null));
+    watchers.add(new TabletGroupWatcher(this, new RootTabletStateStore(instance, systemAuths, this), watchers.get(0)));
+    watchers.add(new TabletGroupWatcher(this, new ZooTabletStateStore(new ZooStore(zroot)), watchers.get(1)));
     for (TabletGroupWatcher watcher : watchers) {
       watcher.start();
     }
@@ -2324,6 +1728,8 @@ public class Master implements LiveTServ
     if (getMasterState() != MasterState.NORMAL) {
       if (getMasterState() != MasterState.UNLOAD_METADATA_TABLETS)
         result.add(MetadataTable.ID);
+      if (getMasterState() != MasterState.UNLOAD_ROOT_TABLET)
+        result.add(RootTable.ID);
       return result;
     }
     TableManager manager = TableManager.getInstance();



Mime
View raw message