]> git.ipfire.org Git - thirdparty/squid.git/blob - src/stat.cc
major code cleanup/unification/rewrite
[thirdparty/squid.git] / src / stat.cc
1 /* $Id: stat.cc,v 1.15 1996/04/04 01:30:51 wessels Exp $ */
2
3 /*
4 * DEBUG: Section 18 stat
5 */
6
7 #include "squid.h"
8
9 #ifdef _SQUID_HPUX_
10 #include <sys/syscall.h>
11 #define getrusage(a, b) syscall(SYS_GETRUSAGE, a, b)
12 #define getpagesize( ) sysconf(_SC_PAGE_SIZE)
13 #endif /* _SQUID_HPUX_ */
14
15 extern int emulate_httpd_log;
16
17 #define MIN_BUFSIZE (4096)
18 #define MAX_LINELEN (4096)
19 #define max(a,b) ((a)>(b)? (a): (b))
20
21 typedef struct _log_read_data_t {
22 StoreEntry *sentry;
23 } log_read_data_t;
24
25 typedef struct _cached_read_data_t {
26 StoreEntry *sentry;
27 int fd;
28 } cached_read_data_t;
29
30 /* GLOBALS */
31 Meta_data meta_data;
32 unsigned long nconn = 0;
33
34 char *stat_describe();
35 char *mem_describe();
36 char *ttl_describe();
37 char *flags_describe();
38 char *elapsed_time();
39 char *diskFileName();
40
41 /* LOCALS */
42 static char *open_bracket = "{\n";
43 static char *close_bracket = "}\n";
44
45 /* process utilization information */
46 void stat_utilization_get(obj, sentry)
47 cacheinfo *obj;
48 StoreEntry *sentry;
49 {
50 static char tempbuf[MAX_LINELEN];
51 int proto_id;
52 proto_stat *p = &obj->proto_stat_data[0];
53 proto_stat *q = NULL;
54 int secs = 0;
55
56 secs = (int) (cached_curtime - cached_starttime);
57
58 storeAppend(sentry, open_bracket, (int) strlen(open_bracket));
59
60 p->object_count = 0;
61 p->kb.max = 0;
62 p->kb.min = 0;
63 p->kb.avg = 0;
64 p->kb.now = 0;
65 p->hit = 0;
66 p->miss = 0;
67 p->refcount = 0;
68 p->transferbyte = 0;
69
70
71 /* find the total */
72 for (proto_id = 1; proto_id <= PROTOCOL_SUPPORTED; ++proto_id) {
73 q = &obj->proto_stat_data[proto_id];
74
75 p->object_count += q->object_count;
76 p->kb.max += q->kb.max;
77 p->kb.min += q->kb.min;
78 p->kb.avg += q->kb.avg;
79 p->kb.now += q->kb.now;
80 p->hit += q->hit;
81 p->miss += q->miss;
82 p->refcount += q->refcount;
83 p->transferbyte += q->transferbyte;
84 }
85
86 /* dump it */
87 for (proto_id = 0; proto_id < PROTOCOL_SUPPORTED + PROTOCOL_EXTRA; ++proto_id) {
88 p = &obj->proto_stat_data[proto_id];
89 if (p->hit != 0) {
90 p->hitratio =
91 (float) p->hit /
92 ((float) p->hit +
93 (float) p->miss);
94 }
95 sprintf(tempbuf, "{%s %d %d %d %d %4.2f %d %d %d}\n",
96 p->protoname,
97 p->object_count,
98 p->kb.max,
99 p->kb.now,
100 p->kb.min,
101 p->hitratio,
102 (secs ? p->transferbyte / secs : 0),
103 p->refcount,
104 p->transferbyte);
105 storeAppend(sentry, tempbuf, strlen(tempbuf));
106 }
107
108 storeAppend(sentry, close_bracket, strlen(close_bracket));
109 }
110
111
112 /* return total bytes of all registered and known objects.
113 * may not reflect the retrieving object....
114 * something need to be done here to get more accurate cache size */
115 int cache_size_get(obj)
116 cacheinfo *obj;
117 {
118 int size = 0;
119 int proto_id;
120 /* sum all size, exclude total */
121 for (proto_id = 1; proto_id <= PROTOCOL_SUPPORTED + PROTOCOL_EXTRA - 1;
122 ++proto_id) {
123 size += obj->proto_stat_data[proto_id].kb.now;
124 }
125 return (size);
126 }
127
128 /* process general IP cache information */
129 void stat_general_get(obj, sentry)
130 cacheinfo *obj;
131 StoreEntry *sentry;
132 {
133 /* have to use old method for this guy,
134 * otherwise we have to make ipcache know about StoreEntry */
135 stat_ipcache_get(sentry, obj);
136 }
137
138
139 /* process objects list */
140 void stat_objects_get(obj, sentry, vm_or_not)
141 cacheinfo *obj;
142 StoreEntry *sentry;
143 int vm_or_not;
144 {
145 static char tempbuf[MAX_LINELEN];
146 static char space[40];
147 static char space2[40];
148 int npend = 0;
149 StoreEntry *entry = NULL;
150 int N = 0;
151 int obj_size;
152
153 storeAppend(sentry, open_bracket, (int) strlen(open_bracket));
154
155 for (entry = storeGetFirst();
156 entry != NULL;
157 entry = storeGetNext()) {
158 if (vm_or_not && (entry->mem_status == NOT_IN_MEMORY) &&
159 (entry->swap_status == SWAP_OK))
160 continue;
161 if ((++N & 0xFF) == 0) {
162 getCurrentTime();
163 debug(18, 3, "stat_objects_get: Processed %d objects...\n", N);
164 }
165 obj_size = entry->object_len;
166 npend = storePendingNClients(entry);
167 if (entry->mem_obj)
168 obj_size = entry->mem_obj->e_current_len;
169 tempbuf[0] = '\0';
170 sprintf(tempbuf, "{ %s %d %s %s %s %s %d %d %s %s }\n",
171 entry->url,
172 obj_size,
173 elapsed_time(entry, (int) entry->timestamp, space),
174 flags_describe(entry),
175 elapsed_time(entry, (int) entry->lastref, space2),
176 ttl_describe(entry),
177 npend,
178 (int) entry->refcount,
179 mem_describe(entry),
180 stat_describe(entry));
181 storeAppend(sentry, tempbuf, strlen(tempbuf));
182 }
183 storeAppend(sentry, close_bracket, strlen(close_bracket));
184 }
185
186
187 /* process a requested object into a manager format */
188 void stat_get(obj, req, sentry)
189 cacheinfo *obj;
190 char *req;
191 StoreEntry *sentry;
192 {
193
194 if (strncmp(req, "objects", strlen("objects")) == 0) {
195 stat_objects_get(obj, sentry, 0);
196 } else if (strncmp(req, "vm_objects", strlen("vm_objects")) == 0) {
197 stat_objects_get(obj, sentry, 1);
198 } else if (strncmp(req, "general", strlen("general")) == 0) {
199 stat_general_get(obj, sentry);
200 } else if (strncmp(req, "utilization", strlen("utilization")) == 0) {
201 stat_utilization_get(obj, sentry);
202 }
203 }
204
205
206 /* generate logfile status information */
207 void log_status_get(obj, sentry)
208 cacheinfo *obj;
209 StoreEntry *sentry;
210 {
211 static char tempbuf[MAX_LINELEN];
212
213 if (obj->logfile_status == LOG_ENABLE) {
214 sprintf(tempbuf, "{\"Logfile is Enabled. Filename: %s\"}\n",
215 obj->logfilename);
216 } else {
217 sprintf(tempbuf, "{\"Logfile is Disabled.\"}\n");
218 }
219 storeAppend(sentry, tempbuf, strlen(tempbuf));
220 }
221
222
223
224 /* log convert handler */
225 /* call for each line in file, use fileWalk routine */
226 int logReadHandler(fd_unused, buf, size_unused, data)
227 int fd_unused;
228 char *buf;
229 int size_unused;
230 log_read_data_t *data;
231 {
232 static char tempbuf[MAX_LINELEN];
233
234 sprintf(tempbuf, "{%s}\n", buf);
235 return storeAppend(data->sentry,
236 tempbuf,
237 (int) strlen(tempbuf) % MAX_LINELEN);
238 }
239
240 /* log convert end handler */
241 /* call when a walk is completed or error. */
242 void logReadEndHandler(fd_unused, errflag_unused, data)
243 int fd_unused;
244 int errflag_unused;
245 log_read_data_t *data;
246 {
247 storeAppend(data->sentry, close_bracket, strlen(close_bracket));
248 storeComplete(data->sentry);
249 safe_free(data);
250 }
251
252
253
254 /* start converting logfile to processed format */
255 void log_get_start(obj, sentry)
256 cacheinfo *obj;
257 StoreEntry *sentry;
258 {
259 char tmp[3];
260 log_read_data_t *data = NULL;
261
262 if (obj->logfile_status == LOG_DISABLE) {
263 /* Manufacture status when logging is disabled */
264 log_status_get(obj, sentry);
265 storeComplete(sentry);
266 return;
267 }
268 data = (log_read_data_t *) xmalloc(sizeof(log_read_data_t));
269 memset(data, '\0', sizeof(log_read_data_t));
270 data->sentry = sentry;
271 strcpy(tmp, open_bracket);
272 storeAppend(sentry, tmp, 2);
273 file_walk(obj->logfile_fd, (FILE_WALK_HD) logReadEndHandler,
274 (caddr_t) data, (FILE_WALK_LHD) logReadHandler, (caddr_t) data);
275 return;
276 }
277
278
279 /* cached convert handler */
280 /* call for each line in file, use fileWalk routine */
281 int cachedReadHandler(fd_unused, buf, size_unused, data)
282 int fd_unused;
283 char *buf;
284 int size_unused;
285 cached_read_data_t *data;
286 {
287 static char tempbuf[MAX_LINELEN];
288 tempbuf[0] = '\0';
289 sprintf(tempbuf, "{\"%s\"}\n", buf);
290 return storeAppend(data->sentry,
291 tempbuf,
292 (int) strlen(tempbuf) % MAX_LINELEN);
293 }
294
295 /* cached convert end handler */
296 /* call when a walk is completed or error. */
297 void cachedReadEndHandler(fd_unused, errflag_unused, data)
298 int fd_unused;
299 int errflag_unused;
300 cached_read_data_t *data;
301 {
302 storeAppend(data->sentry, close_bracket, strlen(close_bracket));
303 storeComplete(data->sentry);
304 file_close(data->fd);
305 safe_free(data);
306 }
307
308
309 /* start convert cached.conf file to processed format */
310 void cached_get_start(obj, sentry)
311 cacheinfo *obj;
312 StoreEntry *sentry;
313 {
314 cached_read_data_t *data;
315 extern char *config_file;
316
317 data = (cached_read_data_t *) xmalloc(sizeof(cached_read_data_t));
318 memset(data, '\0', sizeof(cached_read_data_t));
319 data->sentry = sentry;
320 data->fd = file_open((char *) config_file, NULL, O_RDONLY);
321 storeAppend(sentry, open_bracket, (int) strlen(open_bracket));
322 file_walk(data->fd, (FILE_WALK_HD) cachedReadEndHandler, (caddr_t) data,
323 (FILE_WALK_LHD) cachedReadHandler, (caddr_t) data);
324 }
325
326
327 void dummyhandler(obj, sentry)
328 cacheinfo *obj;
329 StoreEntry *sentry;
330 {
331 static char *msg = "{ \"Not_Implemented_yet.\"}\n";
332 storeAppend(sentry, msg, strlen(msg));
333 }
334
335 void server_list(obj, sentry)
336 cacheinfo *obj;
337 StoreEntry *sentry;
338 {
339 static char tempbuf[MAX_LINELEN];
340 edge *e = NULL;
341 dom_list *d = NULL;
342
343 storeAppend(sentry, open_bracket, (int) strlen(open_bracket));
344
345 if (getFirstEdge() == (edge *) NULL) {
346 sprintf(tempbuf, "{There are no neighbors installed.}\n");
347 storeAppend(sentry, tempbuf, strlen(tempbuf));
348 }
349 for (e = getFirstEdge(); e; e = getNextEdge(e)) {
350 if (e->host == NULL)
351 fatal_dump("Found an edge without a hostname!");
352 sprintf(tempbuf, "\n{Hostname: %s}\n", e->host);
353 storeAppend(sentry, tempbuf, strlen(tempbuf));
354 sprintf(tempbuf, "{Edge type: %s}\n",
355 e->type == is_a_parent ? "parent" : "neighbor");
356 storeAppend(sentry, tempbuf, strlen(tempbuf));
357 sprintf(tempbuf, "{Status: %s}\n",
358 e->neighbor_up ? "Up" : "Down");
359 storeAppend(sentry, tempbuf, strlen(tempbuf));
360 sprintf(tempbuf, "{UDP PORT: %d}\n", e->udp_port);
361 storeAppend(sentry, tempbuf, strlen(tempbuf));
362 sprintf(tempbuf, "{ASCII PORT: %d}\n", e->ascii_port);
363 storeAppend(sentry, tempbuf, strlen(tempbuf));
364 sprintf(tempbuf, "{ACK DEFICIT: %d}\n", e->ack_deficit);
365 storeAppend(sentry, tempbuf, strlen(tempbuf));
366 sprintf(tempbuf, "{PINGS SENT: %d}\n", e->num_pings);
367 storeAppend(sentry, tempbuf, strlen(tempbuf));
368 sprintf(tempbuf, "{PINGS ACKED: %d}\n", e->pings_acked);
369 storeAppend(sentry, tempbuf, strlen(tempbuf));
370 if (e->last_fail_time) {
371 sprintf(tempbuf, "{Last failed connect() at: %s}\n",
372 mkhttpdlogtime(&(e->last_fail_time)));
373 storeAppend(sentry, tempbuf, strlen(tempbuf));
374 }
375 sprintf(tempbuf, "{DOMAIN LIST: ");
376 storeAppend(sentry, tempbuf, strlen(tempbuf));
377 for (d = e->domains; d; d = d->next) {
378 if (d->do_ping)
379 sprintf(tempbuf, "%s ", d->domain);
380 else
381 sprintf(tempbuf, "!%s ", d->domain);
382 storeAppend(sentry, tempbuf, strlen(tempbuf));
383 }
384 storeAppend(sentry, close_bracket, strlen(close_bracket)); /* } */
385 }
386 storeAppend(sentry, close_bracket, strlen(close_bracket));
387 }
388
389
390
391 void info_get(obj, sentry)
392 cacheinfo *obj;
393 StoreEntry *sentry;
394 {
395 char *tod = NULL;
396 static char line[MAX_LINELEN];
397
398 #if defined(HAVE_GETRUSAGE) && defined(RUSAGE_SELF)
399 struct rusage rusage;
400 #endif
401
402 #if HAVE_MALLINFO
403 struct mallinfo mp;
404 #endif
405
406 memset(line, '\0', SM_PAGE_SIZE);
407
408 storeAppend(sentry, open_bracket, (int) strlen(open_bracket));
409
410 sprintf(line, "{Harvest Object Cache: Version %s}\n", SQUID_VERSION);
411 storeAppend(sentry, line, strlen(line));
412
413 tod = mkrfc850(&cached_starttime);
414
415 sprintf(line, "{Start Time:\t%s}\n", tod);
416 storeAppend(sentry, line, strlen(line));
417
418 tod = mkrfc850(&cached_curtime);
419 sprintf(line, "{Current Time:\t%s}\n", tod);
420 storeAppend(sentry, line, strlen(line));
421
422 /* -------------------------------------------------- */
423
424 sprintf(line, "{Connection information for cached:}\n");
425 storeAppend(sentry, line, strlen(line));
426
427 sprintf(line, "{\tNumber of connections:\t%lu}\n", nconn);
428 storeAppend(sentry, line, strlen(line));
429
430 {
431 float f;
432 f = cached_curtime - cached_starttime;
433 sprintf(line, "{\tConnections per hour:\t%.1f}\n", f == 0.0 ? 0.0 :
434 (nconn / (f / 3600)));
435 storeAppend(sentry, line, strlen(line));
436 }
437
438 /* -------------------------------------------------- */
439
440
441
442 sprintf(line, "{Cache information for cached:}\n");
443 storeAppend(sentry, line, strlen(line));
444
445 sprintf(line, "{\tStorage Swap size:\t%d MB}\n", storeGetSwapSize() >> 10);
446 storeAppend(sentry, line, strlen(line));
447
448 sprintf(line, "{\tStorage Mem size:\t%d KB}\n", storeGetMemSize() >> 10);
449 storeAppend(sentry, line, strlen(line));
450
451 tod = mkrfc850(&next_cleaning);
452 sprintf(line, "{\tStorage Expiration at:\t%s}\n", tod);
453 storeAppend(sentry, line, strlen(line));
454
455 #if defined(HAVE_GETRUSAGE) && defined(RUSAGE_SELF)
456 sprintf(line, "{Resource usage for cached:}\n");
457 storeAppend(sentry, line, strlen(line));
458
459 getrusage(RUSAGE_SELF, &rusage);
460 sprintf(line, "{\tCPU Usage: user %d sys %d}\n{\tProcess Size: rss %d KB}\n",
461 rusage.ru_utime.tv_sec, rusage.ru_stime.tv_sec,
462 rusage.ru_maxrss * getpagesize() >> 10);
463 storeAppend(sentry, line, strlen(line));
464
465 sprintf(line, "{\tPage faults with physical i/o:\t%d}\n",
466 rusage.ru_majflt);
467 storeAppend(sentry, line, strlen(line));
468
469 #endif
470
471 #if HAVE_MALLINFO
472 mp = mallinfo();
473
474 sprintf(line, "{Memory usage for cached via mallinfo():}\n");
475 storeAppend(sentry, line, strlen(line));
476
477 sprintf(line, "{\ttotal space in arena:\t%d KB}\n", mp.arena >> 10);
478 storeAppend(sentry, line, strlen(line));
479 sprintf(line, "{\tnumber of ordinary blocks:\t%d}\n", mp.ordblks);
480 storeAppend(sentry, line, strlen(line));
481 sprintf(line, "{\tnumber of small blocks:\t%d}\n", mp.smblks);
482 storeAppend(sentry, line, strlen(line));
483 if (mp.hblks) {
484 sprintf(line, "{\tnumber of holding blocks:\t%d}\n", mp.hblks);
485 storeAppend(sentry, line, strlen(line));
486 }
487 if (mp.hblkhd) {
488 sprintf(line, "{\tspace in holding block headers:\t%d}\n", mp.hblkhd);
489 storeAppend(sentry, line, strlen(line));
490 }
491 if (mp.usmblks) {
492 sprintf(line, "{\tspace in small blocks in use:\t%d}\n", mp.usmblks);
493 storeAppend(sentry, line, strlen(line));
494 }
495 if (mp.fsmblks) {
496 sprintf(line, "{\tspace in free blocks:\t%d}\n", mp.fsmblks);
497 storeAppend(sentry, line, strlen(line));
498 }
499 sprintf(line, "{\tspace in ordinary blocks in use:\t%d KB}\n",
500 mp.uordblks >> 10);
501 storeAppend(sentry, line, strlen(line));
502 sprintf(line, "{\tspace in free ordinary blocks:\t%d KB}\n", mp.fordblks >> 10);
503 storeAppend(sentry, line, strlen(line));
504 if (mp.keepcost) {
505 sprintf(line, "{\tcost of enabling keep option:\t%d}\n", mp.keepcost);
506 storeAppend(sentry, line, strlen(line));
507 }
508 #if LNG_MALLINFO
509 sprintf(line, "{\tmax size of small blocks:\t%d}\n", mp.mxfast);
510 storeAppend(sentry, line, strlen(line));
511 sprintf(line, "{\tnumber of small blocks in a holding block:\t%d}\n",
512 mp.nlblks);
513 storeAppend(sentry, line, strlen(line));
514 sprintf(line, "{\tsmall block rounding factor:\t%d}\n", mp.grain);
515 storeAppend(sentry, line, strlen(line));
516 sprintf(line, "{\tspace (including overhead) allocated in ord. blks:\t%d}\n"
517 ,mp.uordbytes);
518 sprintf(line, "{\tnumber of ordinary blocks allocated:\t%d}\n",
519 mp.allocated);
520 storeAppend(sentry, line, strlen(line));
521 sprintf(line, "{\tbytes used in maintaining the free tree:\t%d}\n",
522 mp.treeoverhead);
523 storeAppend(sentry, line, strlen(line));
524
525 #endif /* LNG_MALLINFO */
526
527 #endif /* HAVE_MALLINFO */
528
529 sprintf(line, "{File descriptor usage for cached:}\n");
530 storeAppend(sentry, line, strlen(line));
531
532 sprintf(line, "{\tMax number of file desc available:\t%d}\n", getMaxFD());
533 storeAppend(sentry, line, strlen(line));
534
535 sprintf(line, "{\tLargest file desc currently in use:\t%d}\n",
536 fdstat_biggest_fd());
537 storeAppend(sentry, line, strlen(line));
538
539 sprintf(line, "{\tAvailable number of file descriptors :\t%d}\n",
540 fdstat_are_n_free_fd(0));
541 storeAppend(sentry, line, strlen(line));
542
543 sprintf(line, "{\tReserved number of file descriptors :\t%d}\n",
544 RESERVED_FD);
545 storeAppend(sentry, line, strlen(line));
546
547 {
548 int i, max_fd = getMaxFD();
549 char *s = NULL;
550
551 sprintf(line, "{\tActive file descriptors:}\n");
552 storeAppend(sentry, line, strlen(line));
553
554 for (i = 0; i < max_fd; i++) {
555 int lft, to;
556 if (!fdstat_isopen(i))
557 continue;
558 line[0] = '\0';
559 switch (fdstat_type(i)) {
560 case Socket:
561 /* the lifetime should be greater than curtime */
562 lft = comm_get_fd_lifetime(i);
563 to = comm_get_fd_timeout(i);
564 sprintf(line, "{\t\t(%3d = %3d, %3d) NET %s}\n",
565 i,
566 (int) (lft > 0 ? lft - cached_curtime : -1),
567 (int) max((to - cached_curtime), 0),
568 fd_note(i, NULL));
569 break;
570 case File:
571 sprintf(line, "{\t\t(%3d = FILE) %s}\n", i,
572 (s = diskFileName(i)) ? s : "Unknown");
573 break;
574 case Pipe:
575 sprintf(line, "{\t\t(%3d = PIPE) %s}\n", i, fd_note(i, NULL));
576 break;
577 case LOG:
578 sprintf(line, "{\t\t(%3d = LOG) %s}\n", i, fd_note(i, NULL));
579 break;
580 case Unknown:
581 default:
582 sprintf(line, "{\t\t(%3d = UNKNOWN) %s}\n", i, fd_note(i, NULL));
583 break;
584 }
585 storeAppend(sentry, line, strlen(line));
586 }
587 }
588
589
590 sprintf(line, "{Stop List:}\n");
591 storeAppend(sentry, line, strlen(line));
592 if (http_stoplist) {
593 stoplist *p;
594 p = http_stoplist;
595 sprintf(line, "{\tHTTP:}\n");
596 storeAppend(sentry, line, strlen(line));
597 while (p) {
598 sprintf(line, "{\t\t%s}\n", p->key);
599 storeAppend(sentry, line, strlen(line));
600 p = p->next;
601 }
602 }
603 if (gopher_stoplist) {
604 stoplist *p;
605 p = gopher_stoplist;
606 sprintf(line, "{\tGOPHER:}\n");
607 storeAppend(sentry, line, strlen(line));
608 while (p) {
609 sprintf(line, "{\t\t%s}\n", p->key);
610 storeAppend(sentry, line, strlen(line));
611 p = p->next;
612 }
613 }
614 if (ftp_stoplist) {
615 stoplist *p;
616 p = ftp_stoplist;
617 sprintf(line, "{\tFTP:}\n");
618 storeAppend(sentry, line, strlen(line));
619 while (p) {
620 sprintf(line, "{\t\t%s}\n", p->key);
621 storeAppend(sentry, line, strlen(line));
622 p = p->next;
623 }
624 }
625 sprintf(line, "{Internal Data Structures:}\n");
626 storeAppend(sentry, line, strlen(line));
627 sprintf(line, "{Meta Data:}\n");
628 storeAppend(sentry, line, strlen(line));
629 sprintf(line, "{\t\tStoreEntry %d x %d}\n", (int) sizeof(StoreEntry),
630 meta_data.store_entries);
631 storeAppend(sentry, line, strlen(line));
632 sprintf(line, "{\t\tStoreMemObject %d x %d}\n", (int) sizeof(MemObject),
633 meta_data.store_in_mem_objects);
634 storeAppend(sentry, line, strlen(line));
635 sprintf(line, "{\t\tIPCacheEntry %d x %d}\n", (int) sizeof(ipcache_entry),
636 meta_data.ipcache_count);
637 storeAppend(sentry, line, strlen(line));
638 sprintf(line, "{\t\tHash link %d x %d}\n", (int) sizeof(hash_link),
639 meta_data.hash_links = hash_links_allocated);
640 storeAppend(sentry, line, strlen(line));
641 sprintf(line, "{\t\tURL strings %d}\n", meta_data.url_strings);
642 storeAppend(sentry, line, strlen(line));
643 sprintf(line, "{\t\tHot Object Cache Items %d}\n", meta_data.hot_vm);
644 storeAppend(sentry, line, strlen(line));
645 sprintf(line, "{\t\tPool for disk I/O %d KB (Free %d KB)}\n",
646 (disk_stats.total_pages_allocated * disk_stats.page_size) / (1 << 10),
647 ((disk_stats.total_pages_allocated - disk_stats.n_pages_in_use) * disk_stats.page_size) /
648 (1 << 10)
649 );
650 storeAppend(sentry, line, strlen(line));
651 sprintf(line, "{\t\tPool for in-memory objects %d KB (Free %d KB)}\n",
652 (sm_stats.total_pages_allocated * sm_stats.page_size) / (1 << 10),
653 ((sm_stats.total_pages_allocated - sm_stats.n_pages_in_use) * sm_stats.page_size) / (1 << 10));
654 storeAppend(sentry, line, strlen(line));
655 sprintf(line, "{\tTotal Accounted %d KB}\n",
656 (int) (meta_data.store_entries * sizeof(StoreEntry) +
657 meta_data.store_in_mem_objects * sizeof(MemObject) +
658 meta_data.ipcache_count * sizeof(ipcache_entry) +
659 meta_data.hash_links * sizeof(hash_link) +
660 sm_stats.total_pages_allocated * sm_stats.page_size +
661 disk_stats.total_pages_allocated * disk_stats.page_size +
662 meta_data.url_strings) >> 10);
663 storeAppend(sentry, line, strlen(line));
664
665 storeAppend(sentry, close_bracket, strlen(close_bracket));
666 }
667
668
669 void parameter_get(obj, sentry)
670 cacheinfo *obj;
671 StoreEntry *sentry;
672
673 {
674 /* be careful if an object is bigger than 4096,
675 * need more malloc here */
676 static char line[MAX_LINELEN];
677
678 memset(line, '\0', MAX_LINELEN);
679
680 storeAppend(sentry, open_bracket, (int) strlen(open_bracket));
681
682 sprintf(line, "{VM-Max %d \"# Maximum hot-vm cache (MB)\"}\n",
683 getCacheMemMax() / (1 << 20));
684 storeAppend(sentry, line, strlen(line));
685
686 sprintf(line, "{VM-High %d \"# High water mark hot-vm cache (%%)\"}\n",
687 getCacheMemHighWaterMark());
688 storeAppend(sentry, line, strlen(line));
689
690 sprintf(line, "{VM-Low %d \"# Low water-mark hot-vm cache (%%)\"}\n",
691 getCacheMemLowWaterMark());
692 storeAppend(sentry, line, strlen(line));
693
694 sprintf(line, "{Swap-Max %d \"# Maximum disk cache (MB)\"}\n",
695 getCacheSwapMax() / (1 << 10));
696 storeAppend(sentry, line, strlen(line));
697
698 sprintf(line, "{Swap-High %d \"# High Water mark disk cache (%%)\"}\n",
699 getCacheSwapHighWaterMark());
700 storeAppend(sentry, line, strlen(line));
701
702 sprintf(line, "{Swap-Low %d \"# Low water mark disk cache (%%)\"}\n",
703 getCacheSwapLowWaterMark());
704 storeAppend(sentry, line, strlen(line));
705
706 sprintf(line, "{HTTP-Max %d\"# Maximum size HTTP objects (KB)\"}\n",
707 getHttpMax() / (1 << 10));
708 storeAppend(sentry, line, strlen(line));
709
710 sprintf(line, "{HTTP-TTL %d \"# Http object default TTL (hrs)\"}\n", getHttpTTL() / 3600);
711 storeAppend(sentry, line, strlen(line));
712
713 sprintf(line, "{Gopher-Max %d \"# Maximum size gopher objects (KB)\"}\n",
714 getGopherMax() / (1 << 10));
715 storeAppend(sentry, line, strlen(line));
716
717 sprintf(line, "{Gopher-TTL %d \"# TTL for gopher objects (hrs)\"}\n", getGopherTTL() / 3600);
718 storeAppend(sentry, line, strlen(line));
719
720 sprintf(line, "{FTP-Max %d \"# Maximum size FTP objects (KB)\"}\n",
721 getFtpMax() / (1 << 10));
722 storeAppend(sentry, line, strlen(line));
723
724 sprintf(line, "{FTP-TTL %d \"# TTL for FTP objects (hrs)\"}\n", getFtpTTL() / 3600);
725 storeAppend(sentry, line, strlen(line));
726
727 sprintf(line, "{Neg-TTL %d \"# TTL for negative cache (s)\"}\n",
728 getNegativeTTL());
729 storeAppend(sentry, line, strlen(line));
730
731 sprintf(line, "{ReadTimeout %d \"# Maximum idle connection (s)\"}\n", getReadTimeout());
732 storeAppend(sentry, line, strlen(line));
733
734 sprintf(line, "{ClientLifetime %d \"# Lifetime for incoming ascii port requests or outgoing clients (s)\"}\n", getClientLifetime());
735 storeAppend(sentry, line, strlen(line));
736
737 sprintf(line, "{CleanRate %d \"# Rate for periodic object expiring\"}\n",
738 getCleanRate());
739 storeAppend(sentry, line, strlen(line));
740
741 /* Cachemgr.cgi expects an integer in the second field of the string */
742 sprintf(line, "{HttpAccelMode %d \"# Is operating as an HTTP accelerator\"}\n",
743 httpd_accel_mode);
744 storeAppend(sentry, line, strlen(line));
745
746 /* end of stats */
747 storeAppend(sentry, close_bracket, strlen(close_bracket));
748 }
749
750
751 void log_append(obj, url, id, size, action, method, http_code, msec)
752 cacheinfo *obj;
753 char *url;
754 char *id;
755 int size;
756 char *action;
757 char *method;
758 int http_code;
759 int msec;
760 {
761 static char tmp[6000]; /* MAX_URL is 4096 */
762 char *buf = NULL;
763
764 getCurrentTime();
765
766 #ifdef LOG_FQDN
767 /* ENABLE THIS IF YOU WANT A *SLOW* CACHE, OR
768 * JUST WRITE A PERL SCRIPT TO MUCK YOUR LOGS */
769 {
770 int ipx[4];
771 unsigned long ipy;
772 struct hostent *h = NULL;
773 if (sscanf(id, "%d.%d.%d.%d", &ipx[0], &ipx[1], &ipx[2], &ipx[3]) == 4) {
774 ipy = inet_addr(id);
775 if (h = gethostbyaddr((char *) &ipy, 4, AF_INET)) {
776 id = xstrdup(h->h_name);
777 }
778 }
779 }
780 #endif
781
782 if (!method)
783 method = "-";
784 if (!url)
785 url = "-";
786
787 if (obj->logfile_status == LOG_ENABLE) {
788 if (emulate_httpd_log)
789 sprintf(tmp, "%s - - [%s] \"%s %s\" %s %d\n",
790 id, mkhttpdlogtime(&cached_curtime), method, url, action, size);
791 else
792 sprintf(tmp, "%9d.%03d %6d %s %s/%03d %d %s %s\n",
793 (int) current_time.tv_sec,
794 (int) current_time.tv_usec / 1000,
795 msec,
796 id,
797 action,
798 http_code,
799 size,
800 method,
801 url);
802
803
804 if (file_write(obj->logfile_fd, buf = xstrdup(tmp), strlen(tmp),
805 obj->logfile_access, NULL, NULL) != DISK_OK) {
806 debug(18, 1, "log_append: File write failed.\n");
807 safe_free(buf);
808 }
809 }
810 }
811
812 void log_enable(obj, sentry)
813 cacheinfo *obj;
814 StoreEntry *sentry;
815 {
816 static char tempbuf[MAX_LINELEN];
817
818 if (obj->logfile_status == LOG_DISABLE) {
819 obj->logfile_status = LOG_ENABLE;
820
821 /* open the logfile */
822 obj->logfile_fd = file_open(obj->logfilename, NULL, O_RDWR | O_CREAT);
823 if (obj->logfile_fd == DISK_ERROR) {
824 debug(18, 0, "Cannot open logfile: %s\n", obj->logfilename);
825 obj->logfile_status = LOG_DISABLE;
826 }
827 obj->logfile_access = file_write_lock(obj->logfile_fd);
828
829 }
830 /* at the moment, store one char to make a storage manager happy */
831 sprintf(tempbuf, " ");
832 storeAppend(sentry, tempbuf, strlen(tempbuf));
833 }
834
835 void log_disable(obj, sentry)
836 cacheinfo *obj;
837 StoreEntry *sentry;
838 {
839 static char tempbuf[MAX_LINELEN];
840
841 if (obj->logfile_status == LOG_ENABLE)
842 file_close(obj->logfile_fd);
843
844 obj->logfile_status = LOG_DISABLE;
845 /* at the moment, store one char to make a storage manager happy */
846 sprintf(tempbuf, " ");
847 storeAppend(sentry, tempbuf, strlen(tempbuf));
848 }
849
850
851
852 void log_clear(obj, sentry)
853 cacheinfo *obj;
854 StoreEntry *sentry;
855 {
856 static char tempbuf[MAX_LINELEN];
857
858
859 /* what should be done here. Erase file ??? or move it to another name */
860 /* At the moment, just erase it. */
861 /* bug here need to be fixed. what if there are still data in memory. Need flush here */
862 if (obj->logfile_status == LOG_ENABLE)
863 file_close(obj->logfile_fd);
864
865 unlink(obj->logfilename);
866
867 /* reopen it anyway */
868 obj->logfile_fd = file_open(obj->logfilename, NULL, O_RDWR | O_CREAT);
869 if (obj->logfile_fd == DISK_ERROR) {
870 debug(18, 0, "Cannot open logfile: %s\n", obj->logfilename);
871 obj->logfile_status = LOG_DISABLE;
872 }
873 /* at the moment, store one char to make a storage manager happy */
874 sprintf(tempbuf, " ");
875 storeAppend(sentry, tempbuf, strlen(tempbuf));
876 }
877
878
879
880 void proto_newobject(obj, proto_id, size, restart)
881 cacheinfo *obj;
882 int proto_id;
883 int size;
884 int restart;
885 {
886 proto_stat *p = &obj->proto_stat_data[proto_id];
887
888 p->object_count++;
889
890 /* Account for 1KB granularity */
891 p->kb.now += ((size + 1023) >> 10);
892
893 if (p->kb.now > p->kb.max)
894 p->kb.max = p->kb.now;
895 if (restart)
896 p->kb.min = p->kb.now;
897 }
898
899
900 void proto_purgeobject(obj, proto_id, size)
901 cacheinfo *obj;
902 int proto_id;
903 int size;
904 {
905 proto_stat *p = &obj->proto_stat_data[proto_id];
906
907 p->object_count--;
908
909 /* Scale down to KB */
910 p->kb.now -= ((size + 1023) >> 10);
911
912 if (p->kb.now < p->kb.min)
913 p->kb.min = p->kb.now;
914 }
915
916 /* update stat for each particular protocol when an object is fetched */
917 void proto_touchobject(obj, proto_id, size)
918 cacheinfo *obj;
919 int proto_id;
920 int size;
921 {
922 obj->proto_stat_data[proto_id].refcount++;
923 obj->proto_stat_data[proto_id].transferbyte += (1023 + size) >> 10;
924 }
925
926 void proto_hit(obj, proto_id)
927 cacheinfo *obj;
928 int proto_id;
929 {
930 obj->proto_stat_data[proto_id].hit++;
931 }
932
933 void proto_miss(obj, proto_id)
934 cacheinfo *obj;
935 int proto_id;
936 {
937 obj->proto_stat_data[proto_id].miss++;
938 }
939
940 int proto_url_to_id(url)
941 char *url;
942 {
943 if (strncmp(url, "http:", 5) == 0)
944 return HTTP_ID;
945 if (strncmp(url, "ftp:", 4) == 0)
946 return FTP_ID;
947 if (strncmp(url, "gopher:", 7) == 0)
948 return GOPHER_ID;
949 if (strncmp(url, "cache_object:", 13) == 0)
950 return CACHEOBJ_ID;
951 if (strncmp(url, "abort:", 6) == 0)
952 return ABORT_ID;
953 if (strncmp(url, "news:", 5) == 0)
954 return NOTIMPLE_ID;
955 if (strncmp(url, "file:", 5) == 0)
956 return NOTIMPLE_ID;
957 return NOTIMPLE_ID;
958 }
959
960
961
962 void stat_init(object, logfilename)
963 cacheinfo **object;
964 char *logfilename;
965 {
966 cacheinfo *obj = NULL;
967 int i;
968
969 obj = (cacheinfo *) xmalloc(sizeof(cacheinfo));
970 memset(obj, '\0', sizeof(cacheinfo));
971
972 obj->stat_get = stat_get;
973 obj->info_get = info_get;
974 obj->cache_size_get = cache_size_get;
975
976 obj->log_get_start = log_get_start;
977 obj->log_status_get = log_status_get;
978 obj->log_append = log_append;
979 obj->log_clear = log_clear;
980 obj->log_enable = log_enable;
981 obj->log_disable = log_disable;
982 obj->logfile_status = LOG_ENABLE;
983
984 obj->cached_get_start = cached_get_start;
985
986 obj->parameter_get = parameter_get;
987 obj->server_list = server_list;
988
989 memcpy(obj->logfilename, logfilename, (int) (strlen(logfilename) + 1) % 256);
990 obj->logfile_fd = file_open(obj->logfilename, NULL, O_RDWR | O_CREAT);
991 if (obj->logfile_fd == DISK_ERROR) {
992 debug(18, 0, "Cannot open logfile: %s\n", obj->logfilename);
993 obj->logfile_status = LOG_DISABLE;
994 fatal("Cannot open logfile.");
995 }
996 obj->logfile_access = file_write_lock(obj->logfile_fd);
997
998 obj->proto_id = proto_url_to_id;
999 obj->proto_newobject = proto_newobject;
1000 obj->proto_purgeobject = proto_purgeobject;
1001 obj->proto_touchobject = proto_touchobject;
1002 obj->proto_hit = proto_hit;
1003 obj->proto_miss = proto_miss;
1004 obj->NotImplement = dummyhandler;
1005
1006 for (i = 0; i < PROTOCOL_SUPPORTED + PROTOCOL_EXTRA; ++i) {
1007
1008 switch (i) {
1009
1010 case TOTAL_ID:
1011 strcpy(obj->proto_stat_data[i].protoname, "TOTAL");
1012 break;
1013
1014 case HTTP_ID:
1015 strcpy(obj->proto_stat_data[i].protoname, "HTTP");
1016 break;
1017
1018 case GOPHER_ID:
1019 strcpy(obj->proto_stat_data[i].protoname, "GOPHER");
1020 break;
1021
1022 case FTP_ID:
1023 strcpy(obj->proto_stat_data[i].protoname, "FTP");
1024 break;
1025
1026 case CACHEOBJ_ID:
1027 strcpy(obj->proto_stat_data[i].protoname, "CACHEMGR");
1028 break;
1029
1030 case ABORT_ID:
1031 strcpy(obj->proto_stat_data[i].protoname, "ABORTED");
1032 break;
1033
1034 case NOTIMPLE_ID:
1035 default:
1036 strcpy(obj->proto_stat_data[i].protoname, "UNKNOWN");
1037 break;
1038 }
1039
1040 obj->proto_stat_data[i].object_count = 0;
1041 obj->proto_stat_data[i].hit = 0;
1042 obj->proto_stat_data[i].miss = 0;
1043 obj->proto_stat_data[i].hitratio = 0.0;
1044 obj->proto_stat_data[i].transferrate = 0;
1045 obj->proto_stat_data[i].refcount = 0;
1046 obj->proto_stat_data[i].transferbyte = 0;
1047
1048 obj->proto_stat_data[i].kb.max = 0;
1049 obj->proto_stat_data[i].kb.min = 0;
1050 obj->proto_stat_data[i].kb.avg = 0;
1051 obj->proto_stat_data[i].kb.now = 0;
1052
1053 }
1054
1055 *object = obj;
1056 }
1057
1058 char *stat_describe(entry)
1059 StoreEntry *entry;
1060 {
1061 static char state[256];
1062
1063 state[0] = '\0';
1064 switch (entry->status) {
1065 case STORE_OK:
1066 strncat(state, "STORE-OK", sizeof(state));
1067 break;
1068 case STORE_PENDING:
1069 strncat(state, "ST-PEND", sizeof(state));
1070 break;
1071 case STORE_ABORTED:
1072 strncat(state, "ABORTED", sizeof(state));
1073 break;
1074 default:
1075 strncat(state, "YEEHAH", sizeof(state));
1076 break;
1077 }
1078 strncat(state, "/", sizeof(state));
1079
1080 switch (entry->ping_status) {
1081 case WAITING:
1082 strncat(state, "PING-WAIT", sizeof(state));
1083 break;
1084 case TIMEOUT:
1085 strncat(state, "PING-TIMEOUT", sizeof(state));
1086 break;
1087 case DONE:
1088 strncat(state, "PING-DONE", sizeof(state));
1089 break;
1090 case NOPING:
1091 strncat(state, "NO-PING", sizeof(state));
1092 break;
1093 default:
1094 strncat(state, "YEEHAH", sizeof(state));
1095 break;
1096 }
1097 return (state);
1098 }
1099
1100 char *mem_describe(entry)
1101 StoreEntry *entry;
1102 {
1103 static char where[100];
1104
1105 where[0] = '\0';
1106 if (entry->swap_file_number >= 0)
1107 sprintf(where, "D%d", entry->swap_file_number);
1108 if (entry->swap_status == SWAPPING_OUT)
1109 strncat(where, "/SWAP-OUT", sizeof(where));
1110 if (entry->swap_status == SWAP_OK)
1111 strncat(where, "/SWAP-OK", sizeof(where));
1112 else
1113 strncat(where, "/NO-SWAP", sizeof(where));
1114
1115 if (entry->mem_status == SWAPPING_IN)
1116 strncat(where, "/SWAP-IN", sizeof(where));
1117 else if (entry->mem_status == IN_MEMORY)
1118 strncat(where, "/IN-MEM", sizeof(where));
1119 else /* STORE_PENDING */
1120 strncat(where, "/OUT-MEM", sizeof(where));
1121 return (where);
1122 }
1123
1124
1125 char *ttl_describe(entry)
1126 StoreEntry *entry;
1127 {
1128 int hh, mm, ss;
1129 static char TTL[60];
1130 int ttl;
1131
1132 TTL[0] = '\0';
1133 strcpy(TTL, "UNKNOWN"); /* sometimes the TTL isn't set below */
1134 ttl = entry->expires - cached_curtime;
1135 if (ttl < 0)
1136 strcpy(TTL, "EXPIRED");
1137 else {
1138
1139 hh = ttl / 3600;
1140 ttl -= hh * 3600;
1141 mm = ttl / 60;
1142 ttl -= mm * 60;
1143 ss = ttl;
1144
1145 sprintf(TTL, "% 6d:%02d:%02d", hh, mm, ss);
1146 }
1147 return (TTL);
1148 }
1149
1150 char *elapsed_time(entry, since, TTL)
1151 StoreEntry *entry;
1152 int since;
1153 char *TTL;
1154 {
1155 int hh, mm, ss, ttl;
1156
1157 TTL[0] = '\0';
1158 strcpy(TTL, "UNKNOWN"); /* sometimes TTL doesn't get set */
1159 ttl = cached_curtime - since;
1160 if (since == 0) {
1161 strcpy(TTL, "NEVER");
1162 } else if (ttl < 0) {
1163 strcpy(TTL, "EXPIRED");
1164 } else {
1165 hh = ttl / 3600;
1166 ttl -= hh * 3600;
1167 mm = ttl / 60;
1168 ttl -= mm * 60;
1169 ss = ttl;
1170 sprintf(TTL, "% 6d:%02d:%02d", hh, mm, ss);
1171 }
1172 return (TTL);
1173 }
1174
1175
1176 char *flags_describe(entry)
1177 StoreEntry *entry;
1178 {
1179 static char FLAGS[32];
1180 char LOCK_CNT[32];
1181
1182 strcpy(FLAGS, "F:");
1183 if (BIT_TEST(entry->flag, KEY_CHANGE))
1184 strncat(FLAGS, "K", sizeof(FLAGS) - 1);
1185 if (BIT_TEST(~entry->flag, CACHABLE))
1186 strncat(FLAGS, "C", sizeof(FLAGS) - 1);
1187 if (BIT_TEST(entry->flag, REFRESH_REQUEST))
1188 strncat(FLAGS, "R", sizeof(FLAGS) - 1);
1189 if (BIT_TEST(entry->flag, RELEASE_REQUEST))
1190 strncat(FLAGS, "Z", sizeof(FLAGS) - 1);
1191 if (BIT_TEST(entry->flag, ABORT_MSG_PENDING))
1192 strncat(FLAGS, "A", sizeof(FLAGS) - 1);
1193 if (BIT_TEST(entry->flag, DELAY_SENDING))
1194 strncat(FLAGS, "D", sizeof(FLAGS) - 1);
1195 if (BIT_TEST(entry->flag, IP_LOOKUP_PENDING))
1196 strncat(FLAGS, "P", sizeof(FLAGS) - 1);
1197 if (entry->lock_count)
1198 strncat(FLAGS, "L", sizeof(FLAGS) - 1);
1199 if (entry->lock_count) {
1200 sprintf(LOCK_CNT, "%d", entry->lock_count);
1201 strncat(FLAGS, LOCK_CNT, sizeof(FLAGS) - 1);
1202 }
1203 return (FLAGS);
1204 }
1205
1206 void stat_rotate_log()
1207 {
1208 int i;
1209 static char from[MAXPATHLEN];
1210 static char to[MAXPATHLEN];
1211 char *fname = NULL;
1212
1213 if ((fname = CacheInfo->logfilename) == NULL)
1214 return;
1215
1216 debug(18, 1, "stat_rotate_log: Rotating\n");
1217
1218 /* Rotate numbers 0 through N up one */
1219 for (i = getLogfileRotateNumber(); i > 1;) {
1220 i--;
1221 sprintf(from, "%s.%d", fname, i - 1);
1222 sprintf(to, "%s.%d", fname, i);
1223 rename(from, to);
1224 }
1225 /* Rotate the current log to .0 */
1226 if (getLogfileRotateNumber() > 0) {
1227 sprintf(to, "%s.%d", fname, 0);
1228 rename(fname, to);
1229 }
1230 /* Close and reopen the log. It may have been renamed "manually"
1231 * before HUP'ing us. */
1232 file_close(CacheInfo->logfile_fd);
1233 CacheInfo->logfile_fd = file_open(fname, NULL, O_RDWR | O_CREAT | O_APPEND);
1234 if (CacheInfo->logfile_fd == DISK_ERROR) {
1235 debug(18, 0, "rotate_logs: Cannot open logfile: %s\n", fname);
1236 CacheInfo->logfile_status = LOG_DISABLE;
1237 fatal("Cannot open logfile.");
1238 }
1239 CacheInfo->logfile_access = file_write_lock(CacheInfo->logfile_fd);
1240 }