| /** @file |
| |
| A brief file description |
| |
| @section license License |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| #include "P_Cache.h" |
| |
| #include "Show.h" |
| #include "I_Tasks.h" |
| |
| struct ShowCacheInternal : public ShowCont { |
| int vol_index = 0; |
| int seg_index = 0; |
| CacheKey show_cache_key; |
| CacheVC *cache_vc = nullptr; |
| |
| int showMain(int event, Event *e); |
| int showEvacuations(int event, Event *e); |
| int showVolEvacuations(int event, Event *e); |
| int showVolumes(int event, Event *e); |
| int showVolVolumes(int event, Event *e); |
| int showSegments(int event, Event *e); |
| int showSegSegment(int event, Event *e); |
| #ifdef CACHE_STAT_PAGES |
| int showConnections(int event, Event *e); |
| int showVolConnections(int event, Event *e); |
| #endif |
| |
| ShowCacheInternal(Continuation *c, HTTPHdr *h) : ShowCont(c, h) { SET_HANDLER(&ShowCacheInternal::showMain); } |
| |
| ~ShowCacheInternal() override {} |
| }; |
| extern ShowCacheInternal *theshowcacheInternal; |
| Action *register_ShowCacheInternal(Continuation *c, HTTPHdr *h); |
| |
| extern Vol **gvol; |
| |
| // Stat Pages |
| ShowCacheInternal *theshowcacheInternal = nullptr; |
| |
| #define STREQ_PREFIX(_x, _s) (!strncasecmp(_x, _s, sizeof(_s) - 1)) |
| #define STREQ_LEN_PREFIX(_x, _l, _s) (path_len < sizeof(_s) && !strncasecmp(_x, _s, sizeof(_s) - 1)) |
| |
| Action * |
| register_ShowCacheInternal(Continuation *c, HTTPHdr *h) |
| { |
| theshowcacheInternal = new ShowCacheInternal(c, h); |
| URL *u = h->url_get(); |
| |
| int path_len; |
| const char *path = u->path_get(&path_len); |
| |
| if (!path) { |
| } |
| #ifdef CACHE_STAT_PAGES |
| else if (STREQ_LEN_PREFIX(path, path_len, "connections")) { |
| SET_CONTINUATION_HANDLER(theshowcacheInternal, &ShowCacheInternal::showConnections); |
| } |
| #endif |
| else if (STREQ_PREFIX(path, "evacuations")) { |
| SET_CONTINUATION_HANDLER(theshowcacheInternal, &ShowCacheInternal::showEvacuations); |
| } else if (STREQ_PREFIX(path, "volumes")) { |
| SET_CONTINUATION_HANDLER(theshowcacheInternal, &ShowCacheInternal::showVolumes); |
| } |
| |
| if (theshowcacheInternal->mutex->thread_holding) { |
| CONT_SCHED_LOCK_RETRY(theshowcacheInternal); |
| } else { |
| eventProcessor.schedule_imm(theshowcacheInternal, ET_TASK); |
| } |
| return &theshowcacheInternal->action; |
| } |
| |
| int |
| ShowCacheInternal::showMain(int event, Event *e) |
| { |
| CHECK_SHOW(begin("Cache")); |
| #ifdef CACHE_STAT_PAGES |
| CHECK_SHOW(show("<H3>Show <A HREF=\"./connections\">Connections</A></H3>\n" |
| "<H3>Show <A HREF=\"./evacuations\">Evacuations</A></H3>\n" |
| "<H3>Show <A HREF=\"./volumes\">Volumes</A></H3>\n")); |
| #else |
| CHECK_SHOW(show("<H3>Show <A HREF=\"./evacuations\">Evacuations</A></H3>\n" |
| "<H3>Show <A HREF=\"./volumes\">Volumes</A></H3>\n")); |
| #endif |
| return complete(event, e); |
| } |
| |
| #ifdef CACHE_STAT_PAGES |
| int |
| ShowCacheInternal::showConnections(int event, Event *e) |
| { |
| CHECK_SHOW(begin("Cache VConnections")); |
| CHECK_SHOW(show("<H3>Cache Connections</H3>\n" |
| "<table border=1><tr>" |
| "<th>Operation</th>" |
| "<th>Volume</th>" |
| "<th>URL/Hash</th>" |
| "<th>Bytes Done</th>" |
| "<th>Total Bytes</th>" |
| "<th>Bytes Todo</th>" |
| "</tr>\n")); |
| |
| SET_HANDLER(&ShowCacheInternal::showVolConnections); |
| CONT_SCHED_LOCK_RETRY_RET(this); |
| } |
| |
| int |
| ShowCacheInternal::showVolConnections(int event, Event *e) |
| { |
| CACHE_TRY_LOCK(lock, gvol[vol_index]->mutex, mutex->thread_holding); |
| if (!lock) { |
| CONT_SCHED_LOCK_RETRY_RET(this); |
| } |
| for (CacheVC *vc = (CacheVC *)gvol[vol_index]->stat_cache_vcs.head; vc; vc = vc->stat_link.next) { |
| char nbytes[60], todo[60], url[81092]; |
| int ib = 0, xd = 0; |
| URL uu; |
| |
| SCOPED_MUTEX_LOCK(lock2, vc->mutex, mutex->thread_holding); |
| // if vc is closed ignore - Ramki 08/30/2000 |
| if (vc->closed == 1) |
| continue; |
| sprintf(nbytes, "%d", vc->vio.nbytes); |
| sprintf(todo, "%d", vc->vio.ntodo()); |
| |
| if (vc->f.frag_type == CACHE_FRAG_TYPE_HTTP && vc->request.valid()) { |
| URL *u = vc->request.url_get(&uu); |
| u->print(url, 8000, &ib, &xd); |
| url[ib] = 0; |
| } else if (vc->alternate.valid()) { |
| URL *u = vc->alternate.request_url_get(&uu); |
| u->print(url, 8000, &ib, &xd); |
| url[ib] = 0; |
| } else |
| vc->key.string(url); |
| CHECK_SHOW(show("<tr>" |
| "<td>%s</td>" // operation |
| "<td>%s</td>" // Vol |
| "<td>%s</td>" // URL/Hash |
| "<td>%d</td>" |
| "<td>%s</td>" |
| "<td>%s</td>" |
| "</tr>\n", |
| ((vc->vio.op == VIO::READ) ? "Read" : "Write"), vc->vol->hash_id, url, vc->vio.ndone, |
| vc->vio.nbytes == INT64_MAX ? "all" : nbytes, vc->vio.nbytes == INT64_MAX ? "all" : todo)); |
| } |
| vol_index++; |
| if (vol_index < gnvol) |
| CONT_SCHED_LOCK_RETRY(this); |
| else { |
| CHECK_SHOW(show("</table>\n")); |
| return complete(event, e); |
| } |
| return EVENT_CONT; |
| } |
| |
| #endif |
| |
| int |
| ShowCacheInternal::showEvacuations(int event, Event *e) |
| { |
| CHECK_SHOW(begin("Cache Pending Evacuations")); |
| CHECK_SHOW(show("<H3>Cache Evacuations</H3>\n" |
| "<table border=1><tr>" |
| "<th>Offset</th>" |
| "<th>Estimated Size</th>" |
| "<th>Reader Count</th>" |
| "<th>Done</th>" |
| "</tr>\n")); |
| |
| SET_HANDLER(&ShowCacheInternal::showVolEvacuations); |
| CONT_SCHED_LOCK_RETRY_RET(this); |
| } |
| |
| int |
| ShowCacheInternal::showVolEvacuations(int event, Event *e) |
| { |
| Vol *p = gvol[vol_index]; |
| CACHE_TRY_LOCK(lock, p->mutex, mutex->thread_holding); |
| if (!lock.is_locked()) { |
| CONT_SCHED_LOCK_RETRY_RET(this); |
| } |
| |
| EvacuationBlock *b; |
| int last = (p->len - (p->start - p->skip)) / EVACUATION_BUCKET_SIZE; |
| for (int i = 0; i < last; i++) { |
| for (b = p->evacuate[i].head; b; b = b->link.next) { |
| char offset[60]; |
| sprintf(offset, "%" PRIu64 "", static_cast<uint64_t>(p->vol_offset(&b->dir))); |
| CHECK_SHOW(show("<tr>" |
| "<td>%s</td>" // offset |
| "<td>%d</td>" // estimated size |
| "<td>%d</td>" // reader count |
| "<td>%s</td>" // done |
| "</tr>\n", |
| offset, (int)dir_approx_size(&b->dir), b->readers, b->f.done ? "yes" : "no")); |
| } |
| } |
| vol_index++; |
| if (vol_index < gnvol) { |
| CONT_SCHED_LOCK_RETRY(this); |
| } else { |
| CHECK_SHOW(show("</table>\n")); |
| return complete(event, e); |
| } |
| return EVENT_CONT; |
| } |
| |
| int |
| ShowCacheInternal::showVolumes(int event, Event *e) |
| { |
| CHECK_SHOW(begin("Cache Volumes")); |
| CHECK_SHOW(show("<H3>Cache Volumes</H3>\n" |
| "<table border=1><tr>" |
| "<th>ID</th>" |
| "<th>Blocks</th>" |
| "<th>Directory Entries</th>" |
| "<th>Write Position</th>" |
| "<th>Write Agg Todo</th>" |
| "<th>Write Agg Todo Size</th>" |
| "<th>Write Agg Done</th>" |
| "<th>Phase</th>" |
| "<th>Create Time</th>" |
| "<th>Sync Serial</th>" |
| "<th>Write Serial</th>" |
| "</tr>\n")); |
| |
| SET_HANDLER(&ShowCacheInternal::showVolVolumes); |
| CONT_SCHED_LOCK_RETRY_RET(this); |
| } |
| |
| int |
| ShowCacheInternal::showVolVolumes(int event, Event *e) |
| { |
| Vol *p = gvol[vol_index]; |
| CACHE_TRY_LOCK(lock, p->mutex, mutex->thread_holding); |
| if (!lock.is_locked()) { |
| CONT_SCHED_LOCK_RETRY_RET(this); |
| } |
| |
| char ctime[256]; |
| ink_ctime_r(&p->header->create_time, ctime); |
| ctime[strlen(ctime) - 1] = 0; |
| int agg_todo = 0; |
| int agg_done = p->agg_buf_pos; |
| CacheVC *c = nullptr; |
| for (c = p->agg.head; c; c = (CacheVC *)c->link.next) { |
| agg_todo++; |
| } |
| CHECK_SHOW(show("<tr>" |
| "<td>%s</td>" // ID |
| "<td>%" PRId64 "</td>" // blocks |
| "<td>%" PRId64 "</td>" // directory entries |
| "<td>%" PRId64 "</td>" // write position |
| "<td>%d</td>" // write agg to do |
| "<td>%d</td>" // write agg to do size |
| "<td>%d</td>" // write agg done |
| "<td>%d</td>" // phase |
| "<td>%s</td>" // create time |
| "<td>%u</td>" // sync serial |
| "<td>%u</td>" // write serial |
| "</tr>\n", |
| p->hash_text.get(), (uint64_t)((p->len - (p->start - p->skip)) / CACHE_BLOCK_SIZE), |
| (uint64_t)(p->buckets * DIR_DEPTH * p->segments), |
| (uint64_t)((p->header->write_pos - p->start) / CACHE_BLOCK_SIZE), agg_todo, p->agg_todo_size, agg_done, |
| p->header->phase, ctime, p->header->sync_serial, p->header->write_serial)); |
| CHECK_SHOW(show("</table>\n")); |
| SET_HANDLER(&ShowCacheInternal::showSegments); |
| return showSegments(event, e); |
| } |
| |
| int |
| ShowCacheInternal::showSegments(int event, Event *e) |
| { |
| CHECK_SHOW(show("<H3>Cache Volume Segments</H3>\n" |
| "<table border=1><tr>" |
| "<th>Free</th>" |
| "<th>Used</th>" |
| "<th>Empty</th>" |
| "<th>Valid</th>" |
| "<th>Agg Valid</th>" |
| "<th>Avg Size</th>" |
| "</tr>\n")); |
| |
| SET_HANDLER(&ShowCacheInternal::showSegSegment); |
| seg_index = 0; |
| CONT_SCHED_LOCK_RETRY_RET(this); |
| } |
| |
| int |
| ShowCacheInternal::showSegSegment(int event, Event *e) |
| { |
| Vol *p = gvol[vol_index]; |
| CACHE_TRY_LOCK(lock, p->mutex, mutex->thread_holding); |
| if (!lock.is_locked()) { |
| CONT_SCHED_LOCK_RETRY_RET(this); |
| } |
| int free = 0, used = 0, empty = 0, valid = 0, agg_valid = 0, avg_size = 0; |
| dir_segment_accounted(seg_index, p, 0, &free, &used, &empty, &valid, &agg_valid, &avg_size); |
| CHECK_SHOW(show("<tr>" |
| "<td>%d</td>" |
| "<td>%d</td>" |
| "<td>%d</td>" |
| "<td>%d</td>" |
| "<td>%d</td>" |
| "<td>%d</td>" |
| "</tr>\n", |
| free, used, empty, valid, agg_valid, avg_size)); |
| seg_index++; |
| if (seg_index < p->segments) { |
| CONT_SCHED_LOCK_RETRY(this); |
| } else { |
| CHECK_SHOW(show("</table>\n")); |
| seg_index = 0; |
| vol_index++; |
| if (vol_index < gnvol) { |
| CONT_SCHED_LOCK_RETRY(this); |
| } else { |
| return complete(event, e); |
| } |
| } |
| return EVENT_CONT; |
| } |