00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 #ifndef _P_HostDBProcessor_h_
00029 #define _P_HostDBProcessor_h_
00030 
00031 #include "I_HostDBProcessor.h"
00032 
00033 
00034 
00035 
00036 
00037 extern int hostdb_enable;
00038 extern int hostdb_migrate_on_demand;
00039 extern int hostdb_cluster;
00040 extern int hostdb_cluster_round_robin;
00041 extern int hostdb_lookup_timeout;
00042 extern int hostdb_insert_timeout;
00043 extern int hostdb_re_dns_on_reload;
00044 
00045 
00046 enum
00047   { TTL_OBEY, TTL_IGNORE, TTL_MIN, TTL_MAX };
00048 extern int hostdb_ttl_mode;
00049 
00050 extern unsigned int hostdb_current_interval;
00051 extern unsigned int hostdb_ip_stale_interval;
00052 extern unsigned int hostdb_ip_timeout_interval;
00053 extern unsigned int hostdb_ip_fail_timeout_interval;
00054 extern int hostdb_size;
00055 extern int hostdb_srv_enabled;
00056 extern char hostdb_filename[PATH_NAME_MAX + 1];
00057 
00058 
00059 extern int hostdb_sync_frequency;
00060 extern int hostdb_disable_reverse_lookup;
00061 
00062 
00063 extern HostDBCache hostDB;
00064 
00065 
00066 
00067 
00068 
00069 
00070 
00071 enum HostDBMark {
00072   HOSTDB_MARK_GENERIC, 
00073   HOSTDB_MARK_IPV4, 
00074   HOSTDB_MARK_IPV6, 
00075   HOSTDB_MARK_SRV, 
00076 };
00077 
00078 
00079 
00080 extern char const* string_for(HostDBMark mark);
00081 
00082 inline unsigned int HOSTDB_CLIENT_IP_HASH(
00083   sockaddr const* lhs,
00084   sockaddr const* rhs
00085 ) {
00086   unsigned int zret = ~static_cast<unsigned int>(0);
00087   if (ats_ip_are_compatible(lhs,rhs)) {
00088     if (ats_is_ip4(lhs)) {
00089       in_addr_t ip1 = ats_ip4_addr_cast(lhs);
00090       in_addr_t ip2 = ats_ip4_addr_cast(rhs);
00091       zret = (ip1 >> 16) ^ ip1 ^ ip2 ^ (ip2 >> 16);
00092     } else if (ats_is_ip6(lhs)) {
00093       uint32_t const* ip1 = ats_ip_addr32_cast(lhs);
00094       uint32_t const* ip2 = ats_ip_addr32_cast(rhs);
00095       for ( int i = 0 ; i < 4 ; ++i, ++ip1, ++ip2 ) {
00096         zret ^= (*ip1 >> 16) ^ *ip1 ^ *ip2 ^ (*ip2 >> 16);
00097       }
00098     }
00099   }
00100   return zret & 0xFFFF;
00101 }
00102 
00103 
00104 
00105 
00106 
00107 #define HOST_DB_HITS_BITS           3
00108 #define HOST_DB_TAG_BITS            56
00109 
00110 #define CONFIGURATION_HISTORY_PROBE_DEPTH   1
00111 
00112 
00113 #define HOST_DB_CACHE_MAJOR_VERSION         3
00114 #define HOST_DB_CACHE_MINOR_VERSION         0
00115 
00116 
00117 #define DEFAULT_HOST_DB_FILENAME             "host.db"
00118 #define DEFAULT_HOST_DB_SIZE                 (1<<14)
00119 
00120 #define HOST_DB_TIMEOUT_INTERVAL             HRTIME_SECOND
00121 
00122 #define HOST_DB_IP_TIMEOUT                   (24*60*60)
00123 
00124 #define HOST_DB_IP_STALE                     (12*60*60)
00125 
00126 #define HOST_DB_IP_FAIL_TIMEOUT              (60*60)
00127 
00128 
00129 #define HOST_DB_MAX_TTL                      (0x1FFFFF) //24 days
00130 
00131 
00132 
00133 
00134 
00135 
00136 #define HOST_DB_CLUSTER_TIMEOUT  HRTIME_MSECONDS(5000)
00137 #define HOST_DB_RETRY_PERIOD     HRTIME_MSECONDS(20)
00138 
00139 
00140 #define TEST(_x)
00141 
00142 
00143 #ifdef _HOSTDB_CC_
00144 template struct MultiCache <HostDBInfo >;
00145 #endif 
00146 
00147 struct ClusterMachine;
00148 struct HostEnt;
00149 struct ClusterConfiguration;
00150 
00151 
00152 enum HostDB_Stats
00153 {
00154   hostdb_total_entries_stat,
00155   hostdb_total_lookups_stat,
00156   hostdb_total_hits_stat,       
00157   hostdb_ttl_stat,              
00158   hostdb_ttl_expires_stat,      
00159   hostdb_re_dns_on_reload_stat,
00160   hostdb_bytes_stat,
00161   HostDB_Stat_Count
00162 };
00163 
00164 
00165 struct RecRawStatBlock;
00166 extern RecRawStatBlock *hostdb_rsb;
00167 
00168 
00169 
00170 #define HOSTDB_DEBUG_COUNT_DYN_STAT(_x, _y) \
00171 RecIncrRawStatCount(hostdb_rsb, mutex->thread_holding, (int)_x, _y)
00172 
00173 #define HOSTDB_INCREMENT_DYN_STAT(_x)  \
00174 RecIncrRawStatSum(hostdb_rsb, mutex->thread_holding, (int)_x, 1)
00175 
00176 #define HOSTDB_DECREMENT_DYN_STAT(_x) \
00177 RecIncrRawStatSum(hostdb_rsb, mutex->thread_holding, (int)_x, -1)
00178 
00179 #define HOSTDB_SUM_DYN_STAT(_x, _r) \
00180 RecIncrRawStatSum(hostdb_rsb, mutex->thread_holding, (int)_x, _r)
00181 
00182 #define HOSTDB_READ_DYN_STAT(_x, _count, _sum) do {\
00183 RecGetRawStatSum(hostdb_rsb, (int)_x, &_sum);          \
00184 RecGetRawStatCount(hostdb_rsb, (int)_x, &_count);         \
00185 } while (0)
00186 
00187 #define HOSTDB_SET_DYN_COUNT(_x, _count) \
00188 RecSetRawStatCount(hostdb_rsb, _x, _count);
00189 
00190 #define HOSTDB_INCREMENT_THREAD_DYN_STAT(_s, _t) \
00191   RecIncrRawStatSum(hostdb_rsb, _t, (int) _s, 1);
00192 
00193 #define HOSTDB_DECREMENT_THREAD_DYN_STAT(_s, _t) \
00194   RecIncrRawStatSum(hostdb_rsb, _t, (int) _s, -1);
00195 
00196 
00197 
00198 
00199 
00200 struct HostDBCache: public MultiCache<HostDBInfo>
00201 {
00202   int rebuild_callout(HostDBInfo * e, RebuildMC & r);
00203   int start(int flags = 0);
00204   MultiCacheBase *dup()
00205   {
00206     return new HostDBCache;
00207   }
00208 
00209   
00210   
00211   virtual size_t estimated_heap_bytes_per_entry() const { return sizeof(HostDBInfo) * 2 + 512 * hostdb_srv_enabled; }
00212 
00213   Queue<HostDBContinuation, Continuation::Link_link> pending_dns[MULTI_CACHE_PARTITIONS];
00214   Queue<HostDBContinuation, Continuation::Link_link> &pending_dns_for_hash(INK_MD5 & md5);
00215   HostDBCache();
00216 };
00217 
00218 inline int
00219 HostDBRoundRobin::index_of(sockaddr const* ip) {
00220   bool bad = (rrcount <= 0 || rrcount > HOST_DB_MAX_ROUND_ROBIN_INFO || good <= 0 || good > HOST_DB_MAX_ROUND_ROBIN_INFO);
00221   if (bad) {
00222     ink_assert(!"bad round robin size");
00223     return -1;
00224   }
00225 
00226   for (int i = 0; i < good; i++) {
00227     if (ats_ip_addr_eq(ip, info[i].ip())) {
00228       return i;
00229     }
00230   }
00231 
00232   return -1;
00233 }
00234 
00235 inline HostDBInfo*
00236 HostDBRoundRobin::find_ip(sockaddr const* ip) {
00237   int idx = this->index_of(ip);
00238   return idx < 0 ? NULL : &info[idx];
00239 }
00240 
00241 inline HostDBInfo*
00242 HostDBRoundRobin::select_next(sockaddr const* ip) {
00243   HostDBInfo* zret = 0;
00244   if (good > 1) {
00245     int idx = this->index_of(ip);
00246     if (idx >= 0) {
00247       idx = (idx+1)%good;
00248       zret = &info[idx];
00249     }
00250   }
00251   return zret;
00252 }
00253 
00254 inline HostDBInfo *
00255 HostDBRoundRobin::find_target(const char *target) {
00256   bool bad = (rrcount <= 0 || rrcount > HOST_DB_MAX_ROUND_ROBIN_INFO || good <= 0 || good > HOST_DB_MAX_ROUND_ROBIN_INFO);
00257   if (bad) {
00258     ink_assert(!"bad round robin size");
00259     return NULL;
00260   }
00261 
00262   uint32_t key = makeHostHash(target);
00263   for (int i = 0; i < good; i++) {
00264     if (info[i].data.srv.key == key && !strcmp(target, info[i].srvname(this)))
00265       return &info[i];
00266   }
00267   return NULL;
00268 }
00269 
00270 inline HostDBInfo *
00271 HostDBRoundRobin::select_best_http(sockaddr const* client_ip, ink_time_t now, int32_t fail_window)
00272 {
00273   bool bad = (rrcount <= 0 || rrcount > HOST_DB_MAX_ROUND_ROBIN_INFO || good <= 0 || good > HOST_DB_MAX_ROUND_ROBIN_INFO);
00274 
00275   if (bad) {
00276     ink_assert(!"bad round robin size");
00277     return NULL;
00278   }
00279 
00280   int best_any = 0;
00281   int best_up = -1;
00282 
00283   if (HostDBProcessor::hostdb_strict_round_robin) {
00284     Debug("hostdb", "Using strict round robin");
00285     best_up = current++ % good;
00286   } else if (HostDBProcessor::hostdb_timed_round_robin > 0) {
00287     Debug("hostdb", "Using timed round-robin for HTTP");
00288     if ((now - timed_rr_ctime) > HostDBProcessor::hostdb_timed_round_robin) {
00289       Debug("hostdb", "Timed interval expired.. rotating");
00290       ++current;
00291       timed_rr_ctime = now;
00292     }
00293     best_up = current % good;
00294     Debug("hostdb", "Using %d for best_up", best_up);
00295   } else {
00296     Debug("hostdb", "Using default round robin");
00297     unsigned int best_hash_any = 0;
00298     unsigned int best_hash_up = 0;
00299     sockaddr const* ip;
00300     for (int i = 0; i < good; i++) {
00301       ip = info[i].ip();
00302       unsigned int h = HOSTDB_CLIENT_IP_HASH(client_ip, ip);
00303       if (best_hash_any <= h) {
00304         best_any = i;
00305         best_hash_any = h;
00306       }
00307       if (info[i].app.http_data.last_failure == 0 ||
00308           (unsigned int) (now - fail_window) > info[i].app.http_data.last_failure) {
00309         
00310         if (best_hash_up <= h) {
00311           best_up = i;
00312           best_hash_up = h;
00313         }
00314       } else {
00315         
00316         
00317         
00318         
00319         
00320         if (now + fail_window < (int32_t) (info[i].app.http_data.last_failure)) {
00321 #ifdef DEBUG
00322           
00323           
00324           
00325           
00326           HostDBInfo current_info;
00327           HostDBRoundRobin current_rr;
00328           memcpy(¤t_info, &info[i], sizeof(HostDBInfo));
00329           memcpy(¤t_rr, this, sizeof(HostDBRoundRobin));
00330 #endif
00331           ink_assert(!"extreme clock skew");
00332           info[i].app.http_data.last_failure = 0;
00333         }
00334       }
00335     }
00336   }
00337 
00338   if (best_up != -1) {
00339     ink_assert(best_up >= 0 && best_up < good);
00340     return &info[best_up];
00341   } else {
00342     ink_assert(best_any >= 0 && best_any < good);
00343     return &info[best_any];
00344   }
00345 }
00346 
00347 inline HostDBInfo *
00348 HostDBRoundRobin::select_best_srv(char *target, InkRand *rand, ink_time_t now, int32_t fail_window)
00349 {
00350   bool bad = (rrcount <= 0 || rrcount > HOST_DB_MAX_ROUND_ROBIN_INFO || good <= 0 || good > HOST_DB_MAX_ROUND_ROBIN_INFO);
00351 
00352   if (bad) {
00353     ink_assert(!"bad round robin size");
00354     return NULL;
00355   }
00356 
00357 #ifdef DEBUG
00358   for (int i = 1; i < good; ++i) {
00359     ink_assert(info[i].data.srv.srv_priority >= info[i-1].data.srv.srv_priority);
00360   }
00361 #endif
00362 
00363   int i = 0, len = 0;
00364   uint32_t weight = 0, p = INT32_MAX;
00365   HostDBInfo *result = NULL;
00366   HostDBInfo *infos[HOST_DB_MAX_ROUND_ROBIN_INFO];
00367 
00368   do {
00369     if (info[i].app.http_data.last_failure != 0 &&
00370         (uint32_t) (now - fail_window) < info[i].app.http_data.last_failure) {
00371       continue;
00372     }
00373 
00374     if (info[i].app.http_data.last_failure)
00375       info[i].app.http_data.last_failure = 0;
00376 
00377     if (info[i].data.srv.srv_priority <= p) {
00378       p = info[i].data.srv.srv_priority;
00379       weight += info[i].data.srv.srv_weight;
00380       infos[len++] = &info[i];
00381     } else
00382       break;
00383   } while (++i < good);
00384 
00385   if (len == 0) { 
00386     result = &info[current++ % good];
00387   } else if (weight == 0) { 
00388     result = &info[current++ % len];
00389   } else {
00390     uint32_t xx = rand->random() % weight;
00391     for (i = 0; i < len && xx >= infos[i]->data.srv.srv_weight; ++i)
00392       xx -= infos[i]->data.srv.srv_weight;
00393 
00394     result = infos[i];
00395   }
00396 
00397   if (result) {
00398     strcpy(target, result->srvname(this));
00399     return result;
00400   }
00401   return NULL;
00402 }
00403 
00404 
00405 
00406 
00407 
00408 
00409 
00410 
00411 struct HostDBMD5 {
00412   typedef HostDBMD5 self; 
00413 
00414   INK_MD5 hash; 
00415 
00416   char const* host_name; 
00417   int host_len; 
00418   IpAddr ip; 
00419   int port; 
00420 
00421 
00422 
00423   DNSServer* dns_server;
00424   HostDBMark db_mark; 
00425 
00426 
00427   HostDBMD5();
00428 
00429   void refresh();
00430 };
00431 
00432 
00433 
00434 
00435 struct HostDBContinuation;
00436 typedef int (HostDBContinuation::*HostDBContHandler) (int, void *);
00437 
00438 struct HostDBContinuation: public Continuation
00439 {
00440   Action action;
00441   HostDBMD5 md5;
00442   
00443   unsigned int ttl;
00444   
00445 
00446 
00447 
00448   HostResStyle host_res_style; 
00449   int dns_lookup_timeout;
00450   
00451   Event *timeout;
00452   ClusterMachine *from;
00453   Continuation *from_cont;
00454   HostDBApplicationInfo app;
00455   int probe_depth;
00456   ClusterMachine *past_probes[CONFIGURATION_HISTORY_PROBE_DEPTH];
00457   
00458   
00459   char md5_host_name_store[MAXDNAME+1]; 
00460   char srv_target_name[MAXDNAME];
00461   void *m_pDS;
00462   Action *pending_action;
00463 
00464   unsigned int missing:1;
00465   unsigned int force_dns:1;
00466   unsigned int round_robin:1;
00467 
00468   int probeEvent(int event, Event * e);
00469   int clusterEvent(int event, Event * e);
00470   int clusterResponseEvent(int event, Event * e);
00471   int dnsEvent(int event, HostEnt * e);
00472   int dnsPendingEvent(int event, Event * e);
00473   int backgroundEvent(int event, Event * e);
00474   int retryEvent(int event, Event * e);
00475   int removeEvent(int event, Event * e);
00476   int setbyEvent(int event, Event * e);
00477 
00478 
00479   void refresh_MD5();
00480   void do_dns();
00481   bool is_byname()
00482   {
00483     return md5.db_mark == HOSTDB_MARK_IPV4 || md5.db_mark == HOSTDB_MARK_IPV6;
00484   }
00485   bool is_srv()
00486   {
00487     return md5.db_mark == HOSTDB_MARK_SRV;
00488   }
00489   HostDBInfo *lookup_done(IpAddr const& ip, char const* aname, bool round_robin, unsigned int attl, SRVHosts * s = NULL);
00490   bool do_get_response(Event * e);
00491   void do_put_response(ClusterMachine * m, HostDBInfo * r, Continuation * cont);
00492   int failed_cluster_request(Event * e);
00493   int key_partition();
00494   void remove_trigger_pending_dns();
00495   int set_check_pending_dns();
00496 
00497   ClusterMachine *master_machine(ClusterConfiguration * cc);
00498 
00499   HostDBInfo *insert(unsigned int attl);
00500 
00501 
00502 
00503   struct Options {
00504     typedef Options self; 
00505 
00506     int timeout; 
00507     HostResStyle host_res_style; 
00508     bool force_dns; 
00509     Continuation* cont; 
00510 
00511     Options()
00512       : timeout(0), host_res_style(HOST_RES_NONE), force_dns(false), cont(0)
00513     { }
00514   };
00515   static const Options DEFAULT_OPTIONS; 
00516   void init(HostDBMD5 const& md5,
00517             Options const& opt = DEFAULT_OPTIONS);
00518   int make_get_message(char *buf, int len);
00519   int make_put_message(HostDBInfo * r, Continuation * c, char *buf, int len);
00520 
00521 HostDBContinuation():
00522   Continuation(NULL), ttl(0),
00523     host_res_style(DEFAULT_OPTIONS.host_res_style),
00524     dns_lookup_timeout(DEFAULT_OPTIONS.timeout),
00525     timeout(0), from(0),
00526     from_cont(0), probe_depth(0), missing(false),
00527     force_dns(DEFAULT_OPTIONS.force_dns), round_robin(false) {
00528     ink_zero(md5_host_name_store);
00529     ink_zero(md5.hash);
00530     SET_HANDLER((HostDBContHandler) & HostDBContinuation::probeEvent);
00531   }
00532 };
00533 
00534 
00535 
00536 inline unsigned int
00537 master_hash(INK_MD5 const& md5)
00538 {
00539   return static_cast<int>(md5[1] >> 32);
00540 }
00541 
00542 inline bool
00543 is_dotted_form_hostname(const char *c)
00544 {
00545   return -1 != (int) ink_inet_addr(c);
00546 }
00547 
00548 inline Queue<HostDBContinuation> &
00549 HostDBCache::pending_dns_for_hash(INK_MD5 & md5)
00550 {
00551   return pending_dns[partition_of_bucket((int) (fold_md5(md5) % hostDB.buckets))];
00552 }
00553 
00554 inline int
00555 HostDBContinuation::key_partition()
00556 {
00557   return hostDB.partition_of_bucket(fold_md5(md5.hash) % hostDB.buckets);
00558 }
00559 
00560 #endif