Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion proxy/http2/Http2ConnectionState.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,7 @@ bool
Http2ConnectionState::delete_stream(Http2Stream *stream)
{
ink_assert(nullptr != stream);
SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());

// If stream has already been removed from the list, just go on
if (!stream_list.in(stream)) {
Expand All @@ -1120,7 +1121,9 @@ Http2ConnectionState::delete_stream(Http2Stream *stream)
dependency_tree->deactivate(node, 0);
}
dependency_tree->remove(node);
// ink_release_assert(dependency_tree->find(stream->get_id()) == nullptr);
}
stream->priority_node = nullptr;
}

if (stream->get_state() == Http2StreamState::HTTP2_STREAM_STATE_HALF_CLOSED_LOCAL) {
Expand All @@ -1146,7 +1149,6 @@ Http2ConnectionState::release_stream(Http2Stream *stream)
ink_assert(client_streams_out_count > 0);
--client_streams_out_count;
}
stream_list.remove(stream);
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.

Now release_stream() doesn't release stream ;) We need some cleanup here like a) move counter updates outside of this function, b) remove argument, and c) rename this function.
But fixing the crash is urgency, so I'm fine with this changes.

}

if (ua_session) {
Expand Down
25 changes: 25 additions & 0 deletions proxy/http2/Http2DependencyTree.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ template <typename T> class Tree
void activate(Node *node);
void deactivate(Node *node, uint32_t sent);
void update(Node *node, uint32_t sent);
bool in(Node *current, Node *node);
uint32_t size() const;

private:
Expand Down Expand Up @@ -202,6 +203,7 @@ Tree<T>::add(uint32_t parent_id, uint32_t id, uint32_t weight, bool exclusive, T

parent->children.push(node);
if (!node->queue->empty()) {
ink_release_assert(!node->queued);
parent->queue->push(node->entry);
node->queued = true;
}
Expand All @@ -210,6 +212,27 @@ Tree<T>::add(uint32_t parent_id, uint32_t id, uint32_t weight, bool exclusive, T
return node;
}

template <typename T>
bool
Tree<T>::in(Node *current, Node *node)
{
bool retval = false;
if (current == nullptr)
current = _root;
if (current->queue->in(node->entry)) {
return true;
} else {
Node *child = current->children.head;
while (child) {
if (in(child, node)) {
return true;
}
child = child->link.next;
}
}
return retval;
}

template <typename T>
void
Tree<T>::remove(Node *node)
Expand Down Expand Up @@ -242,6 +265,8 @@ Tree<T>::remove(Node *node)
remove(parent);
}

// ink_release_assert(!this->in(nullptr, node));

--_node_count;
delete node;
}
Expand Down
17 changes: 5 additions & 12 deletions proxy/http2/Http2Stream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -664,21 +664,14 @@ Http2Stream::destroy()

// Safe to initiate SSN_CLOSE if this is the last stream
if (parent) {
// release_stream and delete_stream indirectly call each other and seem to have a lot of commonality
// Should get resolved at somepoint.
Http2ClientSession *h2_parent = static_cast<Http2ClientSession *>(parent);
SCOPED_MUTEX_LOCK(lock, h2_parent->connection_state.mutex, this_ethread());
h2_parent->connection_state.release_stream(this);
// Make sure the stream is removed from the stream list and priority tree
// In many cases, this has been called earlier, so this call is a no-op
h2_parent->connection_state.delete_stream(this);

// Current Http2ConnectionState implementation uses a memory pool for instantiating streams and DLL<> stream_list for storing
// active streams. Destroying a stream before deleting it from stream_list and then creating a new one + reusing the same chunk
// from the memory pool right away always leads to destroying the DLL structure (deadlocks, inconsistencies).
// The following is meant as a safety net since the consequences are disastrous. Until the design/implementation changes it
// seems
// less error prone to (double) delete before destroying (noop if already deleted).
if (h2_parent->connection_state.delete_stream(this)) {
Warning("Http2Stream was about to be deallocated without removing it from the active stream list");
}
// Update session's stream counts, so it accurately goes into keep-alive state
h2_parent->connection_state.release_stream(this);
}

// Clean up the write VIO in case of inactivity timeout
Expand Down