DisjointSequence.cpp

Go to the documentation of this file.
00001 /*
00002  *
00003  *
00004  * Distributed under the OpenDDS License.
00005  * See: http://www.opendds.org/license.html
00006  */
00007 
00008 #include "DCPS/DdsDcps_pch.h" //Only the _pch include should start with DCPS/
00009 
00010 #include "DisjointSequence.h"
00011 
00012 #include "ace/Log_Msg.h"
00013 
00014 #include <stdexcept>
00015 #include <algorithm>
00016 #include <iterator>
00017 
00018 #ifndef __ACE_INLINE__
00019 # include "DisjointSequence.inl"
00020 #endif /* __ACE_INLINE__ */
00021 
00022 namespace OpenDDS {
00023 namespace DCPS {
00024 
00025 bool
00026 DisjointSequence::insert_i(const SequenceRange& range,
00027                            OPENDDS_VECTOR(SequenceRange)* gaps /* = 0 */)
00028 {
00029   validate(range);
00030 
00031   RangeSet::iterator range_above = sequences_.lower_bound(range);
00032   if (range_above != sequences_.end()
00033       && range_above->first <= range.first) {
00034     return false; // already have this range, nothing to insert
00035   }
00036 
00037   SequenceRange newRange = range;
00038   if (range_above != sequences_.end()
00039       && ++SequenceNumber(newRange.second) >= range_above->first) {
00040     // newRange overlaps range_above, replace range_above with modified newRange
00041     newRange.second = range_above->second;
00042     // move to just past this iterator for the erase
00043     ++range_above;
00044   }
00045 
00046   const SequenceNumber::Value previous = range.first.getValue() - 1;
00047   // find the lower_bound for the SequenceNumber just before this range
00048   // to see if any ranges need to combine
00049   const RangeSet::iterator range_below =
00050     sequences_.lower_bound(SequenceRange(1 /*ignored*/,
00051                                          (previous > 0) ? previous
00052                                          : SequenceNumber::ZERO()));
00053   if (range_below != sequences_.end()) {
00054     // if low end falls inside of the range_below range
00055     // then combine
00056     if (newRange.first > range_below->first) {
00057       newRange.first = range_below->first;
00058     }
00059 
00060     if (gaps) {
00061       RangeSet::iterator gap_iter = range_below;
00062       if (range.first < gap_iter->second) {
00063         gaps->push_back(SequenceRange(range.first,
00064                                       gap_iter->second.previous()));
00065       }
00066       SequenceNumber last_gap = gap_iter++->second;
00067       for (; gap_iter != range_above; ++gap_iter) {
00068         const SequenceNumber in_range =
00069           std::min(gap_iter->first.previous().getValue(),
00070                    range.second.getValue());
00071         gaps->push_back(SequenceRange(++last_gap, in_range));
00072         last_gap = gap_iter->second;
00073       }
00074       if (last_gap < range.second) {
00075         gaps->push_back(SequenceRange(++last_gap, range.second));
00076       }
00077     }
00078 
00079     sequences_.erase(range_below, range_above);
00080   }
00081 
00082   sequences_.insert(newRange);
00083   return true;
00084 }
00085 
00086 bool
00087 DisjointSequence::insert(SequenceNumber value, CORBA::ULong num_bits,
00088                          const CORBA::Long bits[])
00089 {
00090   bool inserted = false;
00091   RangeSet::iterator iter = sequences_.end();
00092   SequenceNumber::Value range_start = 0;
00093   const SequenceNumber::Value val = value.getValue();
00094 
00095   // See RTPS v2.1 section 9.4.2.6 SequenceNumberSet
00096   for (CORBA::ULong i = 0, x = 0, bit = 0; i < num_bits; ++i, ++bit) {
00097 
00098     if (bit == 32) bit = 0;
00099 
00100     if (bit == 0) {
00101       x = static_cast<CORBA::ULong>(bits[i / 32]);
00102       if (x == 0) {
00103         // skip an entire Long if it's all 0's (adds 32 due to ++i)
00104         i += 31;
00105         bit = 31;
00106         //FUTURE: this could be generalized with something like the x86 "bsr"
00107         //        instruction using compiler intrinsics, VC++ _BitScanReverse()
00108         //        and GCC __builtin_clz()
00109         continue;
00110       }
00111     }
00112 
00113     if (x & (1 << (31 - bit))) {
00114       if (range_start == 0) {
00115         range_start = val + i;
00116       }
00117 
00118     } else if (range_start != 0) {
00119       // this is a "0" bit and we've previously seen a "1": insert a range
00120       const SequenceNumber::Value to_insert = val + i - 1;
00121       if (insert_bitmap_range(iter, SequenceRange(range_start, to_insert))) {
00122         inserted = true;
00123       }
00124       range_start = 0;
00125 
00126       if (iter != sequences_.end() && iter->second.getValue() != to_insert) {
00127         // skip ahead: next gap in sequence must be past iter->second
00128         CORBA::ULong next_i = CORBA::ULong(iter->second.getValue() - val);
00129         bit = next_i % 32;
00130         if (next_i / 32 != i / 32) {
00131           x = static_cast<CORBA::ULong>(bits[next_i / 32]);
00132         }
00133         i = next_i;
00134       }
00135     }
00136   }
00137 
00138   if (range_start != 0) {
00139     // iteration finished before we saw a "0" (inside a range)
00140     SequenceNumber range_end = (value + num_bits).previous();
00141     if (insert_bitmap_range(iter, SequenceRange(range_start, range_end))) {
00142       return true;
00143     }
00144   }
00145   return inserted;
00146 }
00147 
00148 bool
00149 DisjointSequence::insert_bitmap_range(RangeSet::iterator& iter,
00150                                       const SequenceRange& range)
00151 {
00152   // This is similar to insert_i(), except it doesn't need an O(log(n)) search
00153   // of sequences_ every time to find the starting point, and it doesn't
00154   // compute the 'gaps'.
00155 
00156   const SequenceNumber::Value previous = range.first.getValue() - 1,
00157     next = range.second.getValue() + 1;
00158 
00159   if (!sequences_.empty()) {
00160     if (iter == sequences_.end()) {
00161       iter = sequences_.lower_bound(SequenceRange(1 /*ignored*/, previous));
00162     } else {
00163       // start where we left off last time and get the lower_bound(previous)
00164       for (; iter != sequences_.end() && iter->second < previous; ++iter) ;
00165     }
00166   }
00167 
00168   if (iter == sequences_.end() || iter->first > next) {
00169     // can't combine on either side, insert a new range
00170     iter = sequences_.insert(iter, range);
00171     return true;
00172   }
00173 
00174   if (iter->first <= range.first && iter->second >= range.second) {
00175     // range is already covered by this DisjointSet
00176     return false;
00177   }
00178 
00179   // find the right-most (highest) range we can use
00180   RangeSet::iterator right = iter;
00181   for (; right != sequences_.end() && right->second < next; ++right) ;
00182 
00183   SequenceNumber high = range.second;
00184   if (right != sequences_.end()
00185       && right->first <= next && right->first > range.first) {
00186     high = right->second;
00187     ++right;
00188   }
00189 
00190   const SequenceNumber low = std::min(iter->first, range.first);
00191   sequences_.erase(iter, right);
00192 
00193   iter = sequences_.insert(SequenceRange(low, high)).first;
00194   return true;
00195 }
00196 
00197 bool
00198 DisjointSequence::to_bitmap(CORBA::Long bitmap[], CORBA::ULong length,
00199                             CORBA::ULong& num_bits, bool invert) const
00200 {
00201   // num_bits will be 1 more than the index of the last bit we wrote
00202   num_bits = 0;
00203   if (!disjoint()) {
00204     return true;
00205   }
00206 
00207   const SequenceNumber base = ++SequenceNumber(cumulative_ack());
00208 
00209   for (RangeSet::const_iterator iter = sequences_.begin(), prev = iter++;
00210        iter != sequences_.end(); ++iter, ++prev) {
00211 
00212     CORBA::ULong low = 0, high = 0;
00213 
00214     if (invert) {
00215       low = CORBA::ULong(prev->second.getValue() + 1 - base.getValue());
00216       high = CORBA::ULong(iter->first.getValue() - 1 - base.getValue());
00217 
00218     } else {
00219       low = CORBA::ULong(iter->first.getValue() - base.getValue());
00220       high = CORBA::ULong(iter->second.getValue() - base.getValue());
00221     }
00222 
00223     if (!fill_bitmap_range(low, high, bitmap, length, num_bits)) {
00224       return false;
00225     }
00226   }
00227 
00228   return true;
00229 }
00230 
00231 bool
00232 DisjointSequence::fill_bitmap_range(CORBA::ULong low, CORBA::ULong high,
00233                                     CORBA::Long bitmap[], CORBA::ULong length,
00234                                     CORBA::ULong& num_bits)
00235 {
00236   bool clamped = false;
00237   CORBA::ULong idx_low = low / 32, bit_low = low % 32,
00238                idx_high = high / 32, bit_high = high % 32;
00239 
00240   if (idx_low >= length) {
00241     return false;
00242   }
00243   if (idx_high >= length) {
00244     // clamp to largest number we can represent
00245     high = length * 32 - 1;
00246     idx_high = length - 1;
00247     bit_high = high % 32;
00248     clamped = true;
00249   }
00250 
00251   // clear any full Longs between the last bit we wrote and idx_low
00252   for (CORBA::ULong i = (num_bits + 31) / 32; i < idx_low; ++i) {
00253     bitmap[i] = 0;
00254   }
00255 
00256   // write the Long at idx_low, preserving bits that may already be there
00257   CORBA::ULong x = bitmap[idx_low]; // use unsigned for bitwise operators
00258   //    clear the bits in x in the range [bit_last, bit_low)
00259   if (num_bits > 0) {
00260     const size_t bit_last = ((num_bits - 1) / 32 == idx_low)
00261                             ? ((num_bits - 1) % 32 + 1) : 0;
00262     for (size_t m = bit_last; m < bit_low; ++m) {
00263       x &= ~(1 << (31 - m));
00264     }
00265   } else {
00266     x = 0;
00267   }
00268   //    set the bits in x in the range [bit_low, limit)
00269   const size_t limit = (idx_high == idx_low) ? bit_high : 31;
00270   for (size_t b = bit_low; b <= limit; ++b) {
00271     x |= (1 << (31 - b));
00272   }
00273   bitmap[idx_low] = x;
00274 
00275   // any full Longs inside the current range are set to all 1's
00276   for (CORBA::ULong elt = idx_low + 1; elt < idx_high; ++elt) {
00277     bitmap[elt] = 0xFFFFFFFF;
00278   }
00279 
00280   if (idx_high > idx_low) {
00281     // write the Long at idx_high, no need to preserve bits since this is
00282     // the first iteration that's writing it
00283     x = 0;
00284     for (size_t b = 0; b <= bit_high; ++b) {
00285       x |= (1 << (31 - b));
00286     }
00287     bitmap[idx_high] = x;
00288   }
00289 
00290   num_bits = high + 1;
00291   return !clamped;
00292 }
00293 
00294 OPENDDS_VECTOR(SequenceRange)
00295 DisjointSequence::missing_sequence_ranges() const
00296 {
00297   OPENDDS_VECTOR(SequenceRange) missing;
00298   if (!disjoint()) {
00299     return missing;
00300   }
00301 
00302   RangeSet::const_iterator secondIter = sequences_.begin();
00303   for (RangeSet::const_iterator firstIter = secondIter++;
00304        secondIter != sequences_.end(); ++firstIter, ++secondIter) {
00305 
00306     const SequenceNumber missingLow = ++SequenceNumber(firstIter->second),
00307                          missingHigh = secondIter->first.previous();
00308 
00309     if (missingLow <= missingHigh) {
00310       missing.push_back(SequenceRange(missingLow, missingHigh));
00311     }
00312   }
00313 
00314   return missing;
00315 }
00316 
00317 OPENDDS_VECTOR(SequenceRange)
00318 DisjointSequence::present_sequence_ranges() const
00319 {
00320   OPENDDS_VECTOR(SequenceRange) present;
00321   std::copy(sequences_.begin(), sequences_.end(), std::back_inserter(present));
00322   return present;
00323 }
00324 
00325 bool
00326 DisjointSequence::contains(SequenceNumber value) const
00327 {
00328   RangeSet::const_iterator iter =
00329     sequences_.lower_bound(SequenceRange(0 /*ignored*/, value));
00330   return iter != sequences_.end() && iter->first <= value;
00331 }
00332 
00333 void
00334 DisjointSequence::validate(const SequenceRange& range)
00335 {
00336   if (range.first > range.second) {
00337     throw std::runtime_error("SequenceNumber range invalid, range must "
00338                              "be ascending.");
00339   }
00340 }
00341 
00342 void
00343 DisjointSequence::dump() const
00344 {
00345   ACE_DEBUG((LM_DEBUG, "(%P|%t) DisjointSequence[%X]::dump Ranges of seen "
00346                        "SequenceNumbers:\n", this));
00347   for (RangeSet::const_iterator iter = sequences_.begin();
00348        iter != sequences_.end(); ++iter) {
00349     ACE_DEBUG((LM_DEBUG, "(%P|%t) DisjointSequence[%X]::dump\t%q-%q\n",
00350                this, iter->first.getValue(), iter->second.getValue()));
00351   }
00352 }
00353 
00354 } // namespace DCPS
00355 } // namespace OpenDDS

Generated on Fri Feb 12 20:05:22 2016 for OpenDDS by  doxygen 1.4.7