kevinrr888 commented on code in PR #5490: URL: https://github.com/apache/accumulo/pull/5490#discussion_r2056785555
########## core/src/main/java/org/apache/accumulo/core/iteratorsImpl/ClientIteratorEnvironment.java: ########## @@ -0,0 +1,219 @@ +/* + * 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.iteratorsImpl; + +import java.io.IOException; +import java.util.Optional; + +import org.apache.accumulo.core.client.AccumuloClient; +import org.apache.accumulo.core.client.PluginEnvironment; +import org.apache.accumulo.core.client.SampleNotPresentException; +import org.apache.accumulo.core.client.sample.SamplerConfiguration; +import org.apache.accumulo.core.clientImpl.ClientContext; +import org.apache.accumulo.core.clientImpl.ClientServiceEnvironmentImpl; +import org.apache.accumulo.core.data.Key; +import org.apache.accumulo.core.data.TableId; +import org.apache.accumulo.core.data.Value; +import org.apache.accumulo.core.iterators.IteratorEnvironment; +import org.apache.accumulo.core.iterators.IteratorUtil.IteratorScope; +import org.apache.accumulo.core.iterators.SortedKeyValueIterator; +import org.apache.accumulo.core.security.Authorizations; +import org.apache.accumulo.core.spi.common.ServiceEnvironment; + +public class ClientIteratorEnvironment implements IteratorEnvironment { + + public static class Builder { + + private Optional<IteratorScope> scope = Optional.empty(); + private boolean isFullMajorCompaction = false; + private Optional<Authorizations> auths = Optional.empty(); + private boolean isUserCompaction = false; + private Optional<TableId> tableId = Optional.empty(); + private Optional<SamplerConfiguration> samplerConfig = Optional.empty(); + private boolean samplingEnabled = false; + protected Optional<ClientServiceEnvironmentImpl> env = Optional.empty(); + + public Builder withScope(IteratorScope scope) { + this.scope = Optional.of(scope); + return this; + } + + public Builder isFullMajorCompaction() { + this.isFullMajorCompaction = true; + return this; + } + + public Builder withAuthorizations(Authorizations auths) { + this.auths = Optional.of(auths); + return this; + } + + public Builder isUserCompaction() { + this.isUserCompaction = true; + return this; + } + + public Builder withTableId(TableId tableId) { + this.tableId = Optional.of(tableId); + return this; + } + + public Builder withSamplingEnabled() { + this.samplingEnabled = true; + return this; + } + + public Builder withSamplerConfiguration(SamplerConfiguration sc) { + this.samplerConfig = Optional.ofNullable(sc); + return this; + } + + public ClientIteratorEnvironment.Builder withEnvironment(ClientServiceEnvironmentImpl env) { + this.env = Optional.of(env); + return this; + } + + public Builder withClient(AccumuloClient client) { + this.env = Optional.of(new ClientServiceEnvironmentImpl((ClientContext) client)); + return this; + } + + public ClientIteratorEnvironment build() { + return new ClientIteratorEnvironment(this); + } + + } + + public static final IteratorEnvironment DEFAULT = new Builder().build(); + + private final Optional<IteratorScope> scope; + private final boolean isFullMajorCompaction; + private final Optional<Authorizations> auths; + private final boolean isUserCompaction; + private final Optional<TableId> tableId; + private final Optional<SamplerConfiguration> samplerConfig; + private final boolean samplingEnabled; + private final Optional<ClientServiceEnvironmentImpl> env; + + private ClientIteratorEnvironment(Builder builder) { + this.scope = builder.scope; + this.isFullMajorCompaction = builder.isFullMajorCompaction; + this.auths = builder.auths; + this.isUserCompaction = builder.isUserCompaction; + this.tableId = builder.tableId; + this.samplerConfig = builder.samplerConfig; + this.env = builder.env; + this.samplingEnabled = builder.samplingEnabled; + } + + /** + * Copy constructor used for enabling sample. Only called from {@link cloneWithSamplingEnabled}. + */ + private ClientIteratorEnvironment(ClientIteratorEnvironment copy) { + this.scope = copy.scope; + this.isFullMajorCompaction = copy.isFullMajorCompaction; + this.auths = copy.auths; + this.isUserCompaction = copy.isUserCompaction; + this.tableId = copy.tableId; + this.samplerConfig = copy.samplerConfig; + this.env = copy.env; + this.samplingEnabled = true; + } + + @Override + @Deprecated(since = "2.0.0") + public SortedKeyValueIterator<Key,Value> reserveMapFileReader(String mapFileName) + throws IOException { + throw new UnsupportedOperationException("Feature not supported"); + } + + @Override + public IteratorScope getIteratorScope() { + return scope.orElseThrow(); + } + + @Override + public boolean isFullMajorCompaction() { + if (getIteratorScope() != IteratorScope.majc) { + throw new IllegalStateException("Iterator scope is not majc"); + } + return isFullMajorCompaction; + } + + @Override + @Deprecated(since = "2.0.0") + public void registerSideChannel(SortedKeyValueIterator<Key,Value> iter) { + throw new UnsupportedOperationException("Feature not supported"); + } + + @Override + public Authorizations getAuthorizations() { + if (getIteratorScope() != IteratorScope.scan) { + throw new IllegalStateException("Iterator scope is not scan"); + } + return auths.orElseThrow(); + } + + @Override + public IteratorEnvironment cloneWithSamplingEnabled() { + if (samplerConfig.isEmpty()) { + throw new SampleNotPresentException(); + } + return new ClientIteratorEnvironment(this); Review Comment: Should the returned value have `sampleEnabled` set to true on it? A `sampleEnabled = false` in `this` will persist in the new returned value ########## core/src/main/java/org/apache/accumulo/core/iteratorsImpl/ClientIteratorEnvironment.java: ########## @@ -0,0 +1,219 @@ +/* + * 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.iteratorsImpl; + +import java.io.IOException; +import java.util.Optional; + +import org.apache.accumulo.core.client.AccumuloClient; +import org.apache.accumulo.core.client.PluginEnvironment; +import org.apache.accumulo.core.client.SampleNotPresentException; +import org.apache.accumulo.core.client.sample.SamplerConfiguration; +import org.apache.accumulo.core.clientImpl.ClientContext; +import org.apache.accumulo.core.clientImpl.ClientServiceEnvironmentImpl; +import org.apache.accumulo.core.data.Key; +import org.apache.accumulo.core.data.TableId; +import org.apache.accumulo.core.data.Value; +import org.apache.accumulo.core.iterators.IteratorEnvironment; +import org.apache.accumulo.core.iterators.IteratorUtil.IteratorScope; +import org.apache.accumulo.core.iterators.SortedKeyValueIterator; +import org.apache.accumulo.core.security.Authorizations; +import org.apache.accumulo.core.spi.common.ServiceEnvironment; + +public class ClientIteratorEnvironment implements IteratorEnvironment { + + public static class Builder { + + private Optional<IteratorScope> scope = Optional.empty(); + private boolean isFullMajorCompaction = false; + private Optional<Authorizations> auths = Optional.empty(); + private boolean isUserCompaction = false; + private Optional<TableId> tableId = Optional.empty(); + private Optional<SamplerConfiguration> samplerConfig = Optional.empty(); + private boolean samplingEnabled = false; + protected Optional<ClientServiceEnvironmentImpl> env = Optional.empty(); + + public Builder withScope(IteratorScope scope) { + this.scope = Optional.of(scope); + return this; + } + + public Builder isFullMajorCompaction() { + this.isFullMajorCompaction = true; + return this; + } + + public Builder withAuthorizations(Authorizations auths) { + this.auths = Optional.of(auths); + return this; + } + + public Builder isUserCompaction() { + this.isUserCompaction = true; + return this; + } + + public Builder withTableId(TableId tableId) { + this.tableId = Optional.of(tableId); + return this; + } + + public Builder withSamplingEnabled() { + this.samplingEnabled = true; + return this; + } + + public Builder withSamplerConfiguration(SamplerConfiguration sc) { + this.samplerConfig = Optional.ofNullable(sc); + return this; + } + + public ClientIteratorEnvironment.Builder withEnvironment(ClientServiceEnvironmentImpl env) { + this.env = Optional.of(env); + return this; + } + + public Builder withClient(AccumuloClient client) { + this.env = Optional.of(new ClientServiceEnvironmentImpl((ClientContext) client)); + return this; + } + + public ClientIteratorEnvironment build() { + return new ClientIteratorEnvironment(this); + } + + } + + public static final IteratorEnvironment DEFAULT = new Builder().build(); + + private final Optional<IteratorScope> scope; + private final boolean isFullMajorCompaction; + private final Optional<Authorizations> auths; + private final boolean isUserCompaction; + private final Optional<TableId> tableId; + private final Optional<SamplerConfiguration> samplerConfig; + private final boolean samplingEnabled; + private final Optional<ClientServiceEnvironmentImpl> env; + + private ClientIteratorEnvironment(Builder builder) { + this.scope = builder.scope; + this.isFullMajorCompaction = builder.isFullMajorCompaction; + this.auths = builder.auths; + this.isUserCompaction = builder.isUserCompaction; + this.tableId = builder.tableId; + this.samplerConfig = builder.samplerConfig; + this.env = builder.env; + this.samplingEnabled = builder.samplingEnabled; + } + + /** + * Copy constructor used for enabling sample. Only called from {@link cloneWithSamplingEnabled}. + */ + private ClientIteratorEnvironment(ClientIteratorEnvironment copy) { + this.scope = copy.scope; + this.isFullMajorCompaction = copy.isFullMajorCompaction; + this.auths = copy.auths; + this.isUserCompaction = copy.isUserCompaction; + this.tableId = copy.tableId; + this.samplerConfig = copy.samplerConfig; + this.env = copy.env; + this.samplingEnabled = true; + } + + @Override + @Deprecated(since = "2.0.0") + public SortedKeyValueIterator<Key,Value> reserveMapFileReader(String mapFileName) + throws IOException { + throw new UnsupportedOperationException("Feature not supported"); + } + + @Override + public IteratorScope getIteratorScope() { + return scope.orElseThrow(); + } + + @Override + public boolean isFullMajorCompaction() { + if (getIteratorScope() != IteratorScope.majc) { + throw new IllegalStateException("Iterator scope is not majc"); + } + return isFullMajorCompaction; + } + + @Override + @Deprecated(since = "2.0.0") + public void registerSideChannel(SortedKeyValueIterator<Key,Value> iter) { + throw new UnsupportedOperationException("Feature not supported"); + } + + @Override + public Authorizations getAuthorizations() { + if (getIteratorScope() != IteratorScope.scan) { + throw new IllegalStateException("Iterator scope is not scan"); + } + return auths.orElseThrow(); + } + + @Override + public IteratorEnvironment cloneWithSamplingEnabled() { + if (samplerConfig.isEmpty()) { Review Comment: Should this be checking `sampleEnabled` instead or in addition to or is this the correct check? Maybe this method is saying clone it with sampling enabled, regardless of state of `sampleEnabled` in `this`, so this check might be correct. ########## core/src/main/java/org/apache/accumulo/core/client/ClientSideIteratorScanner.java: ########## @@ -295,9 +230,14 @@ public Iterator<Entry<Key,Value>> iterator() { SortedKeyValueIterator<Key,Value> skvi; try { - IteratorEnvironment iterEnv = new ClientSideIteratorEnvironment( - getSamplerConfiguration() != null, getIteratorSamplerConfigurationInternal()); - + ClientIteratorEnvironment.Builder builder = new ClientIteratorEnvironment.Builder() + .withClient(context.get()).withAuthorizations(getAuthorizations()) + .withScope(IteratorScope.scan).withTableId(tableId.get()) + .withSamplerConfiguration(getIteratorSamplerConfigurationInternal()); + if (getSamplerConfiguration() != null) { + builder.withSamplingEnabled(); + } + IteratorEnvironment iterEnv = builder.build(); Review Comment: I believe this (and maybe elsewhere the Builder is used) needs a `withEnvironment` to keep functionality of `getServiceEnv` and `getPluginEnv` ########## core/src/main/java/org/apache/accumulo/core/client/ClientSideIteratorScanner.java: ########## @@ -295,9 +230,14 @@ public Iterator<Entry<Key,Value>> iterator() { SortedKeyValueIterator<Key,Value> skvi; try { - IteratorEnvironment iterEnv = new ClientSideIteratorEnvironment( - getSamplerConfiguration() != null, getIteratorSamplerConfigurationInternal()); - + ClientIteratorEnvironment.Builder builder = new ClientIteratorEnvironment.Builder() + .withClient(context.get()).withAuthorizations(getAuthorizations()) + .withScope(IteratorScope.scan).withTableId(tableId.get()) + .withSamplerConfiguration(getIteratorSamplerConfigurationInternal()); + if (getSamplerConfiguration() != null) { + builder.withSamplingEnabled(); + } + IteratorEnvironment iterEnv = builder.build(); Review Comment: Nevermind, I think `withClient` covers this ########## core/src/main/java/org/apache/accumulo/core/client/rfile/RFileScanner.java: ########## @@ -74,8 +78,46 @@ class RFileScanner extends ScannerOptions implements Scanner { + private static class RFileScannerEnvironmentImpl extends ClientServiceEnvironmentImpl { + + private final Configuration conf; + private final Configuration tableConf; + + public RFileScannerEnvironmentImpl(Opts opts) { + super(null); + conf = new ConfigurationImpl(new ConfigurationCopy(DefaultConfiguration.getInstance())); + ConfigurationCopy tableCC = new ConfigurationCopy(DefaultConfiguration.getInstance()); + if (opts.tableConfig != null) { + opts.tableConfig.forEach(tableCC::set); + } + tableConf = new ConfigurationImpl(tableCC); + } + + @Override + public String getTableName(TableId tableId) throws TableNotFoundException { + Preconditions.checkArgument(tableId == TABLE_ID, "Expected " + TABLE_ID + " obtained" + + " from IteratorEnvironment.getTableId(), but got: " + tableId); + return TABLE_NAME; + } Review Comment: I don't think `getTableName` should be supported here. There is no need for a user to call this. Should probably just throw an exception ########## core/src/main/java/org/apache/accumulo/core/client/rfile/RFileScanner.java: ########## @@ -74,8 +78,46 @@ class RFileScanner extends ScannerOptions implements Scanner { + private static class RFileScannerEnvironmentImpl extends ClientServiceEnvironmentImpl { + + private final Configuration conf; + private final Configuration tableConf; + + public RFileScannerEnvironmentImpl(Opts opts) { + super(null); + conf = new ConfigurationImpl(new ConfigurationCopy(DefaultConfiguration.getInstance())); + ConfigurationCopy tableCC = new ConfigurationCopy(DefaultConfiguration.getInstance()); + if (opts.tableConfig != null) { + opts.tableConfig.forEach(tableCC::set); + } + tableConf = new ConfigurationImpl(tableCC); + } + + @Override + public String getTableName(TableId tableId) throws TableNotFoundException { + Preconditions.checkArgument(tableId == TABLE_ID, "Expected " + TABLE_ID + " obtained" + + " from IteratorEnvironment.getTableId(), but got: " + tableId); + return TABLE_NAME; + } + + @Override + public Configuration getConfiguration() { + return conf; + } + + @Override + public Configuration getConfiguration(TableId tableId) { + Preconditions.checkArgument(tableId == TABLE_ID, "Expected " + TABLE_ID + " obtained" + + " from IteratorEnvironment.getTableId(), but got: " + tableId); + return tableConf; + } + + } + private static final byte[] EMPTY_BYTES = new byte[0]; private static final Range EMPTY_RANGE = new Range(); + private static final String TABLE_NAME = "rfileScanner"; + private static final TableId TABLE_ID = TableId.of(TABLE_NAME); Review Comment: I discussed in more detail [here](https://github.com/apache/accumulo/pull/4816#issuecomment-2347164444) but I'm not sure about a dummy table id/name here. Both `null` and a dummy id have their drawbacks though, so may be up to preference. In my opinion, a `null` table id makes sense since there is no table in this context while still allowing for `env.getPluginEnv().getConfiguration(env.getTableId())` to work (`getConfiguration` just ensures the passed in value is `null`) ########## core/src/main/java/org/apache/accumulo/core/client/rfile/RFileScanner.java: ########## @@ -74,8 +78,46 @@ class RFileScanner extends ScannerOptions implements Scanner { + private static class RFileScannerEnvironmentImpl extends ClientServiceEnvironmentImpl { + + private final Configuration conf; + private final Configuration tableConf; + + public RFileScannerEnvironmentImpl(Opts opts) { + super(null); + conf = new ConfigurationImpl(new ConfigurationCopy(DefaultConfiguration.getInstance())); + ConfigurationCopy tableCC = new ConfigurationCopy(DefaultConfiguration.getInstance()); + if (opts.tableConfig != null) { + opts.tableConfig.forEach(tableCC::set); + } + tableConf = new ConfigurationImpl(tableCC); + } + + @Override + public String getTableName(TableId tableId) throws TableNotFoundException { + Preconditions.checkArgument(tableId == TABLE_ID, "Expected " + TABLE_ID + " obtained" + + " from IteratorEnvironment.getTableId(), but got: " + tableId); + return TABLE_NAME; + } + + @Override + public Configuration getConfiguration() { + return conf; + } + + @Override + public Configuration getConfiguration(TableId tableId) { + Preconditions.checkArgument(tableId == TABLE_ID, "Expected " + TABLE_ID + " obtained" + + " from IteratorEnvironment.getTableId(), but got: " + tableId); + return tableConf; + } + + } + private static final byte[] EMPTY_BYTES = new byte[0]; private static final Range EMPTY_RANGE = new Range(); + private static final String TABLE_NAME = "rfileScanner"; Review Comment: This should be deleted if `getTableName` is removed -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: notifications-unsubscr...@accumulo.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org