| /* |
| * 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 |
| * |
| * https://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.clientImpl; |
| |
| import static com.google.common.base.Preconditions.checkArgument; |
| import static java.util.Objects.requireNonNull; |
| import static java.util.concurrent.TimeUnit.MILLISECONDS; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Objects; |
| import java.util.Set; |
| import java.util.SortedSet; |
| import java.util.TreeSet; |
| import java.util.concurrent.TimeUnit; |
| |
| import org.apache.accumulo.core.client.IteratorSetting; |
| import org.apache.accumulo.core.client.ScannerBase; |
| import org.apache.accumulo.core.client.sample.SamplerConfiguration; |
| import org.apache.accumulo.core.data.Column; |
| import org.apache.accumulo.core.data.Key; |
| import org.apache.accumulo.core.data.Value; |
| import org.apache.accumulo.core.dataImpl.thrift.IterInfo; |
| import org.apache.accumulo.core.security.Authorizations; |
| import org.apache.accumulo.core.util.TextUtil; |
| import org.apache.hadoop.io.Text; |
| |
| public class ScannerOptions implements ScannerBase { |
| |
| protected List<IterInfo> serverSideIteratorList = Collections.emptyList(); |
| protected Map<String,Map<String,String>> serverSideIteratorOptions = Collections.emptyMap(); |
| |
| protected SortedSet<Column> fetchedColumns = new TreeSet<>(); |
| |
| protected long retryTimeout = Long.MAX_VALUE; |
| |
| protected long batchTimeout = Long.MAX_VALUE; |
| |
| private String regexIterName = null; |
| |
| private SamplerConfiguration samplerConfig = null; |
| |
| protected String classLoaderContext = null; |
| |
| protected Map<String,String> executionHints = Collections.emptyMap(); |
| |
| private ConsistencyLevel consistencyLevel = ConsistencyLevel.IMMEDIATE; |
| |
| protected ScannerOptions() {} |
| |
| public ScannerOptions(ScannerOptions so) { |
| setOptions(this, so); |
| } |
| |
| @Override |
| public synchronized void addScanIterator(IteratorSetting si) { |
| checkArgument(si != null, "si is null"); |
| if (serverSideIteratorList.isEmpty()) { |
| serverSideIteratorList = new ArrayList<>(); |
| } |
| |
| for (IterInfo ii : serverSideIteratorList) { |
| if (ii.iterName.equals(si.getName())) { |
| throw new IllegalArgumentException("Iterator name is already in use " + si.getName()); |
| } |
| if (ii.getPriority() == si.getPriority()) { |
| throw new IllegalArgumentException( |
| "Iterator priority is already in use " + si.getPriority()); |
| } |
| } |
| |
| serverSideIteratorList.add(new IterInfo(si.getPriority(), si.getIteratorClass(), si.getName())); |
| |
| if (serverSideIteratorOptions.isEmpty()) { |
| serverSideIteratorOptions = new HashMap<>(); |
| } |
| serverSideIteratorOptions.computeIfAbsent(si.getName(), k -> new HashMap<>()) |
| .putAll(si.getOptions()); |
| } |
| |
| @Override |
| public synchronized void removeScanIterator(String iteratorName) { |
| checkArgument(iteratorName != null, "iteratorName is null"); |
| // if no iterators are set, we don't have it, so it is already removed |
| if (serverSideIteratorList.isEmpty()) { |
| return; |
| } |
| |
| for (IterInfo ii : serverSideIteratorList) { |
| if (ii.iterName.equals(iteratorName)) { |
| serverSideIteratorList.remove(ii); |
| break; |
| } |
| } |
| |
| serverSideIteratorOptions.remove(iteratorName); |
| } |
| |
| @Override |
| public synchronized void updateScanIteratorOption(String iteratorName, String key, String value) { |
| checkArgument(iteratorName != null, "iteratorName is null"); |
| checkArgument(key != null, "key is null"); |
| checkArgument(value != null, "value is null"); |
| if (serverSideIteratorOptions.isEmpty()) { |
| serverSideIteratorOptions = new HashMap<>(); |
| } |
| serverSideIteratorOptions.computeIfAbsent(iteratorName, k -> new HashMap<>()).put(key, value); |
| } |
| |
| @Override |
| public synchronized void fetchColumnFamily(Text col) { |
| checkArgument(col != null, "col is null"); |
| Column c = new Column(TextUtil.getBytes(col), null, null); |
| fetchedColumns.add(c); |
| } |
| |
| @Override |
| public synchronized void fetchColumn(Text colFam, Text colQual) { |
| checkArgument(colFam != null, "colFam is null"); |
| checkArgument(colQual != null, "colQual is null"); |
| Column c = new Column(TextUtil.getBytes(colFam), TextUtil.getBytes(colQual), null); |
| fetchedColumns.add(c); |
| } |
| |
| @Override |
| public void fetchColumn(IteratorSetting.Column column) { |
| checkArgument(column != null, "Column is null"); |
| fetchColumn(column.getColumnFamily(), column.getColumnQualifier()); |
| } |
| |
| @Override |
| public synchronized void clearColumns() { |
| fetchedColumns.clear(); |
| } |
| |
| public synchronized SortedSet<Column> getFetchedColumns() { |
| return fetchedColumns; |
| } |
| |
| @Override |
| public synchronized void clearScanIterators() { |
| serverSideIteratorList = Collections.emptyList(); |
| serverSideIteratorOptions = Collections.emptyMap(); |
| regexIterName = null; |
| } |
| |
| protected static void setOptions(ScannerOptions dst, ScannerOptions src) { |
| synchronized (dst) { |
| synchronized (src) { |
| dst.regexIterName = src.regexIterName; |
| dst.fetchedColumns = new TreeSet<>(src.fetchedColumns); |
| dst.serverSideIteratorList = new ArrayList<>(src.serverSideIteratorList); |
| dst.classLoaderContext = src.classLoaderContext; |
| |
| dst.serverSideIteratorOptions = new HashMap<>(); |
| Set<Entry<String,Map<String,String>>> es = src.serverSideIteratorOptions.entrySet(); |
| for (Entry<String,Map<String,String>> entry : es) { |
| dst.serverSideIteratorOptions.put(entry.getKey(), new HashMap<>(entry.getValue())); |
| } |
| |
| dst.samplerConfig = src.samplerConfig; |
| dst.batchTimeout = src.batchTimeout; |
| |
| // its an immutable map, so can avoid copy here |
| dst.executionHints = src.executionHints; |
| |
| dst.consistencyLevel = src.consistencyLevel; |
| } |
| } |
| } |
| |
| @Override |
| public Iterator<Entry<Key,Value>> iterator() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public synchronized void setTimeout(long timeout, TimeUnit timeUnit) { |
| if (timeout < 0) { |
| throw new IllegalArgumentException("retry timeout must be positive : " + timeout); |
| } |
| |
| if (timeout == 0) { |
| this.retryTimeout = Long.MAX_VALUE; |
| } else { |
| this.retryTimeout = timeUnit.toMillis(timeout); |
| } |
| } |
| |
| @Override |
| public synchronized long getTimeout(TimeUnit timeunit) { |
| return timeunit.convert(retryTimeout, MILLISECONDS); |
| } |
| |
| @Override |
| public void close() { |
| // Nothing needs to be closed |
| } |
| |
| @Override |
| public Authorizations getAuthorizations() { |
| throw new UnsupportedOperationException("No authorizations to return"); |
| } |
| |
| @Override |
| public synchronized void setSamplerConfiguration(SamplerConfiguration samplerConfig) { |
| requireNonNull(samplerConfig); |
| this.samplerConfig = samplerConfig; |
| } |
| |
| @Override |
| public synchronized SamplerConfiguration getSamplerConfiguration() { |
| return samplerConfig; |
| } |
| |
| @Override |
| public synchronized void clearSamplerConfiguration() { |
| this.samplerConfig = null; |
| } |
| |
| @Override |
| public void setBatchTimeout(long timeout, TimeUnit timeUnit) { |
| if (timeout < 0) { |
| throw new IllegalArgumentException("Batch timeout must be positive : " + timeout); |
| } |
| if (timeout == 0) { |
| this.batchTimeout = Long.MAX_VALUE; |
| } else { |
| this.batchTimeout = timeUnit.toMillis(timeout); |
| } |
| } |
| |
| @Override |
| public long getBatchTimeout(TimeUnit timeUnit) { |
| return timeUnit.convert(batchTimeout, MILLISECONDS); |
| } |
| |
| @Override |
| public void setClassLoaderContext(String classLoaderContext) { |
| requireNonNull(classLoaderContext, "classloader context name cannot be null"); |
| this.classLoaderContext = classLoaderContext; |
| } |
| |
| @Override |
| public void clearClassLoaderContext() { |
| this.classLoaderContext = null; |
| } |
| |
| @Override |
| public String getClassLoaderContext() { |
| return this.classLoaderContext; |
| } |
| |
| @Override |
| public synchronized void setExecutionHints(Map<String,String> hints) { |
| this.executionHints = Map.copyOf(Objects.requireNonNull(hints)); |
| } |
| |
| @Override |
| public ConsistencyLevel getConsistencyLevel() { |
| return consistencyLevel; |
| } |
| |
| @Override |
| public void setConsistencyLevel(ConsistencyLevel level) { |
| this.consistencyLevel = Objects.requireNonNull(level); |
| } |
| |
| } |