| OLD | NEW |
| 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 #include "net/quic/core/quic_stream_sequencer_buffer.h" | 4 #include "net/quic/core/quic_stream_sequencer_buffer.h" |
| 5 | 5 |
| 6 #include <algorithm> | 6 #include <algorithm> |
| 7 #include <limits> | 7 #include <limits> |
| 8 #include <map> | 8 #include <map> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <utility> | 10 #include <utility> |
| 11 | 11 |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/macros.h" | 13 #include "base/macros.h" |
| 14 #include "base/rand_util.h" | 14 #include "base/rand_util.h" |
| 15 #include "net/quic/test_tools/mock_clock.h" | 15 #include "net/quic/test_tools/mock_clock.h" |
| 16 #include "net/quic/test_tools/quic_stream_sequencer_buffer_peer.h" |
| 16 #include "net/quic/test_tools/quic_test_utils.h" | 17 #include "net/quic/test_tools/quic_test_utils.h" |
| 17 #include "net/test/gtest_util.h" | 18 #include "net/test/gtest_util.h" |
| 18 #include "testing/gmock/include/gmock/gmock.h" | 19 #include "testing/gmock/include/gmock/gmock.h" |
| 19 #include "testing/gmock_mutant.h" | 20 #include "testing/gmock_mutant.h" |
| 20 #include "testing/gtest/include/gtest/gtest.h" | 21 #include "testing/gtest/include/gtest/gtest.h" |
| 21 | 22 |
| 22 using std::min; | 23 using std::min; |
| 23 using std::string; | 24 using std::string; |
| 24 | 25 |
| 25 namespace net { | 26 namespace net { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 48 } | 49 } |
| 49 | 50 |
| 50 const size_t kMaxNumGapsAllowed = 2 * kMaxPacketGap; | 51 const size_t kMaxNumGapsAllowed = 2 * kMaxPacketGap; |
| 51 | 52 |
| 52 static const size_t kBlockSizeBytes = | 53 static const size_t kBlockSizeBytes = |
| 53 QuicStreamSequencerBuffer::kBlockSizeBytes; | 54 QuicStreamSequencerBuffer::kBlockSizeBytes; |
| 54 typedef QuicStreamSequencerBuffer::BufferBlock BufferBlock; | 55 typedef QuicStreamSequencerBuffer::BufferBlock BufferBlock; |
| 55 typedef QuicStreamSequencerBuffer::Gap Gap; | 56 typedef QuicStreamSequencerBuffer::Gap Gap; |
| 56 typedef QuicStreamSequencerBuffer::FrameInfo FrameInfo; | 57 typedef QuicStreamSequencerBuffer::FrameInfo FrameInfo; |
| 57 | 58 |
| 58 class QuicStreamSequencerBufferPeer { | |
| 59 public: | |
| 60 explicit QuicStreamSequencerBufferPeer(QuicStreamSequencerBuffer* buffer) | |
| 61 : buffer_(buffer) {} | |
| 62 | |
| 63 // Read from this buffer_ into the given destination buffer_ up to the | |
| 64 // size of the destination. Returns the number of bytes read. Reading from | |
| 65 // an empty buffer_->returns 0. | |
| 66 size_t Read(char* dest_buffer, size_t size) { | |
| 67 iovec dest; | |
| 68 dest.iov_base = dest_buffer, dest.iov_len = size; | |
| 69 size_t bytes_read; | |
| 70 string error_details; | |
| 71 EXPECT_EQ(QUIC_NO_ERROR, | |
| 72 buffer_->Readv(&dest, 1, &bytes_read, &error_details)); | |
| 73 return bytes_read; | |
| 74 } | |
| 75 | |
| 76 // If buffer is empty, the blocks_ array must be empty, which means all | |
| 77 // blocks are deallocated. | |
| 78 bool CheckEmptyInvariants() { | |
| 79 return !buffer_->Empty() || IsBlockArrayEmpty(); | |
| 80 } | |
| 81 | |
| 82 bool IsBlockArrayEmpty() { | |
| 83 if (FLAGS_quic_reduce_sequencer_buffer_memory_life_time && // NOLINT | |
| 84 buffer_->blocks_ == nullptr) { | |
| 85 return true; | |
| 86 } | |
| 87 | |
| 88 size_t count = buffer_->blocks_count_; | |
| 89 for (size_t i = 0; i < count; i++) { | |
| 90 if (buffer_->blocks_[i] != nullptr) { | |
| 91 return false; | |
| 92 } | |
| 93 } | |
| 94 return true; | |
| 95 } | |
| 96 | |
| 97 bool CheckInitialState() { | |
| 98 EXPECT_TRUE(buffer_->Empty() && buffer_->total_bytes_read_ == 0 && | |
| 99 buffer_->num_bytes_buffered_ == 0); | |
| 100 return CheckBufferInvariants(); | |
| 101 } | |
| 102 | |
| 103 bool CheckBufferInvariants() { | |
| 104 QuicStreamOffset data_span = | |
| 105 buffer_->gaps_.back().begin_offset - buffer_->total_bytes_read_; | |
| 106 bool capacity_sane = data_span <= buffer_->max_buffer_capacity_bytes_ && | |
| 107 data_span >= buffer_->num_bytes_buffered_; | |
| 108 if (!capacity_sane) { | |
| 109 LOG(ERROR) << "data span is larger than capacity."; | |
| 110 LOG(ERROR) << "total read: " << buffer_->total_bytes_read_ | |
| 111 << " last byte: " << buffer_->gaps_.back().begin_offset; | |
| 112 } | |
| 113 bool total_read_sane = | |
| 114 buffer_->gaps_.front().begin_offset >= buffer_->total_bytes_read_; | |
| 115 if (!total_read_sane) { | |
| 116 LOG(ERROR) << "read across 1st gap."; | |
| 117 } | |
| 118 bool read_offset_sane = buffer_->ReadOffset() < kBlockSizeBytes; | |
| 119 if (!capacity_sane) { | |
| 120 LOG(ERROR) << "read offset go beyond 1st block"; | |
| 121 } | |
| 122 bool block_match_capacity = | |
| 123 (buffer_->max_buffer_capacity_bytes_ <= | |
| 124 buffer_->blocks_count_ * kBlockSizeBytes) && | |
| 125 (buffer_->max_buffer_capacity_bytes_ > | |
| 126 (buffer_->blocks_count_ - 1) * kBlockSizeBytes); | |
| 127 if (!capacity_sane) { | |
| 128 LOG(ERROR) << "block number not match capcaity."; | |
| 129 } | |
| 130 bool block_retired_when_empty = CheckEmptyInvariants(); | |
| 131 if (!block_retired_when_empty) { | |
| 132 LOG(ERROR) << "block is not retired after use."; | |
| 133 } | |
| 134 return capacity_sane && total_read_sane && read_offset_sane && | |
| 135 block_match_capacity && block_retired_when_empty; | |
| 136 } | |
| 137 | |
| 138 size_t GetInBlockOffset(QuicStreamOffset offset) { | |
| 139 return buffer_->GetInBlockOffset(offset); | |
| 140 } | |
| 141 | |
| 142 BufferBlock* GetBlock(size_t index) { return buffer_->blocks_[index]; } | |
| 143 | |
| 144 int GapSize() { return buffer_->gaps_.size(); } | |
| 145 | |
| 146 std::list<Gap> GetGaps() { return buffer_->gaps_; } | |
| 147 | |
| 148 size_t max_buffer_capacity() { return buffer_->max_buffer_capacity_bytes_; } | |
| 149 | |
| 150 size_t ReadableBytes() { return buffer_->ReadableBytes(); } | |
| 151 | |
| 152 std::map<QuicStreamOffset, FrameInfo>* frame_arrival_time_map() { | |
| 153 return &(buffer_->frame_arrival_time_map_); | |
| 154 } | |
| 155 | |
| 156 void set_total_bytes_read(QuicStreamOffset total_bytes_read) { | |
| 157 buffer_->total_bytes_read_ = total_bytes_read; | |
| 158 } | |
| 159 | |
| 160 void set_gaps(const std::list<Gap>& gaps) { buffer_->gaps_ = gaps; } | |
| 161 | |
| 162 bool IsBufferAllocated() { return buffer_->blocks_ != nullptr; } | |
| 163 | |
| 164 private: | |
| 165 QuicStreamSequencerBuffer* buffer_; | |
| 166 }; | |
| 167 | |
| 168 namespace { | 59 namespace { |
| 169 | 60 |
| 170 class QuicStreamSequencerBufferTest : public testing::Test { | 61 class QuicStreamSequencerBufferTest : public testing::Test { |
| 171 public: | 62 public: |
| 172 void SetUp() override { Initialize(); } | 63 void SetUp() override { Initialize(); } |
| 173 | 64 |
| 174 void ResetMaxCapacityBytes(size_t max_capacity_bytes) { | 65 void ResetMaxCapacityBytes(size_t max_capacity_bytes) { |
| 175 max_capacity_bytes_ = max_capacity_bytes; | 66 max_capacity_bytes_ = max_capacity_bytes; |
| 176 Initialize(); | 67 Initialize(); |
| 177 } | 68 } |
| (...skipping 987 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1165 EXPECT_LE(bytes_to_buffer_, total_bytes_read_) << "iterations: " | 1056 EXPECT_LE(bytes_to_buffer_, total_bytes_read_) << "iterations: " |
| 1166 << iterations; | 1057 << iterations; |
| 1167 EXPECT_LE(bytes_to_buffer_, total_bytes_written_); | 1058 EXPECT_LE(bytes_to_buffer_, total_bytes_written_); |
| 1168 } | 1059 } |
| 1169 | 1060 |
| 1170 } // anonymous namespace | 1061 } // anonymous namespace |
| 1171 | 1062 |
| 1172 } // namespace test | 1063 } // namespace test |
| 1173 | 1064 |
| 1174 } // namespace net | 1065 } // namespace net |
| OLD | NEW |