| 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 | 4 |
| 5 #include "net/quic/core/quic_stream_sequencer_buffer.h" | 5 #include "net/quic/core/quic_stream_sequencer_buffer.h" |
| 6 | 6 |
| 7 #include "base/format_macros.h" | 7 #include "base/format_macros.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
| 10 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 73 num_bytes_buffered_ = 0; | 73 num_bytes_buffered_ = 0; |
| 74 // Reset gaps_ so that buffer is in a state as if all data before | 74 // Reset gaps_ so that buffer is in a state as if all data before |
| 75 // total_bytes_read_ has been consumed, and those after total_bytes_read_ | 75 // total_bytes_read_ has been consumed, and those after total_bytes_read_ |
| 76 // has never arrived. | 76 // has never arrived. |
| 77 gaps_ = std::list<Gap>( | 77 gaps_ = std::list<Gap>( |
| 78 1, Gap(total_bytes_read_, std::numeric_limits<QuicStreamOffset>::max())), | 78 1, Gap(total_bytes_read_, std::numeric_limits<QuicStreamOffset>::max())), |
| 79 frame_arrival_time_map_.clear(); | 79 frame_arrival_time_map_.clear(); |
| 80 } | 80 } |
| 81 | 81 |
| 82 bool QuicStreamSequencerBuffer::RetireBlock(size_t idx) { | 82 bool QuicStreamSequencerBuffer::RetireBlock(size_t idx) { |
| 83 if (FLAGS_quic_stream_sequencer_buffer_debug && blocks_[idx] == nullptr) { | 83 if (blocks_[idx] == nullptr) { |
| 84 QUIC_BUG << "Try to retire block twice"; | 84 QUIC_BUG << "Try to retire block twice"; |
| 85 return false; | 85 return false; |
| 86 } | 86 } |
| 87 delete blocks_[idx]; | 87 delete blocks_[idx]; |
| 88 blocks_[idx] = nullptr; | 88 blocks_[idx] = nullptr; |
| 89 DVLOG(1) << "Retired block with index: " << idx; | 89 DVLOG(1) << "Retired block with index: " << idx; |
| 90 return true; | 90 return true; |
| 91 } | 91 } |
| 92 | 92 |
| 93 QuicErrorCode QuicStreamSequencerBuffer::OnStreamData( | 93 QuicErrorCode QuicStreamSequencerBuffer::OnStreamData( |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 bytes_avail = total_bytes_read_ + max_buffer_capacity_bytes_ - offset; | 181 bytes_avail = total_bytes_read_ + max_buffer_capacity_bytes_ - offset; |
| 182 } | 182 } |
| 183 | 183 |
| 184 if (reduce_sequencer_buffer_memory_life_time_ && blocks_ == nullptr) { | 184 if (reduce_sequencer_buffer_memory_life_time_ && blocks_ == nullptr) { |
| 185 blocks_.reset(new BufferBlock*[blocks_count_]()); | 185 blocks_.reset(new BufferBlock*[blocks_count_]()); |
| 186 for (size_t i = 0; i < blocks_count_; ++i) { | 186 for (size_t i = 0; i < blocks_count_; ++i) { |
| 187 blocks_[i] = nullptr; | 187 blocks_[i] = nullptr; |
| 188 } | 188 } |
| 189 } | 189 } |
| 190 | 190 |
| 191 if (FLAGS_quic_stream_sequencer_buffer_debug && | 191 if (write_block_num >= blocks_count_) { |
| 192 write_block_num >= blocks_count_) { | |
| 193 *error_details = StringPrintf( | 192 *error_details = StringPrintf( |
| 194 "QuicStreamSequencerBuffer error: OnStreamData() exceed array bounds." | 193 "QuicStreamSequencerBuffer error: OnStreamData() exceed array bounds." |
| 195 "write offset = %" PRIu64 " write_block_num = %" PRIuS | 194 "write offset = %" PRIu64 " write_block_num = %" PRIuS |
| 196 " blocks_count_ = %" PRIuS, | 195 " blocks_count_ = %" PRIuS, |
| 197 offset, write_block_num, blocks_count_); | 196 offset, write_block_num, blocks_count_); |
| 198 return QUIC_STREAM_SEQUENCER_INVALID_STATE; | 197 return QUIC_STREAM_SEQUENCER_INVALID_STATE; |
| 199 } | 198 } |
| 200 if (blocks_ == nullptr) { | 199 if (blocks_ == nullptr) { |
| 201 *error_details = | 200 *error_details = |
| 202 "QuicStreamSequencerBuffer error: OnStreamData() blocks_ is null"; | 201 "QuicStreamSequencerBuffer error: OnStreamData() blocks_ is null"; |
| 203 return QUIC_STREAM_SEQUENCER_INVALID_STATE; | 202 return QUIC_STREAM_SEQUENCER_INVALID_STATE; |
| 204 } | 203 } |
| 205 if (blocks_[write_block_num] == nullptr) { | 204 if (blocks_[write_block_num] == nullptr) { |
| 206 // TODO(danzh): Investigate if using a freelist would improve performance. | 205 // TODO(danzh): Investigate if using a freelist would improve performance. |
| 207 // Same as RetireBlock(). | 206 // Same as RetireBlock(). |
| 208 blocks_[write_block_num] = new BufferBlock(); | 207 blocks_[write_block_num] = new BufferBlock(); |
| 209 } | 208 } |
| 210 | 209 |
| 211 const size_t bytes_to_copy = min<size_t>(bytes_avail, source_remaining); | 210 const size_t bytes_to_copy = min<size_t>(bytes_avail, source_remaining); |
| 212 char* dest = blocks_[write_block_num]->buffer + write_block_offset; | 211 char* dest = blocks_[write_block_num]->buffer + write_block_offset; |
| 213 DVLOG(1) << "Write at offset: " << offset << " length: " << bytes_to_copy; | 212 DVLOG(1) << "Write at offset: " << offset << " length: " << bytes_to_copy; |
| 214 | 213 |
| 215 if (FLAGS_quic_stream_sequencer_buffer_debug && | 214 if (dest == nullptr || source == nullptr) { |
| 216 (dest == nullptr || source == nullptr)) { | |
| 217 *error_details = StringPrintf( | 215 *error_details = StringPrintf( |
| 218 "QuicStreamSequencerBuffer error: OnStreamData()" | 216 "QuicStreamSequencerBuffer error: OnStreamData()" |
| 219 " dest == nullptr: %s" | 217 " dest == nullptr: %s" |
| 220 " source == nullptr: %s" | 218 " source == nullptr: %s" |
| 221 " Writing at offset %" PRIu64 | 219 " Writing at offset %" PRIu64 |
| 222 " Gaps: %s" | 220 " Gaps: %s" |
| 223 " Remaining frames: %s" | 221 " Remaining frames: %s" |
| 224 " total_bytes_read_ = %" PRIu64, | 222 " total_bytes_read_ = %" PRIu64, |
| 225 (dest == nullptr ? "true" : "false"), | 223 (dest == nullptr ? "true" : "false"), |
| 226 (source == nullptr ? "true" : "false"), offset, | 224 (source == nullptr ? "true" : "false"), offset, |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 size_t dest_remaining = dest_iov[i].iov_len; | 283 size_t dest_remaining = dest_iov[i].iov_len; |
| 286 while (dest_remaining > 0 && ReadableBytes() > 0) { | 284 while (dest_remaining > 0 && ReadableBytes() > 0) { |
| 287 size_t block_idx = NextBlockToRead(); | 285 size_t block_idx = NextBlockToRead(); |
| 288 size_t start_offset_in_block = ReadOffset(); | 286 size_t start_offset_in_block = ReadOffset(); |
| 289 size_t block_capacity = GetBlockCapacity(block_idx); | 287 size_t block_capacity = GetBlockCapacity(block_idx); |
| 290 size_t bytes_available_in_block = | 288 size_t bytes_available_in_block = |
| 291 min<size_t>(ReadableBytes(), block_capacity - start_offset_in_block); | 289 min<size_t>(ReadableBytes(), block_capacity - start_offset_in_block); |
| 292 size_t bytes_to_copy = | 290 size_t bytes_to_copy = |
| 293 min<size_t>(bytes_available_in_block, dest_remaining); | 291 min<size_t>(bytes_available_in_block, dest_remaining); |
| 294 DCHECK_GT(bytes_to_copy, 0UL); | 292 DCHECK_GT(bytes_to_copy, 0UL); |
| 295 if (FLAGS_quic_stream_sequencer_buffer_debug && | 293 if (blocks_[block_idx] == nullptr || dest == nullptr) { |
| 296 (blocks_[block_idx] == nullptr || dest == nullptr)) { | |
| 297 *error_details = StringPrintf( | 294 *error_details = StringPrintf( |
| 298 "QuicStreamSequencerBuffer error:" | 295 "QuicStreamSequencerBuffer error:" |
| 299 " Readv() dest == nullptr: %s" | 296 " Readv() dest == nullptr: %s" |
| 300 " blocks_[%" PRIuS "] == nullptr: %s", | 297 " blocks_[%" PRIuS "] == nullptr: %s", |
| 301 (dest == nullptr ? "true" : "false"), block_idx, | 298 (dest == nullptr ? "true" : "false"), block_idx, |
| 302 (blocks_[block_idx] == nullptr ? "true" : "false")); | 299 (blocks_[block_idx] == nullptr ? "true" : "false")); |
| 303 return QUIC_STREAM_SEQUENCER_INVALID_STATE; | 300 return QUIC_STREAM_SEQUENCER_INVALID_STATE; |
| 304 } | 301 } |
| 305 memcpy(dest, blocks_[block_idx]->buffer + start_offset_in_block, | 302 memcpy(dest, blocks_[block_idx]->buffer + start_offset_in_block, |
| 306 bytes_to_copy); | 303 bytes_to_copy); |
| 307 dest += bytes_to_copy; | 304 dest += bytes_to_copy; |
| 308 dest_remaining -= bytes_to_copy; | 305 dest_remaining -= bytes_to_copy; |
| 309 num_bytes_buffered_ -= bytes_to_copy; | 306 num_bytes_buffered_ -= bytes_to_copy; |
| 310 total_bytes_read_ += bytes_to_copy; | 307 total_bytes_read_ += bytes_to_copy; |
| 311 *bytes_read += bytes_to_copy; | 308 *bytes_read += bytes_to_copy; |
| 312 | 309 |
| 313 // Retire the block if all the data is read out and no other data is | 310 // Retire the block if all the data is read out and no other data is |
| 314 // stored in this block. | 311 // stored in this block. |
| 315 // In case of failing to retire a block which is ready to retire, return | 312 // In case of failing to retire a block which is ready to retire, return |
| 316 // immediately. | 313 // immediately. |
| 317 if (bytes_to_copy == bytes_available_in_block) { | 314 if (bytes_to_copy == bytes_available_in_block) { |
| 318 bool retire_successfully = RetireBlockIfEmpty(block_idx); | 315 bool retire_successfully = RetireBlockIfEmpty(block_idx); |
| 319 if (FLAGS_quic_stream_sequencer_buffer_debug && !retire_successfully) { | 316 if (!retire_successfully) { |
| 320 *error_details = StringPrintf( | 317 *error_details = StringPrintf( |
| 321 "QuicStreamSequencerBuffer error: fail to retire block %" PRIuS | 318 "QuicStreamSequencerBuffer error: fail to retire block %" PRIuS |
| 322 " as the block is already released + total_bytes_read_ = %" PRIu64 | 319 " as the block is already released + total_bytes_read_ = %" PRIu64 |
| 323 " Gaps: %s", | 320 " Gaps: %s", |
| 324 block_idx, total_bytes_read_, GapsDebugString().c_str()); | 321 block_idx, total_bytes_read_, GapsDebugString().c_str()); |
| 325 return QUIC_STREAM_SEQUENCER_INVALID_STATE; | 322 return QUIC_STREAM_SEQUENCER_INVALID_STATE; |
| 326 } | 323 } |
| 327 } | 324 } |
| 328 } | 325 } |
| 329 } | 326 } |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 585 } | 582 } |
| 586 return current_gaps_string; | 583 return current_gaps_string; |
| 587 } | 584 } |
| 588 | 585 |
| 589 string QuicStreamSequencerBuffer::ReceivedFramesDebugString() { | 586 string QuicStreamSequencerBuffer::ReceivedFramesDebugString() { |
| 590 string current_frames_string; | 587 string current_frames_string; |
| 591 for (auto it : frame_arrival_time_map_) { | 588 for (auto it : frame_arrival_time_map_) { |
| 592 QuicStreamOffset current_frame_begin_offset = it.first; | 589 QuicStreamOffset current_frame_begin_offset = it.first; |
| 593 QuicStreamOffset current_frame_end_offset = | 590 QuicStreamOffset current_frame_end_offset = |
| 594 it.second.length + current_frame_begin_offset; | 591 it.second.length + current_frame_begin_offset; |
| 595 if (FLAGS_quic_stream_sequencer_buffer_debug) { | 592 current_frames_string = string(StringPrintf( |
| 596 current_frames_string = string(StringPrintf( | 593 "%s[%" PRIu64 ", %" PRIu64 ") ", current_frames_string.c_str(), |
| 597 "%s[%" PRIu64 ", %" PRIu64 ") receiving time %" PRId64 " ", | 594 current_frame_begin_offset, current_frame_end_offset)); |
| 598 current_frames_string.c_str(), current_frame_begin_offset, | |
| 599 current_frame_end_offset, it.second.timestamp.ToDebuggingValue())); | |
| 600 } else { | |
| 601 current_frames_string = string(StringPrintf( | |
| 602 "%s[%" PRIu64 ", %" PRIu64 ") ", current_frames_string.c_str(), | |
| 603 current_frame_begin_offset, current_frame_end_offset)); | |
| 604 } | |
| 605 } | 595 } |
| 606 return current_frames_string; | 596 return current_frames_string; |
| 607 } | 597 } |
| 608 | 598 |
| 609 } // namespace net | 599 } // namespace net |
| OLD | NEW |