blob: 531797cd9fa6c41a84dbb34d0ac04e3ee151f0ac [file] [log] [blame]
/** @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;
}