Skip to content
This repository has been archived by the owner on Nov 20, 2018. It is now read-only.

Use pooled StringBuilder to reduce allocations when adding response cookies #594

Closed
wants to merge 5 commits into from

Conversation

dougbu
Copy link
Member

@dougbu dougbu commented Mar 21, 2016

  • ResponseCookies.Append() allocates lots, big lots #561
  • new SetCookieHeaderValue.AppendToStringBuilder() method; avoids per-call StringBuilder allocation
  • ResponseCookies uses ObjectPool<StringBuilder> that ResponseCookiesFeature provides
  • ResponseCookiesFeature creates an ObjectPoolProvider instance if none in DI
  • IResponseCookiesFeature exposes int properties supporting middleware overrides of the pool policy

nit: Add some doc comments

/// For example, the maximum retained capacity of <see cref="System.Text.StringBuilder"/> instances obtained
/// from an object pool.
/// </remarks>
int MaximumRetainedPooledInstanceCapacity { get; set; }
Copy link
Member Author

Choose a reason for hiding this comment

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

Copying @Tratcher's comment from previous PR: 👎 This is an implementation detail, not a generic feature property.

Copy link
Member Author

Choose a reason for hiding this comment

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

What do you suggest? This is at least abstracted from StringBuilder and ObjectPool<T>. I'm loath to expose an even-more-specific ObjectPool<StringBuilder> property anywhere.

One thought: We could expose these properties only on the feature implementation once I fix #592. Then the required downcast would at least be to a public class.

@dougbu dougbu force-pushed the dougbu/cookie.maker.561.II branch from b5b204c to 1f2d8bb Compare March 21, 2016 22:11
@dougbu
Copy link
Member Author

dougbu commented Mar 21, 2016

🆙📅

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Http.Features.Internal;
Copy link
Member Author

Choose a reason for hiding this comment

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

Won't need this addition once I'm done #592.

@Tratcher
Copy link
Member

👍 progress

@davidfowl
Copy link
Member

Much better, I'm not 100% comfortable with this yet. Trying to see how it scales when we add things.

@dougbu
Copy link
Member Author

dougbu commented Mar 21, 2016

Trying to see how it scales when we add things

  1. Main "thing" not visible in this PR is the code in our cookie-related middleware setup to (try)add an ObjectPoolProvider to DI. Worst case is something adding cookies doesn't perform as well as it could.
  2. If later added "things" are additional ObjectPool<StringBuilder> uses, likely the existing one in HttpContextFactory will suffice -- the sizes are fine for this and the form parsing use cases. Extra code would instantiate and set additional features with an ObjectPool<StringBuilder> constructor parameter.
  3. If later added "things" are other pools (or the existing one isn't configured correctly), HttpContextFactory could create more ObjectPool<T> instances. Would of course also need the extra code from (1) and might need (3) as well.
  4. If later added "things" are IPooledObjectPolicy<T> instances or int values for particular pools, would add IOptions<HttpContextFactorySettings> parameters to the HttpContextFactory constructor overloads accepting an ObjectPoolProvider. That's a bit ugly but it uses our bog-standard options pattern. We'd end up with at most 6 ObjectPoolProvider constructor overloads but the existing 3 seems much more likely, at least until we need to pool something besides StringBuilders.

@dougbu
Copy link
Member Author

dougbu commented Mar 22, 2016

🆙📅 addressed @Tratcher's comments

… cookies

- #561
- new `SetCookieHeaderValue.AppendToStringBuilder()` method; avoids per-call `StringBuilder` allocation
- `ResponseCookies` uses `ObjectPool<StringBuilder>` that `ResponseCookiesFeature` provides
- `ResponseCookiesFeature` creates an `ObjectPoolProvider` instance if none in DI
- `IResponseCookiesFeature` exposes `int` properties supporting middleware overrides of the pool policy

nit: Add some doc comments
- `IHttpContextFactory` instance is a singleton instantiated from CI
 - make `HttpContextFactory` `ObjectPoolProvider` and `ResponseCookiesFeature`-aware
 - apply same pattern to sample `PooledHttpContextFactory`
- pool is not currently configurable; defaults are fine for response cookies
 - if we need (policy) configuration, would add an `IOptions<HttpContextFactorySettings>`
- `ResponseCookies` works fine if no `ObjectPoolProvider` is available
@dougbu dougbu force-pushed the dougbu/cookie.maker.561.II branch from 668719b to 52cb1f9 Compare March 23, 2016 16:20
@@ -27,7 +27,7 @@
"System.Net.WebSockets": "4.0.0-*",
"System.Runtime.Extensions": "4.1.0-*",
"System.Security.Claims": "4.0.1-*",
"System.Security.Cryptography.X509Certificates": "4.1.0-*",
"System.Security.Cryptography.X509Certificates": "4.0.0-*",
Copy link
Member Author

Choose a reason for hiding this comment

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

Not sure this will be necessary next time CI updates the feed. @pranavkm?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yup, the 4.1.0 package is available in the new corefx build.

@dougbu
Copy link
Member Author

dougbu commented Mar 23, 2016

🆙📅 (rebased)

ping @Tratcher @davidfowl

@Tratcher
Copy link
Member

:shipit:

@dougbu
Copy link
Member Author

dougbu commented Mar 23, 2016

🆙📅 (as requested, @davidfowl)

using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Http.Features.Internal;
using Microsoft.Extensions.ObjectPool;

namespace Microsoft.AspNetCore.Http.Internal
Copy link

Choose a reason for hiding this comment

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

Wasn't the plan to move the Features out of Internal namespace?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yup. I have a second wave of breaking changes (after moving the feature implementations) queued up. That'll cover both #549 and #592.

dougbu added a commit to aspnet/HttpSysServer that referenced this pull request Mar 25, 2016
@dougbu
Copy link
Member Author

dougbu commented Mar 25, 2016

80813f7

@dougbu dougbu closed this Mar 25, 2016
@dougbu dougbu deleted the dougbu/cookie.maker.561.II branch March 25, 2016 19:21
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants