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
00026 #include "Show.h"
00027 #include "I_Tasks.h"
00028
00029 struct ShowCacheInternal: public ShowCont
00030 {
00031 int vol_index;
00032 int seg_index;
00033 CacheKey show_cache_key;
00034 CacheVC *cache_vc;
00035
00036
00037 int showMain(int event, Event * e);
00038 int showEvacuations(int event, Event * e);
00039 int showVolEvacuations(int event, Event * e);
00040 int showVolumes(int event, Event * e);
00041 int showVolVolumes(int event, Event * e);
00042 int showSegments(int event, Event * e);
00043 int showSegSegment(int event, Event * e);
00044 #ifdef CACHE_STAT_PAGES
00045 int showConnections(int event, Event * e);
00046 int showVolConnections(int event, Event * e);
00047 #endif
00048
00049 ShowCacheInternal(Continuation * c, HTTPHdr * h)
00050 : ShowCont(c, h), vol_index(0), seg_index(0)
00051 {
00052 SET_HANDLER(&ShowCacheInternal::showMain);
00053 }
00054
00055 ~ShowCacheInternal() {
00056 }
00057
00058 };
00059 extern ShowCacheInternal *theshowcacheInternal;
00060 Action *register_ShowCacheInternal(Continuation * c, HTTPHdr * h);
00061
00062
00063
00064
00065 extern Vol **gvol;
00066 extern volatile int gnvol;
00067
00068
00069
00070 ShowCacheInternal *theshowcacheInternal = NULL;
00071
00072
00073 #define STREQ_PREFIX(_x,_s) (!strncasecmp(_x,_s,sizeof(_s)-1))
00074 #define STREQ_LEN_PREFIX(_x,_l,_s) (path_len < sizeof(_s) && !strncasecmp(_x,_s,sizeof(_s)-1))
00075
00076
00077 Action *
00078 register_ShowCacheInternal(Continuation * c, HTTPHdr * h)
00079 {
00080 theshowcacheInternal = new ShowCacheInternal(c, h);
00081 URL *u = h->url_get();
00082
00083 int path_len;
00084 const char *path = u->path_get(&path_len);
00085
00086 if (!path) {
00087 }
00088 #ifdef CACHE_STAT_PAGES
00089 else if (STREQ_LEN_PREFIX(path, path_len, "connections")) {
00090 SET_CONTINUATION_HANDLER(theshowcacheInternal, &ShowCacheInternal::showConnections);
00091 }
00092 #endif
00093 else if (STREQ_PREFIX(path, "evacuations")) {
00094 SET_CONTINUATION_HANDLER(theshowcacheInternal, &ShowCacheInternal::showEvacuations);
00095 } else if (STREQ_PREFIX(path, "volumes")) {
00096 SET_CONTINUATION_HANDLER(theshowcacheInternal, &ShowCacheInternal::showVolumes);
00097 }
00098
00099 if (theshowcacheInternal->mutex->thread_holding)
00100 CONT_SCHED_LOCK_RETRY(theshowcacheInternal);
00101 else
00102 eventProcessor.schedule_imm(theshowcacheInternal, ET_TASK);
00103 return &theshowcacheInternal->action;
00104 }
00105
00106
00107 int
00108 ShowCacheInternal::showMain(int event, Event * e)
00109 {
00110 CHECK_SHOW(begin("Cache"));
00111 #ifdef CACHE_STAT_PAGES
00112 CHECK_SHOW(show("<H3>Show <A HREF=\"./connections\">Connections</A></H3>\n"
00113 "<H3>Show <A HREF=\"./evacuations\">Evacuations</A></H3>\n"
00114 "<H3>Show <A HREF=\"./volumes\">Volumes</A></H3>\n"));
00115 #else
00116 CHECK_SHOW(show("<H3>Show <A HREF=\"./evacuations\">Evacuations</A></H3>\n"
00117 "<H3>Show <A HREF=\"./volumes\">Volumes</A></H3>\n"));
00118 #endif
00119 return complete(event, e);
00120 }
00121
00122 #ifdef CACHE_STAT_PAGES
00123 int
00124 ShowCacheInternal::showConnections(int event, Event * e)
00125 {
00126 CHECK_SHOW(begin("Cache VConnections"));
00127 CHECK_SHOW(show("<H3>Cache Connections</H3>\n"
00128 "<table border=1><tr>"
00129 "<th>Operation</th>"
00130 "<th>Volume</th>"
00131 "<th>URL/Hash</th>" "<th>Bytes Done</th>" "<th>Total Bytes</th>" "<th>Bytes Todo</th>" "</tr>\n"));
00132
00133 SET_HANDLER(&ShowCacheInternal::showVolConnections);
00134 CONT_SCHED_LOCK_RETRY_RET(this);
00135 }
00136
00137
00138 int
00139 ShowCacheInternal::showVolConnections(int event, Event * e)
00140 {
00141 CACHE_TRY_LOCK(lock, gvol[vol_index]->mutex, mutex->thread_holding);
00142 if (!lock) {
00143 CONT_SCHED_LOCK_RETRY_RET(this);
00144 }
00145 for (CacheVC * vc = (CacheVC *) gvol[vol_index]->stat_cache_vcs.head; vc; vc = vc->stat_link.next) {
00146
00147 char nbytes[60], todo[60], url[81092];
00148 int ib = 0, xd = 0;
00149 URL uu;
00150
00151 MUTEX_LOCK(lock2, vc->mutex, mutex->thread_holding);
00152
00153 if (vc->closed == 1)
00154 continue;
00155 sprintf(nbytes, "%d", vc->vio.nbytes);
00156 sprintf(todo, "%d", vc->vio.ntodo());
00157
00158 if (vc->f.frag_type == CACHE_FRAG_TYPE_HTTP && vc->request.valid()) {
00159 URL *u = vc->request.url_get(&uu);
00160 u->print(url, 8000, &ib, &xd);
00161 url[ib] = 0;
00162 } else if (vc->alternate.valid()) {
00163 URL *u = vc->alternate.request_url_get(&uu);
00164 u->print(url, 8000, &ib, &xd);
00165 url[ib] = 0;
00166 } else
00167 vc->key.string(url);
00168 CHECK_SHOW(show("<tr>" "<td>%s</td>"
00169 "<td>%s</td>"
00170 "<td>%s</td>"
00171 "<td>%d</td>"
00172 "<td>%s</td>"
00173 "<td>%s</td>"
00174 "</tr>\n",
00175 ((vc->vio.op == VIO::READ) ? "Read" : "Write"),
00176 vc->vol->hash_id,
00177 url,
00178 vc->vio.ndone,
00179 vc->vio.nbytes == INT64_MAX ? "all" : nbytes, vc->vio.nbytes == INT64_MAX ? "all" : todo));
00180 }
00181 vol_index++;
00182 if (vol_index < gnvol)
00183 CONT_SCHED_LOCK_RETRY(this);
00184 else {
00185 CHECK_SHOW(show("</table>\n"));
00186 return complete(event, e);
00187 }
00188 return EVENT_CONT;
00189 }
00190
00191 #endif
00192
00193
00194 int
00195 ShowCacheInternal::showEvacuations(int event, Event * e)
00196 {
00197 CHECK_SHOW(begin("Cache Pending Evacuations"));
00198 CHECK_SHOW(show("<H3>Cache Evacuations</H3>\n"
00199 "<table border=1><tr>"
00200 "<th>Offset</th>" "<th>Estimated Size</th>" "<th>Reader Count</th>" "<th>Done</th>" "</tr>\n"));
00201
00202 SET_HANDLER(&ShowCacheInternal::showVolEvacuations);
00203 CONT_SCHED_LOCK_RETRY_RET(this);
00204 }
00205
00206
00207 int
00208 ShowCacheInternal::showVolEvacuations(int event, Event * e)
00209 {
00210 Vol *p = gvol[vol_index];
00211 CACHE_TRY_LOCK(lock, p->mutex, mutex->thread_holding);
00212 if (!lock)
00213 CONT_SCHED_LOCK_RETRY_RET(this);
00214
00215 EvacuationBlock *b;
00216 int last = (p->len - (p->start - p->skip)) / EVACUATION_BUCKET_SIZE;
00217 for (int i = 0; i < last; i++) {
00218 for (b = p->evacuate[i].head; b; b = b->link.next) {
00219 char offset[60];
00220 sprintf(offset, "%" PRIu64 "", (uint64_t) vol_offset(p, &b->dir));
00221 CHECK_SHOW(show("<tr>" "<td>%s</td>"
00222 "<td>%d</td>"
00223 "<td>%d</td>"
00224 "<td>%s</td>"
00225 "</tr>\n", offset, (int) dir_approx_size(&b->dir), b->readers, b->f.done ? "yes" : "no"));
00226 }
00227 }
00228 vol_index++;
00229 if (vol_index < gnvol)
00230 CONT_SCHED_LOCK_RETRY(this);
00231 else {
00232 CHECK_SHOW(show("</table>\n"));
00233 return complete(event, e);
00234 }
00235 return EVENT_CONT;
00236 }
00237
00238 int
00239 ShowCacheInternal::showVolumes(int event, Event * e)
00240 {
00241 CHECK_SHOW(begin("Cache Volumes"));
00242 CHECK_SHOW(show("<H3>Cache Volumes</H3>\n"
00243 "<table border=1><tr>"
00244 "<th>ID</th>"
00245 "<th>Blocks</th>"
00246 "<th>Directory Entries</th>"
00247 "<th>Write Position</th>"
00248 "<th>Write Agg Todo</th>"
00249 "<th>Write Agg Todo Size</th>"
00250 "<th>Write Agg Done</th>"
00251 "<th>Phase</th>" "<th>Create Time</th>" "<th>Sync Serial</th>" "<th>Write Serial</th>" "</tr>\n"));
00252
00253 SET_HANDLER(&ShowCacheInternal::showVolVolumes);
00254 CONT_SCHED_LOCK_RETRY_RET(this);
00255 }
00256
00257
00258 int
00259 ShowCacheInternal::showVolVolumes(int event, Event * e)
00260 {
00261 Vol *p = gvol[vol_index];
00262 CACHE_TRY_LOCK(lock, p->mutex, mutex->thread_holding);
00263 if (!lock)
00264 CONT_SCHED_LOCK_RETRY_RET(this);
00265
00266 char ctime[256];
00267 ink_ctime_r(&p->header->create_time, ctime);
00268 ctime[strlen(ctime) - 1] = 0;
00269 int agg_todo = 0;
00270 int agg_done = p->agg_buf_pos;
00271 CacheVC *c = 0;
00272 for (c = p->agg.head; c; c = (CacheVC *) c->link.next)
00273 agg_todo++;
00274 CHECK_SHOW(show("<tr>" "<td>%s</td>"
00275 "<td>%" PRId64 "</td>"
00276 "<td>%" PRId64 "</td>"
00277 "<td>%" PRId64 "</td>"
00278 "<td>%d</td>"
00279 "<td>%d</td>"
00280 "<td>%d</td>"
00281 "<td>%d</td>"
00282 "<td>%s</td>"
00283 "<td>%u</td>"
00284 "<td>%u</td>"
00285 "</tr>\n",
00286 p->hash_text.get(),
00287 (uint64_t)((p->len - (p->start - p->skip)) / CACHE_BLOCK_SIZE),
00288 (uint64_t)(p->buckets * DIR_DEPTH * p->segments),
00289 (uint64_t)((p->header->write_pos - p->start) / CACHE_BLOCK_SIZE),
00290 agg_todo,
00291 p->agg_todo_size,
00292 agg_done, p->header->phase, ctime, p->header->sync_serial, p->header->write_serial));
00293 CHECK_SHOW(show("</table>\n"));
00294 SET_HANDLER(&ShowCacheInternal::showSegments);
00295 return showSegments(event, e);
00296 }
00297
00298 int
00299 ShowCacheInternal::showSegments(int event, Event * e)
00300 {
00301 CHECK_SHOW(show("<H3>Cache Volume Segments</H3>\n"
00302 "<table border=1><tr>"
00303 "<th>Free</th>"
00304 "<th>Used</th>"
00305 "<th>Empty</th>" "<th>Valid</th>" "<th>Agg Valid</th>" "<th>Avg Size</th>" "</tr>\n"));
00306
00307 SET_HANDLER(&ShowCacheInternal::showSegSegment);
00308 seg_index = 0;
00309 CONT_SCHED_LOCK_RETRY_RET(this);
00310 }
00311
00312 int
00313 ShowCacheInternal::showSegSegment(int event, Event * e)
00314 {
00315 Vol *p = gvol[vol_index];
00316 CACHE_TRY_LOCK(lock, p->mutex, mutex->thread_holding);
00317 if (!lock)
00318 CONT_SCHED_LOCK_RETRY_RET(this);
00319 int free = 0, used = 0, empty = 0, valid = 0, agg_valid = 0, avg_size = 0;
00320 dir_segment_accounted(seg_index, p, 0, &free, &used, &empty, &valid, &agg_valid, &avg_size);
00321 CHECK_SHOW(show("<tr>"
00322 "<td>%d</td>"
00323 "<td>%d</td>"
00324 "<td>%d</td>"
00325 "<td>%d</td>" "<td>%d</td>" "<td>%d</td>" "</tr>\n", free, used, empty, valid, agg_valid, avg_size));
00326 seg_index++;
00327 if (seg_index < p->segments)
00328 CONT_SCHED_LOCK_RETRY(this);
00329 else {
00330 CHECK_SHOW(show("</table>\n"));
00331 seg_index = 0;
00332 vol_index++;
00333 if (vol_index < gnvol)
00334 CONT_SCHED_LOCK_RETRY(this);
00335 else
00336 return complete(event, e);
00337 }
00338 return EVENT_CONT;
00339 }
00340