Skip to content

Buffer: Implement tracking for BufferMemoryAccounts in WatermarkFactory.#17093

Merged
htuch merged 16 commits intoenvoyproxy:mainfrom
KBaichoo:acct-streams
Jul 30, 2021
Merged

Buffer: Implement tracking for BufferMemoryAccounts in WatermarkFactory.#17093
htuch merged 16 commits intoenvoyproxy:mainfrom
KBaichoo:acct-streams

Conversation

@KBaichoo
Copy link
Copy Markdown
Contributor

@KBaichoo KBaichoo commented Jun 22, 2021

Signed-off-by: Kevin Baichoo kbaichoo@google.com

Commit Message: Implement Tracking for BufferMemoryAccounts in Watermark Factory.
Additional Description: This PR tracks memory accounts using >1MB of allocated space, with feedback mechanisms based on credits and debits on accounts. It further creates the handle from which the BufferMemoryAccount can reset the stream, and has the WatermarkBufferFactory also produce the particular BufferMemoryAccountImpl used for tracking.
Risk Level: Medium
Testing: Unit and Integration test
Docs Changes: NA
Release Notes: NA -- not yet user facing
Platform Specific Features: NA
Runtime guard: Yes, envoy.test_only.per_stream_buffer_accounting from #16218 sufficient
Related Issue #15791

Signed-off-by: Kevin Baichoo <kbaichoo@google.com>
@KBaichoo
Copy link
Copy Markdown
Contributor Author

/assign @antoniovicente

Copy link
Copy Markdown
Contributor

@antoniovicente antoniovicente left a comment

Choose a reason for hiding this comment

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

Here's some initial feedback. Looks like a good start.

/wait

Comment thread envoy/buffer/buffer.h Outdated
*
* @param reason the reason for reseting the stream.
*/
virtual void resetStream(Http::StreamResetReason reason) PURE;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Consider changing the name to resetDownstream(reason) or resetDownstreamDueToOverload()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Changed to resetDownstream

Comment thread envoy/buffer/buffer.h
Comment thread envoy/buffer/buffer.h Outdated
/**
* Unregister a buffer memory account.
*/
virtual void unregisterAccount(const BufferMemoryAccountSharedPtr& account) PURE;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think these two methods need to be part of the general factory interface. I think accounts can depend on the concrete implementation in order to do a more optimized account balance update only in cases where there's a significant change in account balance which requires moving the account from one bucket to another. By having some of the update logic in the account proper we can optimize away unnecessary calls to update the balance.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

SGTM. Moved the BufferMemoryAccountImpl to the WatermarkBuffer impl's file, since it's the factory that produces that object. This inturn allows us to more easily couple between the two, while external classes use there interfaces.

Comment thread source/common/buffer/BUILD Outdated
hdrs = ["buffer_impl.h"],
deps = [
"//envoy/buffer:buffer_interface",
"//envoy/http:codec_interface",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think this depends on stream_reset_handler_interface, not codec_interface

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Whoops, must of got mixed up when breaking this out. Done.

Comment thread envoy/buffer/buffer.h
++class_idx;
}

return class_idx;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Consider the following version. Also, consider that class_idx in your implementation is simply the location of the most significant bit that is set. See std::bit_width or std::countl_zero or the abseil equivalents (since I think c++20 is not allowed yet) for optimized O(1) MSB computation functions.

int class_idx = absl::bit_width(shifted_balance);
return std::min(class_idx, size_class_account_sets_.size() - 1);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Neat, done.

done_notification.WaitForNotification();
}

void TrackedWatermarkBufferFactory::inspectMemoryClasses(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

function seems unused.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Used in test/common/buffer/buffer_memory_account_test.cc

Comment thread source/common/buffer/watermark_buffer.h Outdated
};

using WatermarkBufferPtr = std::unique_ptr<WatermarkBuffer>;
using MemoryClassesToAccountsSet = std::array<absl::flat_hash_set<BufferMemoryAccountSharedPtr>, 8>;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please move type definition to the protected section below, just before it is used.

using MemoryClassesToAccountsSet = std::array<absl::flat_hash_set<BufferMemoryAccountSharedPtr>, 8>;
MemoryClassesToAccountsSet size_class_account_sets_;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.


protected:
// Enable subclasses to inspect the mapping.
MemoryClassesToAccountsSet size_class_account_sets_;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Verify in WatermarkBufferFactory destructor that size_class_account_sets_ is empty

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment thread source/common/buffer/buffer_impl.h Outdated
KBaichoo added 2 commits June 24, 2021 21:26
abstract interfaces coupling the concrete impls.

Signed-off-by: Kevin Baichoo <kbaichoo@google.com>
Signed-off-by: Kevin Baichoo <kbaichoo@google.com>
Copy link
Copy Markdown
Contributor Author

@KBaichoo KBaichoo left a comment

Choose a reason for hiding this comment

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

Thanks for the feedback @antoniovicente, addressed most of your comments

Comment thread envoy/buffer/buffer.h Outdated
*
* @param reason the reason for reseting the stream.
*/
virtual void resetStream(Http::StreamResetReason reason) PURE;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Changed to resetDownstream

done_notification.WaitForNotification();
}

void TrackedWatermarkBufferFactory::inspectMemoryClasses(
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Used in test/common/buffer/buffer_memory_account_test.cc


protected:
// Enable subclasses to inspect the mapping.
MemoryClassesToAccountsSet size_class_account_sets_;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment thread source/common/buffer/watermark_buffer.h Outdated
};

using WatermarkBufferPtr = std::unique_ptr<WatermarkBuffer>;
using MemoryClassesToAccountsSet = std::array<absl::flat_hash_set<BufferMemoryAccountSharedPtr>, 8>;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

++class_idx;
}

return class_idx;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Neat, done.

Comment thread source/common/buffer/BUILD Outdated
hdrs = ["buffer_impl.h"],
deps = [
"//envoy/buffer:buffer_interface",
"//envoy/http:codec_interface",
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Whoops, must of got mixed up when breaking this out. Done.

Comment thread envoy/buffer/buffer.h Outdated
/**
* Unregister a buffer memory account.
*/
virtual void unregisterAccount(const BufferMemoryAccountSharedPtr& account) PURE;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

SGTM. Moved the BufferMemoryAccountImpl to the WatermarkBuffer impl's file, since it's the factory that produces that object. This inturn allows us to more easily couple between the two, while external classes use there interfaces.

return BufferMemoryAccountImpl::createAccount(this, reset_handler);
}

void WatermarkBufferFactory::onAccountBalanceUpdate(const BufferMemoryAccountSharedPtr& account,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Would be worried about lifetime issues that might occur from this.

uint64_t prior_balance) {

int prev_idx = accountBalanceToClassIndex(prior_balance);
int new_idx = accountBalanceToClassIndex(account->balance());
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Now use something like updateAccountClass.

cases.

Signed-off-by: Kevin Baichoo <kbaichoo@google.com>
@KBaichoo KBaichoo changed the title WIP: Implement tracking for BufferMemoryAccounts in WatermarkFactory. Buffer: Implement tracking for BufferMemoryAccounts in WatermarkFactory. Jun 25, 2021
Comment thread source/common/buffer/watermark_buffer.cc Outdated
@antoniovicente
Copy link
Copy Markdown
Contributor

Please address the magic number issues

/wait

KBaichoo added 2 commits June 29, 2021 17:12
Signed-off-by: Kevin Baichoo <kbaichoo@google.com>
Signed-off-by: Kevin Baichoo <kbaichoo@google.com>
@KBaichoo
Copy link
Copy Markdown
Contributor Author

/retest

@repokitteh-read-only
Copy link
Copy Markdown

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #17093 (comment) was created by @KBaichoo.

see: more, trace.

Signed-off-by: Kevin Baichoo <kbaichoo@google.com>
Comment thread envoy/buffer/buffer.h Outdated
/**
*@return the balance of the account.
*/
virtual uint64_t balance() const PURE;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I see no non-test uses of this API method. Consider removing from the interface.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

ASSERT(reset_handler_ != nullptr);
reset_handler_ = nullptr;

factory_->unregisterAccount(shared_this_, current_bucket_idx_);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

current_bucket_idx_ does not contain the right value after unregistration, please add:

current_bucket_idx_ = -1;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

if (shared_this_ && new_class != current_bucket_idx_) {
factory_->updateAccountClass(shared_this_, current_bucket_idx_, new_class);
current_bucket_idx_ = new_class;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The previous 5 lines are repeated in the charge method below. Consider refactoring to an updateAccountClass() private method which you can call in the two places.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment thread envoy/buffer/buffer.h
Comment thread envoy/buffer/buffer.h Outdated
*
* @param reason the reason for reseting the stream.
*/
virtual void resetDownstream(Http::StreamResetReason reason) PURE;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: reset reason could be omitted, resetting via this interface implies that the termination is related to overload.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

uint64_t shifted_balance = buffer_memory_allocated_ >> 20; // shift by 1MB.

if (shifted_balance == 0) {
return -1; // Not worth tracking anything < 1MB.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You're not allowing for a lot of configuration for this accounting. Will we need some configuration in the future?

Note that the recommended stream buffer limits for edge configurations are around 64kb. Tracking high memory connections at 1MB or larger leaves a fairly wide gap of ~16x before this mechanism can terminate expensive streams. It seems very unlikely that we'll have streams using >1MB given the 64kb edge config stream limit.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We will need some configuration of this probably. Shall I do it in this PR or a follow up? Plumbing from the bootstrap to the watermark factory might require a good amount of changes.

I'm thinking that exposing the starting_bucket_size which is rounded to nearest power of two should be sufficient, as with 8 buckets the largest bucket will be 128x the smallest. WDYT?

TODO(kbaichoo): Either implement in this PR or follow up PR.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would consider requiring that the config be powers of two. I do think that the addition of config will force you to undo some of the micro optimizations in this component.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Implemented this in KBaichoo#105

Comment thread source/common/buffer/watermark_buffer.h Outdated
// and shared_this_.
static BufferMemoryAccountSharedPtr createAccount(WatermarkBufferFactory* factory,
Http::StreamResetHandler* reset_handler);
~BufferMemoryAccountImpl() override { ASSERT(buffer_memory_allocated_ == 0); }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ASSERT(reset_handler_ == nullptr); despite it being impossible for this to not be the case given use of shared_this_.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment thread source/common/buffer/watermark_buffer.h Outdated

void resetDownstream(Http::StreamResetReason reason) override {
if (reset_handler_ != nullptr) {
reset_handler_->resetStream(reason);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You may be making an assumption that reset_handler_->resetStream(reason); calls clearDownstream()

You may run into some problems in the watermark factory while iterating through accounts and calling resetDownstream if some implementation doesn't invoke clearDownstream() from resetStream. I'm fairly sure that some of the stream implementations like HTTP2 do not call clearDownstream() from resetStream since they use the deferred delete mechanism provided by the dispatcher. Another potential danger is you calling reset_handler_->resetStream(); on a stream that is waiting to be deleted via deferred deletion. If the stream doesn't correctly handle the case by ignoring the resetStream we may trigger a crash.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Great point. Will have it such that resetStream(reason) always calls clearDownstream() to avoid situations where a stream might be reset for a non-OM situation, and is not yet destroyed, but Envoy Overload resets it again.

To avoid the deferred deletion issue whenever the stream is added to a zombie stream list, make sure that clearDownstream has been called.

TODO(kbaichoo): implement.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

// be called, but the downstream stream isn't going to terminate soon
// such as StreamDecoderFilterCallbacks::recreateStream().
if (buffer_memory_account_) {
buffer_memory_account_->clearDownstream();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Doing this from the destructor may be too late and result in calls to resetStream after deferred deletion started. Consider hooking into StreamImpl::destroy which is called before scheduling the deferred deletion.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Great catch! Yes, this should happen in destroy s.t. we unlink the stream from the account at that point as we don't want it to reset the stream at that point.

// be called, but the downstream stream isn't going to terminate soon
// such as StreamDecoderFilterCallbacks::recreateStream().
if (buffer_memory_account_) {
buffer_memory_account_->clearDownstream();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

See comment in the H2 codec, it's not clear to me if this happens early enough.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You are correct, the QUIC streams go into a deferred deletion mechanism that periodically is cleared by an Envoy QUIC alarm. Will instead call clearDownstream when the stream is added to the list of zombie streams that no data should be re-transmitted for it.

TODO(kbaichoo): implement

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

interface cleanups.

Signed-off-by: Kevin Baichoo <kbaichoo@google.com>
by clearing downstream when writeSideCloses (the stream shouldn't have
additional writes on it).

Signed-off-by: Kevin Baichoo <kbaichoo@google.com>
@KBaichoo
Copy link
Copy Markdown
Contributor Author

/retest

@repokitteh-read-only
Copy link
Copy Markdown

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #17093 (comment) was created by @KBaichoo.

see: more, trace.

@KBaichoo
Copy link
Copy Markdown
Contributor Author

/retest

@repokitteh-read-only
Copy link
Copy Markdown

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #17093 (comment) was created by @KBaichoo.

see: more, trace.

@KBaichoo
Copy link
Copy Markdown
Contributor Author

Anything else @antoniovicente ? Thanks

Comment thread source/common/buffer/watermark_buffer.cc
Comment thread source/common/http/http1/codec_impl.cc Outdated

// Clear the downstream on the account since we're resetting the downstream.
if (buffer_memory_account_) {
buffer_memory_account_->clearDownstream();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Consider doing this before calling the base class method for safety.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good idea, done.

// Clear the downstream on the account since we're resetting the downstream.
if (buffer_memory_account_) {
buffer_memory_account_->clearDownstream();
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clear before calling base class method may make sense. But isn't this covered by the call in ServerStreamImpl::destroy()?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Now call clear before the base class method.

StreamImpl::resetStream can sometimes defer the reset (if end stream already but not end stream sent). By having this in the SeverStreamImpl::resetStream, we know the BufferFactory won't try to reset the stream again since clearing downstream unregister's the account.

}
if (buffer_memory_account_) {
buffer_memory_account_->clearDownstream();
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Consider doing this before reset callbacks.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good idea, done.

KBaichoo added 2 commits July 22, 2021 00:47
derived classes for safety.

Signed-off-by: Kevin Baichoo <kbaichoo@google.com>
Signed-off-by: Kevin Baichoo <kbaichoo@google.com>
Copy link
Copy Markdown
Contributor Author

@KBaichoo KBaichoo left a comment

Choose a reason for hiding this comment

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

Thanks for the review @antoniovicente

Comment thread source/common/buffer/watermark_buffer.cc
Comment thread source/common/http/http1/codec_impl.cc Outdated

// Clear the downstream on the account since we're resetting the downstream.
if (buffer_memory_account_) {
buffer_memory_account_->clearDownstream();
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good idea, done.

}
if (buffer_memory_account_) {
buffer_memory_account_->clearDownstream();
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good idea, done.

// Clear the downstream on the account since we're resetting the downstream.
if (buffer_memory_account_) {
buffer_memory_account_->clearDownstream();
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Now call clear before the base class method.

StreamImpl::resetStream can sometimes defer the reset (if end stream already but not end stream sent). By having this in the SeverStreamImpl::resetStream, we know the BufferFactory won't try to reset the stream again since clearing downstream unregister's the account.

antoniovicente
antoniovicente previously approved these changes Jul 22, 2021
Copy link
Copy Markdown
Contributor

@antoniovicente antoniovicente left a comment

Choose a reason for hiding this comment

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

Thanks for the improvement. Off to senior-maintainers for final review.

/assign-from @envoyproxy/senior-maintainers

// be called, but the downstream stream isn't going to terminate soon
// such as StreamDecoderFilterCallbacks::recreateStream().
if (buffer_memory_account_) {
buffer_memory_account_->clearDownstream();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Also move before base class call

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

@repokitteh-read-only
Copy link
Copy Markdown

@envoyproxy/senior-maintainers assignee is @htuch

🐱

Caused by: a #17093 (review) was submitted by @antoniovicente.

see: more, trace.

Comment thread envoy/buffer/buffer.h Outdated
* invoke to reset the stream.
* @return a BufferMemoryAccountSharedPtr of the newly created account.
*/
virtual BufferMemoryAccountSharedPtr createAccount(Http::StreamResetHandler* reset_handler) PURE;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: StreamResetHandler& (unless optional?)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.

Comment thread source/common/buffer/watermark_buffer.h Outdated
}
}

// The number of memory classes the Account expects to exists.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Where is the memory class size scheme explained?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added additional comments to WatermarkBufferFactory and BufferMemoryAccountImpl::balanceToClassIndex

Comment thread source/common/http/conn_manager_impl.cc Outdated
downstream_request_account = std::make_shared<Buffer::BufferMemoryAccountImpl>();
// Create account, wiring the stream to use it.
auto& buffer_factory = read_callbacks_->connection().dispatcher().getWatermarkFactory();
downstream_request_account = buffer_factory.createAccount(&response_encoder.getStream());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Very dumb question - why are we talking about a downstream request account but all the wiring is happening for the response encoder?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The primary owner of the account right is the server-side(e.i. downstream) stream. Perhaps we should change "request" to "stream" in this variable name.

There's a desire to split the accounts used for the request and response directions, but have both of those accounts associated primarily with the downstream stream. But that change will happen in a future PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've changed it to downstream_stream_account as suggested.

document WatermarkBufferFactory tracking.

Signed-off-by: Kevin Baichoo <kbaichoo@google.com>
Copy link
Copy Markdown
Contributor Author

@KBaichoo KBaichoo left a comment

Choose a reason for hiding this comment

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

Thanks for the reviews @antoniovicente and @htuch.

// be called, but the downstream stream isn't going to terminate soon
// such as StreamDecoderFilterCallbacks::recreateStream().
if (buffer_memory_account_) {
buffer_memory_account_->clearDownstream();
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment thread source/common/buffer/watermark_buffer.h Outdated
}
}

// The number of memory classes the Account expects to exists.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added additional comments to WatermarkBufferFactory and BufferMemoryAccountImpl::balanceToClassIndex

Comment thread envoy/buffer/buffer.h Outdated
* invoke to reset the stream.
* @return a BufferMemoryAccountSharedPtr of the newly created account.
*/
virtual BufferMemoryAccountSharedPtr createAccount(Http::StreamResetHandler* reset_handler) PURE;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.

Comment thread source/common/http/conn_manager_impl.cc Outdated
downstream_request_account = std::make_shared<Buffer::BufferMemoryAccountImpl>();
// Create account, wiring the stream to use it.
auto& buffer_factory = read_callbacks_->connection().dispatcher().getWatermarkFactory();
downstream_request_account = buffer_factory.createAccount(&response_encoder.getStream());
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've changed it to downstream_stream_account as suggested.

Comment thread source/common/buffer/watermark_buffer.h Outdated
Comment thread source/common/buffer/watermark_buffer.h Outdated
Comment thread source/common/buffer/watermark_buffer.cc Outdated
Comment thread source/common/buffer/watermark_buffer.cc
Signed-off-by: Kevin Baichoo <kbaichoo@google.com>
@KBaichoo
Copy link
Copy Markdown
Contributor Author

/retest

@repokitteh-read-only
Copy link
Copy Markdown

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #17093 (comment) was created by @KBaichoo.

see: more, trace.

Copy link
Copy Markdown
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

KBaichoo added 2 commits July 30, 2021 13:16
Signed-off-by: Kevin Baichoo <kbaichoo@google.com>
Signed-off-by: Kevin Baichoo <kbaichoo@google.com>
@KBaichoo
Copy link
Copy Markdown
Contributor Author

verified examples kept failing, but merging in #17549 fixed it. think this is ready for merge, so I can put this follow up: KBaichoo#105 for review.

@htuch htuch merged commit 4506199 into envoyproxy:main Jul 30, 2021
leyao-daily pushed a commit to leyao-daily/envoy that referenced this pull request Sep 30, 2021
…ry. (envoyproxy#17093)

This PR tracks memory accounts using >1MB of allocated space, with feedback mechanisms based on credits and debits on accounts. It further creates the handle from which the BufferMemoryAccount can reset the stream, and has the WatermarkBufferFactory also produce the particular BufferMemoryAccountImpl used for tracking.

Risk Level: Medium
Testing: Unit and Integration test
Docs Changes: NA
Release Notes: NA -- not yet user facing
Platform Specific Features: NA
Runtime guard: Yes, envoy.test_only.per_stream_buffer_accounting from envoyproxy#16218 sufficient
Related Issue envoyproxy#15791

Signed-off-by: Kevin Baichoo <kbaichoo@google.com>
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.

4 participants