-
Notifications
You must be signed in to change notification settings - Fork 136
chore(spanner): support mutation only operation for read-write mux #3423
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
Changes from 10 commits
3f87f79
e942e35
6d1b6dc
9ec3a6c
65b3234
5907ad5
042ef7e
dfc2a39
be71459
f12729e
01c0314
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -22,13 +22,15 @@ | |||||
| import com.google.common.collect.ImmutableList; | ||||||
| import com.google.protobuf.ListValue; | ||||||
| import java.io.Serializable; | ||||||
| import java.util.ArrayList; | ||||||
| import java.util.Collections; | ||||||
| import java.util.HashSet; | ||||||
| import java.util.LinkedHashMap; | ||||||
| import java.util.List; | ||||||
| import java.util.Map; | ||||||
| import java.util.Objects; | ||||||
| import java.util.Set; | ||||||
| import java.util.concurrent.ThreadLocalRandom; | ||||||
| import javax.annotation.Nullable; | ||||||
|
|
||||||
| /** | ||||||
|
|
@@ -402,20 +404,43 @@ private boolean isFloat32NaN(Value value) { | |||||
| return value.getType().equals(Type.float32()) && Float.isNaN(value.getFloat32()); | ||||||
| } | ||||||
|
|
||||||
| static void toProto(Iterable<Mutation> mutations, List<com.google.spanner.v1.Mutation> out) { | ||||||
| /** | ||||||
| * Converts the list of mutations to the corresponding protobuf mutations and returns a random | ||||||
| * mutation from the available list based on the following heuristics: | ||||||
| * | ||||||
| * <p>1. Prefer mutations other than INSERT, as INSERT mutations may contain autogenerated columns | ||||||
| * whose information is unavailable on the client. | ||||||
| * | ||||||
| * <p>2. If the list only contains INSERT mutations, select the one with the highest number of | ||||||
| * values. | ||||||
| */ | ||||||
| static com.google.spanner.v1.Mutation toProtoAndReturnRandomMutation( | ||||||
| Iterable<Mutation> mutations, List<com.google.spanner.v1.Mutation> out) { | ||||||
| Mutation last = null; | ||||||
| // The mutation currently being built. | ||||||
| com.google.spanner.v1.Mutation.Builder proto = null; | ||||||
| // The "write" (!= DELETE) or "keySet" (==DELETE) for the last mutation encoded, for coalescing. | ||||||
| com.google.spanner.v1.Mutation.Write.Builder write = null; | ||||||
| com.google.spanner.v1.KeySet.Builder keySet = null; | ||||||
|
|
||||||
| // Stores all the mutations excluding INSERT mutations. | ||||||
| List<com.google.spanner.v1.Mutation> allMutationsExcludingInsert = new ArrayList<>(); | ||||||
| // Stores the INSERT mutation with largest number of values. | ||||||
| com.google.spanner.v1.Mutation largestInsertMutation = | ||||||
| com.google.spanner.v1.Mutation.getDefaultInstance(); | ||||||
|
|
||||||
| for (Mutation mutation : mutations) { | ||||||
| if (mutation.operation == Op.DELETE) { | ||||||
| if (last != null && last.operation == Op.DELETE && mutation.table.equals(last.table)) { | ||||||
| mutation.keySet.appendToProto(keySet); | ||||||
| } else { | ||||||
| if (proto != null) { | ||||||
| out.add(proto.build()); | ||||||
| com.google.spanner.v1.Mutation builtMutation = proto.build(); | ||||||
| out.add(builtMutation); | ||||||
| if (checkIfInsertMutationWithLargeValue(builtMutation, largestInsertMutation)) { | ||||||
| largestInsertMutation = builtMutation; | ||||||
| } | ||||||
| addMutationsExcludingInsert(builtMutation, allMutationsExcludingInsert); | ||||||
harshachinta marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| } | ||||||
| proto = com.google.spanner.v1.Mutation.newBuilder(); | ||||||
| com.google.spanner.v1.Mutation.Delete.Builder delete = | ||||||
|
|
@@ -437,7 +462,12 @@ static void toProto(Iterable<Mutation> mutations, List<com.google.spanner.v1.Mut | |||||
| write.addValues(values); | ||||||
| } else { | ||||||
| if (proto != null) { | ||||||
| out.add(proto.build()); | ||||||
| com.google.spanner.v1.Mutation builtMutation = proto.build(); | ||||||
| out.add(builtMutation); | ||||||
| if (checkIfInsertMutationWithLargeValue(builtMutation, largestInsertMutation)) { | ||||||
| largestInsertMutation = builtMutation; | ||||||
| } | ||||||
| addMutationsExcludingInsert(builtMutation, allMutationsExcludingInsert); | ||||||
| } | ||||||
| proto = com.google.spanner.v1.Mutation.newBuilder(); | ||||||
| switch (mutation.operation) { | ||||||
|
|
@@ -464,7 +494,44 @@ static void toProto(Iterable<Mutation> mutations, List<com.google.spanner.v1.Mut | |||||
| } | ||||||
| // Flush last item. | ||||||
| if (proto != null) { | ||||||
| com.google.spanner.v1.Mutation builtMutation = proto.build(); | ||||||
| out.add(proto.build()); | ||||||
| if (checkIfInsertMutationWithLargeValue(builtMutation, largestInsertMutation)) { | ||||||
| largestInsertMutation = builtMutation; | ||||||
| } | ||||||
| addMutationsExcludingInsert(builtMutation, allMutationsExcludingInsert); | ||||||
| } | ||||||
|
|
||||||
| // Select a random mutation based on the heuristic. | ||||||
| if (!allMutationsExcludingInsert.isEmpty()) { | ||||||
| return allMutationsExcludingInsert.get( | ||||||
| ThreadLocalRandom.current().nextInt(allMutationsExcludingInsert.size())); | ||||||
| } else { | ||||||
| return largestInsertMutation; | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| // Returns true if the input mutation is of type INSERT and has more values than the current | ||||||
| // largest insert mutation. | ||||||
| private static boolean checkIfInsertMutationWithLargeValue( | ||||||
| com.google.spanner.v1.Mutation mutation, | ||||||
| com.google.spanner.v1.Mutation largestInsertMutation) { | ||||||
| // If largestInsertMutation is a default instance of Mutation, replace it with the current | ||||||
| // INSERT mutation, even if it contains zero values. | ||||||
| if (!largestInsertMutation.hasInsert()) { | ||||||
|
||||||
| if (!largestInsertMutation.hasInsert()) { | |
| if (mutation.hasInsert() && !largestInsertMutation.hasInsert()) { |
Please add a test that fails with the current implementation and succeeds with the above change (unless I missed something here, and the current implementation is correct).
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 just realized that this won't fail, as there are only two possibilities:
- There are only insert mutations. Then the largest insert mutation will be used.
- There is at least one non-insert mutation. Although it is possible that that mutation is set as 'the largest insert mutation' with the current if statement, it would not really make any difference, as the largest insert mutation won't be used anyways.
We should still fix the above if condition, though, as the current implementation is a bit confusing.
There is however another (small) optimization possible here; Once allMutationsExcludingInserts.isEmpty() returns false, you can skip the tracking of the largest insert mutation all-together, as it won't be used anyways.
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.
- Thanks for pointing this out. It does not affect the result, but it is indeed a flaw. Updated the code.
- Added the optimization.
Uh oh!
There was an error while loading. Please reload this page.