-
Notifications
You must be signed in to change notification settings - Fork 35
feat: support commit_options #364
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
Conversation
olavloite
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.
Would you mind also adding a mock server test to verify that the commit options are actually being converted to the correct proto options and included with the commit request?
| @return_commit_stats = options.fetch :return_commit_stats, false | ||
| @max_commit_delay = options.fetch :max_commit_delay, 0 |
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.
nit: would it maybe make sense to just keep these together in one field? So just simply @commit_options=options
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 think it make sense to introduce a commit_options hash here and use that instead. I have updated my implementation to use these changes.
| def set_commit_options options = {} | ||
| return if options.empty? | ||
|
|
||
| options.each do |key, value| |
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.
See also my comment above: would it maybe simplify things if we just keep all commit options in one hash, instead of extracting them to separate fields here?
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 agree. We can use a single hash and that will be more simpler to use. I have addressed this in the updated commits.
I have added a mock server test with the new commit. |
c27ab31 to
fc5578f
Compare
fc5578f to
c65e55e
Compare
| assert_equal _transaction_isolation_level_to_grpc(isolation), | ||
| sql_request.transaction&.begin&.isolation_level | ||
|
|
||
| @mock.requests.clear |
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.
nit: you can remove this. The requests are automatically cleared after each 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.
Done
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 looks like it is still there :-)
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 guess its removed in the recent commit. Can you look at the changes from all commits that shows that it was removed.
| # Sets the commit options for this transaction. | ||
| # This is used to set the options for the commit RPC, such as return_commit_stats and max_commit_delay. | ||
| def set_commit_options commit_options = {} | ||
| @commit_options.merge! commit_options |
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 that this might be a bit confusing. The name is set_commit_options, but the implementation is merge. That means that if you call this method twice, then the result will be the combination of the two. The name set_commit_options however sounds like something that will overwrite the previous setting.
Note: I'm necessarily against the merge behavior, but it should be in line with the name of the 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.
The merge! operation works on the current state of @commit_options, preserving previous changes and only overwriting the keys that are passed in the new call.
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.
My idea was to maintain a state of previous values, but i think this setter should reset the state entirely with the new state even if some attributes are missing.
Something like this
def set_commit_options options # rubocop:disable Naming/AccessorMethodName return if options.nil? @commit_options = options.dup end
| force_begin_read_write if @committable && !@mutations.empty? && !@grpc_transaction | ||
|
|
||
| @connection.session.commit_transaction @grpc_transaction, @mutations if @committable && @grpc_transaction | ||
| com_options = commit_options |
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.
nit: you don't need a separate variable here, you can just use commit_options directly in the call to commit_transaction below.
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.
| # Transaction | ||
|
|
||
| def transaction requires_new: nil, isolation: nil, joinable: true | ||
| def transaction requires_new: nil, isolation: nil, commit_options: nil, joinable: true |
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 can simplify this method to the following:
def transaction requires_new: nil, isolation: nil, joinable: true, **kwargs
commit_options = kwargs.delete :commit_options
if !requires_new && current_transaction.joinable?
return super
end
backoff = 0.2
begin
super do
# Once the transaction has been started by `super`, apply your custom options
# to the Spanner transaction object.
if commit_options && @connection.current_transaction
@connection.current_transaction.set_commit_options commit_options
end
# Now, yield to the user's code block.
yield
end
rescue ActiveRecord::StatementInvalid => err
if err.cause.is_a? Google::Cloud::AbortedError
sleep(delay_from_aborted(err) || (backoff *= 1.3))
retry
end
raise
end
endThere 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.
| attr_reader :commit_options | ||
|
|
||
| def initialize connection, isolation | ||
| DEFAULT_COMMIT_OPTIONS = { |
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.
nit: I think it would be better if the default is just nil, and that we only include commit options with the actual commit if anything has been set.
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.
Makes sense will update it.
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.
Right now i have not added any sort of validations on the commit_options fields. Should we add more validation on this before making an API request or rely on spanner backend to handle such validations and report error if something is wrong.
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 let Spanner handle any invalid values.
| }.freeze | ||
|
|
||
|
|
||
| def initialize connection, isolation, commit_options = DEFAULT_COMMIT_OPTIONS |
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.
so this should then preferably also be:
| def initialize connection, isolation, commit_options = DEFAULT_COMMIT_OPTIONS | |
| def initialize connection, isolation, commit_options = nil |
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.
57134e0 to
b32560c
Compare
| # Sets the commit options for this transaction. | ||
| # This is used to set the options for the commit RPC, such as return_commit_stats and max_commit_delay. | ||
| def set_commit_options options # rubocop:disable Naming/AccessorMethodName | ||
| return if options.nil? |
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.
nit: this should also set @options to nil
so something like this:
if options.nil?
@options = nil
else
@options = options.dup
end| assert_equal _transaction_isolation_level_to_grpc(isolation), | ||
| sql_request.transaction&.begin&.isolation_level | ||
|
|
||
| @mock.requests.clear |
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 looks like it is still there :-)
b32560c to
0d10f2d
Compare
0d10f2d to
f0a9f31
Compare
feat: Add support for
commit_optionswithmax_commit_delayandreturn_commit_statsfor transaction commits.This change introduces the ability to configure transaction commit behavior using the
commit_optionsparameter. Specifically, it enables setting:max_commit_delay: To fine-tune commit behavior for throughput-optimized writes.return_commit_stats: To request commit statistics.Key changes:
service.commitmethod to accept acommit_optionsparameter.max_commit_delayandreturn_commit_statswithin thecommit_optionsparameter.