Blob


1 #include "stdinc.h"
2 #include "dat.h"
3 #include "fns.h"
4 #include "xml.h"
6 typedef struct HttpObj HttpObj;
7 extern QLock memdrawlock;
9 enum
10 {
11 ObjNameSize = 64,
12 MaxObjs = 64
13 };
15 struct HttpObj
16 {
17 char name[ObjNameSize];
18 int (*f)(HConnect*);
19 };
21 static HttpObj objs[MaxObjs];
23 static char *webroot;
25 static void listenproc(void*);
26 static int estats(HConnect *c);
27 static int dindex(HConnect *c);
28 static int xindex(HConnect *c);
29 static int xlog(HConnect *c);
30 static int sindex(HConnect *c);
31 static int hempty(HConnect *c);
32 static int hlcacheempty(HConnect *c);
33 static int hdcacheempty(HConnect *c);
34 static int hicacheempty(HConnect *c);
35 static int hicachekick(HConnect *c);
36 static int hdcachekick(HConnect *c);
37 static int hicacheflush(HConnect *c);
38 static int hdcacheflush(HConnect *c);
39 static int httpdobj(char *name, int (*f)(HConnect*));
40 static int xgraph(HConnect *c);
41 static int xset(HConnect *c);
42 static int fromwebdir(HConnect *c);
44 int
45 httpdinit(char *address, char *dir)
46 {
47 fmtinstall('D', hdatefmt);
48 /* fmtinstall('H', httpfmt); */
49 fmtinstall('U', hurlfmt);
51 if(address == nil)
52 address = "tcp!*!http";
53 webroot = dir;
55 httpdobj("/stats", estats);
56 httpdobj("/index", dindex);
57 httpdobj("/storage", sindex);
58 httpdobj("/xindex", xindex);
59 httpdobj("/flushicache", hicacheflush);
60 httpdobj("/flushdcache", hdcacheflush);
61 httpdobj("/kickicache", hicachekick);
62 httpdobj("/kickdcache", hdcachekick);
63 httpdobj("/graph", xgraph);
64 httpdobj("/set", xset);
65 httpdobj("/log", xlog);
66 httpdobj("/empty", hempty);
67 httpdobj("/emptyicache", hicacheempty);
68 httpdobj("/emptylumpcache", hlcacheempty);
69 httpdobj("/emptydcache", hdcacheempty);
70 httpdobj("/disk", hdisk);
71 httpdobj("/debug", hdebug);
72 httpdobj("/proc/", hproc);
74 if(vtproc(listenproc, address) < 0)
75 return -1;
76 return 0;
77 }
79 static int
80 httpdobj(char *name, int (*f)(HConnect*))
81 {
82 int i;
84 if(name == nil || strlen(name) >= ObjNameSize)
85 return -1;
86 for(i = 0; i < MaxObjs; i++){
87 if(objs[i].name[0] == '\0'){
88 strcpy(objs[i].name, name);
89 objs[i].f = f;
90 return 0;
91 }
92 if(strcmp(objs[i].name, name) == 0)
93 return -1;
94 }
95 return -1;
96 }
98 static HConnect*
99 mkconnect(void)
101 HConnect *c;
103 c = mallocz(sizeof(HConnect), 1);
104 if(c == nil)
105 sysfatal("out of memory");
106 c->replog = nil;
107 c->hpos = c->header;
108 c->hstop = c->header;
109 return c;
112 void httpproc(void*);
114 static void
115 listenproc(void *vaddress)
117 HConnect *c;
118 char *address, ndir[NETPATHLEN], dir[NETPATHLEN];
119 int ctl, nctl, data;
121 address = vaddress;
122 ctl = announce(address, dir);
123 if(ctl < 0){
124 fprint(2, "venti: httpd can't announce on %s: %r\n", address);
125 return;
128 if(0) print("announce ctl %d dir %s\n", ctl, dir);
129 for(;;){
130 /*
131 * wait for a call (or an error)
132 */
133 nctl = listen(dir, ndir);
134 if(0) print("httpd listen %d %s...\n", nctl, ndir);
135 if(nctl < 0){
136 fprint(2, "venti: httpd can't listen on %s: %r\n", address);
137 return;
140 data = accept(ctl, ndir);
141 if(0) print("httpd accept %d...\n", data);
142 if(data < 0){
143 fprint(2, "venti: httpd accept: %r\n");
144 close(nctl);
145 continue;
147 if(0) print("httpd close nctl %d\n", nctl);
148 close(nctl);
149 c = mkconnect();
150 hinit(&c->hin, data, Hread);
151 hinit(&c->hout, data, Hwrite);
152 vtproc(httpproc, c);
156 void
157 httpproc(void *v)
159 HConnect *c;
160 int ok, i, n;
162 c = v;
164 for(;;){
165 /*
166 * No timeout because the signal appears to hit every
167 * proc, not just us.
168 */
169 if(hparsereq(c, 0) < 0)
170 break;
172 for(i = 0; i < MaxObjs && objs[i].name[0]; i++){
173 n = strlen(objs[i].name);
174 if((objs[i].name[n-1] == '/' && strncmp(c->req.uri, objs[i].name, n) == 0)
175 || (objs[i].name[n-1] != '/' && strcmp(c->req.uri, objs[i].name) == 0)){
176 ok = (*objs[i].f)(c);
177 goto found;
180 ok = fromwebdir(c);
181 found:
182 hflush(&c->hout);
183 if(c->head.closeit)
184 ok = -1;
185 hreqcleanup(c);
187 if(ok < 0)
188 break;
190 hreqcleanup(c);
191 close(c->hin.fd);
192 free(c);
195 char*
196 hargstr(HConnect *c, char *name, char *def)
198 HSPairs *p;
200 for(p=c->req.searchpairs; p; p=p->next)
201 if(strcmp(p->s, name) == 0)
202 return p->t;
203 return def;
206 vlong
207 hargint(HConnect *c, char *name, vlong def)
209 char *a;
211 if((a = hargstr(c, name, nil)) == nil)
212 return def;
213 return atoll(a);
216 static int
217 percent(ulong v, ulong total)
219 if(total == 0)
220 total = 1;
221 if(v < 1000*1000)
222 return (v * 100) / total;
223 total /= 100;
224 if(total == 0)
225 total = 1;
226 return v / total;
229 static int
230 preq(HConnect *c)
232 if(hparseheaders(c, 0) < 0)
233 return -1;
234 if(strcmp(c->req.meth, "GET") != 0
235 && strcmp(c->req.meth, "HEAD") != 0)
236 return hunallowed(c, "GET, HEAD");
237 if(c->head.expectother || c->head.expectcont)
238 return hfail(c, HExpectFail, nil);
239 return 0;
242 int
243 hsettype(HConnect *c, char *type)
245 Hio *hout;
246 int r;
248 r = preq(c);
249 if(r < 0)
250 return r;
252 hout = &c->hout;
253 if(c->req.vermaj){
254 hokheaders(c);
255 hprint(hout, "Content-type: %s\r\n", type);
256 if(http11(c))
257 hprint(hout, "Transfer-Encoding: chunked\r\n");
258 hprint(hout, "\r\n");
261 if(http11(c))
262 hxferenc(hout, 1);
263 else
264 c->head.closeit = 1;
265 return 0;
268 int
269 hsethtml(HConnect *c)
271 return hsettype(c, "text/html; charset=utf-8");
274 int
275 hsettext(HConnect *c)
277 return hsettype(c, "text/plain; charset=utf-8");
280 static int
281 herror(HConnect *c)
283 int n;
284 Hio *hout;
286 hout = &c->hout;
287 n = snprint(c->xferbuf, HBufSize, "<html><head><title>Error</title></head>\n<body><h1>Error</h1>\n<pre>%r</pre>\n</body></html>");
288 hprint(hout, "%s %s\r\n", hversion, "400 Bad Request");
289 hprint(hout, "Date: %D\r\n", time(nil));
290 hprint(hout, "Server: Venti\r\n");
291 hprint(hout, "Content-Type: text/html\r\n");
292 hprint(hout, "Content-Length: %d\r\n", n);
293 if(c->head.closeit)
294 hprint(hout, "Connection: close\r\n");
295 else if(!http11(c))
296 hprint(hout, "Connection: Keep-Alive\r\n");
297 hprint(hout, "\r\n");
299 if(c->req.meth == nil || strcmp(c->req.meth, "HEAD") != 0)
300 hwrite(hout, c->xferbuf, n);
302 return hflush(hout);
305 int
306 hnotfound(HConnect *c)
308 int r;
310 r = preq(c);
311 if(r < 0)
312 return r;
313 return hfail(c, HNotFound, c->req.uri);
316 struct {
317 char *ext;
318 char *type;
319 } exttab[] = {
320 ".html", "text/html",
321 ".txt", "text/plain",
322 ".xml", "text/xml",
323 ".png", "image/png",
324 ".gif", "image/gif",
326 };
328 static int
329 fromwebdir(HConnect *c)
331 char buf[4096], *p, *ext, *type;
332 int i, fd, n, defaulted;
333 Dir *d;
335 if(webroot == nil || strstr(c->req.uri, ".."))
336 return hnotfound(c);
337 snprint(buf, sizeof buf-20, "%s/%s", webroot, c->req.uri+1);
338 defaulted = 0;
339 reopen:
340 if((fd = open(buf, OREAD)) < 0)
341 return hnotfound(c);
342 d = dirfstat(fd);
343 if(d == nil){
344 close(fd);
345 return hnotfound(c);
347 if(d->mode&DMDIR){
348 if(!defaulted){
349 defaulted = 1;
350 strcat(buf, "/index.html");
351 free(d);
352 close(fd);
353 goto reopen;
355 free(d);
356 return hnotfound(c);
358 free(d);
359 p = buf+strlen(buf);
360 type = "application/octet-stream";
361 for(i=0; exttab[i].ext; i++){
362 ext = exttab[i].ext;
363 if(p-strlen(ext) >= buf && strcmp(p-strlen(ext), ext) == 0){
364 type = exttab[i].type;
365 break;
368 if(hsettype(c, type) < 0){
369 close(fd);
370 return 0;
372 while((n = read(fd, buf, sizeof buf)) > 0)
373 if(hwrite(&c->hout, buf, n) < 0)
374 break;
375 close(fd);
376 hflush(&c->hout);
377 return 0;
380 static struct
382 char *name;
383 int *p;
384 } namedints[] =
386 "compress", &compressblocks,
387 "devnull", &writestodevnull,
388 "logging", &ventilogging,
389 "stats", &collectstats,
390 "icachesleeptime", &icachesleeptime,
391 "minicachesleeptime", &minicachesleeptime,
392 "arenasumsleeptime", &arenasumsleeptime,
393 "l0quantum", &l0quantum,
394 "l1quantum", &l1quantum,
395 "manualscheduling", &manualscheduling,
396 "ignorebloom", &ignorebloom,
397 "syncwrites", &syncwrites,
398 "icacheprefetch", &icacheprefetch,
399 "bootstrap", &bootstrap,
401 };
403 static int
404 xset(HConnect *c)
406 int i, old;
407 char *name, *value;
409 if(hsettext(c) < 0)
410 return -1;
412 if((name = hargstr(c, "name", nil)) == nil || name[0] == 0){
413 for(i=0; namedints[i].name; i++)
414 hprint(&c->hout, "%s = %d\n", namedints[i].name, *namedints[i].p);
415 hflush(&c->hout);
416 return 0;
419 for(i=0; namedints[i].name; i++)
420 if(strcmp(name, namedints[i].name) == 0)
421 break;
422 if(!namedints[i].name){
423 hprint(&c->hout, "%s not found\n", name);
424 hflush(&c->hout);
425 return 0;
428 if((value = hargstr(c, "value", nil)) == nil || value[0] == 0){
429 hprint(&c->hout, "%s = %d\n", namedints[i].name, *namedints[i].p);
430 hflush(&c->hout);
431 return 0;
434 old = *namedints[i].p;
435 *namedints[i].p = atoll(value);
436 hprint(&c->hout, "%s = %d (was %d)\n", name, *namedints[i].p, old);
437 hflush(&c->hout);
438 return 0;
441 static int
442 estats(HConnect *c)
444 Hio *hout;
445 int r;
447 r = hsettext(c);
448 if(r < 0)
449 return r;
452 hout = &c->hout;
453 /*
454 hprint(hout, "lump writes=%,ld\n", stats.lumpwrites);
455 hprint(hout, "lump reads=%,ld\n", stats.lumpreads);
456 hprint(hout, "lump cache read hits=%,ld\n", stats.lumphit);
457 hprint(hout, "lump cache read misses=%,ld\n", stats.lumpmiss);
459 hprint(hout, "clump disk writes=%,ld\n", stats.clumpwrites);
460 hprint(hout, "clump disk bytes written=%,lld\n", stats.clumpbwrites);
461 hprint(hout, "clump disk bytes compressed=%,lld\n", stats.clumpbcomp);
462 hprint(hout, "clump disk reads=%,ld\n", stats.clumpreads);
463 hprint(hout, "clump disk bytes read=%,lld\n", stats.clumpbreads);
464 hprint(hout, "clump disk bytes uncompressed=%,lld\n", stats.clumpbuncomp);
466 hprint(hout, "clump directory disk writes=%,ld\n", stats.ciwrites);
467 hprint(hout, "clump directory disk reads=%,ld\n", stats.cireads);
469 hprint(hout, "index disk writes=%,ld\n", stats.indexwrites);
470 hprint(hout, "index disk reads=%,ld\n", stats.indexreads);
471 hprint(hout, "index disk bloom filter hits=%,ld %d%% falsemisses=%,ld %d%%\n",
472 stats.indexbloomhits,
473 percent(stats.indexbloomhits, stats.indexreads),
474 stats.indexbloomfalsemisses,
475 percent(stats.indexbloomfalsemisses, stats.indexreads));
476 hprint(hout, "bloom filter bits=%,ld of %,ld %d%%\n",
477 stats.bloomones, stats.bloombits, percent(stats.bloomones, stats.bloombits));
478 hprint(hout, "index disk reads for modify=%,ld\n", stats.indexwreads);
479 hprint(hout, "index disk reads for allocation=%,ld\n", stats.indexareads);
480 hprint(hout, "index block splits=%,ld\n", stats.indexsplits);
482 hprint(hout, "index cache lookups=%,ld\n", stats.iclookups);
483 hprint(hout, "index cache hits=%,ld %d%%\n", stats.ichits,
484 percent(stats.ichits, stats.iclookups));
485 hprint(hout, "index cache fills=%,ld %d%%\n", stats.icfills,
486 percent(stats.icfills, stats.iclookups));
487 hprint(hout, "index cache inserts=%,ld\n", stats.icinserts);
489 hprint(hout, "disk cache hits=%,ld\n", stats.pchit);
490 hprint(hout, "disk cache misses=%,ld\n", stats.pcmiss);
491 hprint(hout, "disk cache reads=%,ld\n", stats.pcreads);
492 hprint(hout, "disk cache bytes read=%,lld\n", stats.pcbreads);
494 hprint(hout, "disk cache writes=%,ld\n", stats.dirtydblocks);
495 hprint(hout, "disk cache writes absorbed=%,ld %d%%\n", stats.absorbedwrites,
496 percent(stats.absorbedwrites, stats.dirtydblocks));
498 hprint(hout, "disk cache flushes=%,ld\n", stats.dcacheflushes);
499 hprint(hout, "disk cache flush writes=%,ld (%,ld per flush)\n",
500 stats.dcacheflushwrites,
501 stats.dcacheflushwrites/(stats.dcacheflushes ? stats.dcacheflushes : 1));
503 hprint(hout, "disk writes=%,ld\n", stats.diskwrites);
504 hprint(hout, "disk bytes written=%,lld\n", stats.diskbwrites);
505 hprint(hout, "disk reads=%,ld\n", stats.diskreads);
506 hprint(hout, "disk bytes read=%,lld\n", stats.diskbreads);
507 */
509 hflush(hout);
510 return 0;
513 static int
514 sindex(HConnect *c)
516 Hio *hout;
517 Index *ix;
518 Arena *arena;
519 vlong clumps, cclumps, uncsize, used, size;
520 int i, r, active;
522 r = hsettext(c);
523 if(r < 0)
524 return r;
525 hout = &c->hout;
527 ix = mainindex;
529 hprint(hout, "index=%s\n", ix->name);
531 active = 0;
532 clumps = 0;
533 cclumps = 0;
534 uncsize = 0;
535 used = 0;
536 size = 0;
537 for(i = 0; i < ix->narenas; i++){
538 arena = ix->arenas[i];
539 if(arena != nil && arena->memstats.clumps != 0){
540 active++;
541 clumps += arena->memstats.clumps;
542 cclumps += arena->memstats.cclumps;
543 uncsize += arena->memstats.uncsize;
544 used += arena->memstats.used;
546 size += arena->size;
548 hprint(hout, "total arenas=%,d active=%,d\n", ix->narenas, active);
549 hprint(hout, "total space=%,lld used=%,lld\n", size, used + clumps * ClumpInfoSize);
550 hprint(hout, "clumps=%,lld compressed clumps=%,lld data=%,lld compressed data=%,lld\n",
551 clumps, cclumps, uncsize, used - clumps * ClumpSize);
552 hflush(hout);
553 return 0;
556 static void
557 darena(Hio *hout, Arena *arena)
559 hprint(hout, "arena='%s' on %s at [%lld,%lld)\n\tversion=%d created=%d modified=%d",
560 arena->name, arena->part->name, arena->base, arena->base + arena->size + 2 * arena->blocksize,
561 arena->version, arena->ctime, arena->wtime);
562 if(arena->memstats.sealed)
563 hprint(hout, " mem=sealed");
564 if(arena->diskstats.sealed)
565 hprint(hout, " disk=sealed");
566 if(arena->inqueue)
567 hprint(hout, " inqueue");
568 hprint(hout, "\n");
569 if(scorecmp(zeroscore, arena->score) != 0)
570 hprint(hout, "\tscore=%V\n", arena->score);
572 hprint(hout, "\twritten: clumps=%d compressed clumps=%d data=%,lld compressed data=%,lld storage=%,lld\n",
573 arena->memstats.clumps, arena->memstats.cclumps, arena->memstats.uncsize,
574 arena->memstats.used - arena->memstats.clumps * ClumpSize,
575 arena->memstats.used + arena->memstats.clumps * ClumpInfoSize);
576 hprint(hout, "\tindexed: clumps=%d compressed clumps=%d data=%,lld compressed data=%,lld storage=%,lld\n",
577 arena->diskstats.clumps, arena->diskstats.cclumps, arena->diskstats.uncsize,
578 arena->diskstats.used - arena->diskstats.clumps * ClumpSize,
579 arena->diskstats.used + arena->diskstats.clumps * ClumpInfoSize);
582 static int
583 hempty(HConnect *c)
585 Hio *hout;
586 int r;
588 r = hsettext(c);
589 if(r < 0)
590 return r;
591 hout = &c->hout;
593 emptylumpcache();
594 emptydcache();
595 emptyicache();
596 hprint(hout, "emptied all caches\n");
597 hflush(hout);
598 return 0;
601 static int
602 hlcacheempty(HConnect *c)
604 Hio *hout;
605 int r;
607 r = hsettext(c);
608 if(r < 0)
609 return r;
610 hout = &c->hout;
612 emptylumpcache();
613 hprint(hout, "emptied lumpcache\n");
614 hflush(hout);
615 return 0;
618 static int
619 hicacheempty(HConnect *c)
621 Hio *hout;
622 int r;
624 r = hsettext(c);
625 if(r < 0)
626 return r;
627 hout = &c->hout;
629 emptyicache();
630 hprint(hout, "emptied icache\n");
631 hflush(hout);
632 return 0;
635 static int
636 hdcacheempty(HConnect *c)
638 Hio *hout;
639 int r;
641 r = hsettext(c);
642 if(r < 0)
643 return r;
644 hout = &c->hout;
646 emptydcache();
647 hprint(hout, "emptied dcache\n");
648 hflush(hout);
649 return 0;
651 static int
652 hicachekick(HConnect *c)
654 Hio *hout;
655 int r;
657 r = hsettext(c);
658 if(r < 0)
659 return r;
660 hout = &c->hout;
662 kickicache();
663 hprint(hout, "kicked icache\n");
664 hflush(hout);
665 return 0;
668 static int
669 hdcachekick(HConnect *c)
671 Hio *hout;
672 int r;
674 r = hsettext(c);
675 if(r < 0)
676 return r;
677 hout = &c->hout;
679 kickdcache();
680 hprint(hout, "kicked dcache\n");
681 hflush(hout);
682 return 0;
684 static int
685 hicacheflush(HConnect *c)
687 Hio *hout;
688 int r;
690 r = hsettext(c);
691 if(r < 0)
692 return r;
693 hout = &c->hout;
695 flushicache();
696 hprint(hout, "flushed icache\n");
697 hflush(hout);
698 return 0;
701 static int
702 hdcacheflush(HConnect *c)
704 Hio *hout;
705 int r;
707 r = hsettext(c);
708 if(r < 0)
709 return r;
710 hout = &c->hout;
712 flushdcache();
713 hprint(hout, "flushed dcache\n");
714 hflush(hout);
715 return 0;
718 static int
719 dindex(HConnect *c)
721 Hio *hout;
722 Index *ix;
723 int i, r;
725 r = hsettext(c);
726 if(r < 0)
727 return r;
728 hout = &c->hout;
731 ix = mainindex;
732 hprint(hout, "index=%s version=%d blocksize=%d tabsize=%d\n",
733 ix->name, ix->version, ix->blocksize, ix->tabsize);
734 hprint(hout, "\tbuckets=%d div=%d\n", ix->buckets, ix->div);
735 for(i = 0; i < ix->nsects; i++)
736 hprint(hout, "\tsect=%s for buckets [%lld,%lld) buckmax=%d\n", ix->smap[i].name, ix->smap[i].start, ix->smap[i].stop, ix->sects[i]->buckmax);
737 for(i = 0; i < ix->narenas; i++){
738 if(ix->arenas[i] != nil && ix->arenas[i]->memstats.clumps != 0){
739 hprint(hout, "arena=%s at index [%lld,%lld)\n\t", ix->amap[i].name, ix->amap[i].start, ix->amap[i].stop);
740 darena(hout, ix->arenas[i]);
743 hflush(hout);
744 return 0;
747 typedef struct Arg Arg;
748 struct Arg
750 int index;
751 int index2;
752 };
754 static long
755 rawgraph(Stats *s, Stats *t, void *va)
757 Arg *a;
759 USED(s);
760 a = va;
761 return t->n[a->index];
764 static long
765 diffgraph(Stats *s, Stats *t, void *va)
767 Arg *a;
769 a = va;
770 return t->n[a->index] - s->n[a->index];
773 static long
774 pctgraph(Stats *s, Stats *t, void *va)
776 Arg *a;
778 USED(s);
779 a = va;
780 return percent(t->n[a->index], t->n[a->index2]);
783 static long
784 pctdiffgraph(Stats *s, Stats *t, void *va)
786 Arg *a;
788 a = va;
789 return percent(t->n[a->index]-s->n[a->index], t->n[a->index2]-s->n[a->index2]);
792 static long
793 xdiv(long a, long b)
795 if(b == 0)
796 b++;
797 return a/b;
800 static long
801 divdiffgraph(Stats *s, Stats *t, void *va)
803 Arg *a;
805 a = va;
806 return xdiv(t->n[a->index] - s->n[a->index], t->n[a->index2] - s->n[a->index2]);
809 static long
810 netbw(Stats *s)
812 ulong *n;
814 n = s->n;
815 return n[StatRpcReadBytes]+n[StatRpcWriteBytes]; /* not exactly right */
818 static long
819 diskbw(Stats *s)
821 ulong *n;
823 n = s->n;
824 return n[StatApartReadBytes]+n[StatApartWriteBytes]
825 + n[StatIsectReadBytes]+n[StatIsectWriteBytes]
826 + n[StatSumReadBytes];
829 static long
830 iobw(Stats *s)
832 return netbw(s)+diskbw(s);
835 static long
836 diskgraph(Stats *s, Stats *t, void *va)
838 USED(va);
839 return diskbw(t)-diskbw(s);
842 static long
843 netgraph(Stats *s, Stats *t, void *va)
845 USED(va);
846 return netbw(t)-netbw(s);
849 static long
850 iograph(Stats *s, Stats *t, void *va)
852 USED(va);
853 return iobw(t)-iobw(s);
857 static char* graphname[] =
859 "rpctotal",
860 "rpcread",
861 "rpcreadok",
862 "rpcreadfail",
863 "rpcreadbyte",
864 "rpcreadtime",
865 "rpcreadcached",
866 "rpcreadcachedtime",
867 "rpcreaduncached",
868 "rpcreaduncachedtime",
869 "rpcwrite",
870 "rpcwritenew",
871 "rpcwriteold",
872 "rpcwritefail",
873 "rpcwritebyte",
874 "rpcwritetime",
875 "rpcwritenewtime",
876 "rpcwriteoldtime",
878 "lcachehit",
879 "lcachemiss",
880 "lcachelookup",
881 "lcachewrite",
882 "lcachesize",
883 "lcachestall",
884 "lcachelookuptime",
886 "dcachehit",
887 "dcachemiss",
888 "dcachelookup",
889 "dcacheread",
890 "dcachewrite",
891 "dcachedirty",
892 "dcachesize",
893 "dcacheflush",
894 "dcachestall",
895 "dcachelookuptime",
897 "dblockstall",
898 "lumpstall",
900 "icachehit",
901 "icachemiss",
902 "icacheread",
903 "icachewrite",
904 "icachefill",
905 "icacheprefetch",
906 "icachedirty",
907 "icachesize",
908 "icacheflush",
909 "icachestall",
910 "icachelookuptime",
911 "icachelookup",
912 "scachehit",
913 "scacheprefetch",
915 "bloomhit",
916 "bloommiss",
917 "bloomfalsemiss",
918 "bloomlookup",
919 "bloomones",
920 "bloombits",
922 "apartread",
923 "apartreadbyte",
924 "apartwrite",
925 "apartwritebyte",
927 "isectread",
928 "isectreadbyte",
929 "isectwrite",
930 "isectwritebyte",
932 "sumread",
933 "sumreadbyte",
935 "cigload",
936 "cigloadtime",
937 };
939 static int
940 findname(char *s)
942 int i;
944 for(i=0; i<nelem(graphname); i++)
945 if(strcmp(graphname[i], s) == 0)
946 return i;
947 return -1;
950 static void
951 dotextbin(Hio *io, Graph *g)
953 int i, nbin;
954 Statbin *b, bin[2000]; /* 32 kB, but whack is worse */
956 needstack(8192); /* double check that bin didn't kill us */
957 nbin = 100;
958 binstats(g->fn, g->arg, g->t0, g->t1, bin, nbin);
960 hprint(io, "stats\n\n");
961 for(i=0; i<nbin; i++){
962 b = &bin[i];
963 hprint(io, "%d: nsamp=%d min=%d max=%d avg=%d\n",
964 i, b->nsamp, b->min, b->max, b->avg);
968 static int
969 xgraph(HConnect *c)
971 char *name;
972 Hio *hout;
973 Memimage *m;
974 int dotext;
975 Graph g;
976 Arg arg;
977 char *graph, *a;
979 name = hargstr(c, "arg", "");
980 if((arg.index = findname(name)) == -1 && strcmp(name, "*") != 0){
981 werrstr("unknown name %s", name);
982 goto error;
984 a = hargstr(c, "arg2", "");
985 if(a[0] && (arg.index2 = findname(a)) == -1){
986 werrstr("unknown name %s", a);
987 goto error;
990 g.arg = &arg;
991 g.t0 = hargint(c, "t0", -120);
992 g.t1 = hargint(c, "t1", 0);
993 g.min = hargint(c, "min", -1);
994 g.max = hargint(c, "max", -1);
995 g.wid = hargint(c, "wid", -1);
996 g.ht = hargint(c, "ht", -1);
997 dotext = hargstr(c, "text", "")[0] != 0;
998 g.fill = hargint(c, "fill", -1);
1000 graph = hargstr(c, "graph", "raw");
1001 if(strcmp(graph, "raw") == 0)
1002 g.fn = rawgraph;
1003 else if(strcmp(graph, "diskbw") == 0)
1004 g.fn = diskgraph;
1005 else if(strcmp(graph, "iobw") == 0)
1006 g.fn = iograph;
1007 else if(strcmp(graph, "netbw") == 0)
1008 g.fn = netgraph;
1009 else if(strcmp(graph, "diff") == 0)
1010 g.fn = diffgraph;
1011 else if(strcmp(graph, "pct") == 0)
1012 g.fn = pctgraph;
1013 else if(strcmp(graph, "pctdiff") == 0)
1014 g.fn = pctdiffgraph;
1015 else if(strcmp(graph, "divdiff") == 0)
1016 g.fn = divdiffgraph;
1017 else{
1018 werrstr("unknown graph %s", graph);
1019 goto error;
1022 if(dotext){
1023 hsettype(c, "text/plain");
1024 dotextbin(&c->hout, &g);
1025 hflush(&c->hout);
1026 return 0;
1029 m = statgraph(&g);
1030 if(m == nil)
1031 goto error;
1033 if(hsettype(c, "image/png") < 0)
1034 return -1;
1035 hout = &c->hout;
1036 writepng(hout, m);
1037 qlock(&memdrawlock);
1038 freememimage(m);
1039 qunlock(&memdrawlock);
1040 hflush(hout);
1041 return 0;
1043 error:
1044 return herror(c);
1047 static int
1048 xloglist(HConnect *c)
1050 if(hsettype(c, "text/html") < 0)
1051 return -1;
1052 vtloghlist(&c->hout);
1053 hflush(&c->hout);
1054 return 0;
1057 static int
1058 xlog(HConnect *c)
1060 char *name;
1061 VtLog *l;
1063 name = hargstr(c, "log", "");
1064 if(!name[0])
1065 return xloglist(c);
1066 l = vtlogopen(name, 0);
1067 if(l == nil)
1068 return hnotfound(c);
1069 if(hsettype(c, "text/html") < 0){
1070 vtlogclose(l);
1071 return -1;
1073 vtloghdump(&c->hout, l);
1074 vtlogclose(l);
1075 hflush(&c->hout);
1076 return 0;
1079 static int
1080 xindex(HConnect *c)
1082 if(hsettype(c, "text/xml") < 0)
1083 return -1;
1084 xmlindex(&c->hout, mainindex, "index", 0);
1085 hflush(&c->hout);
1086 return 0;
1089 void
1090 xmlindent(Hio *hout, int indent)
1092 int i;
1094 for(i = 0; i < indent; i++)
1095 hputc(hout, '\t');
1098 void
1099 xmlaname(Hio *hout, char *v, char *tag)
1101 hprint(hout, " %s=\"%s\"", tag, v);
1104 void
1105 xmlscore(Hio *hout, u8int *v, char *tag)
1107 if(scorecmp(zeroscore, v) == 0)
1108 return;
1109 hprint(hout, " %s=\"%V\"", tag, v);
1112 void
1113 xmlsealed(Hio *hout, int v, char *tag)
1115 if(!v)
1116 return;
1117 hprint(hout, " %s=\"yes\"", tag);
1120 void
1121 xmlu32int(Hio *hout, u32int v, char *tag)
1123 hprint(hout, " %s=\"%ud\"", tag, v);
1126 void
1127 xmlu64int(Hio *hout, u64int v, char *tag)
1129 hprint(hout, " %s=\"%llud\"", tag, v);
1132 void
1133 vtloghdump(Hio *h, VtLog *l)
1135 int i;
1136 VtLogChunk *c;
1137 char *name;
1139 name = l ? l->name : "&lt;nil&gt;";
1141 hprint(h, "<html><head>\n");
1142 hprint(h, "<title>Venti Server Log: %s</title>\n", name);
1143 hprint(h, "</head><body>\n");
1144 hprint(h, "<b>Venti Server Log: %s</b>\n<p>\n", name);
1146 if(l){
1147 c = l->w;
1148 for(i=0; i<l->nchunk; i++){
1149 if(++c == l->chunk+l->nchunk)
1150 c = l->chunk;
1151 hwrite(h, c->p, c->wp-c->p);
1154 hprint(h, "</body></html>\n");
1157 static int
1158 strpcmp(const void *va, const void *vb)
1160 return strcmp(*(char**)va, *(char**)vb);
1163 void
1164 vtloghlist(Hio *h)
1166 char **p;
1167 int i, n;
1169 hprint(h, "<html><head>\n");
1170 hprint(h, "<title>Venti Server Logs</title>\n");
1171 hprint(h, "</head><body>\n");
1172 hprint(h, "<b>Venti Server Logs</b>\n<p>\n");
1174 p = vtlognames(&n);
1175 qsort(p, n, sizeof(p[0]), strpcmp);
1176 for(i=0; i<n; i++)
1177 hprint(h, "<a href=\"/log?log=%s\">%s</a><br>\n", p[i], p[i]);
1178 vtfree(p);
1179 hprint(h, "</body></html>\n");