gfe-relnote: Fix Http2PriorityWriteScheduler::UpdateStreamParent. Not used in prod. Not protected. Current UpdateStreamParent() early returns if parent does not change. But exclusive bit should be considered as well. PiperOrigin-RevId: 260496394 Change-Id: I9401a41140e12d19fbb36e9d5d13dcf58090be47
diff --git a/spdy/core/http2_priority_write_scheduler.h b/spdy/core/http2_priority_write_scheduler.h index a35e076..f89dc8d 100644 --- a/spdy/core/http2_priority_write_scheduler.h +++ b/spdy/core/http2_priority_write_scheduler.h
@@ -405,8 +405,10 @@ return; } - // If the new parent is already the stream's parent, we're done. - if (stream_info->parent == new_parent) { + if (stream_info->parent == new_parent && + (!exclusive || new_parent->children.size() == 1)) { + // If the new parent is already the stream's parent, and exclusivity (if + // specified) is already satisfied, we are done. return; }
diff --git a/spdy/core/http2_priority_write_scheduler_test.cc b/spdy/core/http2_priority_write_scheduler_test.cc index e498c37..0629de9 100644 --- a/spdy/core/http2_priority_write_scheduler_test.cc +++ b/spdy/core/http2_priority_write_scheduler_test.cc
@@ -426,16 +426,139 @@ ASSERT_TRUE(peer_.ValidateInvariants()); } +TEST_F(Http2PriorityWriteSchedulerTest, RegisterStreamParentExclusive) { + /* 0 + / \ + 1 2 + */ + scheduler_.RegisterStream(1, SpdyStreamPrecedence(0, 100, false)); + scheduler_.RegisterStream(2, SpdyStreamPrecedence(0, 100, false)); + /* 0 + | + 3 + / \ + 1 2 + */ + scheduler_.RegisterStream(3, SpdyStreamPrecedence(0, 100, true)); + EXPECT_THAT(scheduler_.GetStreamChildren(0), ElementsAre(3)); + EXPECT_THAT(scheduler_.GetStreamChildren(3), UnorderedElementsAre(1, 2)); + EXPECT_THAT(scheduler_.GetStreamChildren(1), IsEmpty()); + EXPECT_THAT(scheduler_.GetStreamChildren(2), IsEmpty()); + ASSERT_TRUE(peer_.ValidateInvariants()); +} + +TEST_F(Http2PriorityWriteSchedulerTest, UpdateStreamParentExclusive) { + /* 0 + /|\ + 1 2 3 + */ + scheduler_.RegisterStream(1, SpdyStreamPrecedence(0, 100, false)); + scheduler_.RegisterStream(2, SpdyStreamPrecedence(0, 100, false)); + scheduler_.RegisterStream(3, SpdyStreamPrecedence(0, 100, false)); + /* 0 + | + 1 + / \ + 2 3 + */ + scheduler_.UpdateStreamPrecedence(1, SpdyStreamPrecedence(0, 100, true)); + EXPECT_THAT(scheduler_.GetStreamChildren(0), ElementsAre(1)); + EXPECT_THAT(scheduler_.GetStreamChildren(1), UnorderedElementsAre(2, 3)); + EXPECT_THAT(scheduler_.GetStreamChildren(2), IsEmpty()); + EXPECT_THAT(scheduler_.GetStreamChildren(3), IsEmpty()); + ASSERT_TRUE(peer_.ValidateInvariants()); +} + +TEST_F(Http2PriorityWriteSchedulerTest, UpdateStreamParentExclusive2) { + /* 0 + | + 1 + / \ + 2 3 + / \ + 4 5 + | + 6 + */ + scheduler_.RegisterStream(1, SpdyStreamPrecedence(0, 100, false)); + scheduler_.RegisterStream(2, SpdyStreamPrecedence(1, 100, false)); + scheduler_.RegisterStream(3, SpdyStreamPrecedence(1, 100, false)); + scheduler_.RegisterStream(4, SpdyStreamPrecedence(3, 100, false)); + scheduler_.RegisterStream(5, SpdyStreamPrecedence(3, 100, false)); + scheduler_.RegisterStream(6, SpdyStreamPrecedence(4, 100, false)); + // Update stream 1's parent to 4 exclusive. + /* 0 + | + 4 + | + 1 + /|\ + 2 3 6 + | + 5 + */ + scheduler_.UpdateStreamPrecedence(1, SpdyStreamPrecedence(4, 100, true)); + EXPECT_THAT(scheduler_.GetStreamChildren(0), ElementsAre(4)); + EXPECT_THAT(scheduler_.GetStreamChildren(4), ElementsAre(1)); + EXPECT_THAT(scheduler_.GetStreamChildren(1), UnorderedElementsAre(2, 3, 6)); + EXPECT_THAT(scheduler_.GetStreamChildren(2), IsEmpty()); + EXPECT_THAT(scheduler_.GetStreamChildren(3), ElementsAre(5)); + EXPECT_THAT(scheduler_.GetStreamChildren(6), IsEmpty()); + ASSERT_TRUE(peer_.ValidateInvariants()); +} + +TEST_F(Http2PriorityWriteSchedulerTest, UpdateStreamParentNonExclusive) { + /* 0 + | + 1 + / \ + 2 3 + / \ + 4 5 + | + 6 + */ + scheduler_.RegisterStream(1, SpdyStreamPrecedence(0, 100, false)); + scheduler_.RegisterStream(2, SpdyStreamPrecedence(1, 100, false)); + scheduler_.RegisterStream(3, SpdyStreamPrecedence(1, 100, false)); + scheduler_.RegisterStream(4, SpdyStreamPrecedence(3, 100, false)); + scheduler_.RegisterStream(5, SpdyStreamPrecedence(3, 100, false)); + scheduler_.RegisterStream(6, SpdyStreamPrecedence(4, 100, false)); + // Update stream 1's parent to 4. + /* 0 + | + 4 + / \ + 6 1 + / \ + 2 3 + | + 5 + */ + scheduler_.UpdateStreamPrecedence(1, SpdyStreamPrecedence(4, 100, false)); + EXPECT_THAT(scheduler_.GetStreamChildren(0), ElementsAre(4)); + EXPECT_THAT(scheduler_.GetStreamChildren(4), UnorderedElementsAre(6, 1)); + EXPECT_THAT(scheduler_.GetStreamChildren(6), IsEmpty()); + EXPECT_THAT(scheduler_.GetStreamChildren(1), UnorderedElementsAre(2, 3)); + EXPECT_THAT(scheduler_.GetStreamChildren(2), IsEmpty()); + EXPECT_THAT(scheduler_.GetStreamChildren(3), ElementsAre(5)); + EXPECT_THAT(scheduler_.GetStreamChildren(5), IsEmpty()); + ASSERT_TRUE(peer_.ValidateInvariants()); +} + TEST_F(Http2PriorityWriteSchedulerTest, UpdateStreamParentToParent) { scheduler_.RegisterStream(1, SpdyStreamPrecedence(0, 100, false)); scheduler_.RegisterStream(2, SpdyStreamPrecedence(1, 100, false)); scheduler_.RegisterStream(3, SpdyStreamPrecedence(1, 100, false)); + EXPECT_THAT(scheduler_.GetStreamChildren(1), UnorderedElementsAre(2, 3)); + EXPECT_THAT(scheduler_.GetStreamChildren(2), IsEmpty()); + EXPECT_THAT(scheduler_.GetStreamChildren(3), IsEmpty()); for (bool exclusive : {true, false}) { scheduler_.UpdateStreamPrecedence(2, SpdyStreamPrecedence(1, 100, exclusive)); EXPECT_THAT(scheduler_.GetStreamChildren(0), ElementsAre(1)); - EXPECT_THAT(scheduler_.GetStreamChildren(1), UnorderedElementsAre(2, 3)); - EXPECT_THAT(scheduler_.GetStreamChildren(2), IsEmpty()); + EXPECT_THAT(scheduler_.GetStreamChildren(1), UnorderedElementsAre(2)); + EXPECT_THAT(scheduler_.GetStreamChildren(2), UnorderedElementsAre(3)); EXPECT_THAT(scheduler_.GetStreamChildren(3), IsEmpty()); } ASSERT_TRUE(peer_.ValidateInvariants());