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

CacheHosting.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 #include "P_Cache.h"
00025 #include "I_Layout.h"
00026 
00027 extern int gndisks;
00028 
00029 matcher_tags CacheHosting_tags = {
00030   "hostname", "domain"
00031 };
00032 
00033 /*************************************************************
00034  *   Begin class HostMatcher
00035  *************************************************************/
00036 
00037 CacheHostMatcher::CacheHostMatcher(const char * name, CacheType typ):
00038 data_array(NULL),
00039 array_len(-1),
00040 num_el(-1),
00041 type(typ)
00042 {
00043   host_lookup = new HostLookup(name);
00044 }
00045 
00046 CacheHostMatcher::~CacheHostMatcher()
00047 {
00048 
00049   delete host_lookup;
00050   delete[]data_array;
00051 }
00052 
00053 //
00054 // template <class Data,class Result>
00055 // void HostMatcher<Data,Result>::Print()
00056 //
00057 //  Debugging Method
00058 //
00059 void
00060 CacheHostMatcher::Print()
00061 {
00062 
00063   printf("\tHost/Domain Matcher with %d elements\n", num_el);
00064   host_lookup->Print(PrintFunc);
00065 }
00066 
00067 //
00068 // template <class Data,class Result>
00069 // void CacheHostMatcher::PrintFunc(void* opaque_data)
00070 //
00071 //  Debugging Method
00072 //
00073 void
00074 CacheHostMatcher::PrintFunc(void *opaque_data)
00075 {
00076   CacheHostRecord *d = (CacheHostRecord *) opaque_data;
00077   d->Print();
00078 }
00079 
00080 // void CacheHostMatcher::AllocateSpace(int num_entries)
00081 //
00082 //  Allocates the the HostLeaf and Data arrays
00083 //
00084 void
00085 CacheHostMatcher::AllocateSpace(int num_entries)
00086 {
00087   // Should not have been allocated before
00088   ink_assert(array_len == -1);
00089 
00090   host_lookup->AllocateSpace(num_entries);
00091 
00092   data_array = new CacheHostRecord[num_entries];
00093 
00094   array_len = num_entries;
00095   num_el = 0;
00096 }
00097 
00098 // void CacheHostMatcher::Match(RequestData* rdata, Result* result)
00099 //
00100 //  Searches our tree and updates argresult for each element matching
00101 //    arg hostname
00102 //
00103 void
00104 CacheHostMatcher::Match(char const* rdata, int rlen, CacheHostResult * result)
00105 {
00106 
00107   void *opaque_ptr;
00108   CacheHostRecord *data_ptr;
00109   bool r;
00110 
00111   // Check to see if there is any work to do before makeing
00112   //   the stirng copy
00113   if (num_el <= 0) {
00114     return;
00115   }
00116 
00117   if (rlen == 0)
00118     return;
00119   char *data = (char *)ats_malloc(rlen + 1);
00120   memcpy(data, rdata, rlen);
00121   *(data + rlen) = '\0';
00122   HostLookupState s;
00123 
00124   r = host_lookup->MatchFirst(data, &s, &opaque_ptr);
00125 
00126   while (r == true) {
00127     ink_assert(opaque_ptr != NULL);
00128     data_ptr = (CacheHostRecord *) opaque_ptr;
00129     data_ptr->UpdateMatch(result, data);
00130 
00131     r = host_lookup->MatchNext(&s, &opaque_ptr);
00132   }
00133   ats_free(data);
00134 }
00135 
00136 //
00137 // char* CacheHostMatcher::NewEntry(bool domain_record,
00138 //          char* match_data, char* match_info, int line_num)
00139 //
00140 //   Creates a new host/domain record
00141 //
00142 
00143 void
00144 CacheHostMatcher::NewEntry(matcher_line * line_info)
00145 {
00146 
00147   CacheHostRecord *cur_d;
00148   int errNo;
00149   char *match_data;
00150 
00151   // Make sure space has been allocated
00152   ink_assert(num_el >= 0);
00153   ink_assert(array_len >= 0);
00154 
00155   // Make sure we do not overrun the array;
00156   ink_assert(num_el < array_len);
00157 
00158   match_data = line_info->line[1][line_info->dest_entry];
00159 
00160   // Make sure that the line_info is not bogus
00161   ink_assert(line_info->dest_entry < MATCHER_MAX_TOKENS);
00162   ink_assert(match_data != NULL);
00163 
00164   // Remove our consumed label from the parsed line
00165   if (line_info->dest_entry < MATCHER_MAX_TOKENS)
00166     line_info->line[0][line_info->dest_entry] = NULL;
00167   line_info->num_el--;
00168 
00169   // Fill in the parameter info
00170   cur_d = data_array + num_el;
00171   errNo = cur_d->Init(line_info, type);
00172 
00173   if (errNo) {
00174     // There was a problem so undo the effects this function
00175     memset(cur_d, 0, sizeof(CacheHostRecord));
00176     return;
00177   }
00178   Debug("cache_hosting", "hostname: %s, host record: %p", match_data, cur_d);
00179   // Fill in the matching info
00180   host_lookup->NewEntry(match_data, (line_info->type == MATCH_DOMAIN) ? true : false, cur_d);
00181 
00182   num_el++;
00183   return;
00184 }
00185 
00186 /*************************************************************
00187  *   End class HostMatcher
00188  *************************************************************/
00189 
00190 CacheHostTable::CacheHostTable(Cache * c, CacheType typ)
00191 {
00192   ats_scoped_str config_path;
00193 
00194   config_tags = &CacheHosting_tags;
00195   ink_assert(config_tags != NULL);
00196 
00197   type = typ;
00198   cache = c;
00199   matcher_name = "[CacheHosting]";;
00200   hostMatch = NULL;
00201 
00202   config_path = RecConfigReadConfigPath("proxy.config.cache.hosting_filename");
00203   ink_release_assert(config_path);
00204 
00205   m_numEntries = this->BuildTable(config_path);
00206 }
00207 
00208 CacheHostTable::~CacheHostTable()
00209 {
00210 
00211   if (hostMatch != NULL) {
00212     delete hostMatch;
00213   }
00214 }
00215 
00216 // void ControlMatcher<Data, Result>::Print()
00217 //
00218 //   Debugging method
00219 //
00220 void
00221 CacheHostTable::Print()
00222 {
00223   printf("Control Matcher Table: %s\n", matcher_name);
00224   if (hostMatch != NULL) {
00225     hostMatch->Print();
00226   }
00227 }
00228 
00229 
00230 // void ControlMatcher<Data, Result>::Match(RequestData* rdata
00231 //                                          Result* result)
00232 //
00233 //   Queries each table for the Result*
00234 //
00235 void
00236 CacheHostTable::Match(char const* rdata, int rlen, CacheHostResult * result)
00237 {
00238 
00239   hostMatch->Match(rdata, rlen, result);
00240 }
00241 
00242 int
00243 CacheHostTable::config_callback(const char * /* name ATS_UNUSED */, RecDataT /* data_type ATS_UNUSED */,
00244                                 RecData /* data ATS_UNUSED */, void *cookie)
00245 {
00246   CacheHostTable **ppt = (CacheHostTable **) cookie;
00247   eventProcessor.schedule_imm(new CacheHostTableConfig(ppt));
00248   return 0;
00249 }
00250 
00251 int fstat_wrapper(int fd, struct stat *s);
00252 
00253 // int ControlMatcher::BuildTable() {
00254 //
00255 //    Reads the cache.config file and build the records array
00256 //      from it
00257 //
00258 int
00259 CacheHostTable::BuildTableFromString(const char * config_file_path, char *file_buf)
00260 {
00261   // Table build locals
00262   Tokenizer bufTok("\n");
00263   tok_iter_state i_state;
00264   const char *tmp;
00265   matcher_line *first = NULL;
00266   matcher_line *current;
00267   matcher_line *last = NULL;
00268   int line_num = 0;
00269   int second_pass = 0;
00270   int numEntries = 0;
00271   const char *errPtr = NULL;
00272 
00273   // type counts
00274   int hostDomain = 0;
00275 
00276   if (bufTok.Initialize(file_buf, SHARE_TOKS | ALLOW_EMPTY_TOKS) == 0) {
00277     // We have an empty file
00278     /* no hosting customers -- put all the volumes in the
00279        generic table */
00280     if (gen_host_rec.Init(type))
00281       Warning("Problems encountered while initializing the Generic Volume");
00282     return 0;
00283   }
00284   // First get the number of entries
00285   tmp = bufTok.iterFirst(&i_state);
00286   while (tmp != NULL) {
00287 
00288     line_num++;
00289 
00290     // skip all blank spaces at beginning of line
00291     while (*tmp && isspace(*tmp)) {
00292       tmp++;
00293     }
00294 
00295     if (*tmp != '#' && *tmp != '\0') {
00296 
00297       current = (matcher_line *)ats_malloc(sizeof(matcher_line));
00298       errPtr = parseConfigLine((char *) tmp, current, config_tags);
00299 
00300       if (errPtr != NULL) {
00301         RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "%s discarding %s entry at line %d : %s",
00302                  matcher_name, config_file_path, line_num, errPtr);
00303         ats_free(current);
00304       } else {
00305 
00306         // Line parsed ok.  Figure out what the destination
00307         //  type is and link it into our list
00308         numEntries++;
00309         current->line_num = line_num;
00310 
00311         switch (current->type) {
00312         case MATCH_HOST:
00313         case MATCH_DOMAIN:
00314           hostDomain++;
00315           break;
00316         case MATCH_NONE:
00317         default:
00318           ink_assert(0);
00319         }
00320 
00321         if (first == NULL) {
00322           ink_assert(last == NULL);
00323           first = last = current;
00324         } else {
00325           last->next = current;
00326           last = current;
00327         }
00328       }
00329     }
00330     tmp = bufTok.iterNext(&i_state);
00331   }
00332 
00333   // Make we have something to do before going on
00334   if (numEntries == 0) {
00335     /* no hosting customers -- put all the volumes in the
00336        generic table */
00337 
00338     if (gen_host_rec.Init(type)) {
00339       Warning("Problems encountered while initializing the Generic Volume");
00340     }
00341 
00342     if (first != NULL) {
00343       ats_free(first);
00344     }
00345     return 0;
00346   }
00347 
00348   if (hostDomain > 0) {
00349     hostMatch = new CacheHostMatcher(matcher_name, type);
00350     hostMatch->AllocateSpace(hostDomain);
00351   }
00352   // Traverse the list and build the records table
00353   int generic_rec_initd = 0;
00354   current = first;
00355   while (current != NULL) {
00356     second_pass++;
00357     if ((current->type == MATCH_DOMAIN) || (current->type == MATCH_HOST)) {
00358 
00359       char *match_data = current->line[1][current->dest_entry];
00360       ink_assert(match_data != NULL);
00361 
00362       if (!strcasecmp(match_data, "*")) {
00363         // generic volume - initialize the generic hostrecord */
00364         // Make sure that the line_info is not bogus
00365         ink_assert(current->dest_entry < MATCHER_MAX_TOKENS);
00366 
00367         // Remove our consumed label from the parsed line
00368         if (current->dest_entry < MATCHER_MAX_TOKENS)
00369           current->line[0][current->dest_entry] = NULL;
00370         else
00371           Warning("Problems encountered while initializing the Generic Volume");
00372 
00373         current->num_el--;
00374         if (!gen_host_rec.Init(current, type))
00375           generic_rec_initd = 1;
00376         else
00377           Warning("Problems encountered while initializing the Generic Volume");
00378 
00379       } else {
00380         hostMatch->NewEntry(current);
00381       }
00382     } else {
00383       RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "%s discarding %s entry with unknown type at line %d",
00384                matcher_name, config_file_path, current->line_num);
00385     }
00386 
00387     // Deallocate the parsing structure
00388     last = current;
00389     current = current->next;
00390     ats_free(last);
00391   }
00392 
00393   if (!generic_rec_initd) {
00394     const char *cache_type = (type == CACHE_HTTP_TYPE) ? "http" : "mixt";
00395     RecSignalWarning(REC_SIGNAL_CONFIG_ERROR,
00396              "No Volumes specified for Generic Hostnames for %s documents: %s cache will be disabled", cache_type,
00397              cache_type);
00398   }
00399 
00400   ink_assert(second_pass == numEntries);
00401 
00402   if (is_debug_tag_set("matcher")) {
00403     Print();
00404   }
00405   return numEntries;
00406 }
00407 
00408 int
00409 CacheHostTable::BuildTable(const char * config_file_path)
00410 {
00411   char *file_buf;
00412   int ret;
00413 
00414   file_buf = readIntoBuffer(config_file_path, matcher_name, NULL);
00415 
00416   if (file_buf == NULL) {
00417     Warning("Cannot read the config file: %s", config_file_path);
00418     gen_host_rec.Init(type);
00419     return 0;
00420   }
00421 
00422   ret = BuildTableFromString(config_file_path, file_buf);
00423   ats_free(file_buf);
00424   return ret;
00425 }
00426 
00427 int
00428 CacheHostRecord::Init(CacheType typ)
00429 {
00430 
00431   int i, j;
00432   extern Queue<CacheVol> cp_list;
00433   extern int cp_list_len;
00434 
00435   num_vols = 0;
00436   type = typ;
00437   cp = (CacheVol **)ats_malloc(cp_list_len * sizeof(CacheVol *));
00438   memset(cp, 0, cp_list_len * sizeof(CacheVol *));
00439   num_cachevols = 0;
00440   CacheVol *cachep = cp_list.head;
00441   for (; cachep; cachep = cachep->link.next) {
00442     if (cachep->scheme == type) {
00443       Debug("cache_hosting", "Host Record: %p, Volume: %d, size: %" PRId64, this, cachep->vol_number, (int64_t)cachep->size);
00444       cp[num_cachevols] = cachep;
00445       num_cachevols++;
00446       num_vols += cachep->num_vols;
00447     }
00448   }
00449   if (!num_cachevols) {
00450     RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "error: No volumes found for Cache Type %d", type);
00451     return -1;
00452   }
00453   vols = (Vol **)ats_malloc(num_vols * sizeof(Vol *));
00454   int counter = 0;
00455   for (i = 0; i < num_cachevols; i++) {
00456     CacheVol *cachep1 = cp[i];
00457     for (j = 0; j < cachep1->num_vols; j++) {
00458       vols[counter++] = cachep1->vols[j];
00459     }
00460   }
00461   ink_assert(counter == num_vols);
00462 
00463   build_vol_hash_table(this);
00464   return 0;
00465 }
00466 
00467 int
00468 CacheHostRecord::Init(matcher_line * line_info, CacheType typ)
00469 {
00470   int i, j;
00471   extern Queue<CacheVol> cp_list;
00472   int is_vol_present = 0;
00473   char config_file[PATH_NAME_MAX];
00474 
00475   REC_ReadConfigString(config_file, "proxy.config.cache.hosting_filename", PATH_NAME_MAX);
00476   type = typ;
00477   for (i = 0; i < MATCHER_MAX_TOKENS; i++) {
00478     char *label = line_info->line[0][i];
00479     if (!label)
00480       continue;
00481     char *val;
00482 
00483     if (!strcasecmp(label, "volume")) {
00484       /* parse the list of volumes */
00485       val = ats_strdup(line_info->line[1][i]);
00486       char *vol_no = val;
00487       char *s = val;
00488       int volume_number;
00489       CacheVol *cachep;
00490 
00491       /* first find out the number of volumes */
00492       while (*s) {
00493         if (*s == ',') {
00494           num_cachevols++;
00495           s++;
00496           if (!(*s)) {
00497             const char *errptr = "A volume number expected";
00498             RecSignalWarning(REC_SIGNAL_CONFIG_ERROR,
00499                          "%s discarding %s entry at line %d :%s",
00500                          "[CacheHosting]", config_file, line_info->line_num, errptr);
00501             if (val != NULL) {
00502               ats_free(val);
00503             }
00504             return -1;
00505           }
00506         }
00507         if ((*s<'0') || (*s> '9')) {
00508           RecSignalWarning(REC_SIGNAL_CONFIG_ERROR,
00509                        "%s discarding %s entry at line %d : bad token [%c]",
00510                        "[CacheHosting]", config_file, line_info->line_num, *s);
00511           if (val != NULL) {
00512             ats_free(val);
00513           }
00514           return -1;
00515         }
00516         s++;
00517       }
00518       s = val;
00519       num_cachevols++;
00520       cp = (CacheVol **)ats_malloc(num_cachevols * sizeof(CacheVol *));
00521       memset(cp, 0, num_cachevols * sizeof(CacheVol *));
00522       num_cachevols = 0;
00523       while (1) {
00524         char c = *s;
00525         if ((c == ',') || (c == '\0')) {
00526           *s = '\0';
00527           volume_number = atoi(vol_no);
00528 
00529           cachep = cp_list.head;
00530           for (; cachep; cachep = cachep->link.next) {
00531             if (cachep->vol_number == volume_number) {
00532               is_vol_present = 1;
00533               if (cachep->scheme == type) {
00534                 Debug("cache_hosting",
00535                       "Host Record: %p, Volume: %d, size: %ld",
00536                       this, volume_number, (long)(cachep->size * STORE_BLOCK_SIZE));
00537                 cp[num_cachevols] = cachep;
00538                 num_cachevols++;
00539                 num_vols += cachep->num_vols;
00540                 break;
00541               }
00542             }
00543           }
00544           if (!is_vol_present) {
00545             RecSignalWarning(REC_SIGNAL_CONFIG_ERROR,
00546                          "%s discarding %s entry at line %d : bad volume number [%d]",
00547                          "[CacheHosting]", config_file, line_info->line_num, volume_number);
00548             if (val != NULL) {
00549               ats_free(val);
00550             }
00551             return -1;
00552           }
00553           if (c == '\0')
00554             break;
00555           vol_no = s + 1;
00556         }
00557         s++;
00558       }
00559       if (val != NULL) {
00560         ats_free(val);
00561       }
00562       break;
00563     }
00564 
00565     RecSignalWarning(REC_SIGNAL_CONFIG_ERROR,
00566                  "%s discarding %s entry at line %d : bad token [%s]",
00567                  "[CacheHosting]", config_file, line_info->line_num, label);
00568     return -1;
00569   }
00570 
00571   if (i == MATCHER_MAX_TOKENS) {
00572     RecSignalWarning(REC_SIGNAL_CONFIG_ERROR,
00573                  "%s discarding %s entry at line %d : No volumes specified",
00574                  "[CacheHosting]", config_file, line_info->line_num);
00575     return -1;
00576   }
00577 
00578   if (!num_vols) {
00579     return -1;
00580   }
00581   vols = (Vol **)ats_malloc(num_vols * sizeof(Vol *));
00582   int counter = 0;
00583   for (i = 0; i < num_cachevols; i++) {
00584     CacheVol *cachep = cp[i];
00585     for (j = 0; j < cp[i]->num_vols; j++) {
00586       vols[counter++] = cachep->vols[j];
00587     }
00588   }
00589   ink_assert(counter == num_vols);
00590 
00591   build_vol_hash_table(this);
00592   return 0;
00593 }
00594 
00595 void
00596 CacheHostRecord::UpdateMatch(CacheHostResult * r, char * /* rd ATS_UNUSED */)
00597 {
00598   r->record = this;
00599 }
00600 
00601 void
00602 CacheHostRecord::Print()
00603 {
00604 }
00605 
00606 
00607 
00608 void
00609 ConfigVolumes::read_config_file()
00610 {
00611   ats_scoped_str config_path;
00612   char *file_buf;
00613 
00614   config_path = RecConfigReadConfigPath("proxy.config.cache.volume_filename");
00615   ink_release_assert(config_path);
00616 
00617   file_buf = readIntoBuffer(config_path, "[CacheVolition]", NULL);
00618   if (file_buf == NULL) {
00619     Warning("Cannot read the config file: %s", (const char *)config_path);
00620     return;
00621   }
00622 
00623   BuildListFromString(config_path, file_buf);
00624   ats_free(file_buf);
00625   return;
00626 }
00627 
00628 void
00629 ConfigVolumes::BuildListFromString(char *config_file_path, char *file_buf)
00630 {
00631 
00632 #define PAIR_ZERO 0
00633 #define PAIR_ONE 1
00634 #define PAIR_TWO 2
00635 #define DONE 3
00636 #define INK_ERROR -1
00637 
00638 #define INK_ERROR_VOLUME -2  //added by YTS Team, yamsat for bug id 59632
00639 // Table build locals
00640   Tokenizer bufTok("\n");
00641   tok_iter_state i_state;
00642   const char *tmp;
00643   char *end;
00644   char *line_end = NULL;
00645   int line_num = 0;
00646   int total = 0;                //added by YTS Team, yamsat for bug id 59632
00647 
00648   char volume_seen[256];
00649   int state = 0;                //changed by YTS Team, yamsat for bug id 59632
00650   int volume_number = 0;
00651   CacheType scheme = CACHE_NONE_TYPE;
00652   int size = 0;
00653   int in_percent = 0;
00654   const char *matcher_name = "[CacheVolition]";
00655 
00656   memset(volume_seen, 0, sizeof(volume_seen));
00657   num_volumes = 0;
00658   num_stream_volumes = 0;
00659   num_http_volumes = 0;
00660 
00661   if (bufTok.Initialize(file_buf, SHARE_TOKS | ALLOW_EMPTY_TOKS) == 0) {
00662     // We have an empty file
00663     /* no volumes */
00664     return;
00665   }
00666   // First get the number of entries
00667   tmp = bufTok.iterFirst(&i_state);
00668   while (tmp != NULL) {
00669     state = PAIR_ZERO;
00670     line_num++;
00671 
00672     // skip all blank spaces at beginning of line
00673     while (1) {
00674       while (*tmp && isspace(*tmp)) {
00675         tmp++;
00676       }
00677 
00678       if (!(*tmp) && state == DONE) {
00679         /* add the config */
00680 
00681         ConfigVol *configp = new ConfigVol();
00682         configp->number = volume_number;
00683         if (in_percent) {
00684           configp->percent = size;
00685           configp->in_percent = 1;
00686         } else {
00687           configp->in_percent = 0;
00688         }
00689         configp->scheme = scheme;
00690         configp->size = size;
00691         configp->cachep = NULL;
00692         cp_queue.enqueue(configp);
00693         num_volumes++;
00694         if (scheme == CACHE_HTTP_TYPE)
00695           num_http_volumes++;
00696         else
00697           num_stream_volumes++;
00698         Debug("cache_hosting",
00699               "added volume=%d, scheme=%d, size=%d percent=%d\n", volume_number, scheme, size, in_percent);
00700         break;
00701       }
00702 
00703       if (state == PAIR_ZERO) {
00704         if (*tmp == '\0' || *tmp == '#')
00705           break;
00706       } else {
00707         if (!(*tmp)) {
00708           RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "%s discarding %s entry at line %d : Unexpected end of line",
00709                    matcher_name, config_file_path, line_num);
00710           break;
00711         }
00712       }
00713 
00714       end = (char *) tmp;
00715       while (*end && !isspace(*end))
00716         end++;
00717 
00718       if (!(*end))
00719         line_end = end;
00720       else {
00721         line_end = end + 1;
00722         *end = '\0';
00723       }
00724       char *eq_sign;
00725 
00726       eq_sign = (char *) strchr(tmp, '=');
00727       if (!eq_sign) {
00728         state = INK_ERROR;
00729       } else
00730         *eq_sign = '\0';
00731 
00732       switch (state) {
00733       case PAIR_ZERO:
00734         if (strcasecmp(tmp, "volume")) {
00735           state = INK_ERROR;
00736           break;
00737         }
00738         tmp += 7;              //size of string volume including null
00739         volume_number = atoi(tmp);
00740 
00741         if (volume_number<1 || volume_number> 255 || volume_seen[volume_number]) {
00742           const char *err;
00743 
00744           if (volume_number<1 || volume_number> 255) {
00745             err = "Bad Volume Number";
00746           } else {
00747             err = "Volume Already Specified";
00748           }
00749 
00750           RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "%s discarding %s entry at line %d : %s [%d]",
00751                    matcher_name, config_file_path, line_num, err, volume_number);
00752           state = INK_ERROR;
00753           break;
00754         }
00755 
00756         volume_seen[volume_number] = 1;
00757         while (ParseRules::is_digit(*tmp))
00758           tmp++;
00759         state = PAIR_ONE;
00760         break;
00761 
00762       case PAIR_ONE:
00763         if (strcasecmp(tmp, "scheme")) {
00764           state = INK_ERROR;
00765           break;
00766         }
00767         tmp += 7;               //size of string scheme including null
00768 
00769         if (!strcasecmp(tmp, "http")) {
00770           tmp += 4;
00771           scheme = CACHE_HTTP_TYPE;
00772         } else if (!strcasecmp(tmp, "mixt")) {
00773           tmp += 4;
00774           scheme = CACHE_RTSP_TYPE;
00775         } else {
00776           state = INK_ERROR;
00777           break;
00778         }
00779 
00780         state = PAIR_TWO;
00781         break;
00782 
00783       case PAIR_TWO:
00784 
00785         if (strcasecmp(tmp, "size")) {
00786           state = INK_ERROR;
00787           break;
00788         }
00789         tmp += 5;
00790         size = atoi(tmp);
00791 
00792         while (ParseRules::is_digit(*tmp))
00793           tmp++;
00794 
00795         if (*tmp == '%') {
00796           //added by YTS Team, yamsat for bug id 59632
00797           total += size;
00798           if (size > 100 || total > 100) {
00799             state = INK_ERROR_VOLUME;
00800             if (state == INK_ERROR_VOLUME || *tmp) {
00801               RecSignalWarning(REC_SIGNAL_CONFIG_ERROR,
00802                        "Total volume size added upto more than 100 percent,No volumes created");
00803               break;
00804             }
00805           }
00806           //ends here
00807           in_percent = 1;
00808           tmp++;
00809         } else
00810           in_percent = 0;
00811         state = DONE;
00812         break;
00813 
00814       }
00815 
00816       if (state == INK_ERROR || *tmp) {
00817         RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "%s discarding %s entry at line %d : Invalid token [%s]",
00818                  matcher_name, config_file_path, line_num, tmp);
00819         break;
00820       }
00821       //added by YTS Team, yamsat for bug id 59632
00822       if (state == INK_ERROR_VOLUME || *tmp) {
00823         RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "Total volume size added upto more than 100 percent,No volumes created");
00824         break;
00825       }
00826       // ends here
00827       if (end < line_end)
00828         tmp++;
00829     }
00830     tmp = bufTok.iterNext(&i_state);
00831   }
00832 
00833   return;
00834 }
00835 
00836 
00837 
00838 /* Test the cache volumeing with different configurations */
00839 #define MEGS_128 (128 * 1024 * 1024)
00840 #define ROUND_TO_VOL_SIZE(_x) (((_x) + (MEGS_128 - 1)) &~ (MEGS_128 - 1))
00841 extern CacheDisk **gdisks;
00842 extern Queue<CacheVol> cp_list;
00843 extern int cp_list_len;
00844 extern ConfigVolumes config_volumes;
00845 extern volatile int gnvol;
00846 
00847 extern void cplist_init();
00848 extern int cplist_reconfigure();
00849 static int configs = 4;
00850 
00851 Queue<CacheVol> saved_cp_list;
00852 int saved_cp_list_len;
00853 ConfigVolumes saved_config_volumes;
00854 int saved_gnvol;
00855 
00856 int ClearConfigVol(ConfigVolumes * configp);
00857 int ClearCacheVolList(Queue<CacheVol> *cpl, int len);
00858 int create_config(RegressionTest * t, int i);
00859 int execute_and_verify(RegressionTest * t);
00860 void save_state();
00861 void restore_state();
00862 
00863 EXCLUSIVE_REGRESSION_TEST(Cache_vol) (RegressionTest * t, int /* atype ATS_UNUSED */, int *status) {
00864   save_state();
00865   srand48(time(NULL));
00866   *status = REGRESSION_TEST_PASSED;
00867   for (int i = 0; i < configs; i++) {
00868     if (create_config(t, i)) {
00869       if (execute_and_verify(t) == REGRESSION_TEST_FAILED) {
00870         *status = REGRESSION_TEST_FAILED;
00871       }
00872     }
00873   }
00874   restore_state();
00875   return;
00876 }
00877 
00878 int
00879 create_config(RegressionTest * t, int num)
00880 {
00881   int i = 0;
00882   int vol_num = 1;
00883   // clear all old configurations before adding new test cases
00884   config_volumes.clear_all();
00885   switch (num) {
00886   case 0:
00887     for (i = 0; i < gndisks; i++) {
00888       CacheDisk *d = gdisks[i];
00889       int blocks = d->num_usable_blocks;
00890       if (blocks < STORE_BLOCKS_PER_VOL) {
00891         rprintf(t, "Cannot run Cache_vol regression: not enough disk space\n");
00892         return 0;
00893       }
00894       /* create 128 MB volumes */
00895       for (; blocks >= STORE_BLOCKS_PER_VOL; blocks -= STORE_BLOCKS_PER_VOL) {
00896         if (vol_num > 255)
00897           break;
00898         ConfigVol *cp = new ConfigVol();
00899         cp->number = vol_num++;
00900         cp->scheme = CACHE_HTTP_TYPE;
00901         cp->size = 128;
00902         cp->in_percent = 0;
00903         cp->cachep = 0;
00904         config_volumes.cp_queue.enqueue(cp);
00905         config_volumes.num_volumes++;
00906         config_volumes.num_http_volumes++;
00907       }
00908 
00909     }
00910     rprintf(t, "%d 128 Megabyte Volumes\n", vol_num - 1);
00911     break;
00912 
00913   case 1:
00914     {
00915       for (i = 0; i < gndisks; i++) {
00916         gdisks[i]->delete_all_volumes();
00917       }
00918 
00919       // calculate the total free space
00920       off_t total_space = 0;
00921       for (i = 0; i < gndisks; i++) {
00922         off_t vol_blocks = gdisks[i]->num_usable_blocks;
00923         /* round down the blocks to the nearest
00924            multiple of STORE_BLOCKS_PER_VOL */
00925         vol_blocks = (vol_blocks / STORE_BLOCKS_PER_VOL)
00926           * STORE_BLOCKS_PER_VOL;
00927         total_space += vol_blocks;
00928       }
00929 
00930       // make sure we have atleast 1280 M bytes
00931       if (total_space<(10 << 27)>> STORE_BLOCK_SHIFT) {
00932         rprintf(t, "Not enough space for 10 volume\n");
00933         return 0;
00934       }
00935 
00936       vol_num = 1;
00937       rprintf(t, "Cleared  disk\n");
00938       for (i = 0; i < 10; i++) {
00939         ConfigVol *cp = new ConfigVol();
00940         cp->number = vol_num++;
00941         cp->scheme = CACHE_HTTP_TYPE;
00942         cp->size = 10;
00943         cp->percent = 10;
00944         cp->in_percent = 1;
00945         cp->cachep = 0;
00946         config_volumes.cp_queue.enqueue(cp);
00947         config_volumes.num_volumes++;
00948         config_volumes.num_http_volumes++;
00949       }
00950       rprintf(t, "10 volume, 10 percent each\n");
00951     }
00952     break;
00953 
00954   case 2:
00955   case 3:
00956 
00957     {
00958       /* calculate the total disk space */
00959       InkRand *gen = &this_ethread()->generator;
00960       off_t total_space = 0;
00961       vol_num = 1;
00962       if (num == 2) {
00963         rprintf(t, "Random Volumes after clearing the disks\n");
00964       } else {
00965         rprintf(t, "Random Volumes without clearing the disks\n");
00966       }
00967 
00968       for (i = 0; i < gndisks; i++) {
00969         off_t vol_blocks = gdisks[i]->num_usable_blocks;
00970         /* round down the blocks to the nearest
00971            multiple of STORE_BLOCKS_PER_VOL */
00972         vol_blocks = (vol_blocks / STORE_BLOCKS_PER_VOL)
00973           * STORE_BLOCKS_PER_VOL;
00974         total_space += vol_blocks;
00975 
00976         if (num == 2) {
00977           gdisks[i]->delete_all_volumes();
00978         } else {
00979           gdisks[i]->cleared = 0;
00980         }
00981       }
00982       while (total_space > 0) {
00983         if (vol_num > 255)
00984           break;
00985         off_t modu = MAX_VOL_SIZE;
00986         if (total_space<(MAX_VOL_SIZE>> STORE_BLOCK_SHIFT)) {
00987           modu = total_space * STORE_BLOCK_SIZE;
00988         }
00989 
00990         off_t random_size = (gen->random() % modu) + 1;
00991         /* convert to 128 megs multiple */
00992         CacheType scheme = (random_size % 2) ? CACHE_HTTP_TYPE : CACHE_RTSP_TYPE;
00993         random_size = ROUND_TO_VOL_SIZE(random_size);
00994         off_t blocks = random_size / STORE_BLOCK_SIZE;
00995         ink_assert(blocks <= (int) total_space);
00996         total_space -= blocks;
00997 
00998         ConfigVol *cp = new ConfigVol();
00999 
01000         cp->number = vol_num++;
01001         cp->scheme = scheme;
01002         cp->size = random_size >> 20;
01003         cp->percent = 0;
01004         cp->in_percent = 0;
01005         cp->cachep = 0;
01006         config_volumes.cp_queue.enqueue(cp);
01007         config_volumes.num_volumes++;
01008         if (cp->scheme == CACHE_HTTP_TYPE) {
01009           config_volumes.num_http_volumes++;
01010           rprintf(t, "volume=%d scheme=http size=%d\n", cp->number, cp->size);
01011         } else {
01012           config_volumes.num_stream_volumes++;
01013           rprintf(t, "volume=%d scheme=rtsp size=%d\n", cp->number, cp->size);
01014 
01015         }
01016       }
01017     }
01018     break;
01019 
01020   default:
01021     return 1;
01022   }
01023   return 1;
01024 }
01025 
01026 int
01027 execute_and_verify(RegressionTest * t)
01028 {
01029   cplist_init();
01030   cplist_reconfigure();
01031 
01032   /* compare the volumes */
01033   if (cp_list_len != config_volumes.num_volumes)
01034     return REGRESSION_TEST_FAILED;
01035 
01036   /* check that the volumes and sizes
01037      match the configuration */
01038   int matched = 0;
01039   ConfigVol *cp = config_volumes.cp_queue.head;
01040   CacheVol *cachep;
01041 
01042   for (int i = 0; i < config_volumes.num_volumes; i++) {
01043     cachep = cp_list.head;
01044     while (cachep) {
01045       if (cachep->vol_number == cp->number) {
01046         if ((cachep->scheme != cp->scheme) ||
01047             (cachep->size != (cp->size << (20 - STORE_BLOCK_SHIFT))) || (cachep != cp->cachep)) {
01048           rprintf(t, "Configuration and Actual volumes don't match\n");
01049           return REGRESSION_TEST_FAILED;
01050         }
01051 
01052         /* check that the number of volumes match the ones
01053            on disk */
01054         int d_no;
01055         int m_vols = 0;
01056         for (d_no = 0; d_no < gndisks; d_no++) {
01057           if (cachep->disk_vols[d_no]) {
01058             DiskVol *dp = cachep->disk_vols[d_no];
01059             if (dp->vol_number != cachep->vol_number) {
01060               rprintf(t, "DiskVols and CacheVols don't match\n");
01061               return REGRESSION_TEST_FAILED;
01062             }
01063 
01064             /* check the diskvolblock queue */
01065             DiskVolBlockQueue *dpbq = dp->dpb_queue.head;
01066             while (dpbq) {
01067               if (dpbq->b->number != cachep->vol_number) {
01068                 rprintf(t, "DiskVol and DiskVolBlocks don't match\n");
01069                 return REGRESSION_TEST_FAILED;
01070               }
01071               dpbq = dpbq->link.next;
01072             }
01073 
01074             m_vols += dp->num_volblocks;
01075           }
01076         }
01077         if (m_vols != cachep->num_vols) {
01078           rprintf(t, "Num volumes in CacheVol and DiskVol don't match\n");
01079           return REGRESSION_TEST_FAILED;
01080         }
01081         matched++;
01082         break;
01083       }
01084       cachep = cachep->link.next;
01085     }
01086   }
01087 
01088   if (matched != config_volumes.num_volumes) {
01089     rprintf(t, "Num of Volumes created and configured don't match\n");
01090     return REGRESSION_TEST_FAILED;
01091   }
01092 
01093   ClearConfigVol(&config_volumes);
01094 
01095   ClearCacheVolList(&cp_list, cp_list_len);
01096 
01097   for (int i = 0; i < gndisks; i++) {
01098     CacheDisk *d = gdisks[i];
01099     if (is_debug_tag_set("cache_hosting")) {
01100 
01101       Debug("cache_hosting", "Disk: %d: Vol Blocks: %u: Free space: %" PRIu64,
01102             i, d->header->num_diskvol_blks, d->free_space);
01103       for (int j = 0; j < (int) d->header->num_volumes; j++) {
01104 
01105         Debug("cache_hosting", "\tVol: %d Size: %" PRIu64, d->disk_vols[j]->vol_number, d->disk_vols[j]->size);
01106       }
01107       for (int j = 0; j < (int) d->header->num_diskvol_blks; j++) {
01108         Debug("cache_hosting", "\tBlock No: %d Size: %" PRIu64" Free: %u",
01109               d->header->vol_info[j].number, d->header->vol_info[j].len, d->header->vol_info[j].free);
01110       }
01111     }
01112   }
01113   return REGRESSION_TEST_PASSED;
01114 }
01115 
01116 int
01117 ClearConfigVol(ConfigVolumes * configp)
01118 {
01119 
01120   int i = 0;
01121   ConfigVol *cp = NULL;
01122   while ((cp = configp->cp_queue.dequeue())) {
01123     delete cp;
01124     i++;
01125   }
01126   if (i != configp->num_volumes) {
01127     Warning("failed");
01128     return 0;
01129   }
01130   configp->num_volumes = 0;
01131   configp->num_http_volumes = 0;
01132   configp->num_stream_volumes = 0;
01133   return 1;
01134 }
01135 
01136 int
01137 ClearCacheVolList(Queue<CacheVol> *cpl, int len)
01138 {
01139 
01140   int i = 0;
01141   CacheVol *cp = NULL;
01142   while ((cp = cpl->dequeue())) {
01143     ats_free(cp->disk_vols);
01144     ats_free(cp->vols);
01145     delete(cp);
01146     i++;
01147   }
01148 
01149   if (i != len) {
01150     Warning("Failed");
01151     return 0;
01152   }
01153   return 1;
01154 }
01155 
01156 
01157 void
01158 save_state()
01159 {
01160   saved_cp_list = cp_list;
01161   saved_cp_list_len = cp_list_len;
01162   memcpy(&saved_config_volumes, &config_volumes, sizeof(ConfigVolumes));
01163   saved_gnvol = gnvol;
01164   memset(&cp_list, 0, sizeof(Queue<CacheVol>));
01165   memset(&config_volumes, 0, sizeof(ConfigVolumes));
01166   gnvol = 0;
01167 }
01168 
01169 void
01170 restore_state()
01171 {
01172   cp_list = saved_cp_list;
01173   cp_list_len = saved_cp_list_len;
01174   memcpy(&config_volumes, &saved_config_volumes, sizeof(ConfigVolumes));
01175   gnvol = saved_gnvol;
01176 }

Generated by  doxygen 1.7.1