-
Notifications
You must be signed in to change notification settings - Fork 0
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
[WIP] Rocks condition with update #22
base: rocks-condition-expr-rebase
Are you sure you want to change the base?
[WIP] Rocks condition with update #22
Conversation
versioned/tiered/rocksdb/src/main/java/org/projectnessie/versioned/rocksdb/RocksBaseValue.java
Outdated
Show resolved
Hide resolved
switch (updateFunction.getOperator()) { | ||
case REMOVE: | ||
if (childPath == null || !fieldIsList(segment, childPath)) { | ||
throw new UnsupportedOperationException(); |
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.
A comment you will probably get anyway is to provide more information in the exception about what is failing.
versioned/tiered/rocksdb/src/main/java/org/projectnessie/versioned/rocksdb/RocksBaseValue.java
Outdated
Show resolved
Hide resolved
); | ||
break; | ||
case KEY_MUTATIONS_KEY: | ||
if (!childPath.getChild().get().getChild().isPresent()) { |
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.
Just think we may want some utility methods as there is a lot of commonality in drilling through the PathSegment hierarchy.
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 Optionals and path structure do make this a bit ugly. I don't have any good ideas for cleaning this up though. Do you have any suggestions?
...tiered/rocksdb/src/test/java/org/projectnessie/versioned/rocksdb/TestUpdateFunctionBase.java
Outdated
Show resolved
Hide resolved
...red/rocksdb/src/test/java/org/projectnessie/versioned/rocksdb/TestUpdateFunctionRocksL1.java
Outdated
Show resolved
Hide resolved
set(segment, childPath, setFunction.getValue()); | ||
} else if (fieldIsList(segment, childPath) != (setFunction.getValue().getType() == Entity.EntityType.LIST)) { | ||
throw new UnsupportedOperationException(); | ||
} else if (ID.equals(segment)) { |
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.
Should we handle set equals for dt
field here also from BaseValue
?
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 added it now, but I doubt it would actually be used.
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.
They did actually use this in their GC prototyping. Subsequently they dropped it, but shows they sometimes have a need.
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.
OK. It's implemented now, so we should be safe if they start updating date time.
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 may have missed it, but can you add some tests too?
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 is tested in the test classes for the implementations, such as TestUpdateFunctionRocksL1.
...red/rocksdb/src/test/java/org/projectnessie/versioned/rocksdb/TestUpdateFunctionRocksL1.java
Outdated
Show resolved
Hide resolved
.builder(RocksL1.KEY_MUTATIONS) | ||
.position(0) | ||
.name(RocksL1.KEY_MUTATIONS_MUTATION_TYPE) | ||
.build(), Entity.ofNumber(1))); |
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.
Avoid magic numbers, particularly as it is input and output data.
|
||
@Test | ||
void childrenSetEquals() { | ||
final UpdateExpression updateExpression = |
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 is very similar to the childrenSetEquals() test for RocksL1. Could we have a generic test?
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 see what you are thinking here, but it isn't quite as simple as it looks. RocksL1 and RocksL2 do not get the children from a common base class.
Another idea here is to parameterize the Update test classes, move the list tests into the base class and then add parameters for accessing the actual lists. This would get a little ugly with the parameters but would ensure that all lists are tested the same way.
What do you think?
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.
Yes, I'm leaning that way to parameterize the tests. I've been moving that way in TestUpdateFunctionRocksRef
for branch in rocks-update-branch
. Although I haven't moved anything into the base class as it is Branch specific.
...ed/rocksdb/src/test/java/org/projectnessie/versioned/rocksdb/TestUpdateFunctionRocksRef.java
Outdated
Show resolved
Hide resolved
...ed/rocksdb/src/test/java/org/projectnessie/versioned/rocksdb/TestUpdateFunctionRocksRef.java
Outdated
Show resolved
Hide resolved
versioned/tiered/rocksdb/src/main/java/org/projectnessie/versioned/rocksdb/RocksBaseValue.java
Outdated
Show resolved
Hide resolved
set(segment, childPath, setFunction.getValue()); | ||
} else if (fieldIsList(segment, childPath) != (setFunction.getValue().getType() == Entity.EntityType.LIST)) { | ||
throw new UnsupportedOperationException(); | ||
} else if (ID.equals(segment)) { |
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 may have missed it, but can you add some tests too?
|
||
@Test | ||
void childrenSetEquals() { | ||
final UpdateExpression updateExpression = |
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.
Yes, I'm leaning that way to parameterize the tests. I've been moving that way in TestUpdateFunctionRocksRef
for branch in rocks-update-branch
. Although I haven't moved anything into the base class as it is Branch specific.
…ition. Thrown exception did not match API description.
…n and not UpdateExpression
|
||
import org.projectnessie.versioned.store.Entity; | ||
|
||
public class EntityConverter { |
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.
Why public? JavaDocs?
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.
No reason for public. Added JavaDocs.
* @param entity the entity to convert | ||
* @return the object converted from the entity | ||
*/ | ||
public static ValueProtos.Commit entityToCommit(Entity entity) { |
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.
Why public?
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.
Changed to package.
if (!entity.getType().equals(Entity.EntityType.MAP)) { | ||
throw new UnsupportedOperationException(); | ||
} | ||
ValueProtos.Commit.Builder builder = ValueProtos.Commit.newBuilder(); |
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.
Style should be that we append final to everything, unless you have a reason to do so otherwise.
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.
Updated.
if (!level0.getValue().getType().equals(Entity.EntityType.LIST)) { | ||
throw new UnsupportedOperationException(); | ||
} | ||
for (Entity level1 : level0.getValue().getList()) { |
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.
Won't this throw if it's not a list already?
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.
Etc. for all other checks of this sort.
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.
You are correct. Removed the checks.
} | ||
ValueProtos.Commit.Builder builder = ValueProtos.Commit.newBuilder(); | ||
|
||
for (Map.Entry<String, Entity> level0 : entity.getMap().entrySet()) { |
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.
Won't this throw already if it's not a map?
appendToList(segment, childPath, Collections.singletonList(setFunction.getValue())); | ||
} | ||
} else { | ||
throw new UnsupportedOperationException(String.format("The append to list operation is not valid for \"%s\"", segment)); |
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'd prefer stylistically to not have the throws in the else, but to have them in the if. This way you don't even need the else, remove nesting, and don't need to refer to above in the code to find out why the exception is triggered.
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.
Updated what I could to remove some of the nesting and to move the throws up higher.
*/ | ||
class RocksFragment extends RocksBaseValue<Fragment> implements Fragment { | ||
static final String KEY_LIST = "keys"; | ||
|
||
private final ValueProtos.Fragment.Builder builder = ValueProtos.Fragment.newBuilder(); | ||
private final ValueProtos.Fragment.Builder fragmentBuilder = ValueProtos.Fragment.newBuilder(); |
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.
Why the rename?
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 my opinion, builder is an overly generic name. This gets problematic if we have a scope that also has another type of Builder, such as a Key.Builder.
Is there a reason to keep the generic name?
.newBuilder() | ||
.addAllElements(v.getList().stream().map(Entity::getString).collect(Collectors.toList())) | ||
.build() | ||
).collect(Collectors.toList())); |
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.
You should be able to avoid intermediate list creation by adding incrementally and not using addAllKeys.
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.
Please apply this to all applicable locations.
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.
Updated.
|
||
@Override | ||
protected void appendToList(String fieldName, ExpressionPath.PathSegment childPath, List<Entity> valuesToAdd) { | ||
if (new PathPattern().matches(childPath)) { |
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 looks odd, why isn't matches a static?
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 think the PathPattern class needs to be rethought a bit, it looks like it always creates a new one.
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 can see that you would like to remove the PathPattern class as you don't see any benefit to it.
If I remove it, then I will be dealing with ExpressionPath.PathSegment and I will receive a lot of feedback about how difficult it is to understand what is going on.
new PathPattern().nameEquals("foo").anyPosition()
is equivalent to:
if path != null && path.isName() && "foo".equals(path.asName().getName()) && path.getChild().isPresent() && path.getChild().get().isPosition())
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.
It's not that I want to have it removed, just that it looks odd to have to new it every time it's used. I wonder if it wouldn't be better to have a static builder or something?
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 could be improved, and we could have the path patterns stored static in the classes. I'll leave as is for now, since you likely have a different approach in mind.
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 PathPattern has been updated. It is still created new each time it is used. The next step would be to extract the PathPatterns into static variables.
@Override | ||
protected void remove(String fieldName, ExpressionPath.PathSegment path) { | ||
if (TREE.equals(fieldName)) { | ||
List<ByteString> updatedChildren = new ArrayList<>(l2Builder.getTreeList()); |
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.
final
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.
Updated.
… implements the Visitor pattern.
…o rocks-update-branch
This is the RocksDB implementation for
update()
.Ready for review are implementations for:
L1,
L2,
L3,
Value,
CommitMetadata
Fragment
Ref - Tag
Ref - Branch (missing a new tests on KeyMutations)