cache.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #include "cache.h"
  2. #include "thread.h"
  3. #include <util/system/tls.h>
  4. #include <util/system/info.h>
  5. #include <util/system/rwlock.h>
  6. #include <util/thread/singleton.h>
  7. #include <util/generic/singleton.h>
  8. #include <util/generic/hash.h>
  9. using namespace NDns;
  10. namespace {
  11. struct TResolveTask {
  12. enum EMethod {
  13. Normal,
  14. Threaded
  15. };
  16. inline TResolveTask(const TResolveInfo& info, EMethod method)
  17. : Info(info)
  18. , Method(method)
  19. {
  20. }
  21. const TResolveInfo& Info;
  22. const EMethod Method;
  23. };
  24. class IDns {
  25. public:
  26. virtual ~IDns() = default;
  27. virtual const TResolvedHost* Resolve(const TResolveTask&) = 0;
  28. };
  29. typedef TAtomicSharedPtr<TResolvedHost> TResolvedHostPtr;
  30. struct THashResolveInfo {
  31. inline size_t operator()(const TResolveInfo& ri) const {
  32. return ComputeHash(ri.Host) ^ ri.Port;
  33. }
  34. };
  35. struct TCompareResolveInfo {
  36. inline bool operator()(const NDns::TResolveInfo& x, const NDns::TResolveInfo& y) const {
  37. return x.Host == y.Host && x.Port == y.Port;
  38. }
  39. };
  40. class TGlobalCachedDns: public IDns, public TNonCopyable {
  41. public:
  42. const TResolvedHost* Resolve(const TResolveTask& rt) override {
  43. //2. search host in cache
  44. {
  45. TReadGuard guard(L_);
  46. TCache::const_iterator it = C_.find(rt.Info);
  47. if (it != C_.end()) {
  48. return it->second.Get();
  49. }
  50. }
  51. TResolvedHostPtr res = ResolveA(rt);
  52. //update cache
  53. {
  54. TWriteGuard guard(L_);
  55. std::pair<TCache::iterator, bool> updateResult = C_.insert(std::make_pair(TResolveInfo(res->Host, rt.Info.Port), res));
  56. TResolvedHost* rh = updateResult.first->second.Get();
  57. if (updateResult.second) {
  58. //fresh resolved host, set cache record id for it
  59. rh->Id = C_.size() - 1;
  60. }
  61. return rh;
  62. }
  63. }
  64. void AddAlias(const TString& host, const TString& alias) noexcept {
  65. TWriteGuard guard(LA_);
  66. A_[host] = alias;
  67. }
  68. static inline TGlobalCachedDns* Instance() {
  69. return SingletonWithPriority<TGlobalCachedDns, 65530>();
  70. }
  71. private:
  72. inline TResolvedHostPtr ResolveA(const TResolveTask& rt) {
  73. TString originalHost(rt.Info.Host);
  74. TString host(originalHost);
  75. //3. replace host to alias, if exist
  76. if (A_.size()) {
  77. TReadGuard guard(LA_);
  78. TStringBuf names[] = {"*", host};
  79. for (const auto& name : names) {
  80. TAliases::const_iterator it = A_.find(name);
  81. if (it != A_.end()) {
  82. host = it->second;
  83. }
  84. }
  85. }
  86. if (host.length() > 2 && host[0] == '[') {
  87. TString unbracedIpV6(host.data() + 1, host.size() - 2);
  88. host.swap(unbracedIpV6);
  89. }
  90. TAutoPtr<TNetworkAddress> na;
  91. //4. getaddrinfo (direct or in separate thread)
  92. if (rt.Method == TResolveTask::Normal) {
  93. na.Reset(new TNetworkAddress(host, rt.Info.Port));
  94. } else if (rt.Method == TResolveTask::Threaded) {
  95. na = ThreadedResolve(host, rt.Info.Port);
  96. } else {
  97. Y_ASSERT(0);
  98. throw yexception() << TStringBuf("invalid resolve method");
  99. }
  100. return new TResolvedHost(originalHost, *na);
  101. }
  102. typedef THashMap<TResolveInfo, TResolvedHostPtr, THashResolveInfo, TCompareResolveInfo> TCache;
  103. TCache C_;
  104. TRWMutex L_;
  105. typedef THashMap<TString, TString> TAliases;
  106. TAliases A_;
  107. TRWMutex LA_;
  108. };
  109. class TCachedDns: public IDns {
  110. public:
  111. inline TCachedDns(IDns* slave)
  112. : S_(slave)
  113. {
  114. }
  115. const TResolvedHost* Resolve(const TResolveTask& rt) override {
  116. //1. search in local thread cache
  117. {
  118. TCache::const_iterator it = C_.find(rt.Info);
  119. if (it != C_.end()) {
  120. return it->second;
  121. }
  122. }
  123. const TResolvedHost* res = S_->Resolve(rt);
  124. C_[TResolveInfo(res->Host, rt.Info.Port)] = res;
  125. return res;
  126. }
  127. private:
  128. typedef THashMap<TResolveInfo, const TResolvedHost*, THashResolveInfo, TCompareResolveInfo> TCache;
  129. TCache C_;
  130. IDns* S_;
  131. };
  132. struct TThreadedDns: public TCachedDns {
  133. inline TThreadedDns()
  134. : TCachedDns(TGlobalCachedDns::Instance())
  135. {
  136. }
  137. };
  138. inline IDns* ThrDns() {
  139. return FastTlsSingleton<TThreadedDns>();
  140. }
  141. }
  142. namespace NDns {
  143. const TResolvedHost* CachedResolve(const TResolveInfo& ri) {
  144. TResolveTask rt(ri, TResolveTask::Normal);
  145. return ThrDns()->Resolve(rt);
  146. }
  147. const TResolvedHost* CachedThrResolve(const TResolveInfo& ri) {
  148. TResolveTask rt(ri, TResolveTask::Threaded);
  149. return ThrDns()->Resolve(rt);
  150. }
  151. void AddHostAlias(const TString& host, const TString& alias) {
  152. TGlobalCachedDns::Instance()->AddAlias(host, alias);
  153. }
  154. }