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