Repository: trafficserver Updated Branches: refs/heads/master 68b4d8536 -> d0d0afb9a
TS-3468: Fix check option to be a useful stripe inspector. Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/d0d0afb9 Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/d0d0afb9 Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/d0d0afb9 Branch: refs/heads/master Commit: d0d0afb9a97c9449881d1275c93672e1010a2628 Parents: 68b4d85 Author: Alan M. Carroll <[email protected]> Authored: Fri Mar 13 01:41:32 2015 -0500 Committer: Alan M. Carroll <[email protected]> Committed: Tue Mar 31 09:50:01 2015 -0500 ---------------------------------------------------------------------- CHANGES | 2 + iocore/cache/Cache.cc | 60 +++++++++++--- iocore/cache/CacheDir.cc | 171 +++++++++++++++++++++++++++------------- iocore/cache/CacheDisk.cc | 20 ++++- iocore/cache/I_Cache.h | 5 +- iocore/cache/P_CacheDir.h | 2 + iocore/cache/P_CacheDisk.h | 4 +- proxy/Main.cc | 152 ++++++++++++++++------------------- 8 files changed, 259 insertions(+), 157 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d0d0afb9/CHANGES ---------------------------------------------------------------------- diff --git a/CHANGES b/CHANGES index 24a6811..49325fb 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,8 @@ Changes with Apache Traffic Server 6.0.0 Changes with Apache Traffic Server 5.3.0 + *) [TS-3468] Make command 'check' work usefully. + *) [TS-2709] ATS does not send close-notify on shutdown. Confuses some clients. *) [TS-3467] Cleanup tmp files created from traffic_via tests. http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d0d0afb9/iocore/cache/Cache.cc ---------------------------------------------------------------------- diff --git a/iocore/cache/Cache.cc b/iocore/cache/Cache.cc index d8e7bed..c818cc7 100644 --- a/iocore/cache/Cache.cc +++ b/iocore/cache/Cache.cc @@ -103,8 +103,9 @@ Store theCacheStore; volatile int CacheProcessor::initialized = CACHE_INITIALIZING; volatile uint32_t CacheProcessor::cache_ready = 0; volatile int CacheProcessor::start_done = 0; -int CacheProcessor::clear = 0; -int CacheProcessor::fix = 0; +bool CacheProcessor::clear = false; +bool CacheProcessor::fix = false; +bool CacheProcessor::check = false; int CacheProcessor::start_internal_flags = 0; int CacheProcessor::auto_clear_flag = 0; CacheProcessor cacheProcessor; @@ -615,6 +616,7 @@ CacheProcessor::start_internal(int flags) start_internal_flags = flags; clear = !!(flags & PROCESSOR_RECONFIGURE) || auto_clear_flag; fix = !!(flags & PROCESSOR_FIX); + check = (flags & PROCESSOR_CHECK) != 0; start_done = 0; int diskok = 1; Span *sd; @@ -646,18 +648,37 @@ CacheProcessor::start_internal(int flags) #ifdef O_DSYNC opts |= O_DSYNC; #endif + if (check) { + opts &= ~O_CREAT; + opts |= O_RDONLY; + } int fd = open(path, opts, 0644); int blocks = sd->blocks; if (fd > 0) { if (!sd->file_pathname) { - if (ftruncate(fd, ((uint64_t)blocks) * STORE_BLOCK_SIZE) < 0) { - Warning("unable to truncate cache file '%s' to %d blocks", path, blocks); + if (!check) { + if (ftruncate(fd, ((uint64_t)blocks) * STORE_BLOCK_SIZE) < 0) { + Warning("unable to truncate cache file '%s' to %d blocks", path, blocks); + diskok = 0; + } + } else { // read-only mode + struct stat sbuf; diskok = 0; + if (-1 == fstat(fd, &sbuf)) { + fprintf(stderr, "Failed to stat cache file for directory %s", path) + } else if (blocks != sbuf.st_size / STORE_BLOCK_SIZE) { + fprintf(stderr, "Cache file for directory %s is %" PRId64 " bytes, expected %" PRId64, path, sbuf.st_size, + blocks * STORE_BLOCK_SIZE); + } else { + diskok = 1; + } } } if (diskok) { CacheDisk *disk = new CacheDisk(); + if (check) + disk->read_only_p = true; Debug("cache_hosting", "interim Disk: %d, blocks: %d", gn_interim_disks, blocks); int sector_size = sd->hw_sector_size; if (sector_size < cache_config_force_sector_size) @@ -726,6 +747,10 @@ CacheProcessor::start_internal(int flags) #ifdef O_DSYNC opts |= O_DSYNC; #endif + if (check) { + opts &= ~O_CREAT; + opts |= O_RDONLY; + } int fd = open(path, opts, 0644); int blocks = sd->blocks; @@ -735,15 +760,30 @@ CacheProcessor::start_internal(int flags) if (fd >= 0) { if (!sd->file_pathname) { - if (ftruncate(fd, ((uint64_t)blocks) * STORE_BLOCK_SIZE) < 0) { - Warning("unable to truncate cache file '%s' to %d blocks", path, blocks); + if (check) { + if (ftruncate(fd, ((uint64_t)blocks) * STORE_BLOCK_SIZE) < 0) { + Warning("unable to truncate cache file '%s' to %d blocks", path, blocks); + diskok = 0; + } + } else { // read-only mode checks + struct stat sbuf; diskok = 0; + if (-1 == fstat(fd, &sbuf)) { + fprintf(stderr, "Failed to stat cache file for directory %s", path); + } else if (blocks != sbuf.st_size / STORE_BLOCK_SIZE) { + fprintf(stderr, "Cache file for directory %s is %" PRId64 " bytes, expected %" PRId64, path, sbuf.st_size, + blocks * static_cast<int64_t>(STORE_BLOCK_SIZE)); + } else { + diskok = 1; + } } } if (diskok) { int sector_size = sd->hw_sector_size; gdisks[gndisks] = new CacheDisk(); + if (check) + gdisks[gndisks]->read_only_p = true; gdisks[gndisks]->forced_volume_num = sd->forced_volume_num; if (sd->hash_base_string) gdisks[gndisks]->hash_base_string = ats_strdup(sd->hash_base_string); @@ -872,7 +912,8 @@ CacheProcessor::diskInitialized() d->header->vol_info[j].len, d->header->vol_info[j].free); } } - d->sync(); + if (!check) + d->sync(); } if (config_volumes.num_volumes == 0) { theCache = new Cache(); @@ -1087,7 +1128,8 @@ CacheProcessor::cacheInitialized() GLOBAL_CACHE_SET_DYN_STAT(cache_bytes_total_stat, total_cache_bytes); GLOBAL_CACHE_SET_DYN_STAT(cache_direntries_total_stat, total_direntries); GLOBAL_CACHE_SET_DYN_STAT(cache_direntries_used_stat, used_direntries); - dir_sync_init(); + if (!check) + dir_sync_init(); cache_init_ok = 1; } else Warning("cache unable to open any vols, disabled"); @@ -1098,7 +1140,7 @@ CacheProcessor::cacheInitialized() CacheProcessor::cache_ready = caches_ready; Note("cache enabled"); #ifdef CLUSTER_CACHE - if (!(start_internal_flags & PROCESSOR_RECONFIGURE)) { + if (!(start_internal_flags & (PROCESSOR_RECONFIGURE | PROCESSOR_CHECK))) { CacheContinuation::init(); clusterProcessor.start(); } http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d0d0afb9/iocore/cache/CacheDir.cc ---------------------------------------------------------------------- diff --git a/iocore/cache/CacheDir.cc b/iocore/cache/CacheDir.cc index 779c16b..24d0843 100644 --- a/iocore/cache/CacheDir.cc +++ b/iocore/cache/CacheDir.cc @@ -1247,6 +1247,15 @@ Ldone: goto Lrestart; } +namespace { + int + compare_ushort(void const* a, void const* b) + { + return *static_cast<unsigned short const*>(a) - *static_cast<unsigned short const*>(b); + } +} + + // // Check // @@ -1254,75 +1263,127 @@ Ldone: #define HIST_DEPTH 8 int Vol::dir_check(bool /* fix ATS_UNUSED */) // TODO: we should eliminate this parameter ? { - int hist[HIST_DEPTH + 1] = {0}; - int *shist = (int *)ats_malloc(segments * sizeof(int)); - memset(shist, 0, segments * sizeof(int)); + static int const SEGMENT_HISTOGRAM_WIDTH = 16; + int hist[SEGMENT_HISTOGRAM_WIDTH + 1] = { 0 }; + unsigned short chain_tag[MAX_ENTRIES_PER_SEGMENT]; + int32_t chain_mark[MAX_ENTRIES_PER_SEGMENT]; + uint64_t total_buckets = buckets * segments; + uint64_t total_entries = total_buckets * DIR_DEPTH; + int j; int stale = 0, full = 0, empty = 0; - int last = 0, free = 0; + int free = 0, head = 0; + + int max_chain_length = 0; + int64_t bytes_in_use = 0; + + printf("Stripe '[%s]'\n", hash_text.get()); + printf(" Directory Bytes: %" PRIu64 "\n", total_buckets * SIZEOF_DIR); + printf(" Segments: %d\n", segments); + printf(" Buckets: %" PRIu64 "\n", buckets); + printf(" Entries: %" PRIu64 "\n", total_entries); + for (int s = 0; s < segments; s++) { Dir *seg = dir_segment(s, this); + int seg_chain_max = 0; + int seg_empty = 0; + int seg_full = 0; + int seg_stale = 0; + int seg_bytes_in_use = 0; + int seg_dups = 0; + + ink_zero(chain_tag); + memset(chain_mark, -1, sizeof(chain_mark)); + for (int b = 0; b < buckets; b++) { - int h = 0; - Dir *e = dir_bucket(b, seg); - while (e) { - if (!dir_offset(e)) - empty++; - else { - h++; - if (!dir_valid(this, e)) - stale++; - else - full++; + Dir *root = dir_bucket(b, seg); + int h = 0; // chain length starting in this bucket + + // Walk the chain starting in this bucket + int chain_idx = 0; + int mark = 0; + for ( Dir* e = root ; e ; e = next_dir(e, seg) ) { + if (!dir_offset(e)) { // this should only happen on the first dir in a bucket + ++seg_empty; + } else { + int e_idx = e - seg; + ++h; + chain_tag[chain_idx++] = dir_tag(e); + if (chain_mark[e_idx] == mark) { + printf(" - Cycle of length %d detected for bucket %d\n", h, b); + } else if (chain_mark[e_idx] >= 0) { + printf(" - Entry %" PRIu64 " is in chain %d and %d", e - seg, chain_mark[e_idx], mark); + } else { + chain_mark[e_idx] = mark; + } + + if (dir_head(e)) ++head; + + if (!dir_valid(this, e)) { + ++seg_stale; + } else { + ++seg_full; + seg_bytes_in_use += dir_approx_size(e); + } } e = next_dir(e, seg); if (!e) break; } - if (h > HIST_DEPTH) - h = HIST_DEPTH; - hist[h]++; + + // Check for duplicates (identical tags in the same bucket). + if (h > 1) { + unsigned short last; + qsort(chain_tag, h, sizeof(chain_tag[0]), &compare_ushort); + last = chain_tag[0]; + for ( int k = 1 ; k < h ; ++k ) { + if (last == chain_tag[k]) ++seg_dups; + last = chain_tag[k]; + } + } + + ++hist[std::min(h, SEGMENT_HISTOGRAM_WIDTH)]; + seg_chain_max = std::max(seg_chain_max, h); } - int t = stale + full; - shist[s] = t - last; - last = t; + int seg_chains = buckets - seg_empty; + full += seg_full; + empty += seg_empty; + stale += seg_stale; free += dir_freelist_length(this, s); + max_chain_length = std::max(max_chain_length, seg_chain_max); + bytes_in_use += seg_bytes_in_use; + + printf(" - Segment-%d: full:%d stale:%d empty:%d bytes-used:%d chain-count:%d chain-max:%d chain-avg:%.2f chain-dups:%d\n" + , s, seg_full, seg_stale, seg_empty, seg_bytes_in_use + , seg_chains, seg_chain_max, seg_chains ? static_cast<float>(seg_full+seg_stale)/seg_chains : 0.0, seg_dups + ); } - int total = buckets * segments * DIR_DEPTH; - printf(" Directory for [%s]\n", hash_text.get()); - printf(" Bytes: %d\n", total * SIZEOF_DIR); - printf(" Segments: %" PRIu64 "\n", (uint64_t)segments); - printf(" Buckets: %" PRIu64 "\n", (uint64_t)buckets); - printf(" Entries: %d\n", total); - printf(" Full: %d\n", full); - printf(" Empty: %d\n", empty); - printf(" Stale: %d\n", stale); - printf(" Free: %d\n", free); - printf(" Bucket Fullness: "); - for (j = 0; j < HIST_DEPTH; j++) { - printf("%8d ", hist[j]); - if ((j % 4 == 3)) - printf("\n" - " "); - } - printf("\n"); - printf(" Segment Fullness: "); - for (j = 0; j < segments; j++) { - printf("%5d ", shist[j]); - if ((j % 5 == 4)) - printf("\n" - " "); - } - printf("\n"); - printf(" Freelist Fullness: "); - for (j = 0; j < segments; j++) { - printf("%5d ", dir_freelist_length(this, j)); - if ((j % 5 == 4)) - printf("\n" - " "); - } + + int chain_count = total_buckets - empty; + printf(" - Stripe: full:%d stale:%d empty:%d free:%d chain-count:%d chain-max:%d chain-avg:%.2f\n" + , full, stale, empty, free, chain_count, max_chain_length + , chain_count ? static_cast<float>(full + stale)/chain_count : 0 + ); + + printf(" Chain lengths: "); + for (j = 0; j < SEGMENT_HISTOGRAM_WIDTH; ++j) + printf(" %d=%d ", j, hist[j]); + printf(" %d>=%d\n", SEGMENT_HISTOGRAM_WIDTH, hist[SEGMENT_HISTOGRAM_WIDTH]); + + char tt[256]; + printf(" Total Size: %" PRIu64 "\n", (uint64_t)len); + printf(" Bytes in Use: %" PRIu64 "\n", bytes_in_use); + printf(" Objects: %d\n", head); + printf(" Average Size: %" PRIu64 "\n", head ? (bytes_in_use/head) : 0); + printf(" Write Position: %" PRIu64 "\n", (uint64_t) (header->write_pos - skip - start)); + printf(" Phase: %d\n", (int)!!header->phase); + ink_ctime_r(&header->create_time, tt); + tt[strlen(tt) - 1] = 0; + printf(" Create Time: %s\n", tt); + printf(" Sync Serial: %u\n", (unsigned int)header->sync_serial); + printf(" Write Serial: %u\n", (unsigned int)header->write_serial); printf("\n"); - ats_free(shist); + return 0; } http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d0d0afb9/iocore/cache/CacheDisk.cc ---------------------------------------------------------------------- diff --git a/iocore/cache/CacheDisk.cc b/iocore/cache/CacheDisk.cc index 0372d8d..e11acec 100644 --- a/iocore/cache/CacheDisk.cc +++ b/iocore/cache/CacheDisk.cc @@ -57,8 +57,15 @@ CacheDisk::open(char *s, off_t blocks, off_t askip, int ahw_sector_size, int fil header = (DiskHeader *)ats_memalign(ats_pagesize(), header_len); memset(header, 0, header_len); if (clear) { - SET_HANDLER(&CacheDisk::clearDone); - return clearDisk(); + if (read_only_p) { + fprintf(stderr, "Could not read disk header for disk %s", path); + SET_DISK_BAD(this); + SET_HANDLER(&CacheDisk::openDone); + return openDone(EVENT_IMMEDIATE, 0); + } else { + SET_HANDLER(&CacheDisk::clearDone); + return clearDisk(); + } } SET_HANDLER(&CacheDisk::openStart); @@ -142,8 +149,13 @@ CacheDisk::openStart(int event, void * /* data ATS_UNUSED */) // stripe isn't the short one, the split will be different this time. // Further - the size is encoded in to the disk hash so if the size changes, the data is effectively lost anyway. // So no space recovery. - // if (header->num_diskvol_blks == 1) - // header->vol_info[0].len += delta_3_2; +// if (header->num_diskvol_blks == 1) +// header->vol_info[0].len += delta_3_2; + } else if (read_only_p) { + fprintf(stderr, "Disk header is different than expected for disk %s", path); + SET_DISK_BAD(this); + SET_HANDLER(&CacheDisk::openDone); + return EVENT_DONE; } else { Warning("disk header different for disk %s: clearing the disk", path); SET_HANDLER(&CacheDisk::clearDone); http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d0d0afb9/iocore/cache/I_Cache.h ---------------------------------------------------------------------- diff --git a/iocore/cache/I_Cache.h b/iocore/cache/I_Cache.h index af99d30..857f312 100644 --- a/iocore/cache/I_Cache.h +++ b/iocore/cache/I_Cache.h @@ -152,8 +152,9 @@ struct CacheProcessor : public Processor { static volatile uint32_t cache_ready; static volatile int initialized; static volatile int start_done; - static int clear; - static int fix; + static bool clear; + static bool fix; + static bool check; static int start_internal_flags; static int auto_clear_flag; http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d0d0afb9/iocore/cache/P_CacheDir.h ---------------------------------------------------------------------- diff --git a/iocore/cache/P_CacheDir.h b/iocore/cache/P_CacheDir.h index 0a31c32..a4aef0c 100644 --- a/iocore/cache/P_CacheDir.h +++ b/iocore/cache/P_CacheDir.h @@ -44,6 +44,8 @@ struct CacheVC; #define MAX_DIR_SEGMENTS (32 * (1 << 16)) #define DIR_DEPTH 4 +#define MAX_ENTRIES_PER_SEGMENT (1 << 16) +#define MAX_BUCKETS_PER_SEGMENT (MAX_ENTRIES_PER_SEGMENT / DIR_DEPTH) #define DIR_SIZE_WIDTH 6 #define DIR_BLOCK_SIZES 4 #define DIR_BLOCK_SHIFT(_i) (3 * (_i)) http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d0d0afb9/iocore/cache/P_CacheDisk.h ---------------------------------------------------------------------- diff --git a/iocore/cache/P_CacheDisk.h b/iocore/cache/P_CacheDisk.h index 8b51de2..7b470a7 100644 --- a/iocore/cache/P_CacheDisk.h +++ b/iocore/cache/P_CacheDisk.h @@ -96,6 +96,7 @@ struct CacheDisk : public Continuation { DiskVol *free_blocks; int num_errors; int cleared; + bool read_only_p; // Extra configuration values int forced_volume_num; ///< Volume number for this disk. @@ -103,7 +104,8 @@ struct CacheDisk : public Continuation { CacheDisk() : Continuation(new_ProxyMutex()), header(NULL), path(NULL), header_len(0), len(0), start(0), skip(0), num_usable_blocks(0), - fd(-1), free_space(0), wasted_space(0), disk_vols(NULL), free_blocks(NULL), num_errors(0), cleared(0), forced_volume_num(-1) + fd(-1), free_space(0), wasted_space(0), disk_vols(NULL), free_blocks(NULL), num_errors(0), cleared(0), read_only_p(false), + forced_volume_num(-1) { } http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d0d0afb9/proxy/Main.cc ---------------------------------------------------------------------- diff --git a/proxy/Main.cc b/proxy/Main.cc index ef93db0..98d6dba 100644 --- a/proxy/Main.cc +++ b/proxy/Main.cc @@ -132,6 +132,10 @@ int http_accept_file_descriptor = NO_FD; static char core_file[255] = ""; static bool enable_core_file_p = false; // Enable core file dump? int command_flag = DEFAULT_COMMAND_FLAG; +int command_index = -1; +bool command_valid = false; +// Commands that have special processing / requirements. +static char const *CMD_VERIFY_CONFIG = "verify_config"; #if TS_HAS_TESTS static char regression_test[1024] = ""; #endif @@ -546,64 +550,39 @@ CB_After_Cache_Init() } } -struct CmdCacheCont : public Continuation { - int cache_fix; - - int - ClearEvent(int event, Event *e) - { - (void)event; - (void)e; - if (cacheProcessor.IsCacheEnabled() == CACHE_INITIALIZED) { - Note("CLEAR, succeeded"); - _exit(0); - } else if (cacheProcessor.IsCacheEnabled() == CACHE_INIT_FAILED) { - Note("unable to open Cache, CLEAR failed"); - _exit(1); - } - return EVENT_CONT; +void +CB_cmd_cache_clear() +{ + if (cacheProcessor.IsCacheEnabled() == CACHE_INITIALIZED) { + Note("CLEAR, succeeded"); + _exit(0); + } else if (cacheProcessor.IsCacheEnabled() == CACHE_INIT_FAILED) { + Note("unable to open Cache, CLEAR failed"); + _exit(1); } +} - int - CheckEvent(int event, Event *e) - { - (void)event; - (void)e; - int res = 0; - Note("Cache Directory"); - if (cacheProcessor.IsCacheEnabled() == CACHE_INITIALIZED) { - res = cacheProcessor.dir_check(cache_fix) < 0 || res; - - Note("Cache"); - res = cacheProcessor.db_check(cache_fix) < 0 || res; - - cacheProcessor.stop(); - - const char *n = cache_fix ? "REPAIR" : "CHECK"; - - if (res) { - printf("\n%s failed", n); - _exit(1); - } else { - printf("\n%s succeeded\n", n); - _exit(0); - } - } else if (cacheProcessor.IsCacheEnabled() == CACHE_INIT_FAILED) { - Note("unable to open Cache, Check failed"); +void +CB_cmd_cache_check() +{ + int res = 0; + if (cacheProcessor.IsCacheEnabled() == CACHE_INITIALIZED) { + res = cacheProcessor.dir_check(false) < 0 || res; + cacheProcessor.stop(); + const char *n = "CHECK"; + + if (res) { + printf("\n%s failed", n); _exit(1); + } else { + printf("\n%s succeeded\n", n); + _exit(0); } - return EVENT_CONT; - } - - CmdCacheCont(bool check, bool fix = false) : Continuation(new_ProxyMutex()) - { - cache_fix = fix; - if (check) - SET_HANDLER(&CmdCacheCont::CheckEvent); - else - SET_HANDLER(&CmdCacheCont::ClearEvent); + } else if (cacheProcessor.IsCacheEnabled() == CACHE_INIT_FAILED) { + Note("unable to open Cache, Check failed"); + _exit(1); } -}; +} static int cmd_check_internal(char * /* cmd ATS_UNUSED */, bool fix = false) @@ -614,6 +593,7 @@ cmd_check_internal(char * /* cmd ATS_UNUSED */, bool fix = false) hostdb_current_interval = (ink_get_based_hrtime() / HRTIME_MINUTE); +#if 0 printf("Host Database\n"); HostDBCache hd; if (hd.start(fix) < 0) { @@ -622,13 +602,13 @@ cmd_check_internal(char * /* cmd ATS_UNUSED */, bool fix = false) } hd.check("hostdb.config", fix); hd.reset(); +#endif - if (cacheProcessor.start() < 0) { + cacheProcessor.set_after_init_callback(&CB_cmd_cache_check); + if (cacheProcessor.start_internal(PROCESSOR_CHECK) < 0) { printf("\nbad cache configuration, %s failed\n", n); return CMD_FAILED; } - eventProcessor.schedule_every(new CmdCacheCont(true, fix), HRTIME_SECONDS(1)); - return CMD_IN_PROGRESS; } @@ -689,11 +669,11 @@ cmd_clear(char *cmd) if (c_all || c_cache) { Note("Clearing Cache"); + cacheProcessor.set_after_init_callback(&CB_cmd_cache_clear); if (cacheProcessor.start_internal(PROCESSOR_RECONFIGURE) < 0) { Note("unable to open Cache, CLEAR failed"); return CMD_FAILED; } - eventProcessor.schedule_every(new CmdCacheCont(false), HRTIME_SECONDS(1)); return CMD_IN_PROGRESS; } @@ -770,6 +750,7 @@ static const struct CMD { const char *d; // description (part of a line) const char *h; // help string (multi-line) int (*f)(char *); + bool no_process_lock; /// If set this command doesn't need a process level lock. } commands[] = { {"list", "List cache configuration", "LIST\n" "\n" @@ -786,7 +767,7 @@ static const struct CMD { "CHECK does not make any changes to the data stored in\n" "the cache. CHECK requires a scan of the contents of the\n" "cache and may take a long time for large caches.\n", - cmd_check}, + cmd_check, true}, {"clear", "Clear the entire cache", "CLEAR\n" "\n" "FORMAT: clear\n" @@ -810,12 +791,12 @@ static const struct CMD { "Clear the entire hostdb cache. All host name resolution\n" "information is lost.\n", cmd_clear}, - {"verify_config", "Verify the config", "\n" - "\n" - "FORMAT: verify_config\n" - "\n" - "Load the config and verify traffic_server comes up correctly. \n", - cmd_verify}, + {CMD_VERIFY_CONFIG, "Verify the config", "\n" + "\n" + "FORMAT: verify_config\n" + "\n" + "Load the config and verify traffic_server comes up correctly. \n", + cmd_verify, true}, {"help", "Obtain a short description of a command (e.g. 'help clear')", "HELP\n" "\n" "FORMAT: help [command_name]\n" @@ -828,14 +809,14 @@ static const struct CMD { }; static int -cmd_index(char *p) +find_cmd_index(char const *p) { p += strspn(p, " \t"); for (unsigned c = 0; c < countof(commands); c++) { - const char *l = commands[c].n; + char const *l = commands[c].n; while (l) { - const char *s = strchr(l, '/'); - char *e = strpbrk(p, " \t\n"); + char const *s = strchr(l, '/'); + char const *e = strpbrk(p, " \t\n"); int len = s ? s - l : strlen(l); int lenp = e ? e - p : strlen(p); if ((len == lenp) && !strncasecmp(p, l, len)) @@ -858,7 +839,7 @@ cmd_help(char *cmd) } } else { int i; - if ((i = cmd_index(cmd)) < 0) { + if ((i = find_cmd_index(cmd)) < 0) { printf("\nno help found for: %s\n", cmd); return CMD_FAILED; } @@ -892,14 +873,11 @@ check_fd_limit() static int cmd_mode() { - if (*command_string) { - int c = cmd_index(command_string); - if (c >= 0) { - return commands[c].f(command_string); - } else { - Warning("unrecognized command: '%s'", command_string); - return CMD_FAILED; // in error - } + if (command_index >= 0) { + return commands[command_index].f(command_string); + } else if (*command_string) { + Warning("unrecognized command: '%s'", command_string); + return CMD_FAILED; // in error } else { printf("\n"); printf("WARNING\n"); @@ -1429,6 +1407,14 @@ main(int /* argc ATS_UNUSED */, const char **argv) process_args(&appVersionInfo, argument_descriptions, countof(argument_descriptions), argv); command_flag = command_flag || *command_string; + command_index = find_cmd_index(command_string); + command_valid = command_flag && command_index >= 0; + + // Specific validity checks. + if (*conf_dir && command_index != find_cmd_index(CMD_VERIFY_CONFIG)) { + fprintf(stderr, "-D option can only be used with the %s command\n", CMD_VERIFY_CONFIG); + _exit(1); + } // Set stdout/stdin to be unbuffered setbuf(stdout, NULL); @@ -1456,16 +1442,10 @@ main(int /* argc ATS_UNUSED */, const char **argv) // Local process manager initialize_process_manager(); - if ((*command_string) && (cmd_index(command_string) == cmd_index((char *)"verify_config"))) { - fprintf(stderr, "\n\n skip lock check for %s \n\n", command_string); - } else { - if (*conf_dir) { - fprintf(stderr, "-D option should be used with -Cverify_config\n"); - _exit(0); - } - // Ensure only one copy of traffic server is running + // Ensure only one copy of traffic server is running, unless it's a command + // that doesn't require a lock. + if (!(command_valid && commands[command_index].no_process_lock)) check_lockfile(); - } // Set the core limit for the process init_core_size();
