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

HttpCacheSM.cc

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 /****************************************************************************
00025 
00026    HttpCacheSM.cc
00027 
00028    Description:
00029 
00030 
00031  ****************************************************************************/
00032 
00033 #include "HttpCacheSM.h"
00034 #include "HttpSM.h"
00035 #include "HttpDebugNames.h"
00036 
00037 #define STATE_ENTER(state_name, event) { \
00038         REMEMBER(event, -1); \
00039         Debug("http_cache", "[%" PRId64 "] [%s, %s]", master_sm->sm_id, \
00040         #state_name, HttpDebugNames::get_event_name(event)); }
00041 
00042 #define __REMEMBER(x)  #x
00043 #define _REMEMBER(x)   __REMEMBER(x)
00044 
00045 #define REMEMBER(e,r) master_sm->add_history_entry(__FILE__ ":" _REMEMBER (__LINE__), e, r);
00046 
00047 
00048 HttpCacheAction::HttpCacheAction()
00049   : sm(NULL)
00050 {
00051 }
00052 
00053 void
00054 HttpCacheAction::cancel(Continuation * c)
00055 {
00056   ink_assert(c == NULL || c == sm->master_sm);
00057   ink_assert(this->cancelled == 0);
00058 
00059   this->cancelled = 1;
00060   if (sm->pending_action)
00061     sm->pending_action->cancel();
00062 }
00063 
00064 HttpCacheSM::HttpCacheSM():
00065   Continuation(NULL),
00066   cache_read_vc(NULL), cache_write_vc(NULL),
00067   read_locked(false), write_locked(false),
00068   readwhilewrite_inprogress(false),
00069   master_sm(NULL), pending_action(NULL),
00070   captive_action(),
00071   open_read_cb(false), open_write_cb(false), open_read_tries(0),
00072   read_request_hdr(NULL), read_config(NULL),
00073   read_pin_in_cache(0), retry_write(true), open_write_tries(0),
00074   lookup_url(NULL), lookup_max_recursive(0), current_lookup_level(0)
00075 {
00076 }
00077 
00078 //////////////////////////////////////////////////////////////////////////
00079 //
00080 //  HttpCacheSM::state_cache_open_read()
00081 //
00082 //  State the cache calls back the state machine into on a open_read
00083 //  call. The set of allowed events (from the cache) are:
00084 // - CACHE_EVENT_OPEN_READ
00085 //   - document matching request is in the cache
00086 // - CACHE_EVENT_OPEN_READ_FAILED
00087 //   if (data != ECACHEDOCBUSY)
00088 //   - document matching request is not in the cache
00089 //   if (data == ECACHEDOCBUSY)
00090 //   - document with same URL as request is in the cache
00091 //     but is being currently updated by another state
00092 //     machine. Keep in mind that the document may NOT
00093 //     match any of the request headers - it just matches
00094 //     the URL. In other words, the document that is being
00095 //     written to by another state machine may be an
00096 //     alternate of the document the request wants.
00097 // - EVENT_INTERVAL
00098 //   - a previous open_read returned "failed_in_progress". we
00099 //     decided to retry the open read. we scheduled the event
00100 //     processor to call us back after n msecs so that we can
00101 //     reissue the open_read. this is the call from the event
00102 //     processor.
00103 //
00104 //////////////////////////////////////////////////////////////////////////
00105 int
00106 HttpCacheSM::state_cache_open_read(int event, void *data)
00107 {
00108   STATE_ENTER(&HttpCacheSM::state_cache_open_read, event);
00109   ink_assert(captive_action.cancelled == 0);
00110   pending_action = NULL;
00111 
00112   switch (event) {
00113   case CACHE_EVENT_OPEN_READ:
00114     HTTP_INCREMENT_DYN_STAT(http_current_cache_connections_stat);
00115     ink_assert(cache_read_vc == NULL);
00116     open_read_cb = true;
00117     cache_read_vc = (CacheVConnection *) data;
00118     master_sm->handleEvent(event, data);
00119     break;
00120 
00121   case CACHE_EVENT_OPEN_READ_FAILED:
00122     if (data == (void *) -ECACHE_DOC_BUSY) {
00123       // Somebody else is writing the object
00124       if (open_read_tries <= master_sm->t_state.txn_conf->max_cache_open_read_retries) {
00125         // Retry to read; maybe the update finishes in time
00126         open_read_cb = false;
00127         do_schedule_in();
00128       } else {
00129         // Give up; the update didn't finish in time
00130         // HttpSM will inform HttpTransact to 'proxy-only'
00131         open_read_cb = true;
00132         master_sm->handleEvent(event, data);
00133       }
00134     } else {
00135       // Simple miss in the cache.
00136       open_read_cb = true;
00137       master_sm->handleEvent(event, data);
00138     }
00139     break;
00140 
00141   case EVENT_INTERVAL:
00142     // Retry the cache open read if the number retries is less
00143     // than or equal to the max number of open read retries,
00144     // else treat as a cache miss.
00145     ink_assert(open_read_tries <= master_sm->t_state.txn_conf->max_cache_open_read_retries || write_locked);
00146     Debug("http_cache", "[%" PRId64 "] [state_cache_open_read] cache open read failure %d. "
00147           "retrying cache open read...", master_sm->sm_id, open_read_tries);
00148 
00149     do_cache_open_read();
00150     break;
00151 
00152   default:
00153     ink_assert(0);
00154   }
00155 
00156   return VC_EVENT_CONT;
00157 }
00158 
00159 int
00160 HttpCacheSM::state_cache_open_write(int event, void *data)
00161 {
00162   STATE_ENTER(&HttpCacheSM::state_cache_open_write, event);
00163   ink_assert(captive_action.cancelled == 0);
00164   pending_action = NULL;
00165 
00166   switch (event) {
00167   case CACHE_EVENT_OPEN_WRITE:
00168     HTTP_INCREMENT_DYN_STAT(http_current_cache_connections_stat);
00169     ink_assert(cache_write_vc == NULL);
00170     cache_write_vc = (CacheVConnection *) data;
00171     open_write_cb = true;
00172     master_sm->handleEvent(event, data);
00173     break;
00174 
00175   case CACHE_EVENT_OPEN_WRITE_FAILED:
00176     // The cache is hosed or full or something.
00177     // Forward the failure to the main sm
00178     open_write_cb = true;
00179     master_sm->handleEvent(event, data);
00180     break;
00181 
00182   default:
00183     ink_release_assert(0);
00184   }
00185 
00186   return VC_EVENT_CONT;
00187 }
00188 
00189 void
00190 HttpCacheSM::do_schedule_in()
00191 {
00192   ink_assert(pending_action == NULL);
00193   Action *action_handle =
00194     mutex->thread_holding->schedule_in(this, HRTIME_MSECONDS(master_sm->t_state.txn_conf->cache_open_read_retry_time));
00195 
00196   if (action_handle != ACTION_RESULT_DONE) {
00197     pending_action = action_handle;
00198   }
00199 
00200   return;
00201 }
00202 
00203 Action *
00204 HttpCacheSM::do_cache_open_read()
00205 {
00206   open_read_tries++;
00207   ink_assert(pending_action == NULL);
00208   if (write_locked) {
00209     open_read_cb = false;
00210   } else {
00211     ink_assert(open_read_cb == false);
00212   }
00213   //Initialising read-while-write-inprogress flag
00214   this->readwhilewrite_inprogress = false;
00215   Action *action_handle = cacheProcessor.open_read(this, this->lookup_url, master_sm->t_state.cache_control.cluster_cache_local, this->read_request_hdr, this->read_config,
00216                                                    this->read_pin_in_cache);
00217 
00218   if (action_handle != ACTION_RESULT_DONE) {
00219     pending_action = action_handle;
00220   }
00221   // Check to see if we've already called the user back
00222   //  If we have then it's ACTION_RESULT_DONE, other wise
00223   //  return our captive action and ensure that we are actually
00224   //  doing something useful
00225   if (open_read_cb == true) {
00226     return ACTION_RESULT_DONE;
00227   } else {
00228     ink_assert(pending_action != NULL || write_locked == true);
00229     return &captive_action;
00230   }
00231 }
00232 
00233 Action *
00234 HttpCacheSM::open_read(URL * url, HTTPHdr * hdr, CacheLookupHttpConfig * params, time_t pin_in_cache)
00235 {
00236   Action *act_return;
00237 
00238   lookup_url = url;
00239   read_request_hdr = hdr;
00240   read_config = params;
00241   read_pin_in_cache = pin_in_cache;
00242   ink_assert(pending_action == NULL);
00243   SET_HANDLER(&HttpCacheSM::state_cache_open_read);
00244 
00245   lookup_max_recursive++;
00246   current_lookup_level++;
00247   open_read_cb = false;
00248   act_return = do_cache_open_read();
00249   // the following logic is based on the assumption that the secnod
00250   // lookup won't happen if the HttpSM hasn't been called back for the
00251   // first lookup
00252   if (current_lookup_level == lookup_max_recursive) {
00253     current_lookup_level--;
00254     ink_assert(current_lookup_level >= 0);
00255     if (current_lookup_level == 0) {
00256       lookup_max_recursive = 0;
00257     }
00258     return act_return;
00259   } else {
00260     ink_assert(current_lookup_level < lookup_max_recursive);
00261     current_lookup_level--;
00262 
00263     if (current_lookup_level == 0)
00264       lookup_max_recursive = 0;
00265 
00266     return ACTION_RESULT_DONE;
00267   }
00268 }
00269 
00270 Action *
00271 HttpCacheSM::open_write(URL * url, HTTPHdr * request, CacheHTTPInfo * old_info, time_t pin_in_cache,
00272                         bool retry, bool allow_multiple)
00273 {
00274   SET_HANDLER(&HttpCacheSM::state_cache_open_write);
00275   ink_assert(pending_action == NULL);
00276   ink_assert(cache_write_vc == NULL);
00277   // INKqa12119
00278   open_write_cb = false;
00279   open_write_tries++;
00280   this->retry_write = retry;
00281 
00282   // We should be writing the same document we did
00283   //  a lookup on
00284   // this is no longer true for multiple cache lookup
00285   //ink_assert(url == lookup_url || lookup_url == NULL);
00286   ink_assert(request == read_request_hdr || read_request_hdr == NULL);
00287   this->lookup_url = url;
00288   this->read_request_hdr = request;
00289 
00290   // Make sure we are not stuck in a loop where the write
00291   //  fails but the retry read succeeds causing to issue
00292   //  a new write (could happen on a very busy document
00293   //  that must be revalidated every time)
00294   // Changed by YTS Team, yamsat Plugin
00295   if (open_write_tries > master_sm->redirection_tries &&
00296       open_write_tries > master_sm->t_state.http_config_param->max_cache_open_write_retries) {
00297     master_sm->handleEvent(CACHE_EVENT_OPEN_WRITE_FAILED, (void *) -ECACHE_DOC_BUSY);
00298     return ACTION_RESULT_DONE;
00299   }
00300 
00301   Action *action_handle = cacheProcessor.open_write(this,
00302                                                     0,
00303                                                     url,
00304                                                     master_sm->t_state.cache_control.cluster_cache_local,
00305                                                     request,
00306                                                     // INKqa11166
00307                                                     allow_multiple ? (CacheHTTPInfo *) CACHE_ALLOW_MULTIPLE_WRITES :
00308                                                     old_info,
00309                                                     pin_in_cache);
00310 
00311   if (action_handle != ACTION_RESULT_DONE) {
00312     pending_action = action_handle;
00313   }
00314   // Check to see if we've already called the user back
00315   //  If we have then it's ACTION_RESULT_DONE, other wise
00316   //  return our captive action and ensure that we are actually
00317   //  doing something useful
00318   if (open_write_cb == true) {
00319     return ACTION_RESULT_DONE;
00320   } else {
00321     ink_assert(pending_action != NULL);
00322     return &captive_action;
00323   }
00324 }

Generated by  doxygen 1.7.1