accumulo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dlmar...@apache.org
Subject [1/3] accumulo git commit: ACCUMULO-3948: Add ability to set contextClassLoader on Scanners and BatchScanners
Date Tue, 17 Nov 2015 18:33:56 GMT
Repository: accumulo
Updated Branches:
  refs/heads/master 3521b35a1 -> 0e1da5a58


http://git-wip-us.apache.org/repos/asf/accumulo/blob/0e1da5a5/server/tserver/src/main/java/org/apache/accumulo/tserver/session/SessionManager.java
----------------------------------------------------------------------
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/session/SessionManager.java
b/server/tserver/src/main/java/org/apache/accumulo/tserver/session/SessionManager.java
index 83d87b3..7e87c99 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/session/SessionManager.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/session/SessionManager.java
@@ -279,7 +279,7 @@ public class SessionManager {
 
         ActiveScan activeScan = new ActiveScan(ss.client, ss.getUser(), ss.extent.getTableId().toString(),
ct - ss.startTime, ct - ss.lastAccessTime,
             ScanType.SINGLE, state, ss.extent.toThrift(), Translator.translate(ss.columnSet,
Translators.CT), ss.ssiList, ss.ssio,
-            ss.auths.getAuthorizationsBB());
+            ss.auths.getAuthorizationsBB(), ss.context);
 
         // scanId added by ACCUMULO-2641 is an optional thrift argument and not available
in ActiveScan constructor
         activeScan.setScanId(entry.getKey());
@@ -310,7 +310,7 @@ public class SessionManager {
 
         activeScans.add(new ActiveScan(mss.client, mss.getUser(), mss.threadPoolExtent.getTableId().toString(),
ct - mss.startTime, ct - mss.lastAccessTime,
             ScanType.BATCH, state, mss.threadPoolExtent.toThrift(), Translator.translate(mss.columnSet,
Translators.CT), mss.ssiList, mss.ssio, mss.auths
-                .getAuthorizationsBB()));
+                .getAuthorizationsBB(), mss.context));
       }
     }
 

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0e1da5a5/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/ScanDataSource.java
----------------------------------------------------------------------
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/ScanDataSource.java
b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/ScanDataSource.java
index 72c289c..8f61b9d 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/ScanDataSource.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/ScanDataSource.java
@@ -69,10 +69,10 @@ class ScanDataSource implements DataSource {
   private final ScanOptions options;
 
   ScanDataSource(Tablet tablet, Authorizations authorizations, byte[] defaultLabels, HashSet<Column>
columnSet, List<IterInfo> ssiList,
-      Map<String,Map<String,String>> ssio, AtomicBoolean interruptFlag, SamplerConfiguration
samplerConfig, long batchTimeOut) {
+      Map<String,Map<String,String>> ssio, AtomicBoolean interruptFlag, SamplerConfiguration
samplerConfig, long batchTimeOut, String context) {
     this.tablet = tablet;
     expectedDeletionCount = tablet.getDataSourceDeletions();
-    this.options = new ScanOptions(-1, authorizations, defaultLabels, columnSet, ssiList,
ssio, interruptFlag, false, samplerConfig, batchTimeOut);
+    this.options = new ScanOptions(-1, authorizations, defaultLabels, columnSet, ssiList,
ssio, interruptFlag, false, samplerConfig, batchTimeOut, context);
     this.interruptFlag = interruptFlag;
   }
 
@@ -178,8 +178,13 @@ class ScanDataSource implements DataSource {
 
     VisibilityFilter visFilter = new VisibilityFilter(colFilter, options.getAuthorizations(),
options.getDefaultLabels());
 
-    return iterEnv.getTopLevelIterator(IteratorUtil.loadIterators(IteratorScope.scan, visFilter,
tablet.getExtent(), tablet.getTableConfiguration(),
-        options.getSsiList(), options.getSsio(), iterEnv));
+    if (null == options.getClassLoaderContext()) {
+      return iterEnv.getTopLevelIterator(IteratorUtil.loadIterators(IteratorScope.scan, visFilter,
tablet.getExtent(), tablet.getTableConfiguration(),
+          options.getSsiList(), options.getSsio(), iterEnv));
+    } else {
+      return iterEnv.getTopLevelIterator(IteratorUtil.loadIterators(IteratorScope.scan, visFilter,
tablet.getExtent(), tablet.getTableConfiguration(),
+          options.getSsiList(), options.getSsio(), iterEnv, true, options.getClassLoaderContext()));
+    }
   }
 
   void close(boolean sawErrors) {

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0e1da5a5/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/ScanOptions.java
----------------------------------------------------------------------
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/ScanOptions.java
b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/ScanOptions.java
index c97f3ac..2e2445a 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/ScanOptions.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/ScanOptions.java
@@ -39,9 +39,10 @@ final class ScanOptions {
   private final boolean isolated;
   private SamplerConfiguration samplerConfig;
   private final long batchTimeOut;
+  private String classLoaderContext;
 
   ScanOptions(int num, Authorizations authorizations, byte[] defaultLabels, Set<Column>
columnSet, List<IterInfo> ssiList, Map<String,Map<String,String>> ssio,
-      AtomicBoolean interruptFlag, boolean isolated, SamplerConfiguration samplerConfig,
long batchTimeOut) {
+      AtomicBoolean interruptFlag, boolean isolated, SamplerConfiguration samplerConfig,
long batchTimeOut, String classLoaderContext) {
     this.num = num;
     this.authorizations = authorizations;
     this.defaultLabels = defaultLabels;
@@ -52,6 +53,7 @@ final class ScanOptions {
     this.isolated = isolated;
     this.samplerConfig = samplerConfig;
     this.batchTimeOut = batchTimeOut;
+    this.classLoaderContext = classLoaderContext;
   }
 
   public Authorizations getAuthorizations() {
@@ -99,4 +101,12 @@ final class ScanOptions {
   public long getBatchTimeOut() {
     return batchTimeOut;
   }
+
+  public String getClassLoaderContext() {
+    return classLoaderContext;
+  }
+
+  public void setClassLoaderContext(String context) {
+    this.classLoaderContext = context;
+  }
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0e1da5a5/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Tablet.java
----------------------------------------------------------------------
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Tablet.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Tablet.java
index 1f66302..de3bfd3 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Tablet.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Tablet.java
@@ -633,8 +633,8 @@ public class Tablet implements TabletCommitter {
   }
 
   public LookupResult lookup(List<Range> ranges, HashSet<Column> columns, Authorizations
authorizations, List<KVEntry> results, long maxResultSize,
-      List<IterInfo> ssiList, Map<String,Map<String,String>> ssio, AtomicBoolean
interruptFlag, SamplerConfiguration samplerConfig, long batchTimeOut)
-      throws IOException {
+      List<IterInfo> ssiList, Map<String,Map<String,String>> ssio, AtomicBoolean
interruptFlag, SamplerConfiguration samplerConfig, long batchTimeOut,
+      String classLoaderContext) throws IOException {
 
     if (ranges.size() == 0) {
       return new LookupResult();
@@ -653,7 +653,7 @@ public class Tablet implements TabletCommitter {
     }
 
     ScanDataSource dataSource = new ScanDataSource(this, authorizations, this.defaultSecurityLabel,
columns, ssiList, ssio, interruptFlag, samplerConfig,
-        batchTimeOut);
+        batchTimeOut, classLoaderContext);
 
     LookupResult result = null;
 
@@ -757,13 +757,14 @@ public class Tablet implements TabletCommitter {
   }
 
   public Scanner createScanner(Range range, int num, Set<Column> columns, Authorizations
authorizations, List<IterInfo> ssiList,
-      Map<String,Map<String,String>> ssio, boolean isolated, AtomicBoolean interruptFlag,
SamplerConfiguration samplerConfig, long batchTimeOut) {
+      Map<String,Map<String,String>> ssio, boolean isolated, AtomicBoolean interruptFlag,
SamplerConfiguration samplerConfig, long batchTimeOut,
+      String classLoaderContext) {
     // do a test to see if this range falls within the tablet, if it does not
     // then clip will throw an exception
     extent.toDataRange().clip(range);
 
     ScanOptions opts = new ScanOptions(num, authorizations, this.defaultSecurityLabel, columns,
ssiList, ssio, interruptFlag, isolated, samplerConfig,
-        batchTimeOut);
+        batchTimeOut, classLoaderContext);
     return new Scanner(this, range, opts);
   }
 

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0e1da5a5/shell/src/main/java/org/apache/accumulo/shell/commands/ScanCommand.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/ScanCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/ScanCommand.java
index 595829b..c7ab1ff 100644
--- a/shell/src/main/java/org/apache/accumulo/shell/commands/ScanCommand.java
+++ b/shell/src/main/java/org/apache/accumulo/shell/commands/ScanCommand.java
@@ -63,6 +63,7 @@ public class ScanCommand extends Command {
   private Option timeoutOption;
   private Option profileOpt;
   private Option sampleOpt;
+  private Option contextOpt;
 
   protected void setupSampling(final String tableName, final CommandLine cl, final Shell
shellState, ScannerBase scanner) throws TableNotFoundException,
       AccumuloException, AccumuloSecurityException {
@@ -84,11 +85,17 @@ public class ScanCommand extends Command {
     final Class<? extends Formatter> formatter = getFormatter(cl, tableName, shellState);
     final ScanInterpreter interpeter = getInterpreter(cl, tableName, shellState);
 
+    String classLoaderContext = null;
+    if (cl.hasOption(contextOpt.getOpt())) {
+      classLoaderContext = cl.getOptionValue(contextOpt.getOpt());
+    }
     // handle first argument, if present, the authorizations list to
     // scan with
     final Authorizations auths = getAuths(cl, shellState);
     final Scanner scanner = shellState.getConnector().createScanner(tableName, auths);
-
+    if (null != classLoaderContext) {
+      scanner.setClassLoaderContext(classLoaderContext);
+    }
     // handle session-specific scan iterators
     addScanIterators(shellState, cl, scanner, tableName);
 
@@ -316,6 +323,7 @@ public class ScanCommand extends Command {
         "time before scan should fail if no data is returned. If no unit is given assumes
seconds.  Units d,h,m,s,and ms are supported.  e.g. 30s or 100ms");
     outputFileOpt = new Option("o", "output", true, "local file to write the scan output
to");
     sampleOpt = new Option(null, "sample", false, "Show sample");
+    contextOpt = new Option("cc", "context", true, "name of the classloader context");
 
     scanOptAuths.setArgName("comma-separated-authorizations");
     scanOptRow.setArgName("row");
@@ -325,6 +333,7 @@ public class ScanCommand extends Command {
     formatterOpt.setArgName("className");
     timeoutOption.setArgName("timeout");
     outputFileOpt.setArgName("file");
+    contextOpt.setArgName("context");
 
     profileOpt = new Option("pn", "profile", true, "iterator profile name");
     profileOpt.setArgName("profile");
@@ -347,6 +356,7 @@ public class ScanCommand extends Command {
     o.addOption(outputFileOpt);
     o.addOption(profileOpt);
     o.addOption(sampleOpt);
+    o.addOption(contextOpt);
 
     return o;
   }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0e1da5a5/test/pom.xml
----------------------------------------------------------------------
diff --git a/test/pom.xml b/test/pom.xml
index e88bcfb..01b27da 100644
--- a/test/pom.xml
+++ b/test/pom.xml
@@ -226,6 +226,25 @@
             </systemPropertyVariables>
           </configuration>
         </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-jar-plugin</artifactId>
+          <executions>
+            <execution>
+              <goals>
+                <goal>test-jar</goal>
+              </goals>
+              <phase>pre-integration-test</phase>
+              <configuration>
+                <finalName>TestIterators</finalName>
+                <classifier />
+                <includes>
+                  <include>org/apache/accumulo/test/functional/ValueReversingIterator.class</include>
+                </includes>
+              </configuration>
+            </execution>
+          </executions>
+        </plugin>
       </plugins>
     </pluginManagement>
   </build>

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0e1da5a5/test/src/main/java/org/apache/accumulo/test/ShellServerIT.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/accumulo/test/ShellServerIT.java b/test/src/main/java/org/apache/accumulo/test/ShellServerIT.java
index 60f802b..1b100f2 100644
--- a/test/src/main/java/org/apache/accumulo/test/ShellServerIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/ShellServerIT.java
@@ -1723,6 +1723,97 @@ public class ShellServerIT extends SharedMiniClusterBase {
   }
 
   @Test
+  public void scansWithClassLoaderContext() throws Exception {
+    try {
+      Class.forName("org.apache.accumulo.test.functional.ValueReversingIterator");
+      fail("ValueReversingIterator already on the classpath");
+    } catch (Exception e) {
+      // Do nothing here, This is success. The following line is here
+      // so that findbugs doesn't have a stroke.
+      assertTrue(true);
+    }
+    ts.exec("createtable t");
+    make10();
+    setupFakeContextPath();
+    // Add the context to the table so that setscaniter works. After setscaniter succeeds,
then
+    // remove the property from the table.
+    String output = ts.exec("config -s " + Property.VFS_CONTEXT_CLASSPATH_PROPERTY + FAKE_CONTEXT
+ "=" + FAKE_CONTEXT_CLASSPATH);
+    output = ts.exec("config -t t -s table.classpath.context=" + FAKE_CONTEXT);
+    output = ts.exec("setscaniter -n reverse -t t -p 21 -class org.apache.accumulo.test.functional.ValueReversingIterator");
+    String result = ts.exec("scan -np -b row1 -e row1");
+    assertEquals(2, result.split("\n").length);
+    log.error(result);
+    assertTrue(result.contains("value"));
+    result = ts.exec("scan -np -b row3 -e row5");
+    assertEquals(4, result.split("\n").length);
+    assertTrue(result.contains("value"));
+    result = ts.exec("scan -np -r row3");
+    assertEquals(2, result.split("\n").length);
+    assertTrue(result.contains("value"));
+    result = ts.exec("scan -np -b row:");
+    assertEquals(1, result.split("\n").length);
+    result = ts.exec("scan -np -b row");
+    assertEquals(11, result.split("\n").length);
+    assertTrue(result.contains("value"));
+    result = ts.exec("scan -np -e row:");
+    assertEquals(11, result.split("\n").length);
+    assertTrue(result.contains("value"));
+
+    setupRealContextPath();
+    output = ts.exec("config -s " + Property.VFS_CONTEXT_CLASSPATH_PROPERTY + REAL_CONTEXT
+ "=" + REAL_CONTEXT_CLASSPATH);
+    result = ts.exec("scan -np -b row1 -e row1 -cc " + REAL_CONTEXT);
+    log.error(result);
+    assertEquals(2, result.split("\n").length);
+    assertTrue(result.contains("eulav"));
+    assertFalse(result.contains("value"));
+    result = ts.exec("scan -np -b row3 -e row5 -cc " + REAL_CONTEXT);
+    assertEquals(4, result.split("\n").length);
+    assertTrue(result.contains("eulav"));
+    assertFalse(result.contains("value"));
+    result = ts.exec("scan -np -r row3 -cc " + REAL_CONTEXT);
+    assertEquals(2, result.split("\n").length);
+    assertTrue(result.contains("eulav"));
+    assertFalse(result.contains("value"));
+    result = ts.exec("scan -np -b row: -cc " + REAL_CONTEXT);
+    assertEquals(1, result.split("\n").length);
+    result = ts.exec("scan -np -b row -cc " + REAL_CONTEXT);
+    assertEquals(11, result.split("\n").length);
+    assertTrue(result.contains("eulav"));
+    assertFalse(result.contains("value"));
+    result = ts.exec("scan -np -e row: -cc " + REAL_CONTEXT);
+    assertEquals(11, result.split("\n").length);
+    assertTrue(result.contains("eulav"));
+    assertFalse(result.contains("value"));
+    ts.exec("deletetable -f t");
+  }
+
+  private static final String FAKE_CONTEXT = "FAKE";
+  private static final String FAKE_CONTEXT_CLASSPATH = "file:///tmp/ShellServerIT-iterators.jar";
+  private static final String REAL_CONTEXT = "REAL";
+  private static final String REAL_CONTEXT_CLASSPATH = "file:///tmp/TestIterators-tests.jar";
+
+  private void setupRealContextPath() throws Exception {
+    // Copy the TestIterators jar to tmp
+    Path baseDir = new Path(System.getProperty("user.dir"));
+    Path targetDir = new Path(baseDir, "target");
+    Path jarPath = new Path(targetDir, "TestIterators-tests.jar");
+    Path dstPath = new Path(REAL_CONTEXT_CLASSPATH);
+    FileSystem fs = SharedMiniClusterBase.getCluster().getFileSystem();
+    fs.copyFromLocalFile(jarPath, dstPath);
+  }
+
+  private void setupFakeContextPath() throws Exception {
+    // Copy the TestIterators jar to tmp
+    Path baseDir = new Path(System.getProperty("user.dir"));
+    Path targetDir = new Path(baseDir, "target");
+    Path classesDir = new Path(targetDir, "classes");
+    Path jarPath = new Path(classesDir, "ShellServerIT-iterators.jar");
+    Path dstPath = new Path(FAKE_CONTEXT_CLASSPATH);
+    FileSystem fs = SharedMiniClusterBase.getCluster().getFileSystem();
+    fs.copyFromLocalFile(jarPath, dstPath);
+  }
+
+  @Test
   public void whoami() throws Exception {
     AuthenticationToken token = getToken();
     assertTrue(ts.exec("whoami", true).contains(getPrincipal()));

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0e1da5a5/test/src/main/java/org/apache/accumulo/test/functional/ScannerContextIT.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/accumulo/test/functional/ScannerContextIT.java
b/test/src/main/java/org/apache/accumulo/test/functional/ScannerContextIT.java
new file mode 100644
index 0000000..cc581f8
--- /dev/null
+++ b/test/src/main/java/org/apache/accumulo/test/functional/ScannerContextIT.java
@@ -0,0 +1,341 @@
+/*
+ * 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 static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map.Entry;
+
+import org.apache.accumulo.core.client.BatchScanner;
+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.IteratorSetting;
+import org.apache.accumulo.core.client.Scanner;
+import org.apache.accumulo.core.conf.Property;
+import org.apache.accumulo.core.data.Key;
+import org.apache.accumulo.core.data.Mutation;
+import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.Value;
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.core.util.CachedConfiguration;
+import org.apache.accumulo.fate.util.UtilWaitThread;
+import org.apache.accumulo.harness.AccumuloClusterHarness;
+import org.apache.accumulo.minicluster.impl.MiniAccumuloClusterImpl;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.hamcrest.CoreMatchers;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ScannerContextIT extends AccumuloClusterHarness {
+
+  private static final String CONTEXT = ScannerContextIT.class.getSimpleName();
+  private static final String CONTEXT_PROPERTY = Property.VFS_CONTEXT_CLASSPATH_PROPERTY
+ CONTEXT;
+  private static final String CONTEXT_DIR = "file:///tmp";
+  private static final String CONTEXT_CLASSPATH = CONTEXT_DIR + "/Test.jar";
+  private static int ITERATIONS = 10;
+  private static final long WAIT = 7000;
+
+  private FileSystem fs;
+
+  @Override
+  protected int defaultTimeoutSeconds() {
+    return 2 * 60;
+  }
+
+  @Before
+  public void checkCluster() throws Exception {
+    Assume.assumeThat(getClusterType(), CoreMatchers.is(ClusterType.MINI));
+    MiniAccumuloClusterImpl mac = (MiniAccumuloClusterImpl) getCluster();
+    fs = FileSystem.get(CachedConfiguration.getInstance());
+  }
+
+  @Test
+  public void test() throws Exception {
+    // Copy the TestIterators jar to tmp
+    Path baseDir = new Path(System.getProperty("user.dir"));
+    Path targetDir = new Path(baseDir, "target");
+    Path jarPath = new Path(targetDir, "TestIterators-tests.jar");
+    Path dstPath = new Path(CONTEXT_DIR + "/Test.jar");
+    fs.copyFromLocalFile(jarPath, dstPath);
+    // Sleep to ensure jar change gets picked up
+    UtilWaitThread.sleep(WAIT);
+
+    try {
+      Connector c = getConnector();
+      // Set the classloader context property on the table to point to the TestIterators
jar file.
+      c.instanceOperations().setProperty(CONTEXT_PROPERTY, CONTEXT_CLASSPATH);
+
+      // Insert rows with the word "Test" in the value.
+      String tableName = getUniqueNames(1)[0];
+      c.tableOperations().create(tableName);
+      BatchWriter bw = c.createBatchWriter(tableName, new BatchWriterConfig());
+      for (int i = 0; i < ITERATIONS; i++) {
+        Mutation m = new Mutation("row" + i);
+        m.put("cf", "col1", "Test");
+        bw.addMutation(m);
+      }
+      bw.close();
+      // Ensure that we can get the data back
+      scanCheck(c, tableName, null, null, "Test");
+      batchCheck(c, tableName, null, null, "Test");
+
+      // This iterator is in the TestIterators jar file
+      IteratorSetting cfg = new IteratorSetting(21, "reverse", "org.apache.accumulo.test.functional.ValueReversingIterator");
+
+      // Check that ValueReversingIterator is not already on the classpath by not setting
the context. This should fail.
+      try {
+        scanCheck(c, tableName, cfg, null, "tseT");
+        fail("This should have failed because context was not set");
+      } catch (Exception e) {
+        // Do nothing, this should fail as the classloader context is not set.
+      }
+      try {
+        batchCheck(c, tableName, cfg, null, "tseT");
+        fail("This should have failed because context was not set");
+      } catch (Exception e) {
+        // Do nothing, this should fail as the classloader context is not set.
+      }
+
+      // Ensure that the value is reversed using the iterator config and classloader context
+      scanCheck(c, tableName, cfg, CONTEXT, "tseT");
+      batchCheck(c, tableName, cfg, CONTEXT, "tseT");
+    } finally {
+      // Delete file in tmp
+      fs.delete(dstPath, true);
+    }
+  }
+
+  @Test
+  public void testScanContextOverridesTableContext() throws Exception {
+    // Copy the TestIterators jar to tmp
+    Path baseDir = new Path(System.getProperty("user.dir"));
+    Path targetDir = new Path(baseDir, "target");
+    Path jarPath = new Path(targetDir, "TestIterators-tests.jar");
+    Path dstPath = new Path(CONTEXT_DIR + "/Test.jar");
+    fs.copyFromLocalFile(jarPath, dstPath);
+    // Sleep to ensure jar change gets picked up
+    UtilWaitThread.sleep(WAIT);
+
+    try {
+      Connector c = getConnector();
+      // Create two contexts FOO and ScanContextIT. The FOO context will point to a classpath
+      // that contains nothing. The ScanContextIT context will point to the TestIterators.jar
+      String tableContext = "FOO";
+      String tableContextProperty = Property.VFS_CONTEXT_CLASSPATH_PROPERTY + tableContext;
+      String tableContextDir = "file:///tmp";
+      String tableContextClasspath = tableContextDir + "/TestFoo.jar";
+      // Define both contexts
+      c.instanceOperations().setProperty(tableContextProperty, tableContextClasspath);
+      c.instanceOperations().setProperty(CONTEXT_PROPERTY, CONTEXT_CLASSPATH);
+
+      String tableName = getUniqueNames(1)[0];
+      c.tableOperations().create(tableName);
+      // Set the FOO context on the table
+      c.tableOperations().setProperty(tableName, Property.TABLE_CLASSPATH.getKey(), tableContext);
+      BatchWriter bw = c.createBatchWriter(tableName, new BatchWriterConfig());
+      for (int i = 0; i < ITERATIONS; i++) {
+        Mutation m = new Mutation("row" + i);
+        m.put("cf", "col1", "Test");
+        bw.addMutation(m);
+      }
+      bw.close();
+      scanCheck(c, tableName, null, null, "Test");
+      batchCheck(c, tableName, null, null, "Test");
+      // This iterator is in the TestIterators jar file
+      IteratorSetting cfg = new IteratorSetting(21, "reverse", "org.apache.accumulo.test.functional.ValueReversingIterator");
+
+      // Check that ValueReversingIterator is not already on the classpath by not setting
the context. This should fail.
+      try {
+        scanCheck(c, tableName, cfg, null, "tseT");
+        fail("This should have failed because context was not set");
+      } catch (Exception e) {
+        // Do nothing, this should fail as the classloader context is not set.
+      }
+      try {
+        batchCheck(c, tableName, cfg, null, "tseT");
+        fail("This should have failed because context was not set");
+      } catch (Exception e) {
+        // Do nothing, this should fail as the classloader context is not set.
+      }
+
+      // Ensure that the value is reversed using the iterator config and classloader context
+      scanCheck(c, tableName, cfg, CONTEXT, "tseT");
+      batchCheck(c, tableName, cfg, CONTEXT, "tseT");
+    } finally {
+      // Delete file in tmp
+      fs.delete(dstPath, true);
+    }
+
+  }
+
+  @Test
+  public void testOneScannerDoesntInterfereWithAnother() throws Exception {
+    // Copy the TestIterators jar to tmp
+    Path baseDir = new Path(System.getProperty("user.dir"));
+    Path targetDir = new Path(baseDir, "target");
+    Path jarPath = new Path(targetDir, "TestIterators-tests.jar");
+    Path dstPath = new Path(CONTEXT_DIR + "/Test.jar");
+    fs.copyFromLocalFile(jarPath, dstPath);
+    // Sleep to ensure jar change gets picked up
+    UtilWaitThread.sleep(WAIT);
+
+    try {
+      Connector c = getConnector();
+      // Set the classloader context property on the table to point to the TestIterators
jar file.
+      c.instanceOperations().setProperty(CONTEXT_PROPERTY, CONTEXT_CLASSPATH);
+
+      // Insert rows with the word "Test" in the value.
+      String tableName = getUniqueNames(1)[0];
+      c.tableOperations().create(tableName);
+      BatchWriter bw = c.createBatchWriter(tableName, new BatchWriterConfig());
+      for (int i = 0; i < ITERATIONS; i++) {
+        Mutation m = new Mutation("row" + i);
+        m.put("cf", "col1", "Test");
+        bw.addMutation(m);
+      }
+      bw.close();
+
+      Scanner one = c.createScanner(tableName, Authorizations.EMPTY);
+
+      Scanner two = c.createScanner(tableName, Authorizations.EMPTY);
+
+      IteratorSetting cfg = new IteratorSetting(21, "reverse", "org.apache.accumulo.test.functional.ValueReversingIterator");
+      one.addScanIterator(cfg);
+      one.setClassLoaderContext(CONTEXT);
+
+      Iterator<Entry<Key,Value>> iterator = one.iterator();
+      for (int i = 0; i < ITERATIONS; i++) {
+        assertTrue(iterator.hasNext());
+        Entry<Key,Value> next = iterator.next();
+        assertEquals("tseT", next.getValue().toString());
+      }
+
+      Iterator<Entry<Key,Value>> iterator2 = two.iterator();
+      for (int i = 0; i < ITERATIONS; i++) {
+        assertTrue(iterator2.hasNext());
+        Entry<Key,Value> next = iterator2.next();
+        assertEquals("Test", next.getValue().toString());
+      }
+
+    } finally {
+      // Delete file in tmp
+      fs.delete(dstPath, true);
+    }
+  }
+
+  @Test
+  public void testClearContext() throws Exception {
+    // Copy the TestIterators jar to tmp
+    Path baseDir = new Path(System.getProperty("user.dir"));
+    Path targetDir = new Path(baseDir, "target");
+    Path jarPath = new Path(targetDir, "TestIterators-tests.jar");
+    Path dstPath = new Path(CONTEXT_DIR + "/Test.jar");
+    fs.copyFromLocalFile(jarPath, dstPath);
+    // Sleep to ensure jar change gets picked up
+    UtilWaitThread.sleep(WAIT);
+
+    try {
+      Connector c = getConnector();
+      // Set the classloader context property on the table to point to the TestIterators
jar file.
+      c.instanceOperations().setProperty(CONTEXT_PROPERTY, CONTEXT_CLASSPATH);
+
+      // Insert rows with the word "Test" in the value.
+      String tableName = getUniqueNames(1)[0];
+      c.tableOperations().create(tableName);
+      BatchWriter bw = c.createBatchWriter(tableName, new BatchWriterConfig());
+      for (int i = 0; i < ITERATIONS; i++) {
+        Mutation m = new Mutation("row" + i);
+        m.put("cf", "col1", "Test");
+        bw.addMutation(m);
+      }
+      bw.close();
+
+      Scanner one = c.createScanner(tableName, Authorizations.EMPTY);
+      IteratorSetting cfg = new IteratorSetting(21, "reverse", "org.apache.accumulo.test.functional.ValueReversingIterator");
+      one.addScanIterator(cfg);
+      one.setClassLoaderContext(CONTEXT);
+
+      Iterator<Entry<Key,Value>> iterator = one.iterator();
+      for (int i = 0; i < ITERATIONS; i++) {
+        assertTrue(iterator.hasNext());
+        Entry<Key,Value> next = iterator.next();
+        assertEquals("tseT", next.getValue().toString());
+      }
+
+      one.removeScanIterator("reverse");
+      one.clearClassLoaderContext();
+      iterator = one.iterator();
+      for (int i = 0; i < ITERATIONS; i++) {
+        assertTrue(iterator.hasNext());
+        Entry<Key,Value> next = iterator.next();
+        assertEquals("Test", next.getValue().toString());
+      }
+
+    } finally {
+      // Delete file in tmp
+      fs.delete(dstPath, true);
+    }
+  }
+
+  private void scanCheck(Connector c, String tableName, IteratorSetting cfg, String context,
String expected) throws Exception {
+    Scanner bs = c.createScanner(tableName, Authorizations.EMPTY);
+    if (null != context) {
+      bs.setClassLoaderContext(context);
+    }
+    if (null != cfg) {
+      bs.addScanIterator(cfg);
+    }
+    Iterator<Entry<Key,Value>> iterator = bs.iterator();
+    for (int i = 0; i < ITERATIONS; i++) {
+      assertTrue(iterator.hasNext());
+      Entry<Key,Value> next = iterator.next();
+      assertEquals(expected, next.getValue().toString());
+    }
+    assertFalse(iterator.hasNext());
+  }
+
+  private void batchCheck(Connector c, String tableName, IteratorSetting cfg, String context,
String expected) throws Exception {
+    BatchScanner bs = c.createBatchScanner(tableName, Authorizations.EMPTY, 1);
+    bs.setRanges(Collections.singleton(new Range()));
+    try {
+      if (null != context) {
+        bs.setClassLoaderContext(context);
+      }
+      if (null != cfg) {
+        bs.addScanIterator(cfg);
+      }
+      Iterator<Entry<Key,Value>> iterator = bs.iterator();
+      for (int i = 0; i < ITERATIONS; i++) {
+        assertTrue(iterator.hasNext());
+        Entry<Key,Value> next = iterator.next();
+        assertEquals(expected, next.getValue().toString());
+      }
+      assertFalse(iterator.hasNext());
+    } finally {
+      bs.close();
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0e1da5a5/test/src/main/java/org/apache/accumulo/test/performance/thrift/NullTserver.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/accumulo/test/performance/thrift/NullTserver.java
b/test/src/main/java/org/apache/accumulo/test/performance/thrift/NullTserver.java
index 559703f..618d720 100644
--- a/test/src/main/java/org/apache/accumulo/test/performance/thrift/NullTserver.java
+++ b/test/src/main/java/org/apache/accumulo/test/performance/thrift/NullTserver.java
@@ -138,14 +138,15 @@ public class NullTserver {
 
     @Override
     public InitialMultiScan startMultiScan(TInfo tinfo, TCredentials credentials, Map<TKeyExtent,List<TRange>>
batch, List<TColumn> columns,
-        List<IterInfo> ssiList, Map<String,Map<String,String>> ssio, List<ByteBuffer>
authorizations, boolean waitForWrites, TSamplerConfiguration tsc, long batchTimeOut) {
+        List<IterInfo> ssiList, Map<String,Map<String,String>> ssio, List<ByteBuffer>
authorizations, boolean waitForWrites, TSamplerConfiguration tsc, long batchTimeOut,
+        String context) {
       return null;
     }
 
     @Override
     public InitialScan startScan(TInfo tinfo, TCredentials credentials, TKeyExtent extent,
TRange range, List<TColumn> columns, int batchSize,
         List<IterInfo> ssiList, Map<String,Map<String,String>> ssio, List<ByteBuffer>
authorizations, boolean waitForWrites, boolean isolated,
-        long readaheadThreshold, TSamplerConfiguration tsc, long batchTimeOut) {
+        long readaheadThreshold, TSamplerConfiguration tsc, long batchTimeOut, String classLoaderContext)
{
       return null;
     }
 
@@ -211,7 +212,7 @@ public class NullTserver {
 
     @Override
     public TConditionalSession startConditionalUpdate(TInfo tinfo, TCredentials credentials,
List<ByteBuffer> authorizations, String tableID,
-        TDurability durability) throws ThriftSecurityException, TException {
+        TDurability durability, String classLoaderContext) throws ThriftSecurityException,
TException {
       return null;
     }
 

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0e1da5a5/test/src/main/resources/ShellServerIT-iterators.jar
----------------------------------------------------------------------
diff --git a/test/src/main/resources/ShellServerIT-iterators.jar b/test/src/main/resources/ShellServerIT-iterators.jar
new file mode 100644
index 0000000..7a67f21
Binary files /dev/null and b/test/src/main/resources/ShellServerIT-iterators.jar differ

http://git-wip-us.apache.org/repos/asf/accumulo/blob/0e1da5a5/test/src/test/java/org/apache/accumulo/test/functional/ValueReversingIterator.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/accumulo/test/functional/ValueReversingIterator.java
b/test/src/test/java/org/apache/accumulo/test/functional/ValueReversingIterator.java
new file mode 100644
index 0000000..e606f5a
--- /dev/null
+++ b/test/src/test/java/org/apache/accumulo/test/functional/ValueReversingIterator.java
@@ -0,0 +1,68 @@
+/*
+ * 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 java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.accumulo.core.data.ByteSequence;
+import org.apache.accumulo.core.data.Key;
+import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.Value;
+import org.apache.accumulo.core.iterators.IteratorEnvironment;
+import org.apache.accumulo.core.iterators.SortedKeyValueIterator;
+import org.apache.commons.lang3.ArrayUtils;
+
+/**
+ * Iterator used in ScannerContextIT that reverses the bytes of the value
+ *
+ */
+public class ValueReversingIterator implements SortedKeyValueIterator<Key,Value> {
+
+  protected SortedKeyValueIterator<Key,Value> source;
+
+  public ValueReversingIterator deepCopy(IteratorEnvironment env) {
+    throw new UnsupportedOperationException();
+  }
+
+  public Key getTopKey() {
+    return source.getTopKey();
+  }
+
+  public Value getTopValue() {
+    byte[] buf = source.getTopValue().get();
+    ArrayUtils.reverse(buf);
+    return new Value(buf);
+  }
+
+  public boolean hasTop() {
+    return source.hasTop();
+  }
+
+  public void init(SortedKeyValueIterator<Key,Value> source, Map<String,String>
options, IteratorEnvironment env) throws IOException {
+    this.source = source;
+  }
+
+  public void next() throws IOException {
+    source.next();
+  }
+
+  public void seek(Range range, Collection<ByteSequence> columnFamilies, boolean inclusive)
throws IOException {
+    source.seek(range, columnFamilies, inclusive);
+  }
+}


Mime
View raw message