ACCUMULO-3301 Fetch future tablet column from metadata.

We need to fetch both the future and current location for the tablets
in the table to be sure that the table has correctly transitioned
to the expected state. Without this, offline/online may incorrectly
return before the table has actually fully transitioned to its final state.

Lifted the code to create the scanner to its own method to easily
test it.


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

Branch: refs/heads/1.6
Commit: 1f674b4effd84f2e30f52fd624d963a78999d0d4
Parents: 73068c0
Author: Josh Elser <els...@apache.org>
Authored: Wed Nov 5 13:12:19 2014 -0500
Committer: Josh Elser <els...@apache.org>
Committed: Wed Nov 5 15:27:21 2014 -0500

----------------------------------------------------------------------
 .../core/client/impl/TableOperationsImpl.java   | 21 +++--
 .../client/impl/TableOperationsImplTest.java    | 86 ++++++++++++++++++++
 2 files changed, 102 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/1f674b4e/core/src/main/java/org/apache/accumulo/core/client/impl/TableOperationsImpl.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/impl/TableOperationsImpl.java
 
b/core/src/main/java/org/apache/accumulo/core/client/impl/TableOperationsImpl.java
index 547ccc7..07df1bd 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/impl/TableOperationsImpl.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/impl/TableOperationsImpl.java
@@ -1216,11 +1216,8 @@ public class TableOperationsImpl extends 
TableOperationsHelper {
       String metaTable = MetadataTable.NAME;
       if (tableId.equals(MetadataTable.ID))
         metaTable = RootTable.NAME;
-      Scanner scanner = instance.getConnector(credentials.getPrincipal(), 
credentials.getToken()).createScanner(metaTable, Authorizations.EMPTY);
-      scanner = new IsolatedScanner(scanner);
-      TabletsSection.TabletColumnFamily.PREV_ROW_COLUMN.fetch(scanner);
-      
scanner.fetchColumnFamily(TabletsSection.CurrentLocationColumnFamily.NAME);
-      scanner.setRange(range);
+
+      Scanner scanner = createMetadataScanner(instance, credentials, 
metaTable, range);
 
       RowIterator rowIter = new RowIterator(scanner);
 
@@ -1307,6 +1304,20 @@ public class TableOperationsImpl extends 
TableOperationsHelper {
     }
   }
 
+  /**
+   * Create an IsolatedScanner over the given table, fetching the columns 
necessary to determine when a table has transitioned to online or offline.
+   */
+  protected IsolatedScanner createMetadataScanner(Instance inst, Credentials 
creds, String metaTable, Range range) throws TableNotFoundException,
+      AccumuloException,
+      AccumuloSecurityException {
+    Scanner scanner = inst.getConnector(creds.getPrincipal(), 
creds.getToken()).createScanner(metaTable, Authorizations.EMPTY);
+    TabletsSection.TabletColumnFamily.PREV_ROW_COLUMN.fetch(scanner);
+    scanner.fetchColumnFamily(TabletsSection.FutureLocationColumnFamily.NAME);
+    scanner.fetchColumnFamily(TabletsSection.CurrentLocationColumnFamily.NAME);
+    scanner.setRange(range);
+    return new IsolatedScanner(scanner);
+  }
+
   @Override
   public void offline(String tableName) throws AccumuloSecurityException, 
AccumuloException, TableNotFoundException {
     offline(tableName, false);

http://git-wip-us.apache.org/repos/asf/accumulo/blob/1f674b4e/core/src/test/java/org/apache/accumulo/core/client/impl/TableOperationsImplTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/client/impl/TableOperationsImplTest.java
 
b/core/src/test/java/org/apache/accumulo/core/client/impl/TableOperationsImplTest.java
new file mode 100644
index 0000000..20e068b
--- /dev/null
+++ 
b/core/src/test/java/org/apache/accumulo/core/client/impl/TableOperationsImplTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.core.client.impl;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.accumulo.core.client.Connector;
+import org.apache.accumulo.core.client.Instance;
+import org.apache.accumulo.core.client.Scanner;
+import org.apache.accumulo.core.client.security.tokens.PasswordToken;
+import org.apache.accumulo.core.data.KeyExtent;
+import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.metadata.schema.MetadataSchema;
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.core.security.Credentials;
+import org.apache.hadoop.io.Text;
+import org.easymock.EasyMock;
+import org.junit.Test;
+
+public class TableOperationsImplTest {
+
+  @Test
+  public void waitForStoreTransitionScannerConfiguredCorrectly() throws 
Exception {
+    final String tableName = "metadata";
+    Instance instance = EasyMock.createMock(Instance.class);
+    Credentials credentials = EasyMock.createMock(Credentials.class);
+
+    TableOperationsImpl topsImpl = new TableOperationsImpl(instance, 
credentials);
+
+    Connector connector = EasyMock.createMock(Connector.class);
+    Scanner scanner = EasyMock.createMock(Scanner.class);
+
+    Range range = new KeyExtent(new Text("1"), null, null).toMetadataRange();
+
+    String user = "root";
+    PasswordToken token = new PasswordToken("password");
+
+    // Credentials expectations
+    EasyMock.expect(credentials.getPrincipal()).andReturn(user).atLeastOnce();
+    EasyMock.expect(credentials.getToken()).andReturn(token).atLeastOnce();
+
+    // Create the connector and scanner
+    EasyMock.expect(instance.getConnector(user, token)).andReturn(connector);
+    EasyMock.expect(connector.createScanner(tableName, 
Authorizations.EMPTY)).andReturn(scanner);
+
+    // Fetch the columns on the scanner
+    
scanner.fetchColumnFamily(MetadataSchema.TabletsSection.FutureLocationColumnFamily.NAME);
+    EasyMock.expectLastCall();
+    
scanner.fetchColumnFamily(MetadataSchema.TabletsSection.CurrentLocationColumnFamily.NAME);
+    EasyMock.expectLastCall();
+    
scanner.fetchColumn(MetadataSchema.TabletsSection.TabletColumnFamily.PREV_ROW_COLUMN.getColumnFamily(),
+        
MetadataSchema.TabletsSection.TabletColumnFamily.PREV_ROW_COLUMN.getColumnQualifier());
+    EasyMock.expectLastCall();
+
+    // Set the Range
+    scanner.setRange(range);
+    EasyMock.expectLastCall();
+
+    // IsolatedScanner -- make the verification pass, not really relevant
+    EasyMock.expect(scanner.getRange()).andReturn(range).anyTimes();
+    
EasyMock.expect(scanner.getTimeout(TimeUnit.MILLISECONDS)).andReturn(Long.MAX_VALUE);
+    EasyMock.expect(scanner.getBatchSize()).andReturn(1000);
+    EasyMock.expect(scanner.getReadaheadThreshold()).andReturn(100l);
+
+    EasyMock.replay(instance, credentials, connector, scanner);
+
+    topsImpl.createMetadataScanner(instance, credentials, tableName, range);
+
+    EasyMock.verify(instance, credentials, connector, scanner);
+  }
+
+}

Reply via email to