-
Notifications
You must be signed in to change notification settings - Fork 471
Prevents iterator conflicts #6040
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 2.1
Are you sure you want to change the base?
Conversation
This commit adds checks when adding an iterator that the given iterator does not conflict with any existing iterators. Conflict meaning same name or same priority. Iterators can be added several ways, and previously only TableOperations.attachIterator and NamespaceOperations.attachIterator would check for conflicts. This commit adds iterator conflict checks to: - Scanner.addScanIterator - TableOperations.setProperty - TableOperations.modifyProperties - NewTableConfiguration.attachIterator Note that this does not add conflict checks to NamespaceOperations.setProperty or NamespaceOperations.modifyProperties, these will be done in another commit. This commit also accounts for the several ways in which conflicts can arise: - Iterators that are attached directly to a table (either through TableOperations.attachIterator, TableOperations.setProperty, or TableOperations.modifyProperties) - Iterators that are attached to a namespace, inherited by a table (either through NamespaceOperations.attachIterator, NamespaceOperations.setProperty, or NamespaceOperations.modifyProperties) - Conflicts with default table iterators (if the table has them) - Adding the exact iterator already present should not fail This commit also adds a new IteratorConflictsIT to test all of the above. Part of apache#6030
Adds conflict checks to: - NamespaceOperations.attachIterator (was previously only checking for conflicts with iterators in the namespace, now also checks for conflicts with iterators in the tables of the namespace) - NamespaceOperations.setProperty (check conflicts with namespace iterators and all tables in the namespace) - NamespaceOperations.modifyProperties (check conflicts with namespace iterators and all tables in the namespace) New tests to IteratorConflictsIT to test the above
kevinrr888
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From running sunny day tests and all the tests I have changed in this PR, noticed that I unknowingly added new permission requirements to at least TableOperations.create() (new required permission ALTER_NAMESPACE) and Scanner.addScanIterator() (new required permission ALTER_TABLE). I imagine this is a blocker for these changes at this point, but let me know if it's not. I'll look into an alternative to avoid these permissions. See changes to ConditionalWriterIT, ScanIteratorIT, and ShellServerIT for examples of the failures I encountered.
| try { | ||
| TableOperationsHelper.checkIteratorConflicts(noDefaultsPropMap, setting, scopes); | ||
| TableOperationsHelper.checkIteratorConflicts(propertyMap, setting, scopes); | ||
| } catch (AccumuloException e) { | ||
| throw new IllegalStateException(String.format( | ||
| throw new AccumuloException(String.format( | ||
| "conflict with default table iterator: scopes: %s setting: %s", scopes, setting), e); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor mistake when I had originally written this to throw IllegalStateException. Changed to AccumuloException. This is called exclusively by TableOperations.create(), so I thought AccumuloException would be a more appropriate exception for this. This does change a public API method signature, so this may not be desired. If that is the case, I can change this to IllegalArgumentException, which is probably more appropriate than IllegalStateException
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general adding or removing checked exceptions from public API methods will always result in source and binary incompatibilities. When adding checked exceptions any calling code that does not already catch or throw the exception will now fail at compile or runtime. When removing checked exceptions it can cause code that catches them unnecessarily to fail. So would not want to make this change in 2.1 or even 4.0. The only way I know to change checked exceptions cleanly is to deprecate the method and add a new method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I figured there would be an issue with this change. Ill change to IllegalArgumentException
| Preconditions.checkState(valInPropMap == null || valInPropMap.equals(dv), String.format( | ||
| "conflict for property %s : %s (default val) != %s (set val)", dk, dv, valInPropMap)); | ||
| }); | ||
| if (valInPropMap != null && !valInPropMap.equals(dv)) { | ||
| throw new AccumuloException(String.format( | ||
| "conflict for property %s : %s (default val) != %s (set val)", dk, dv, valInPropMap)); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment here about changing from IllegalStateException to AccumuloException
| * <p> | ||
| * - {@link Scanner#addScanIterator(IteratorSetting)} | ||
| * <p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The iterator conflict tests I added for addScanIterator really only test ScannerImpl impl of ScannerOptions not sure if its worthwhile to add testing for all impls
| * | ||
| * @param props the parent namespace config | ||
| */ | ||
| public void configureInheritedIteratorProps(Map<String,String> props) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this had to be public to be accessible in TableOperationsImpl... I think this is fine since a similar thing is done for getProperties(), but let me know if this addition to the public API for 2.1 is a problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the code is only needed by internal code, then its best to avoid adding to the public API. Would it be possible to do somethnig like the following instead in TableOperationsImpl.create() (or maybe even in the manager create table code, it usually better to do validation on the server side for things like this rather than trust the client to do it)?
var tableProps = ntc.getProperties();
var namespaceProps = context.namespaceOperations().getNamespaceProperties(ns);
// TODO throw exception if namespace and table iter props conflictThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, working on doing the validation server side (which removes the need for this method). I started working on this change because getting the namespace properties within TableOperations.create() results in requiring the user to have the ALTER_NAMESPACE permission, which we don't want for a create() table call
| TableOperationsHelper.checkIteratorConflicts(noDefaultsPropMap, setting, scopes); | ||
| TableOperationsHelper.checkIteratorConflicts(propertyMap, setting, scopes); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could remove noDefaultsPropMap since I pushed the check for equality into checkIteratorConflicts
| String valStr = String.format("%s,%s", setting.getPriority(), setting.getIteratorClass()); | ||
| Map<String,String> optionConflicts = new TreeMap<>(); | ||
| // skip if the setting is present in the map... not a conflict if exactly the same | ||
| if (props.containsKey(nameStr) && props.get(nameStr).equals(valStr) | ||
| && IteratorConfigUtil.containsSameIterOpts(props, setting, optStr)) { | ||
| continue; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this method is the same as before except the addition of "valStr" and this if check.
Moved here since same code was used for TableOperationsHelper.checkIteratorConflicts and NamespaceOperationsHelper.checkIteratorConflicts.
|
Transferring to WIP until I resolve #6040 (review) |
| private Consumer<IteratorSetting> getScanIteratorValidator(Callable<String> tableNameGetter) { | ||
| return (givenIter) -> { | ||
| try { | ||
| tableOperations().checkIteratorConflicts(tableNameGetter.call(), givenIter, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Every time an iterator is added to a scanner on the client side this code wil make an RPC to get the tables full config and then check it. This could be expensive and slow down code that is current creating a scanner and adding lots of iterators.
Instead of doing all this validation client side, we could potentially do it server side and not make any changes to the client side code. We are already passing iterators to servers for the scan RPCs, we could potentialy check for the conflicts in the following code and throw an exception if any are seen.
accumulo/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/ScanDataSource.java
Lines 244 to 249 in b3c938a
| // Scan time iterator options were set, so need to merge those with pre-parsed table | |
| // iterator options. | |
| iterOpts = new HashMap<>(pic.getOpts().size() + scanParams.getSsio().size()); | |
| iterInfos = new ArrayList<>(pic.getIterInfo().size() + scanParams.getSsiList().size()); | |
| IteratorConfigUtil.mergeIteratorConfig(iterInfos, iterOpts, pic.getIterInfo(), | |
| pic.getOpts(), scanParams.getSsiList(), scanParams.getSsio()); |
Not sure if that is workable, would be good to rule this in or out as an option. Would be nice to efficiently do the check leveraging the existing merge code if possible.
| try { | ||
| TableOperationsHelper.checkIteratorConflicts(noDefaultsPropMap, setting, scopes); | ||
| TableOperationsHelper.checkIteratorConflicts(propertyMap, setting, scopes); | ||
| } catch (AccumuloException e) { | ||
| throw new IllegalStateException(String.format( | ||
| throw new AccumuloException(String.format( | ||
| "conflict with default table iterator: scopes: %s setting: %s", scopes, setting), e); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general adding or removing checked exceptions from public API methods will always result in source and binary incompatibilities. When adding checked exceptions any calling code that does not already catch or throw the exception will now fail at compile or runtime. When removing checked exceptions it can cause code that catches them unnecessarily to fail. So would not want to make this change in 2.1 or even 4.0. The only way I know to change checked exceptions cleanly is to deprecate the method and add a new method.
| * | ||
| * @param props the parent namespace config | ||
| */ | ||
| public void configureInheritedIteratorProps(Map<String,String> props) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the code is only needed by internal code, then its best to avoid adding to the public API. Would it be possible to do somethnig like the following instead in TableOperationsImpl.create() (or maybe even in the manager create table code, it usually better to do validation on the server side for things like this rather than trust the client to do it)?
var tableProps = ntc.getProperties();
var namespaceProps = context.namespaceOperations().getNamespaceProperties(ns);
// TODO throw exception if namespace and table iter props conflict|
Discussed iterator conflicts today, and here's a summary of some key points:
|
This adds checks when adding an iterator that the given iterator does not conflict with any existing iterators. Conflict meaning same name or same priority. Iterators can be added several ways, and previously only TableOperations.attachIterator and NamespaceOperations.attachIterator would check for conflicts. This adds iterator conflict checks to:
This also accounts for the several ways in which conflicts can arise:
This commit also adds a new IteratorConflictsIT to test all of the above.
Part of #6030