void ReliableSession::expire_naks() { if (this->nak_requests_.empty()) return; // nothing to expire ACE_Time_Value deadline(ACE_OS::gettimeofday()); deadline -= this->link_->config()->nak_timeout_; NakRequestMap::iterator first(this->nak_requests_.begin()); NakRequestMap::iterator last(this->nak_requests_.upper_bound(deadline)); if (first == last) return; // nothing to expire // Skip unrecoverable datagrams to // re-establish a baseline to detect future reception gaps. SequenceNumber lastSeq; if (last == this->nak_requests_.end()) { lastSeq = this->nak_requests_.rbegin()->second; } else { lastSeq = last->second; } if (lastSeq > this->nak_sequence_.low ()) { ACE_ERROR((LM_WARNING, ACE_TEXT("(%P|%t) WARNING: ") ACE_TEXT("ReliableSession::expire_naks: ") ACE_TEXT("timed out waiting on remote peer %d to send missing samples: %d - %d!\n"), this->remote_peer_, this->nak_sequence_.low ().getValue(), lastSeq.getValue())); this->nak_sequence_.shift(lastSeq); } // Clear expired repair requests: this->nak_requests_.erase(first, last); }
void SingleSendBuffer::insert_fragment(SequenceNumber sequence, SequenceNumber fragment, TransportSendStrategy::QueueType* queue, ACE_Message_Block* chain) { check_capacity(); // Insert into buffers_ so that the overall capacity is maintained // The entry in buffers_ with two null pointers indicates that the // actual data is stored in fragments_[sequence]. buffers_[sequence] = std::make_pair(static_cast<QueueType*>(0), static_cast<ACE_Message_Block*>(0)); BufferType& buffer = fragments_[sequence][fragment]; insert_buffer(buffer, queue, chain); if (Transport_debug_level > 5) { ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) SingleSendBuffer::insert_fragment() - ") ACE_TEXT("saved PDU: %q,%q as buffer(0x%@,0x%@)\n"), sequence.getValue(), fragment.getValue(), buffer.first, buffer.second )); } }
void ReliableSession::send_nakack(SequenceNumber low) { size_t len = sizeof(low.getValue()); ACE_Message_Block* data; ACE_NEW(data, ACE_Message_Block(len)); Serializer serializer( data, this->link_->transport()->swap_bytes()); serializer << low.getValue(); // Broadcast control sample to all peers: send_control(MULTICAST_NAKACK, data); }
void send_data(const SequenceNumber& seq) { dsle_.get_header().sequence_ = seq; dsle_.set_sample(new ACE_Message_Block(DataSampleHeader::max_marshaled_size())); *dsle_.get_sample() << dsle_.get_header(); dsle_.get_sample()->cont(payload_.duplicate()); ACE_DEBUG((LM_INFO, "sending with seq#: %q\n", seq.getValue())); send(list_); }
void ReliableSession::expire_naks() { if (this->nak_requests_.empty()) return; // nothing to expire ACE_Time_Value deadline(ACE_OS::gettimeofday()); deadline -= this->link_->config()->nak_timeout_; NakRequestMap::iterator first(this->nak_requests_.begin()); NakRequestMap::iterator last(this->nak_requests_.upper_bound(deadline)); if (first == last) return; // nothing to expire // Skip unrecoverable datagrams to // re-establish a baseline to detect future reception gaps. SequenceNumber lastSeq = (last == this->nak_requests_.end()) ? this->nak_requests_.rbegin()->second : last->second; std::vector<SequenceRange> dropped; if (this->nak_sequence_.insert(SequenceRange(this->nak_sequence_.low(), lastSeq), dropped)) { for (size_t i = 0; i < dropped.size(); ++i) { this->reassembly_.data_unavailable(dropped[i]); } ACE_ERROR((LM_WARNING, ACE_TEXT("(%P|%t) WARNING: ") ACE_TEXT("ReliableSession::expire_naks: ") ACE_TEXT("timed out waiting on remote peer %#08x%08x to send missing samples: %q - %q!\n"), (unsigned int)(this->remote_peer_ >> 32), (unsigned int) this->remote_peer_, this->nak_sequence_.low().getValue(), lastSeq.getValue())); } // Clear expired repair requests: this->nak_requests_.erase(first, last); deliver_held_data(); }
void TransportSendBuffer::insert(SequenceNumber sequence, const buffer_type& value) { // Age off oldest sample if we are at capacity: if (this->buffers_.size() == this->capacity_) { BufferMap::iterator it(this->buffers_.begin()); if (it == this->buffers_.end()) return; if ( OpenDDS::DCPS::Transport_debug_level >= 10) { ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) TransportSendBuffer::insert() - ") ACE_TEXT("aging off PDU: 0x%x as buffer(0x%x,0x%x)\n"), it->first.getValue(), it->second.first, it->second.second )); } release(it->second); this->buffers_.erase(it); } std::pair<BufferMap::iterator, bool> pair = this->buffers_.insert(BufferMap::value_type(sequence, buffer_type())); if (pair.first == this->buffers_.end()) return; buffer_type& buffer(pair.first->second); // Copy sample's TransportQueueElements: TransportSendStrategy::QueueType*& elems = buffer.first; ACE_NEW(elems, TransportSendStrategy::QueueType(value.first->size(), 1)); CopyChainVisitor visitor(*elems, &this->retained_allocator_, &this->retained_mb_allocator_, &this->retained_db_allocator_); value.first->accept_visitor(visitor); // Copy sample's message/data block descriptors: ACE_Message_Block*& data = buffer.second; data = TransportQueueElement::clone(value.second, &this->retained_mb_allocator_, &this->retained_db_allocator_); if ( OpenDDS::DCPS::Transport_debug_level >= 10) { ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) TransportSendBuffer::insert() - ") ACE_TEXT("saved PDU: 0x%x as buffer(0x%x,0x%x)\n"), sequence.getValue(), buffer.first, buffer.second )); } }
void ReliableSession::nakack_received(ACE_Message_Block* control) { if (this->active_) return; // pub send syn, then doesn't receive them. const TransportHeader& header = this->link_->receive_strategy()->received_header(); // Not from the remote peer for this session. if (this->remote_peer_ != header.source_) return; Serializer serializer(control, header.swap_bytes()); SequenceNumber low; serializer >> low; // MULTICAST_NAKACK control samples indicate data which cannot be // repaired by a remote peer; if any values were needed below // this value, then the sequence needs to be shifted: std::vector<SequenceRange> dropped; if (this->nak_sequence_.insert(SequenceRange(this->nak_sequence_.low(), low.previous()), dropped)) { for (size_t i = 0; i < dropped.size(); ++i) { this->reassembly_.data_unavailable(dropped[i]); } if (DCPS_debug_level > 0) { ACE_ERROR((LM_WARNING, ACE_TEXT("(%P|%t) WARNING: ReliableSession::nakack_received ") ACE_TEXT("local %d remote %d [%q - %q] ") ACE_TEXT("not repaired.\n"), this->link_->local_peer(), this->remote_peer_, this->nak_sequence_.low().getValue(), low.getValue())); } } }
void SingleSendBuffer::insert(SequenceNumber sequence, TransportSendStrategy::QueueType* queue, ACE_Message_Block* chain) { check_capacity(); BufferType& buffer = this->buffers_[sequence]; insert_buffer(buffer, queue, chain); if (Transport_debug_level > 5) { ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) SingleSendBuffer::insert() - ") ACE_TEXT("saved PDU: %q as buffer(0x%@,0x%@)\n"), sequence.getValue(), buffer.first, buffer.second )); } }
void ReliableSession::send_naks() { // Could get data samples before syn control message. // No use nak'ing until syn control message is received and session is acked. if (!this->acked()) return; if (DCPS_debug_level > 5) { ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) ReliableSession::send_naks local %d ") ACE_TEXT("remote %d nak request size %d \n"), this->link_->local_peer(), this->remote_peer_, this->nak_requests_.size())); } if (!this->nak_sequence_.disjoint()) return; // nothing to send ACE_Time_Value now(ACE_OS::gettimeofday()); // Record high-water mark for this interval; this value will // be used to reset the low-water mark in the event the remote // peer becomes unresponsive: this->nak_requests_[now] = this->nak_sequence_.high(); typedef std::vector<SequenceRange> RangeVector; RangeVector ignored; /// The range first - second will be skiped (no naks sent for it). SequenceNumber first; SequenceNumber second; NakRequestMap::reverse_iterator itr(this->nak_requests_.rbegin()); if (this->nak_requests_.size() > 1) { // The sequences between rbegin - 1 and rbegin will not be ignored for naking. ++itr; size_t nak_delay_intervals = this->link()->config()->nak_delay_intervals_; size_t nak_max = this->link()->config()->nak_max_; size_t sz = this->nak_requests_.size(); // Image i is the index of element in nak_requests_ in reverse order. // index 0 sequence is most recent high water mark. // e.g index , 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 // 0 (rbegin) is always skipped because missing sample between 1 and 0 interval // should always be naked., // if nak_delay_intervals=4, nak_max=3, any sequence between 5 - 1, 10 - 6, 15 - 11 // are skipped for naking due to nak_delay_intervals and 20 - 16 are skipped for // naking due to nak_max. for (size_t i = 1; i < sz; ++i) { if ((i * 1.0) / (nak_delay_intervals + 1) > nak_max) { if (first != SequenceNumber()) { first = this->nak_requests_.begin()->second; } else { ignored.push_back(std::make_pair(this->nak_requests_.begin()->second, itr->second)); } break; } if (i % (nak_delay_intervals + 1) == 1) { second = itr->second; } if (second != SequenceNumber()) { first = itr->second; } if (i % (nak_delay_intervals + 1) == 0) { first = itr->second; if (first != SequenceNumber() && second != SequenceNumber()) { ignored.push_back(std::make_pair(first, second)); first = SequenceNumber(); second = SequenceNumber(); } } ++itr; } if (first != SequenceNumber() && second != SequenceNumber() && first != second) { ignored.push_back(std::make_pair(first, second)); } } // Take a copy to facilitate temporary suppression: DisjointSequence received(this->nak_sequence_); if (DCPS_debug_level > 0) { received.dump(); } size_t sz = ignored.size(); for (size_t i = 0; i < sz; ++i) { if (ignored[i].second > received.cumulative_ack()) { SequenceNumber high = ignored[i].second; SequenceNumber low = ignored[i].first; if (low < received.cumulative_ack()) { low = received.cumulative_ack(); } if (DCPS_debug_level > 0) { ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%P|%t) ReliableSession::send_naks local %d ") ACE_TEXT("remote %d ignore missing [%q - %q]\n"), this->link_->local_peer(), this->remote_peer_, low.getValue(), high.getValue())); } // Make contiguous between ignored sequences. received.insert(SequenceRange(low, high)); } } for (NakPeerSet::iterator it(this->nak_peers_.begin()); it != this->nak_peers_.end(); ++it) { // Update sequence to temporarily suppress repair requests for // ranges already requested by other peers for this interval: received.insert(*it); } if (received.disjoint()) { send_naks(received); } // Clear peer repair requests: this->nak_peers_.clear(); }
void operator()(SequenceNumber i, SequenceNumber j) const { out << "[" << i.getValue() << "," << j.getValue() << "] "; }
int ACE_TMAIN(int, ACE_TCHAR*[]) { // Construction (default) TEST_CHECK(SequenceNumber(SN_MIN) == SequenceNumber()); TEST_CHECK(SequenceNumber::ZERO().getValue() == 0); TEST_CHECK(SequenceNumber::ZERO() < SequenceNumber()); TEST_CHECK(++SequenceNumber(SequenceNumber::ZERO()) == SequenceNumber()); // testing numerical sequence TEST_CHECK(SequenceNumber(SN_MIN) < SequenceNumber(SN_MIN+1)); TEST_CHECK(!(SequenceNumber(SN_MIN+1) < SequenceNumber(SN_MIN))); TEST_CHECK(SequenceNumber(SN_SEAM) < SequenceNumber(SN_SEAM+1)); TEST_CHECK(!(SequenceNumber(SN_SEAM+1) < SequenceNumber(SN_SEAM))); TEST_CHECK(SequenceNumber(SN_MAX-1) < SequenceNumber(SN_MAX)); TEST_CHECK(!(SequenceNumber(SN_MAX) < SequenceNumber(SN_MAX-1))); // testing values and increment operator { SequenceNumber num(SN_MIN); TEST_CHECK(num.getValue() == SN_MIN); TEST_CHECK((++num).getValue() == SN_MIN+1); } { SequenceNumber num(SN_SEAM); TEST_CHECK(num.getValue() == SN_SEAM); TEST_CHECK((++num).getValue() == SN_SEAM+1); TEST_CHECK((++num).getValue() == SN_SEAM+2); } { SequenceNumber num(SN_MAX); TEST_CHECK(num.getValue() == SN_MAX); TEST_CHECK((++num).getValue() == SN_MIN); // test post-incrementer TEST_CHECK((num++).getValue() == SN_MIN); TEST_CHECK(num.getValue() == SN_MIN+1); } // Test SEQUENCENUMBER_UNKNOWN { SequenceNumber num = SequenceNumber::SEQUENCENUMBER_UNKNOWN(); TEST_CHECK(num.getValue() == ACE_INT64(0xffffffff) << 32); SequenceNumber min; TEST_CHECK(num != min); TEST_CHECK(num == SequenceNumber::SEQUENCENUMBER_UNKNOWN()); } // Test previous() member function { SequenceNumber num(SN_MIN); TEST_CHECK(num.previous() == SN_MAX); } { SequenceNumber num(SN_SEAM+1); TEST_CHECK(num.previous() == SN_SEAM); } { SequenceNumber num(99); TEST_CHECK(num.previous() == 98); } { SequenceNumber num(SN_MAX); TEST_CHECK(num.previous() == SN_MAX-1); } return 0; }