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

Use NatsMemoryOwner for Base64Url Encoder #565

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

to11mtm
Copy link
Collaborator

@to11mtm to11mtm commented Jul 15, 2024

Resolves #557

By using NatsMemoryOwner we can avoid a lot of GC thrashing here.

Note:

Once Microsoft.Bcl.Memory hits 9.0, there will be a Base64Url class to get rid of our encoder, see : dotnet/runtime#103617

If we are OK pulling in 'odd-numbered' deps, once that is released, we will want to revisit the topic.


Above note aside, this PR should lower GC pressure on ObjectStore operations all targets (i.e. NETSTANDARD/NET).

I kept it as simple as I could in the mindset that longer term, we can lean on BCL instead, i.e. Future PRs can optimize for scenarios where more IFDEFs are worth the cost and/or we update deps.

Copy link
Collaborator Author

@to11mtm to11mtm left a comment

Choose a reason for hiding this comment

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

Self review with asks for feedback.

{
using (var owner = EncodeToMemoryOwner(inArray, raw))
{
var segment = owner.DangerousGetArray();
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The use here isn't dangerous since we are owning it in scope,
This was just easiest way to call new string without #if type stuff for different FWs.

As it stands, this should still be a significant improvement as far as array allocations due to the pooling.

LMK if this deserves a comment.

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's good. as you said it's in scope so it's fine. a short comment might be nice for our future selves. btw if you're concerned maybe use span.tostring()? - i believe that was you suggestion to something else before 😅 having said that I'm guessing string.ctor(char[]) must be super fast!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

span.tostring()?

I had the same realization lol... span.ToString is going to be the best way to go on these.


var lengthMod3 = length % 3;
var limit = length - lengthMod3;
var output = new char[(length + 2) / 3 * 4];
var owner = NatsMemoryOwner<char>.Allocate((length + 2) / 3 * 4);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Should we be try-catch-dispose-throw around this, case something derps in the encode?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Also, Should we be adding a flag to the method here to specify 'clearing' and pass it in here? I guess it depends on the security concern of the SHA lingering.

CC @mtmk @caleblloyd

Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we be try-catch-dispose-throw around this, case something derps in the encode?

Should we encode to span instead? in case of sha we can also stackalloc maybe?

Also, Should we be adding a flag to the method here to specify 'clearing' and pass it in here?

Do you mean clearing the input array or output?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Should we encode to span instead? in case of sha we can also stackalloc maybe?

Hmm I can give it a shot, it might be cleaner...

Do you mean clearing the input array or output?

Clearing the buffered array. IIRC NatsMemoryOwner has a flag to say whether the array is cleared on return.

My 'gut' says yes but if we can get away with stackallocing the span, point is moot. Will check.

Comment on lines +145 to +147
if (info.Digest == null
|| info.Digest.StartsWith("SHA-256=") == false
|| info.Digest.AsSpan().Slice("SHA-256=".Length).SequenceEqual(digest.Span) == false)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There is likely a 'better way' to handle this case, but this seemed clear and should be performant enough.

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's good. maybe ordinal StartsWith to avoid cultures?

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.

Optimize Objectstore Base64URL encoding bits
2 participants