• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

I_HostDBProcessor.h

Go to the documentation of this file.
00001 /** @file
00002 
00003   A brief file description
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 #ifndef _I_HostDBProcessor_h_
00025 #define _I_HostDBProcessor_h_
00026 
00027 #include "I_EventSystem.h"
00028 #include "SRV.h"
00029 
00030 // Event returned on a lookup
00031 #define EVENT_HOST_DB_LOOKUP                 (HOSTDB_EVENT_EVENTS_START+0)
00032 #define EVENT_HOST_DB_IP_REMOVED             (HOSTDB_EVENT_EVENTS_START+1)
00033 #define EVENT_HOST_DB_GET_RESPONSE           (HOSTDB_EVENT_EVENTS_START+2)
00034 
00035 #define EVENT_SRV_LOOKUP                 (SRV_EVENT_EVENTS_START+0)
00036 #define EVENT_SRV_IP_REMOVED             (SRV_EVENT_EVENTS_START+1)
00037 #define EVENT_SRV_GET_RESPONSE           (SRV_EVENT_EVENTS_START+2)
00038 
00039 #define HOST_DB_MAX_ROUND_ROBIN_INFO         16
00040 
00041 #define HOST_DB_SRV_PREFIX "_http._tcp."
00042 //
00043 // Data
00044 //
00045 struct HostDBContinuation;
00046 
00047 //
00048 // The host database stores host information, most notably the
00049 // IP address.
00050 //
00051 // Since host information is relatively small, we can afford to have
00052 // a reasonable size memory cache, and use a (relatively) sparce
00053 // disk representation to decrease # of seeks.
00054 //
00055 extern int hostdb_enable;
00056 extern unsigned int hostdb_current_interval;
00057 extern unsigned int hostdb_ip_stale_interval;
00058 extern unsigned int hostdb_ip_timeout_interval;
00059 extern unsigned int hostdb_ip_fail_timeout_interval;
00060 extern unsigned int hostdb_serve_stale_but_revalidate;
00061 
00062 
00063 static inline unsigned int
00064 makeHostHash(const char *string)
00065 {
00066   ink_assert(string && *string);
00067   if (!string || *string == 0)
00068     return 0;
00069 
00070   const uint32_t InitialFNV = 2166136261U;
00071   const int32_t FNVMultiple = 16777619;
00072 
00073   uint64_t hash = InitialFNV;
00074   uint32_t *p = (uint32_t *) &hash;
00075   while(*string)  {
00076     p[0] = p[0] ^ (toupper(*string));
00077     hash = (p[1] ^ p[0]) * FNVMultiple;
00078     ++string;
00079   }
00080   return (p[1] ^ p[0]);
00081 }
00082 
00083 //
00084 // Types
00085 //
00086 
00087 //
00088 // This structure contains the host information required by
00089 // the application.  Except for the initial fields it
00090 // is treated as opacque by the database.
00091 //
00092 
00093 union HostDBApplicationInfo
00094 {
00095   struct application_data_allotment
00096   {
00097     unsigned int application1;
00098     unsigned int application2;
00099   } allotment;
00100 
00101   //////////////////////////////////////////////////////////
00102   // http server attributes in the host database          //
00103   //                                                      //
00104   // http_version       - one of HttpVersion_t            //
00105   // pipeline_max       - max pipeline.     (up to 127).  //
00106   //                      0 - no keep alive               //
00107   //                      1 - no pipeline, only keepalive //
00108   // keep_alive_timeout - in seconds. (up to 63 seconds). //
00109   // last_failure       - UNIX time for the last time     //
00110   //                      we tried the server & failed    //
00111   // fail_count         - Number of times we tried and    //
00112   //                       and failed to contact the host //
00113   //////////////////////////////////////////////////////////
00114   struct http_server_attr
00115   {
00116     unsigned int http_version:3;
00117     unsigned int pipeline_max:7;
00118     unsigned int keepalive_timeout:6;
00119     unsigned int fail_count:8;
00120     unsigned int unused1:8;
00121     unsigned int last_failure:32;
00122   } http_data;
00123 
00124   enum HttpVersion_t
00125   {
00126     HTTP_VERSION_UNDEFINED = 0,
00127     HTTP_VERSION_09 = 1,
00128     HTTP_VERSION_10 = 2,
00129     HTTP_VERSION_11 = 3
00130   };
00131 
00132   struct application_data_rr
00133   {
00134     int offset;
00135   } rr;
00136 };
00137 
00138 struct HostDBRoundRobin;
00139 
00140 struct SRVInfo
00141 {
00142   unsigned int srv_offset:16;
00143   unsigned int srv_weight:16;
00144   unsigned int srv_priority:16;
00145   unsigned int srv_port:16;
00146   unsigned int key;
00147 };
00148 
00149 struct HostDBInfo
00150 {
00151   /** Internal IP address data.
00152       This is at least large enough to hold an IPv6 address.
00153   */
00154   sockaddr* ip()  { return &data.ip.sa; }
00155   sockaddr const* ip() const { return &data.ip.sa; }
00156 
00157   char *hostname();
00158   char *srvname(HostDBRoundRobin *rr);
00159   HostDBRoundRobin *rr();
00160 
00161   /** Indicate that the HostDBInfo is BAD and should be deleted. */
00162   void bad() { full = 0; }
00163 
00164   /**
00165     Application specific data. NOTE: We need an integral number of these
00166     per block. This structure is 32 bytes. (at 200k hosts = 8 Meg). Which
00167     gives us 7 bytes of application information.
00168 
00169   */
00170   HostDBApplicationInfo app;
00171 
00172   unsigned int ip_interval()
00173   {
00174     return (hostdb_current_interval - ip_timestamp) & 0x7FFFFFFF;
00175   }
00176 
00177   int ip_time_remaining()
00178   {
00179     return (int) ip_timeout_interval - (int) ((hostdb_current_interval - ip_timestamp) & 0x7FFFFFFF);
00180   }
00181 
00182   bool is_ip_stale() {
00183     if (ip_timeout_interval >= 2 * hostdb_ip_stale_interval)
00184       return ip_interval() >= hostdb_ip_stale_interval;
00185     else
00186       return false;
00187   }
00188 
00189   bool is_ip_timeout() {
00190     return ip_interval() >= ip_timeout_interval;
00191   }
00192 
00193   bool is_ip_fail_timeout() {
00194     return ip_interval() >= hostdb_ip_fail_timeout_interval;
00195   }
00196 
00197   void refresh_ip()
00198   {
00199     ip_timestamp = hostdb_current_interval;
00200   }
00201 
00202   bool serve_stale_but_revalidate() {
00203     // the option is disabled
00204     if (hostdb_serve_stale_but_revalidate <= 0)
00205       return false;
00206 
00207     // ip_timeout_interval == DNS TTL
00208     // hostdb_serve_stale_but_revalidate == number of seconds
00209     // ip_interval() is the number of seconds between now() and when the entry was inserted
00210     if ((ip_timeout_interval + hostdb_serve_stale_but_revalidate) > ip_interval()) {
00211       Debug("hostdb", "serving stale entry %d | %d | %d as requested by config",
00212             ip_timeout_interval, hostdb_serve_stale_but_revalidate, ip_interval());
00213       return true;
00214     }
00215     // otherwise, the entry is too old
00216     return false;
00217   }
00218 
00219 
00220   //
00221   // Private
00222   //
00223 
00224   union {
00225     IpEndpoint ip; ///< IP address / port data.
00226     int hostname_offset; ///< Some hostname thing.
00227     SRVInfo srv;
00228   } data;
00229 
00230   unsigned int ip_timestamp;
00231   // limited to 0x1FFFFF (24 days)
00232   unsigned int ip_timeout_interval:31;
00233 
00234   unsigned int full:1;
00235   unsigned int backed:1;        // duplicated in lower level
00236   unsigned int deleted:1;
00237   unsigned int hits:3;
00238 
00239   unsigned int is_srv:1; // steal a bit from ip_timeout_interval
00240   unsigned int round_robin:1;
00241   unsigned int reverse_dns:1;
00242 
00243   unsigned int md5_low_low:24;
00244   unsigned int md5_low;
00245 
00246   uint64_t md5_high;
00247 
00248   bool failed() {
00249     return !((is_srv && data.srv.srv_offset) || (reverse_dns && data.hostname_offset) || ats_is_ip(ip()));
00250   }
00251   void set_failed() {
00252     if (is_srv)
00253       data.srv.srv_offset = 0;
00254     else if (reverse_dns)
00255       data.hostname_offset = 0;
00256     else
00257       ats_ip_invalidate(ip());
00258   }
00259 
00260   void set_deleted() { deleted = 1; }
00261   bool is_deleted() const { return deleted; }
00262 
00263   bool is_empty() const { return !full; }
00264 
00265   void set_empty()
00266   {
00267     full = 0;
00268     md5_high = 0;
00269     md5_low = 0;
00270     md5_low_low = 0;
00271   }
00272 
00273   void set_full(uint64_t folded_md5, int buckets)
00274   {
00275     uint64_t ttag = folded_md5 / buckets;
00276 
00277     if (!ttag)
00278       ttag = 1;
00279     md5_low_low = (unsigned int) ttag;
00280     md5_low = (unsigned int) (ttag >> 24);
00281     full = 1;
00282   }
00283 
00284   void reset()
00285   {
00286     ats_ip_invalidate(ip());
00287     app.allotment.application1 = 0;
00288     app.allotment.application2 = 0;
00289     backed = 0;
00290     deleted = 0;
00291     hits = 0;
00292     round_robin = 0;
00293     reverse_dns = 0;
00294     is_srv = 0;
00295   }
00296 
00297   uint64_t tag() {
00298     uint64_t f = md5_low;
00299     return (f << 24) + md5_low_low;
00300   }
00301 
00302   bool match(INK_MD5 &, int, int);
00303   int heap_size();
00304   int *heap_offset_ptr();
00305 };
00306 
00307 
00308 struct HostDBRoundRobin
00309 {
00310   /** Total number (to compute space used). */
00311   short rrcount;
00312 
00313   /** Number which have not failed a connect. */
00314   short good;
00315 
00316   unsigned short current;
00317   unsigned short length;
00318   ink_time_t timed_rr_ctime;
00319 
00320   HostDBInfo info[];
00321 
00322   // Return the allocation size of a HostDBRoundRobin struct suitable for storing
00323   // "count" HostDBInfo records.
00324   static unsigned size(unsigned count, unsigned srv_len = 0)
00325   {
00326     ink_assert(count > 0);
00327     return INK_ALIGN((sizeof(HostDBRoundRobin) + (count * sizeof(HostDBInfo)) + srv_len), 8);
00328   }
00329 
00330   /** Find the index of @a addr in member @a info.
00331       @return The index if found, -1 if not found.
00332   */
00333   int index_of(sockaddr const* addr);
00334   HostDBInfo *find_ip(sockaddr const* addr);
00335   // Find the srv target
00336   HostDBInfo *find_target(const char *target);
00337   /** Select the next entry after @a addr.
00338       @note If @a addr isn't an address in the round robin nothing is updated.
00339       @return The selected entry or @c NULL if @a addr wasn't present.
00340    */
00341   HostDBInfo* select_next(sockaddr const* addr);
00342   HostDBInfo *select_best_http(sockaddr const* client_ip, ink_time_t now, int32_t fail_window);
00343   HostDBInfo *select_best_srv(char *target, InkRand *rand, ink_time_t now, int32_t fail_window);
00344   HostDBRoundRobin()
00345     : rrcount(0), good(0), current(0), length(0), timed_rr_ctime(0)
00346   { }
00347 
00348 };
00349 
00350 struct HostDBCache;
00351 
00352 // Prototype for inline completion functionf or
00353 //  getbyname_imm()
00354 typedef void (Continuation::*process_hostdb_info_pfn) (HostDBInfo * r);
00355 typedef void (Continuation::*process_srv_info_pfn) (HostDBInfo * r);
00356 
00357 
00358 /** The Host Databse access interface. */
00359 struct HostDBProcessor: public Processor
00360 {
00361   friend struct HostDBSyncer;
00362   // Public Interface
00363 
00364   // Lookup Hostinfo by name
00365   //    cont->handleEvent( EVENT_HOST_DB_LOOKUP, HostDBInfo * ); on success
00366   //    cont->handleEVent( EVENT_HOST_DB_LOOKUP, 0); on failure
00367   // Failure occurs when the host cannot be DNS-ed
00368   // NOTE: Will call the continuation back before returning if data is in the
00369   //       cache.  The HostDBInfo * becomes invalid when the callback returns.
00370   //       The HostDBInfo may be changed during the callback.
00371 
00372   enum
00373   { HOSTDB_DO_NOT_FORCE_DNS = 0,
00374     HOSTDB_ROUND_ROBIN = 0,
00375     HOSTDB_FORCE_DNS_RELOAD = 1,
00376     HOSTDB_FORCE_DNS_ALWAYS = 2,
00377     HOSTDB_DO_NOT_ROUND_ROBIN = 4
00378   };
00379 
00380   /// Optional parameters for getby...
00381   struct Options {
00382     typedef Options self; ///< Self reference type.
00383     int port; ///< Target service port (default 0 -> don't care)
00384     int flags; ///< Processing flags (default HOSTDB_DO_NOT_FORCE_DNS)
00385     int timeout; ///< Timeout value (default 0 -> default timeout)
00386     HostResStyle host_res_style; ///< How to query host (default HOST_RES_IPV4)
00387 
00388     Options() : port(0), flags(HOSTDB_DO_NOT_FORCE_DNS), timeout(0), host_res_style(HOST_RES_IPV4)
00389     { }
00390 
00391     /// Set the flags.
00392     self& setFlags(int f) { flags = f; return *this; }
00393   };
00394 
00395   /// Default options.
00396   static Options const DEFAULT_OPTIONS;
00397 
00398   HostDBProcessor()
00399   { }
00400 
00401   inkcoreapi Action *getbyname_re(Continuation * cont, const char *hostname, int len, Options const& opt = DEFAULT_OPTIONS);
00402 
00403   Action *getSRVbyname_imm(Continuation * cont, process_srv_info_pfn process_srv_info, const char *hostname, int len, Options const& opt = DEFAULT_OPTIONS);
00404 
00405   Action *getbyname_imm(
00406     Continuation * cont,
00407     process_hostdb_info_pfn process_hostdb_info,
00408     const char *hostname,
00409     int len,
00410     Options const& opt = DEFAULT_OPTIONS
00411   );
00412 
00413 
00414   /** Lookup Hostinfo by addr */
00415   Action *getbyaddr_re(Continuation * cont, sockaddr const* aip)
00416   {
00417     return getby(cont, NULL, 0, aip, false, HOST_RES_NONE, 0);
00418   }
00419 
00420 #if 0
00421   /**
00422     If you were unable to connect to an IP address associated with a
00423     particular hostname, call this function and that IP address will
00424     be marked "bad" and if the host is using round-robin DNS, next time
00425     you will get a different IP address.
00426 
00427   */
00428   Action *failed_connect_on_ip_for_name(
00429     Continuation * cont,
00430     sockaddr const* aip,
00431     const char *hostname, int len = 0
00432   );
00433 #endif
00434 
00435   /** Set the application information (fire-and-forget). */
00436   void setbyname_appinfo(char *hostname, int len, int port, HostDBApplicationInfo * app)
00437   {
00438     sockaddr_in addr;
00439     ats_ip4_set(&addr, INADDR_ANY, port);
00440     setby(hostname, len, ats_ip_sa_cast(&addr), app);
00441   }
00442 
00443   void setbyaddr_appinfo(sockaddr const* addr, HostDBApplicationInfo * app) {
00444     this->setby(0, 0, addr, app);
00445   }
00446 
00447   void setbyaddr_appinfo(in_addr_t ip, HostDBApplicationInfo * app)
00448   {
00449     sockaddr_in addr;
00450     ats_ip4_set(&addr, ip);
00451     this->setby(0, 0, ats_ip_sa_cast(&addr), app);
00452   }
00453 
00454   /** Configuration. */
00455   static int hostdb_strict_round_robin;
00456   static int hostdb_timed_round_robin;
00457 
00458   // Processor Interface
00459   /* hostdb does not use any dedicated event threads
00460    * currently. Dont pass any value to start
00461    */
00462   int start(int no_of_additional_event_threads = 0, size_t stacksize = DEFAULT_STACKSIZE);
00463 
00464   // Private
00465   HostDBCache *cache();
00466 private:
00467   Action *getby(
00468     Continuation * cont,
00469     const char *hostname, int len,
00470     sockaddr const* ip,
00471     bool aforce_dns, HostResStyle host_res_style, int timeout
00472   );
00473 public:
00474   /** Set something.
00475       @a aip can carry address and / or port information. If setting just
00476       by a port value, the address should be set to INADDR_ANY which is of
00477       type IPv4.
00478    */
00479   void setby(
00480     const char *hostname, ///< Hostname.
00481     int len, ///< Length of hostname.
00482     sockaddr const* aip, ///< Address and/or port.
00483     HostDBApplicationInfo * app ///< I don't know.
00484   );
00485 
00486   void setby_srv(const char *hostname, int len, const char *target,
00487       HostDBApplicationInfo * app);
00488 
00489 };
00490 
00491 void run_HostDBTest();
00492 
00493 extern inkcoreapi HostDBProcessor hostDBProcessor;
00494 
00495 void ink_hostdb_init(ModuleVersion version);
00496 
00497 #endif

Generated by  doxygen 1.7.1