// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/curvecp/sent_block_list.h" #include "base/logging.h" #include "net/base/io_buffer.h" namespace net { static const size_t kMaxBlocks = 128; SentBlockList::SentBlockList() : current_message_id_(1), send_sequence_number_(0) { } SentBlockList::~SentBlockList() { } int64 SentBlockList::CreateBlock(IOBufferWithSize* buffer) { DCHECK_LT(0, buffer->size()); if (is_full()) return -1; Block new_block; new_block.position = send_sequence_number_; new_block.length = buffer->size(); new_block.transmissions = 0; new_block.last_message_id = 0; new_block.data= buffer; send_sequence_number_ += buffer->size(); list_.push_back(new_block); return new_block.position; } bool SentBlockList::MarkBlockSent(int64 position, int64 message_id) { int index = FindBlock(position); if (index < 0) { NOTREACHED(); return false; } list_[index].last_message_id = message_id; list_[index].transmissions++; list_[index].last_sent_time = base::TimeTicks::Now(); return true; } void SentBlockList::AcknowledgeBlocks(int64 begin_range, int64 end_range) { if (begin_range == end_range) return; // TODO(mbelshe): use a better data structure. LOG(ERROR) << "ACK of: " << begin_range << " to " << end_range; BlockList::iterator it = list_.begin(); while (it != list_.end()) { int64 position = it->position; int64 length = it->length; if (position >= begin_range && (position + length) <= end_range) { list_.erase(it); it = list_.begin(); // iterator was invalidated, so go to start of list. continue; } // Verify we didn't have a partial block acknowledgement. CHECK(position < begin_range || position >= end_range); CHECK((position + length) < begin_range || (position + length) > end_range); it++; } } int64 SentBlockList::GetNewMessageId() { return current_message_id_++; } IOBufferWithSize* SentBlockList::FindBlockByPosition(int64 position) const { int index = FindBlock(position); if (index < 0) return NULL; return list_[index].data; } base::TimeTicks SentBlockList::FindLastSendTime(int64 last_message_id) const { for (size_t index = 0; index < list_.size(); ++index) if (list_[index].last_message_id == last_message_id) return list_[index].last_sent_time; return base::TimeTicks(); } int SentBlockList::FindBlock(int64 position) const { for (size_t index = 0; index < list_.size(); ++index) if (list_[index].position == position) return index; return -1; } int64 SentBlockList::FindPositionOfOldestSentBlock() const { base::TimeTicks oldest_time; int64 position = -1; LogBlockList(); // Walks the entire list. for (size_t index = 0; index < list_.size(); ++index) { base::TimeTicks last_sent_time = list_[index].last_sent_time; if (!last_sent_time.is_null()) { if (last_sent_time < oldest_time || oldest_time.is_null()) { oldest_time = last_sent_time; position = list_[index].position; } } } return position; } bool SentBlockList::is_full() const { return list_.size() == kMaxBlocks; } void SentBlockList::LogBlockList() const { LOG(INFO) << "Sent Blocks: " << list_.size(); std::string msg; std::ostringstream stream(msg); for (size_t index = 0; index < list_.size(); ++index) stream << "(" << list_[index].position << "," << list_[index].length << ")"; LOG(INFO) << stream.str(); } } // namespace net