Skip to content
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

feat: Spanner leader routing #11654

Merged
merged 2 commits into from
Feb 8, 2024
Merged

Conversation

amanda-tarafa
Copy link
Contributor

@jskeet as always one commit at a time. Although most of these will be squashed in a single commit for merging.

@amanda-tarafa amanda-tarafa requested a review from a team as a code owner February 6, 2024 07:09
Copy link
Collaborator

@jskeet jskeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's there looks fine, but I'm slightly surprised there isn't connection string support. Is the idea that this would be disabled so rarely that we don't need to make it easy? (I can't remember exactly how SpannerConnection construction works - is there a way of passing in arbitrary settings?)

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Google.Cloud.Spanner.V1
{
public partial class SpannerClientBuilder
{
public partial class SpannerClientBuilder
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some weird changes to indentation in this file...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uhh, yes, fixing

@@ -76,5 +87,17 @@ public SpannerClientBuilder MaybeCreateEmulatorClientBuilder()
builder.CopySettingsForEmulator(this);
return builder;
}

internal new T GetEffectiveSettings<T>(T settings) where T : ServiceSettingsBase, new()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Humbug - I guess we should have made the method virtual in GAX? Not that it's a problem, so long as we don't call it from GAX.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I did add this to the next major version things to consider.

{
if (Settings.LeaderRoutingEnabled)
{
settings = settings.WithHeader(LeaderRoutingHeader, true.ToString());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be clearer to put the constant in here, rather than calling true.ToString(). (It will also return "True" - I'd expect "true" to be more idiomatic, although I'm not sure the value actually matters.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep using the constant. Value matters and the specified value on desing is "True". The header set to False, unset or not present are all equivalent and mean "do not route to leader".

/// some operations will never be explicitly routed to the leader, and some operations will
/// be routed to the leader depending on the transaction type they are using.
/// </remarks>
internal bool LeaderRoutingEnabled { get; set; } = true;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm slightly surprised this is internal rather than public. Is there a reason for that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, because this is just how we trickle this setting down to the client where we actually use it. It's not how this setting is exposed for configuration to the user, that is done through the SpannerClientBuilder for users using Spanner.V1 and the connection string for users using Spanner.Data.

If we make it public here and users also can set it, then we'd have to react to users providing different values in the pairs SpannerClientBuilder.LeaderRoutingEnabled + SpannerSettings.LeaderRoutingEnabled and ConnectionString.LeaderRoutingEnabled + SpannerSettings.LeaderRoutingEnabled. An alternative to avoiding that is removing the setting from SpannerClientBuilder and ConnectionString and make it only available through SpannerSettings. That wouldn't be a huge deal for Spanner.V1 users, they'd just have to set a SpannerClientBuilder.SpannerSettings = new SpannerSettings { LeaderRoutingEnabled = false; } but it would be worse for Spanner.Data users as they wouldn't be able to use the default SessionPoolManager, they'd had to build one themselves to be able to pass custom SpannerSettings.
Does this makes sense? The last commit is now the connection string bit, so happy to chat more about this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, that's fine.

@@ -146,7 +146,11 @@ public void SetsHeaderOnBeginTransaction()
{
var invoker = new FakeCallInvoker();
var client = new SpannerClientBuilder { CallInvoker = invoker }.Build();
client.BeginTransaction(new BeginTransactionRequest { Session = SampleSessionName });
client.BeginTransaction(new BeginTransactionRequest
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than change the test, perhaps we should fix the code so that it doesn't fail with an NRE? (If it definitely would be an invalid request, we could potentially throw an ArgumentException, but to be honest I think it would be better to just default to a particular mode and let the server reject it.)

I suspect it's just a case of using request.Options?.ModeCase ?? TransactionOptions.ModeOneofCase.None

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, of course! Fixing.

Copy link
Contributor Author

@amanda-tarafa amanda-tarafa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jskeet all review comments addressed in new ordered commits prefixed "Address review". Plus a new commit at the end adding connection string support (I was waiting for confirmation this was wanted).

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Google.Cloud.Spanner.V1
{
public partial class SpannerClientBuilder
{
public partial class SpannerClientBuilder
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uhh, yes, fixing

@@ -76,5 +87,17 @@ public SpannerClientBuilder MaybeCreateEmulatorClientBuilder()
builder.CopySettingsForEmulator(this);
return builder;
}

internal new T GetEffectiveSettings<T>(T settings) where T : ServiceSettingsBase, new()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I did add this to the next major version things to consider.

{
if (Settings.LeaderRoutingEnabled)
{
settings = settings.WithHeader(LeaderRoutingHeader, true.ToString());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep using the constant. Value matters and the specified value on desing is "True". The header set to False, unset or not present are all equivalent and mean "do not route to leader".

/// some operations will never be explicitly routed to the leader, and some operations will
/// be routed to the leader depending on the transaction type they are using.
/// </remarks>
internal bool LeaderRoutingEnabled { get; set; } = true;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, because this is just how we trickle this setting down to the client where we actually use it. It's not how this setting is exposed for configuration to the user, that is done through the SpannerClientBuilder for users using Spanner.V1 and the connection string for users using Spanner.Data.

If we make it public here and users also can set it, then we'd have to react to users providing different values in the pairs SpannerClientBuilder.LeaderRoutingEnabled + SpannerSettings.LeaderRoutingEnabled and ConnectionString.LeaderRoutingEnabled + SpannerSettings.LeaderRoutingEnabled. An alternative to avoiding that is removing the setting from SpannerClientBuilder and ConnectionString and make it only available through SpannerSettings. That wouldn't be a huge deal for Spanner.V1 users, they'd just have to set a SpannerClientBuilder.SpannerSettings = new SpannerSettings { LeaderRoutingEnabled = false; } but it would be worse for Spanner.Data users as they wouldn't be able to use the default SessionPoolManager, they'd had to build one themselves to be able to pass custom SpannerSettings.
Does this makes sense? The last commit is now the connection string bit, so happy to chat more about this.

@@ -146,7 +146,11 @@ public void SetsHeaderOnBeginTransaction()
{
var invoker = new FakeCallInvoker();
var client = new SpannerClientBuilder { CallInvoker = invoker }.Build();
client.BeginTransaction(new BeginTransactionRequest { Session = SampleSessionName });
client.BeginTransaction(new BeginTransactionRequest
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, of course! Fixing.

Copy link
Collaborator

@jskeet jskeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one simple change requested, but I think it's an important one (or I've misunderstood something).

@@ -436,6 +437,20 @@ public EmulatorDetection EmulatorDetection
}
}

/// <summary>
/// Options to control leader routing. This is true by default.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is true by default, and we don't have a test for it.

I suspect the change is just to call GetValueOrDefault(EnableLeaderRoutingKeyword, "True")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! thanks for catching this. I'll add a test as well.

/// some operations will never be explicitly routed to the leader, and some operations will
/// be routed to the leader depending on the transaction type they are using.
/// </remarks>
internal bool LeaderRoutingEnabled { get; set; } = true;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, that's fine.

Copy link
Contributor Author

@amanda-tarafa amanda-tarafa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jskeet all previous commits squashed into one plus a new commit fixing the leader routing default in the connection string (I'll squash that one as well before mergin.) PTAL.

@amanda-tarafa amanda-tarafa merged commit eb2157a into googleapis:main Feb 8, 2024
9 checks passed
@amanda-tarafa amanda-tarafa deleted the spanner-lar branch February 8, 2024 18:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants