Line data Source code
1 : /* 2 : * 3 : * 4 : * Distributed under the OpenDDS License. 5 : * See: http://www.opendds.org/license.html 6 : */ 7 : 8 : #ifndef OPENDDS_DCPS_ADDRESSCACHE_H 9 : #define OPENDDS_DCPS_ADDRESSCACHE_H 10 : 11 : #include "dcps_export.h" 12 : 13 : #ifndef ACE_LACKS_PRAGMA_ONCE 14 : # pragma once 15 : #endif /* ACE_LACKS_PRAGMA_ONCE */ 16 : 17 : #include "Definitions.h" 18 : #include "GuidUtils.h" 19 : #include "NetworkAddress.h" 20 : #include "PoolAllocator.h" 21 : #include "RcObject.h" 22 : #include "TimeTypes.h" 23 : 24 : #include "ace/INET_Addr.h" 25 : 26 : OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL 27 : 28 : namespace OpenDDS { 29 : namespace DCPS { 30 : 31 : typedef OPENDDS_SET_CMP(GUID_t, GUID_tKeyLessThan) GuidSet; 32 : 33 : struct AddressCacheEntry : public virtual RcObject { 34 : 35 1 : AddressCacheEntry() : addrs_(), expires_(MonotonicTimePoint::max_value) 36 : #if defined ACE_HAS_CPP11 37 1 : , addrs_hash_(0) 38 : #endif 39 1 : {} 40 : 41 6 : AddressCacheEntry(const AddrSet& addrs, const MonotonicTimePoint& expires) : addrs_(addrs), expires_(expires) 42 : #if defined ACE_HAS_CPP11 43 12 : , addrs_hash_(calculate_hash(addrs_)) 44 : #endif 45 6 : {} 46 : 47 : AddrSet addrs_; 48 : MonotonicTimePoint expires_; 49 : #if defined ACE_HAS_CPP11 50 : size_t addrs_hash_; 51 : #endif 52 : }; 53 : 54 : struct AddressCacheEntryProxy { 55 : AddressCacheEntryProxy(RcHandle<AddressCacheEntry> rch) : entry_(rch) {} 56 : 57 : bool operator==(const AddressCacheEntryProxy& rhs) const { 58 : #if defined ACE_HAS_CPP11 59 : return entry_ && rhs.entry_ && entry_->addrs_hash_ == rhs.entry_->addrs_hash_ && entry_->addrs_ == rhs.entry_->addrs_; 60 : #else 61 : return entry_ && rhs.entry_ && entry_->addrs_ == rhs.entry_->addrs_; 62 : #endif 63 : } 64 : 65 : bool operator<(const AddressCacheEntryProxy& rhs) const { 66 : #if defined ACE_HAS_CPP11 67 : return (rhs.entry_ && (!entry_ || (entry_->addrs_hash_ < rhs.entry_->addrs_hash_ || (entry_->addrs_hash_ == rhs.entry_->addrs_hash_ && entry_->addrs_ < rhs.entry_->addrs_)))); 68 : #else 69 : return (rhs.entry_ && (!entry_ || (entry_->addrs_ < rhs.entry_->addrs_))); 70 : #endif 71 : } 72 : 73 : const AddrSet& addrs() const { return entry_->addrs_; } 74 : 75 : #if defined ACE_HAS_CPP11 76 : size_t hash() const noexcept { return entry_ ? entry_->addrs_hash_ : 0; } 77 : #endif 78 : 79 : private: 80 : RcHandle<AddressCacheEntry> entry_; 81 : }; 82 : 83 : template <typename Key> 84 : class AddressCache { 85 : public: 86 : 87 : #if defined ACE_HAS_CPP11 88 : typedef OPENDDS_UNORDERED_MAP_T(Key, RcHandle<AddressCacheEntry>) MapType; 89 : typedef OPENDDS_VECTOR(Key) KeyVec; 90 : typedef OPENDDS_UNORDERED_MAP_T(GUID_t, KeyVec) IdMapType; 91 : #else 92 : typedef OPENDDS_MAP_T(Key, RcHandle<AddressCacheEntry>) MapType; 93 : typedef OPENDDS_VECTOR(Key) KeyVec; 94 : typedef OPENDDS_MAP_T(GUID_t, KeyVec) IdMapType; 95 : #endif 96 : 97 8 : AddressCache() {} 98 8 : virtual ~AddressCache() {} 99 : 100 : struct ScopedAccess { 101 : ScopedAccess(AddressCache& cache) 102 : : guard_(cache.mutex_) 103 : , rch_() 104 : , is_new_(false) 105 : #if defined ACE_HAS_CPP11 106 : , non_const_touch_(false) 107 : #endif 108 : { 109 : } 110 : 111 3 : ScopedAccess(AddressCache& cache, const Key& key, bool block = true, const MonotonicTimePoint& now = MonotonicTimePoint::now()) 112 3 : : guard_(cache.mutex_, block) 113 3 : , rch_() 114 3 : , is_new_(false) 115 : #if defined ACE_HAS_CPP11 116 3 : , non_const_touch_(false) 117 : #endif 118 : { 119 3 : const typename MapType::iterator pos = cache.map_.find(key); 120 3 : if (pos == cache.map_.end()) { 121 1 : rch_ = make_rch<AddressCacheEntry>(); 122 1 : cache.map_[key] = rch_; 123 1 : GuidSet set; 124 1 : key.get_contained_guids(set); 125 2 : for (GuidSet::const_iterator it = set.begin(), limit = set.end(); it != limit; ++it) { 126 1 : cache.id_map_[*it].push_back(key); 127 : } 128 1 : is_new_ = true; 129 1 : } else { 130 2 : rch_ = pos->second; 131 : } 132 : 133 3 : if (rch_->expires_ < now) { 134 1 : rch_->addrs_.clear(); 135 1 : rch_->expires_ = MonotonicTimePoint::max_value; 136 1 : is_new_ = true; 137 : } 138 3 : } 139 : 140 3 : ~ScopedAccess() 141 : { 142 : #if defined ACE_HAS_CPP11 143 3 : recalculate_hash(); 144 : #endif 145 3 : } 146 : 147 3 : inline AddressCacheEntry& value() { 148 3 : OPENDDS_ASSERT(rch_); 149 : #if defined ACE_HAS_CPP11 150 3 : non_const_touch_ = true; 151 : #endif 152 3 : return *rch_; 153 : } 154 : 155 : inline const AddressCacheEntry& value() const { 156 : OPENDDS_ASSERT(rch_); 157 : return *rch_; 158 : } 159 : 160 : #if defined ACE_HAS_CPP11 161 3 : inline void recalculate_hash() { 162 3 : if (non_const_touch_) { 163 3 : rch_->addrs_hash_ = calculate_hash(rch_->addrs_); 164 3 : non_const_touch_ = false; 165 : } 166 3 : } 167 : #endif 168 : 169 : ACE_Guard<ACE_Thread_Mutex> guard_; 170 : RcHandle<AddressCacheEntry> rch_; 171 : bool is_new_; 172 : #if defined ACE_HAS_CPP11 173 : bool non_const_touch_; 174 : #endif 175 : 176 : private: 177 : ScopedAccess(); 178 : ScopedAccess(const ScopedAccess&); 179 : ScopedAccess& operator=(const ScopedAccess&); 180 : }; 181 : 182 6 : bool load(const Key& key, AddrSet& addrs) const 183 : { 184 6 : ACE_Guard<ACE_Thread_Mutex> guard(mutex_); 185 6 : const typename MapType::const_iterator pos = map_.find(key); 186 6 : if (pos != map_.end()) { 187 3 : if (MonotonicTimePoint::now() < pos->second->expires_) { 188 3 : const AddrSet& as = pos->second->addrs_; 189 7 : for (AddrSet::const_iterator it = as.begin(), limit = as.end(); it != limit; ++it) { 190 4 : addrs.insert(*it); 191 : } 192 3 : return true; 193 : } 194 : } 195 3 : return false; 196 6 : } 197 : 198 7 : void store(const Key& key, const AddrSet& addrs, const MonotonicTimePoint& expires = MonotonicTimePoint::max_value) 199 : { 200 7 : ACE_Guard<ACE_Thread_Mutex> guard(mutex_); 201 7 : RcHandle<AddressCacheEntry>& rch = map_[key]; 202 7 : if (rch) { 203 1 : rch->addrs_ = addrs; 204 1 : rch->expires_ = expires; 205 : } else { 206 6 : rch = make_rch<AddressCacheEntry>(addrs, expires); 207 6 : GuidSet set; 208 6 : key.get_contained_guids(set); 209 12 : for (GuidSet::const_iterator it = set.begin(), limit = set.end(); it != limit; ++it) { 210 6 : id_map_[*it].push_back(key); 211 : } 212 6 : } 213 7 : } 214 : 215 1 : bool remove(const Key& key) 216 : { 217 1 : ACE_Guard<ACE_Thread_Mutex> guard(mutex_); 218 2 : return map_.erase(key) != 0; 219 1 : } 220 : 221 1 : void remove_id(const GUID_t& val) 222 : { 223 1 : ACE_Guard<ACE_Thread_Mutex> guard(mutex_); 224 1 : const typename IdMapType::iterator pos = id_map_.find(val); 225 1 : if (pos != id_map_.end()) { 226 2 : for (typename KeyVec::iterator it = pos->second.begin(), limit = pos->second.end(); it != limit; ++it) { 227 1 : map_.erase(*it); 228 : } 229 1 : id_map_.erase(pos); 230 : } 231 1 : } 232 : 233 : private: 234 : 235 : mutable ACE_Thread_Mutex mutex_; 236 : MapType map_; 237 : IdMapType id_map_; 238 : }; 239 : 240 : } // namespace DCPS 241 : } // namespace OpenDDS 242 : 243 : OPENDDS_END_VERSIONED_NAMESPACE_DECL 244 : 245 : #endif /* OPENDDS_DCPS_RADDRESSCACHE_H */