You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by ct...@apache.org on 2015/02/12 03:16:04 UTC

[1/4] accumulo git commit: ACCUMULO-3580 Make metadata iterator consume in the normal case

Repository: accumulo
Updated Branches:
  refs/heads/master 9af7c1cd8 -> 80e334f31


ACCUMULO-3580 Make metadata iterator consume in the normal case


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

Branch: refs/heads/master
Commit: 33890b00e1cf7f353631439eb6278d646ce70194
Parents: c475c85
Author: Christopher Tubbs <ct...@apache.org>
Authored: Wed Feb 11 17:12:01 2015 -0500
Committer: Christopher Tubbs <ct...@apache.org>
Committed: Wed Feb 11 17:12:01 2015 -0500

----------------------------------------------------------------------
 .../accumulo/server/master/state/TabletStateChangeIterator.java  | 4 ++++
 1 file changed, 4 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/33890b00/server/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java b/server/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
index 405bab7..b11809c 100644
--- a/server/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
+++ b/server/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
@@ -142,11 +142,15 @@ public class TabletStateChangeIterator extends SkippingIterator {
         case HOSTED:
           if (!shouldBeOnline)
             return;
+          break;
         case ASSIGNED_TO_DEAD_SERVER:
           return;
         case UNASSIGNED:
           if (shouldBeOnline)
             return;
+          break;
+        default:
+          throw new AssertionError("Inconceivable! The tablet is an unrecognized state: " + tls.getState(current));
       }
       // table is in the expected state so don't bother returning any information about it
       getSource().next();


[3/4] accumulo git commit: ACCUMULO-3580 Add some testing to exercise the TabletStateChangeIterator

Posted by ct...@apache.org.
ACCUMULO-3580 Add some testing to exercise the TabletStateChangeIterator


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

Branch: refs/heads/master
Commit: fe77101d08ee7ae7b8061c238f4169cb6869bafa
Parents: fc534c9
Author: Christopher Tubbs <ct...@apache.org>
Authored: Wed Feb 11 21:10:52 2015 -0500
Committer: Christopher Tubbs <ct...@apache.org>
Committed: Wed Feb 11 21:10:52 2015 -0500

----------------------------------------------------------------------
 .../master/state/TabletStateChangeIterator.java |  13 +-
 .../functional/TabletStateChangeIteratorIT.java | 170 +++++++++++++++++++
 2 files changed, 182 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/fe77101d/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java b/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
index 687dddc..7ad74fe 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
@@ -42,17 +42,21 @@ import org.apache.accumulo.server.master.state.TabletLocationState.BadLocationSt
 import org.apache.hadoop.io.DataInputBuffer;
 import org.apache.hadoop.io.DataOutputBuffer;
 import org.apache.hadoop.io.Text;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
 
 public class TabletStateChangeIterator extends SkippingIterator {
 
   private static final String SERVERS_OPTION = "servers";
   private static final String TABLES_OPTION = "tables";
   private static final String MERGES_OPTION = "merges";
-  // private static final Logger log = Logger.getLogger(TabletStateChangeIterator.class);
+  private static final String DEBUG_OPTION = "debug";
+  private static final Logger log = Logger.getLogger(TabletStateChangeIterator.class);
 
   Set<TServerInstance> current;
   Set<String> onlineTables;
   Map<Text,MergeInfo> merges;
+  boolean debug = false;
 
   @Override
   public void init(SortedKeyValueIterator<Key,Value> source, Map<String,String> options, IteratorEnvironment env) throws IOException {
@@ -60,6 +64,7 @@ public class TabletStateChangeIterator extends SkippingIterator {
     current = parseServers(options.get(SERVERS_OPTION));
     onlineTables = parseTables(options.get(TABLES_OPTION));
     merges = parseMerges(options.get(MERGES_OPTION));
+    debug = options.containsKey(DEBUG_OPTION);
   }
 
   private Set<String> parseTables(String tables) {
@@ -134,6 +139,12 @@ public class TabletStateChangeIterator extends SkippingIterator {
       // is the table supposed to be online or offline?
       boolean shouldBeOnline = onlineTables.contains(tls.extent.getTableId().toString());
 
+      if (debug) {
+        Level oldLevel = log.getLevel();
+        log.setLevel(Level.DEBUG);
+        log.debug(tls.extent + " is " + tls.getState(current) + " and should be " + (shouldBeOnline ? "on" : "off") + "line");
+        log.setLevel(oldLevel);
+      }
       switch (tls.getState(current)) {
         case ASSIGNED:
           // we always want data about assigned tablets

http://git-wip-us.apache.org/repos/asf/accumulo/blob/fe77101d/test/src/test/java/org/apache/accumulo/test/functional/TabletStateChangeIteratorIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/accumulo/test/functional/TabletStateChangeIteratorIT.java b/test/src/test/java/org/apache/accumulo/test/functional/TabletStateChangeIteratorIT.java
new file mode 100644
index 0000000..ffd7636
--- /dev/null
+++ b/test/src/test/java/org/apache/accumulo/test/functional/TabletStateChangeIteratorIT.java
@@ -0,0 +1,170 @@
+/*
+ * 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.test.functional;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map.Entry;
+import java.util.Set;
+
+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.BatchDeleter;
+import org.apache.accumulo.core.client.BatchWriterConfig;
+import org.apache.accumulo.core.client.Connector;
+import org.apache.accumulo.core.client.MutationsRejectedException;
+import org.apache.accumulo.core.client.Scanner;
+import org.apache.accumulo.core.client.TableExistsException;
+import org.apache.accumulo.core.client.TableNotFoundException;
+import org.apache.accumulo.core.client.impl.Tables;
+import org.apache.accumulo.core.data.Key;
+import org.apache.accumulo.core.data.KeyExtent;
+import org.apache.accumulo.core.data.Value;
+import org.apache.accumulo.core.master.state.tables.TableState;
+import org.apache.accumulo.core.metadata.MetadataTable;
+import org.apache.accumulo.core.metadata.schema.MetadataSchema;
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.core.zookeeper.ZooUtil;
+import org.apache.accumulo.fate.zookeeper.ZooCache;
+import org.apache.accumulo.harness.SharedMiniClusterIT;
+import org.apache.accumulo.server.master.state.CurrentState;
+import org.apache.accumulo.server.master.state.MergeInfo;
+import org.apache.accumulo.server.master.state.MetaDataTableScanner;
+import org.apache.accumulo.server.master.state.TServerInstance;
+import org.apache.accumulo.server.master.state.TabletStateChangeIterator;
+import org.apache.accumulo.server.zookeeper.ZooLock;
+import org.apache.hadoop.io.Text;
+import org.junit.Test;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Sets;
+
+/**
+ * Test to ensure that the {@link TabletStateChangeIterator} properly skips over tablet information in the metadata table when there is no work to be done on
+ * the tablet (see ACCUMULO-3580)
+ */
+public class TabletStateChangeIteratorIT extends SharedMiniClusterIT {
+
+  @Test
+  public void test() throws AccumuloException, AccumuloSecurityException, TableExistsException, TableNotFoundException {
+    String[] tables = getUniqueNames(4);
+    final String t1 = tables[0];
+    final String t2 = tables[1];
+    final String t3 = tables[2];
+    final String cloned = tables[3];
+
+    // create some metadata
+    createTable(t1, true);
+    createTable(t2, false);
+    createTable(t3, true);
+
+    // examine a clone of the metadata table, so we can manipulate it
+    cloneMetadataTable(cloned);
+
+    assertEquals("No tables should need attention", 0, findTabletsNeedingAttention(cloned));
+
+    // test the assigned case (no location)
+    removeLocation(cloned, t3);
+    assertEquals("Should have one tablet without a loc", 1, findTabletsNeedingAttention(cloned));
+
+    // TODO test the cases where the assignment is to a dead tserver
+    // TODO test the cases where there is ongoing merges
+    // TODO test the bad tablet location state case (active split, inconsistent metadata)
+
+    // clean up
+    dropTables(t1, t2, t3);
+  }
+
+  private void removeLocation(String table, String tableNameToModify) throws TableNotFoundException, MutationsRejectedException {
+    String tableIdToModify = getConnector().tableOperations().tableIdMap().get(tableNameToModify);
+    BatchDeleter deleter = getConnector().createBatchDeleter(table, Authorizations.EMPTY, 1, new BatchWriterConfig());
+    deleter.setRanges(Collections.singleton(new KeyExtent(new Text(tableIdToModify), null, null).toMetadataRange()));
+    deleter.fetchColumnFamily(MetadataSchema.TabletsSection.CurrentLocationColumnFamily.NAME);
+    deleter.delete();
+    deleter.close();
+  }
+
+  private int findTabletsNeedingAttention(String table) throws TableNotFoundException {
+    int results = 0;
+    Scanner scanner = getConnector().createScanner(table, Authorizations.EMPTY);
+    MetaDataTableScanner.configureScanner(scanner, new State());
+    scanner.updateScanIteratorOption("tabletChange", "debug", "1");
+    for (Entry<Key,Value> e : scanner) {
+      if (e != null)
+        results++;
+    }
+    return results;
+  }
+
+  private void createTable(String t, boolean online) throws AccumuloSecurityException, AccumuloException, TableNotFoundException, TableExistsException {
+    Connector conn = getConnector();
+    conn.tableOperations().create(t);
+    conn.tableOperations().online(t, true);
+    if (!online) {
+      conn.tableOperations().offline(t, true);
+    }
+  }
+
+  private void cloneMetadataTable(String cloned) throws AccumuloException, AccumuloSecurityException, TableNotFoundException, TableExistsException {
+    getConnector().tableOperations().clone(MetadataTable.NAME, cloned, true, null, null);
+  }
+
+  private void dropTables(String... tables) throws AccumuloException, AccumuloSecurityException, TableNotFoundException {
+    for (String t : tables) {
+      getConnector().tableOperations().delete(t);
+    }
+  }
+
+  private final class State implements CurrentState {
+
+    @Override
+    public Set<TServerInstance> onlineTabletServers() {
+      HashSet<TServerInstance> tservers = new HashSet<TServerInstance>();
+      for (String tserver : getConnector().instanceOperations().getTabletServers()) {
+        try {
+          String zPath = ZooUtil.getRoot(getConnector().getInstance()) + Constants.ZTSERVERS + "/" + tserver;
+          long sessionId = ZooLock.getSessionId(new ZooCache(getCluster().getZooKeepers(), getConnector().getInstance().getZooKeepersSessionTimeOut()), zPath);
+          tservers.add(new TServerInstance(tserver, sessionId));
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+      return tservers;
+    }
+
+    @Override
+    public Set<String> onlineTables() {
+      HashSet<String> onlineTables = new HashSet<String>(getConnector().tableOperations().tableIdMap().values());
+      return Sets.filter(onlineTables, new Predicate<String>() {
+        @Override
+        public boolean apply(String tableId) {
+          return Tables.getTableState(getConnector().getInstance(), tableId) == TableState.ONLINE;
+        }
+      });
+    }
+
+    @Override
+    public Collection<MergeInfo> merges() {
+      return Collections.emptySet();
+    }
+  }
+
+}


[2/4] accumulo git commit: Merge branch '1.5' into 1.6

Posted by ct...@apache.org.
Merge branch '1.5' into 1.6


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

Branch: refs/heads/master
Commit: fc534c93928e0145bc5eee891bcd722a0d6ed68a
Parents: 0a7e117 33890b0
Author: Christopher Tubbs <ct...@apache.org>
Authored: Wed Feb 11 18:18:01 2015 -0500
Committer: Christopher Tubbs <ct...@apache.org>
Committed: Wed Feb 11 18:18:01 2015 -0500

----------------------------------------------------------------------
 .../accumulo/server/master/state/TabletStateChangeIterator.java  | 4 ++++
 1 file changed, 4 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/fc534c93/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
----------------------------------------------------------------------
diff --cc server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
index 83decbd,0000000..687dddc
mode 100644,000000..100644
--- a/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
@@@ -1,190 -1,0 +1,194 @@@
 +/*
 + * 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.server.master.state;
 +
 +import static com.google.common.base.Charsets.UTF_8;
 +
 +import java.io.IOException;
 +import java.util.ArrayList;
 +import java.util.Arrays;
 +import java.util.Collection;
 +import java.util.HashMap;
 +import java.util.HashSet;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Set;
 +
 +import org.apache.accumulo.core.client.IteratorSetting;
 +import org.apache.accumulo.core.data.Key;
 +import org.apache.accumulo.core.data.KeyExtent;
 +import org.apache.accumulo.core.data.Value;
 +import org.apache.accumulo.core.iterators.IteratorEnvironment;
 +import org.apache.accumulo.core.iterators.SkippingIterator;
 +import org.apache.accumulo.core.iterators.SortedKeyValueIterator;
 +import org.apache.accumulo.core.util.AddressUtil;
 +import org.apache.accumulo.core.util.Base64;
 +import org.apache.accumulo.core.util.StringUtil;
 +import org.apache.accumulo.server.master.state.TabletLocationState.BadLocationStateException;
 +import org.apache.hadoop.io.DataInputBuffer;
 +import org.apache.hadoop.io.DataOutputBuffer;
 +import org.apache.hadoop.io.Text;
 +
 +public class TabletStateChangeIterator extends SkippingIterator {
 +
 +  private static final String SERVERS_OPTION = "servers";
 +  private static final String TABLES_OPTION = "tables";
 +  private static final String MERGES_OPTION = "merges";
 +  // private static final Logger log = Logger.getLogger(TabletStateChangeIterator.class);
 +
 +  Set<TServerInstance> current;
 +  Set<String> onlineTables;
 +  Map<Text,MergeInfo> merges;
 +
 +  @Override
 +  public void init(SortedKeyValueIterator<Key,Value> source, Map<String,String> options, IteratorEnvironment env) throws IOException {
 +    super.init(source, options, env);
 +    current = parseServers(options.get(SERVERS_OPTION));
 +    onlineTables = parseTables(options.get(TABLES_OPTION));
 +    merges = parseMerges(options.get(MERGES_OPTION));
 +  }
 +
 +  private Set<String> parseTables(String tables) {
 +    if (tables == null)
 +      return null;
 +    Set<String> result = new HashSet<String>();
 +    for (String table : tables.split(","))
 +      result.add(table);
 +    return result;
 +  }
 +
 +  private Set<TServerInstance> parseServers(String servers) {
 +    if (servers == null)
 +      return null;
 +    // parse "host:port[INSTANCE]"
 +    Set<TServerInstance> result = new HashSet<TServerInstance>();
 +    if (servers.length() > 0) {
 +      for (String part : servers.split(",")) {
 +        String parts[] = part.split("\\[", 2);
 +        String hostport = parts[0];
 +        String instance = parts[1];
 +        if (instance != null && instance.endsWith("]"))
 +          instance = instance.substring(0, instance.length() - 1);
 +        result.add(new TServerInstance(AddressUtil.parseAddress(hostport, false), instance));
 +      }
 +    }
 +    return result;
 +  }
 +
 +  private Map<Text,MergeInfo> parseMerges(String merges) {
 +    if (merges == null)
 +      return null;
 +    try {
 +      Map<Text,MergeInfo> result = new HashMap<Text,MergeInfo>();
 +      DataInputBuffer buffer = new DataInputBuffer();
 +      byte[] data = Base64.decodeBase64(merges.getBytes(UTF_8));
 +      buffer.reset(data, data.length);
 +      while (buffer.available() > 0) {
 +        MergeInfo mergeInfo = new MergeInfo();
 +        mergeInfo.readFields(buffer);
 +        result.put(mergeInfo.extent.getTableId(), mergeInfo);
 +      }
 +      return result;
 +    } catch (Exception ex) {
 +      throw new RuntimeException(ex);
 +    }
 +  }
 +
 +  @Override
 +  protected void consume() throws IOException {
 +    while (getSource().hasTop()) {
 +      Key k = getSource().getTopKey();
 +      Value v = getSource().getTopValue();
 +
 +      if (onlineTables == null || current == null)
 +        return;
 +
 +      TabletLocationState tls;
 +      try {
 +        tls = MetaDataTableScanner.createTabletLocationState(k, v);
 +        if (tls == null)
 +          return;
 +      } catch (BadLocationStateException e) {
 +        // maybe the master can do something with a tablet with bad/inconsistent state
 +        return;
 +      }
 +      // we always want data about merges
 +      MergeInfo merge = merges.get(tls.extent.getTableId());
 +      if (merge != null && merge.getExtent() != null && merge.getExtent().overlaps(tls.extent)) {
 +        return;
 +      }
 +      // is the table supposed to be online or offline?
 +      boolean shouldBeOnline = onlineTables.contains(tls.extent.getTableId().toString());
 +
 +      switch (tls.getState(current)) {
 +        case ASSIGNED:
 +          // we always want data about assigned tablets
 +          return;
 +        case HOSTED:
 +          if (!shouldBeOnline)
 +            return;
++          break;
 +        case ASSIGNED_TO_DEAD_SERVER:
 +          return;
 +        case UNASSIGNED:
 +          if (shouldBeOnline)
 +            return;
++          break;
++        default:
++          throw new AssertionError("Inconceivable! The tablet is an unrecognized state: " + tls.getState(current));
 +      }
 +      // table is in the expected state so don't bother returning any information about it
 +      getSource().next();
 +    }
 +  }
 +
 +  @Override
 +  public SortedKeyValueIterator<Key,Value> deepCopy(IteratorEnvironment env) {
 +    throw new UnsupportedOperationException();
 +  }
 +
 +  public static void setCurrentServers(IteratorSetting cfg, Set<TServerInstance> goodServers) {
 +    if (goodServers != null) {
 +      List<String> servers = new ArrayList<String>();
 +      for (TServerInstance server : goodServers)
 +        servers.add(server.toString());
 +      cfg.addOption(SERVERS_OPTION, StringUtil.join(servers, ","));
 +    }
 +  }
 +
 +  public static void setOnlineTables(IteratorSetting cfg, Set<String> onlineTables) {
 +    if (onlineTables != null)
 +      cfg.addOption(TABLES_OPTION, StringUtil.join(onlineTables, ","));
 +  }
 +
 +  public static void setMerges(IteratorSetting cfg, Collection<MergeInfo> merges) {
 +    DataOutputBuffer buffer = new DataOutputBuffer();
 +    try {
 +      for (MergeInfo info : merges) {
 +        KeyExtent extent = info.getExtent();
 +        if (extent != null && !info.getState().equals(MergeState.NONE)) {
 +          info.write(buffer);
 +        }
 +      }
 +    } catch (Exception ex) {
 +      throw new RuntimeException(ex);
 +    }
 +    String encoded = Base64.encodeBase64String(Arrays.copyOf(buffer.getData(), buffer.getLength()));
 +    cfg.addOption(MERGES_OPTION, encoded);
 +  }
 +
 +}


[4/4] accumulo git commit: Merge branch '1.6'

Posted by ct...@apache.org.
Merge branch '1.6'


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

Branch: refs/heads/master
Commit: 80e334f316f0e9da595c0ac935e89e28c0fbddaf
Parents: 9af7c1c fe77101
Author: Christopher Tubbs <ct...@apache.org>
Authored: Wed Feb 11 21:11:49 2015 -0500
Committer: Christopher Tubbs <ct...@apache.org>
Committed: Wed Feb 11 21:11:49 2015 -0500

----------------------------------------------------------------------
 .../master/state/TabletStateChangeIterator.java |  17 +-
 .../functional/TabletStateChangeIteratorIT.java | 170 +++++++++++++++++++
 2 files changed, 186 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/80e334f3/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
----------------------------------------------------------------------
diff --cc server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
index 9351cd0,7ad74fe..1721be1
--- a/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/state/TabletStateChangeIterator.java
@@@ -41,9 -42,9 +41,11 @@@ import org.apache.accumulo.server.maste
  import org.apache.hadoop.io.DataInputBuffer;
  import org.apache.hadoop.io.DataOutputBuffer;
  import org.apache.hadoop.io.Text;
+ import org.apache.log4j.Level;
+ import org.apache.log4j.Logger;
  
 +import com.google.common.base.Joiner;
 +
  public class TabletStateChangeIterator extends SkippingIterator {
  
    private static final String SERVERS_OPTION = "servers";