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

Generated on 10 Aug 2018 for OpenDDS by  doxygen 1.6.1