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 }