Skip to content

Commit

Permalink
Functionality for removals after specified offset [part 2]
Browse files Browse the repository at this point in the history
Summary: When we send a reliable reset, we don't want to reset the entire `writeBufMeta`, `retransmissionBufMetas`, and `lossBufMetas`. We only want to reset them up to the `reliableSize`. I'm making helper functions to do this.

Reviewed By: jbeshay

Differential Revision: D66120070

fbshipit-source-id: 588db71b846247a9a2316f46ca6c6caef9246ba9
  • Loading branch information
Aman Sharma authored and facebook-github-bot committed Nov 21, 2024
1 parent 486e5d7 commit f72ceb8
Show file tree
Hide file tree
Showing 2 changed files with 351 additions and 0 deletions.
47 changes: 47 additions & 0 deletions quic/state/StreamData.h
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,53 @@ struct QuicStreamState : public QuicStreamLike {
return readBuffer.size() > 0;
}

void removeFromWriteBufMetaAfterOffset(uint64_t removalOffset) {
if (removalOffset < writeBufMeta.offset) {
writeBufMeta.length = 0;
return;
}

if (removalOffset >= writeBufMeta.offset &&
removalOffset < writeBufMeta.offset + writeBufMeta.length) {
writeBufMeta.length = uint32_t(removalOffset - writeBufMeta.offset + 1);
}
}

void removeFromRetransmissionBufMetasAfterOffset(uint64_t removalOffset) {
folly::F14FastSet<uint64_t> offsetsToRemove;

for (auto& [offset, buf] : retransmissionBufMetas) {
if (offset > removalOffset) {
offsetsToRemove.insert(offset);
} else if (offset + buf.length > removalOffset) {
buf.length = uint32_t(removalOffset - offset + 1);
}
}

for (auto offset : offsetsToRemove) {
retransmissionBufMetas.erase(offset);
}
}

void removeFromLossBufMetasAfterOffset(uint64_t removalOffset) {
if (lossBufMetas.empty()) {
// Nothing to do.
return;
}

while (!lossBufMetas.empty()) {
auto& lastElement = lossBufMetas.back();
if (lastElement.offset > removalOffset) {
lossBufMetas.pop_back();
} else if (lastElement.offset + lastElement.length > removalOffset) {
lastElement.length = uint32_t(removalOffset - lastElement.offset + 1);
return;
} else {
return;
}
}
}

std::unique_ptr<DSRPacketizationRequestSender> dsrSender;

// BufferMeta that has been written to the QUIC layer.
Expand Down
304 changes: 304 additions & 0 deletions quic/state/test/StreamDataTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <quic/state/StateData.h>
#include <quic/state/StreamData.h>

using namespace quic;
Expand Down Expand Up @@ -281,4 +282,307 @@ TEST(StreamDataTest, PendingWritesRemovalNoChange) {
EXPECT_EQ(state.pendingWrites.chainLength(), 8);
}

TEST(StreamDataTest, LossBufferMetaRemovalAll) {
QuicConnectionStateBase qcsb(QuicNodeType::Client);
QuicStreamState state(0, qcsb);

// [1, 2] [5, 12] [17, 19]
WriteBufferMeta wbm1 = WriteBufferMeta::Builder()
.setOffset(1)
.setLength(2)
.setEOF(false)
.build();
WriteBufferMeta wbm2 = WriteBufferMeta::Builder()
.setOffset(5)
.setLength(8)
.setEOF(false)
.build();
WriteBufferMeta wbm3 = WriteBufferMeta::Builder()
.setOffset(17)
.setLength(3)
.setEOF(false)
.build();
state.insertIntoLossBufMeta(wbm1);
state.insertIntoLossBufMeta(wbm2);
state.insertIntoLossBufMeta(wbm3);

state.removeFromLossBufMetasAfterOffset(0);

EXPECT_EQ(state.lossBufMetas.size(), 0);
}

TEST(StreamDataTest, LossBufferMetaRemovalExactMatch) {
QuicConnectionStateBase qcsb(QuicNodeType::Client);
QuicStreamState state(0, qcsb);

// [1, 2] [5, 12] [17, 19]
WriteBufferMeta wbm1 = WriteBufferMeta::Builder()
.setOffset(1)
.setLength(2)
.setEOF(false)
.build();
WriteBufferMeta wbm2 = WriteBufferMeta::Builder()
.setOffset(5)
.setLength(8)
.setEOF(false)
.build();
WriteBufferMeta wbm3 = WriteBufferMeta::Builder()
.setOffset(17)
.setLength(3)
.setEOF(false)
.build();
state.insertIntoLossBufMeta(wbm1);
state.insertIntoLossBufMeta(wbm2);
state.insertIntoLossBufMeta(wbm3);

state.removeFromLossBufMetasAfterOffset(4);
EXPECT_EQ(state.lossBufMetas.size(), 1);
EXPECT_EQ(state.lossBufMetas[0].offset, 1);
EXPECT_EQ(state.lossBufMetas[0].length, 2);
}

TEST(StreamDataTest, LossBufferMetaRemovalPartialMatch) {
QuicConnectionStateBase qcsb(QuicNodeType::Client);
QuicStreamState state(0, qcsb);

// [1, 2] [5, 12] [17, 19]
WriteBufferMeta wbm1 = WriteBufferMeta::Builder()
.setOffset(1)
.setLength(2)
.setEOF(false)
.build();
WriteBufferMeta wbm2 = WriteBufferMeta::Builder()
.setOffset(5)
.setLength(8)
.setEOF(false)
.build();
WriteBufferMeta wbm3 = WriteBufferMeta::Builder()
.setOffset(17)
.setLength(3)
.setEOF(false)
.build();
state.insertIntoLossBufMeta(wbm1);
state.insertIntoLossBufMeta(wbm2);
state.insertIntoLossBufMeta(wbm3);

state.removeFromLossBufMetasAfterOffset(5);
EXPECT_EQ(state.lossBufMetas.size(), 2);

EXPECT_EQ(state.lossBufMetas[0].offset, 1);
EXPECT_EQ(state.lossBufMetas[0].length, 2);

EXPECT_EQ(state.lossBufMetas[1].offset, 5);
EXPECT_EQ(state.lossBufMetas[1].length, 1);
}

TEST(StreamDataTest, LossBufferMetaRemovalNoMatch) {
QuicConnectionStateBase qcsb(QuicNodeType::Client);
QuicStreamState state(0, qcsb);

// [1, 2] [5, 12] [17, 19]
WriteBufferMeta wbm1 = WriteBufferMeta::Builder()
.setOffset(1)
.setLength(2)
.setEOF(false)
.build();
WriteBufferMeta wbm2 = WriteBufferMeta::Builder()
.setOffset(5)
.setLength(8)
.setEOF(false)
.build();
WriteBufferMeta wbm3 = WriteBufferMeta::Builder()
.setOffset(17)
.setLength(3)
.setEOF(false)
.build();
state.insertIntoLossBufMeta(wbm1);
state.insertIntoLossBufMeta(wbm2);
state.insertIntoLossBufMeta(wbm3);

state.removeFromLossBufAfterOffset(20);
EXPECT_EQ(state.lossBufMetas.size(), 3);

EXPECT_EQ(state.lossBufMetas[0].offset, 1);
EXPECT_EQ(state.lossBufMetas[0].length, 2);

EXPECT_EQ(state.lossBufMetas[1].offset, 5);
EXPECT_EQ(state.lossBufMetas[1].length, 8);

EXPECT_EQ(state.lossBufMetas[2].offset, 17);
EXPECT_EQ(state.lossBufMetas[2].length, 3);
}

TEST(StreamDataTest, RetxBufferMetaRemovalAll) {
QuicConnectionStateBase qcsb(QuicNodeType::Client);
QuicStreamState state(0, qcsb);

// [1, 2] [5, 12] [17, 19]
WriteBufferMeta wbm1 = WriteBufferMeta::Builder()
.setOffset(1)
.setLength(2)
.setEOF(false)
.build();
WriteBufferMeta wbm2 = WriteBufferMeta::Builder()
.setOffset(5)
.setLength(8)
.setEOF(false)
.build();
WriteBufferMeta wbm3 = WriteBufferMeta::Builder()
.setOffset(17)
.setLength(3)
.setEOF(false)
.build();
state.retransmissionBufMetas.emplace(1, wbm1);
state.retransmissionBufMetas.emplace(5, wbm2);
state.retransmissionBufMetas.emplace(17, wbm3);

state.removeFromRetransmissionBufMetasAfterOffset(0);
EXPECT_EQ(state.retransmissionBufMetas.size(), 0);
}

TEST(StreamDataTest, RetxBufferMetaRemovalExactMatch) {
QuicConnectionStateBase qcsb(QuicNodeType::Client);
QuicStreamState state(0, qcsb);

// [1, 2] [5, 12] [17, 19]
WriteBufferMeta wbm1 = WriteBufferMeta::Builder()
.setOffset(1)
.setLength(2)
.setEOF(false)
.build();
WriteBufferMeta wbm2 = WriteBufferMeta::Builder()
.setOffset(5)
.setLength(8)
.setEOF(false)
.build();
WriteBufferMeta wbm3 = WriteBufferMeta::Builder()
.setOffset(17)
.setLength(3)
.setEOF(false)
.build();
state.retransmissionBufMetas.emplace(1, wbm1);
state.retransmissionBufMetas.emplace(5, wbm2);
state.retransmissionBufMetas.emplace(17, wbm3);

state.removeFromRetransmissionBufMetasAfterOffset(16);
EXPECT_EQ(state.retransmissionBufMetas.size(), 2);

EXPECT_EQ(state.retransmissionBufMetas[1].offset, 1);
EXPECT_EQ(state.retransmissionBufMetas[1].length, 2);

EXPECT_EQ(state.retransmissionBufMetas[5].offset, 5);
EXPECT_EQ(state.retransmissionBufMetas[5].length, 8);
}

TEST(StreamDataTest, RetxBufferMetaRemovalPartialMatch) {
QuicConnectionStateBase qcsb(QuicNodeType::Client);
QuicStreamState state(0, qcsb);

// [1, 2] [5, 12] [17, 19]
WriteBufferMeta wbm1 = WriteBufferMeta::Builder()
.setOffset(1)
.setLength(2)
.setEOF(false)
.build();
WriteBufferMeta wbm2 = WriteBufferMeta::Builder()
.setOffset(5)
.setLength(8)
.setEOF(false)
.build();
WriteBufferMeta wbm3 = WriteBufferMeta::Builder()
.setOffset(17)
.setLength(3)
.setEOF(false)
.build();
state.retransmissionBufMetas.emplace(1, wbm1);
state.retransmissionBufMetas.emplace(5, wbm2);
state.retransmissionBufMetas.emplace(17, wbm3);

state.removeFromRetransmissionBufMetasAfterOffset(5);
EXPECT_EQ(state.retransmissionBufMetas.size(), 2);

EXPECT_EQ(state.retransmissionBufMetas[1].offset, 1);
EXPECT_EQ(state.retransmissionBufMetas[1].length, 2);

EXPECT_EQ(state.retransmissionBufMetas[5].offset, 5);
EXPECT_EQ(state.retransmissionBufMetas[5].length, 1);
}

TEST(StreamDataTest, RetxBufferMetaRemovalNoMatch) {
QuicConnectionStateBase qcsb(QuicNodeType::Client);
QuicStreamState state(0, qcsb);

// [1, 2] [5, 12] [17, 19]
WriteBufferMeta wbm1 = WriteBufferMeta::Builder()
.setOffset(1)
.setLength(2)
.setEOF(false)
.build();
WriteBufferMeta wbm2 = WriteBufferMeta::Builder()
.setOffset(5)
.setLength(8)
.setEOF(false)
.build();
WriteBufferMeta wbm3 = WriteBufferMeta::Builder()
.setOffset(17)
.setLength(3)
.setEOF(false)
.build();
state.retransmissionBufMetas.emplace(1, wbm1);
state.retransmissionBufMetas.emplace(5, wbm2);
state.retransmissionBufMetas.emplace(17, wbm3);

state.removeFromRetransmissionBufMetasAfterOffset(19);
EXPECT_EQ(state.retransmissionBufMetas.size(), 3);

EXPECT_EQ(state.retransmissionBufMetas[1].offset, 1);
EXPECT_EQ(state.retransmissionBufMetas[1].length, 2);

EXPECT_EQ(state.retransmissionBufMetas[5].offset, 5);
EXPECT_EQ(state.retransmissionBufMetas[5].length, 8);

EXPECT_EQ(state.retransmissionBufMetas[17].offset, 17);
EXPECT_EQ(state.retransmissionBufMetas[17].length, 3);
}

TEST(StreamDataTest, WriteBufferMetaRemovalAll) {
QuicConnectionStateBase qcsb(QuicNodeType::Client);
QuicStreamState state(0, qcsb);

// [5, 16]
state.writeBufMeta.offset = 5;
state.writeBufMeta.length = 12;

state.removeFromWriteBufMetaAfterOffset(0);
EXPECT_EQ(state.writeBufMeta.length, 0);
}

TEST(StreamDataTest, WriteBufferMetaRemoval) {
QuicConnectionStateBase qcsb(QuicNodeType::Client);
QuicStreamState state(0, qcsb);

state.writeBufferStartOffset = 5;

// [5, 16]
state.writeBufMeta.offset = 5;
state.writeBufMeta.length = 12;

state.removeFromWriteBufMetaAfterOffset(5);
EXPECT_EQ(state.writeBufMeta.length, 1);
}

TEST(StreamDataTest, WriteBufferMetaRemovalNoChange) {
QuicConnectionStateBase qcsb(QuicNodeType::Client);
QuicStreamState state(0, qcsb);

state.writeBufferStartOffset = 5;

// [5, 16]
state.writeBufMeta.offset = 5;
state.writeBufMeta.length = 12;

state.removeFromWriteBufMetaAfterOffset(16);
EXPECT_EQ(state.writeBufMeta.length, 12);
}

} // namespace quic::test

0 comments on commit f72ceb8

Please sign in to comment.