00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
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 
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 
00055 
00056 
00057 
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 
00069 
00070 
00071 
00072 
00073 void
00074 CacheHostMatcher::PrintFunc(void *opaque_data)
00075 {
00076   CacheHostRecord *d = (CacheHostRecord *) opaque_data;
00077   d->Print();
00078 }
00079 
00080 
00081 
00082 
00083 
00084 void
00085 CacheHostMatcher::AllocateSpace(int num_entries)
00086 {
00087   
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 
00099 
00100 
00101 
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   
00112   
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 
00138 
00139 
00140 
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   
00152   ink_assert(num_el >= 0);
00153   ink_assert(array_len >= 0);
00154 
00155   
00156   ink_assert(num_el < array_len);
00157 
00158   match_data = line_info->line[1][line_info->dest_entry];
00159 
00160   
00161   ink_assert(line_info->dest_entry < MATCHER_MAX_TOKENS);
00162   ink_assert(match_data != NULL);
00163 
00164   
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   
00170   cur_d = data_array + num_el;
00171   errNo = cur_d->Init(line_info, type);
00172 
00173   if (errNo) {
00174     
00175     memset(cur_d, 0, sizeof(CacheHostRecord));
00176     return;
00177   }
00178   Debug("cache_hosting", "hostname: %s, host record: %p", match_data, cur_d);
00179   
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 
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 
00217 
00218 
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 
00231 
00232 
00233 
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 * , RecDataT ,
00244                                 RecData , 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 
00254 
00255 
00256 
00257 
00258 int
00259 CacheHostTable::BuildTableFromString(const char * config_file_path, char *file_buf)
00260 {
00261   
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   
00274   int hostDomain = 0;
00275 
00276   if (bufTok.Initialize(file_buf, SHARE_TOKS | ALLOW_EMPTY_TOKS) == 0) {
00277     
00278     
00279 
00280     if (gen_host_rec.Init(type))
00281       Warning("Problems encountered while initializing the Generic Volume");
00282     return 0;
00283   }
00284   
00285   tmp = bufTok.iterFirst(&i_state);
00286   while (tmp != NULL) {
00287 
00288     line_num++;
00289 
00290     
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         
00307         
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   
00334   if (numEntries == 0) {
00335     
00336 
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   
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         
00364         
00365         ink_assert(current->dest_entry < MATCHER_MAX_TOKENS);
00366 
00367         
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     
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       
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       
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 * )
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 
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;                
00647 
00648   char volume_seen[256];
00649   int state = 0;                
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     
00663     
00664     return;
00665   }
00666   
00667   tmp = bufTok.iterFirst(&i_state);
00668   while (tmp != NULL) {
00669     state = PAIR_ZERO;
00670     line_num++;
00671 
00672     
00673     while (1) {
00674       while (*tmp && isspace(*tmp)) {
00675         tmp++;
00676       }
00677 
00678       if (!(*tmp) && state == DONE) {
00679         
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;              
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;               
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           
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           
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       
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       
00827       if (end < line_end)
00828         tmp++;
00829     }
00830     tmp = bufTok.iterNext(&i_state);
00831   }
00832 
00833   return;
00834 }
00835 
00836 
00837 
00838 
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 , 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   
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       
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       
00920       off_t total_space = 0;
00921       for (i = 0; i < gndisks; i++) {
00922         off_t vol_blocks = gdisks[i]->num_usable_blocks;
00923         
00924 
00925         vol_blocks = (vol_blocks / STORE_BLOCKS_PER_VOL)
00926           * STORE_BLOCKS_PER_VOL;
00927         total_space += vol_blocks;
00928       }
00929 
00930       
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       
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         
00971 
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         
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   
01033   if (cp_list_len != config_volumes.num_volumes)
01034     return REGRESSION_TEST_FAILED;
01035 
01036   
01037 
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         
01053 
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             
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 }