| ---
thttpd.c (22933B)
---
1 #include "stdinc.h"
2 #include "dat.h"
3 #include "fns.h"
4 #include "xml.h"
5
6 typedef struct HttpObj HttpObj;
7 extern QLock memdrawlock;
8
9 enum
10 {
11 ObjNameSize = 64,
12 MaxObjs = 64
13 };
14
15 struct HttpObj
16 {
17 char name[ObjNameSize];
18 int (*f)(HConnect*);
19 };
20
21 static HttpObj objs[MaxObjs];
22
23 static char *webroot;
24
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);
43
44 int
45 httpdinit(char *address, char *dir)
46 {
47 fmtinstall('D', hdatefmt);
48 /* fmtinstall('H', httpfmt); */
49 fmtinstall('U', hurlfmt);
50
51 if(address == nil)
52 address = "tcp!*!http";
53 webroot = dir;
54
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);
73
74 if(vtproc(listenproc, address) < 0)
75 return -1;
76 return 0;
77 }
78
79 static int
80 httpdobj(char *name, int (*f)(HConnect*))
81 {
82 int i;
83
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 }
97
98 static HConnect*
99 mkconnect(void)
100 {
101 HConnect *c;
102
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;
110 }
111
112 void httpproc(void*);
113
114 static void
115 listenproc(void *vaddress)
116 {
117 HConnect *c;
118 char *address, ndir[NETPATHLEN], dir[NETPATHLEN];
119 int ctl, nctl, data;
120
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;
126 }
127
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;
138 }
139
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;
146 }
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);
153 }
154 }
155
156 void
157 httpproc(void *v)
158 {
159 HConnect *c;
160 int ok, i, n;
161
162 c = v;
163
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;
171
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;
178 }
179 }
180 ok = fromwebdir(c);
181 found:
182 hflush(&c->hout);
183 if(c->head.closeit)
184 ok = -1;
185 hreqcleanup(c);
186
187 if(ok < 0)
188 break;
189 }
190 hreqcleanup(c);
191 close(c->hin.fd);
192 free(c);
193 }
194
195 char*
196 hargstr(HConnect *c, char *name, char *def)
197 {
198 HSPairs *p;
199
200 for(p=c->req.searchpairs; p; p=p->next)
201 if(strcmp(p->s, name) == 0)
202 return p->t;
203 return def;
204 }
205
206 vlong
207 hargint(HConnect *c, char *name, vlong def)
208 {
209 char *a;
210
211 if((a = hargstr(c, name, nil)) == nil)
212 return def;
213 return atoll(a);
214 }
215
216 static int
217 percent(ulong v, ulong total)
218 {
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;
227 }
228
229 static int
230 preq(HConnect *c)
231 {
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;
240 }
241
242 int
243 hsettype(HConnect *c, char *type)
244 {
245 Hio *hout;
246 int r;
247
248 r = preq(c);
249 if(r < 0)
250 return r;
251
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");
259 }
260
261 if(http11(c))
262 hxferenc(hout, 1);
263 else
264 c->head.closeit = 1;
265 return 0;
266 }
267
268 int
269 hsethtml(HConnect *c)
270 {
271 return hsettype(c, "text/html; charset=utf-8");
272 }
273
274 int
275 hsettext(HConnect *c)
276 {
277 return hsettype(c, "text/plain; charset=utf-8");
278 }
279
280 static int
281 herror(HConnect *c)
282 {
283 int n;
284 Hio *hout;
285
286 hout = &c->hout;
287 n = snprint(c->xferbuf, HBufSize, "Error\nError\n%r \n");
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");
298
299 if(c->req.meth == nil || strcmp(c->req.meth, "HEAD") != 0)
300 hwrite(hout, c->xferbuf, n);
301
302 return hflush(hout);
303 }
304
305 int
306 hnotfound(HConnect *c)
307 {
308 int r;
309
310 r = preq(c);
311 if(r < 0)
312 return r;
313 return hfail(c, HNotFound, c->req.uri);
314 }
315
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",
325 0
326 };
327
328 static int
329 fromwebdir(HConnect *c)
330 {
331 char buf[4096], *p, *ext, *type;
332 int i, fd, n, defaulted;
333 Dir *d;
334
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);
346 }
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;
354 }
355 free(d);
356 return hnotfound(c);
357 }
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;
366 }
367 }
368 if(hsettype(c, type) < 0){
369 close(fd);
370 return 0;
371 }
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;
378 }
379
380 static struct
381 {
382 char *name;
383 int *p;
384 } namedints[] =
385 {
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,
400 0
401 };
402
403 static int
404 xset(HConnect *c)
405 {
406 int i, old;
407 char *name, *value;
408
409 if(hsettext(c) < 0)
410 return -1;
411
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;
417 }
418
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;
426 }
427
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;
432 }
433
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;
439 }
440
441 static int
442 estats(HConnect *c)
443 {
444 Hio *hout;
445 int r;
446
447 r = hsettext(c);
448 if(r < 0)
449 return r;
450
451
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);
458
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);
465
466 hprint(hout, "clump directory disk writes=%,ld\n", stats.ciwrites);
467 hprint(hout, "clump directory disk reads=%,ld\n", stats.cireads);
468
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);
481
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);
488
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);
493
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));
497
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));
502
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 */
508
509 hflush(hout);
510 return 0;
511 }
512
513 static int
514 sindex(HConnect *c)
515 {
516 Hio *hout;
517 Index *ix;
518 Arena *arena;
519 vlong clumps, cclumps, uncsize, used, size;
520 int i, r, active;
521
522 r = hsettext(c);
523 if(r < 0)
524 return r;
525 hout = &c->hout;
526
527 ix = mainindex;
528
529 hprint(hout, "index=%s\n", ix->name);
530
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;
545 }
546 size += arena->size;
547 }
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;
554 }
555
556 static void
557 darena(Hio *hout, Arena *arena)
558 {
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);
571
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);
580 }
581
582 static int
583 hempty(HConnect *c)
584 {
585 Hio *hout;
586 int r;
587
588 r = hsettext(c);
589 if(r < 0)
590 return r;
591 hout = &c->hout;
592
593 emptylumpcache();
594 emptydcache();
595 emptyicache();
596 hprint(hout, "emptied all caches\n");
597 hflush(hout);
598 return 0;
599 }
600
601 static int
602 hlcacheempty(HConnect *c)
603 {
604 Hio *hout;
605 int r;
606
607 r = hsettext(c);
608 if(r < 0)
609 return r;
610 hout = &c->hout;
611
612 emptylumpcache();
613 hprint(hout, "emptied lumpcache\n");
614 hflush(hout);
615 return 0;
616 }
617
618 static int
619 hicacheempty(HConnect *c)
620 {
621 Hio *hout;
622 int r;
623
624 r = hsettext(c);
625 if(r < 0)
626 return r;
627 hout = &c->hout;
628
629 emptyicache();
630 hprint(hout, "emptied icache\n");
631 hflush(hout);
632 return 0;
633 }
634
635 static int
636 hdcacheempty(HConnect *c)
637 {
638 Hio *hout;
639 int r;
640
641 r = hsettext(c);
642 if(r < 0)
643 return r;
644 hout = &c->hout;
645
646 emptydcache();
647 hprint(hout, "emptied dcache\n");
648 hflush(hout);
649 return 0;
650 }
651 static int
652 hicachekick(HConnect *c)
653 {
654 Hio *hout;
655 int r;
656
657 r = hsettext(c);
658 if(r < 0)
659 return r;
660 hout = &c->hout;
661
662 kickicache();
663 hprint(hout, "kicked icache\n");
664 hflush(hout);
665 return 0;
666 }
667
668 static int
669 hdcachekick(HConnect *c)
670 {
671 Hio *hout;
672 int r;
673
674 r = hsettext(c);
675 if(r < 0)
676 return r;
677 hout = &c->hout;
678
679 kickdcache();
680 hprint(hout, "kicked dcache\n");
681 hflush(hout);
682 return 0;
683 }
684 static int
685 hicacheflush(HConnect *c)
686 {
687 Hio *hout;
688 int r;
689
690 r = hsettext(c);
691 if(r < 0)
692 return r;
693 hout = &c->hout;
694
695 flushicache();
696 hprint(hout, "flushed icache\n");
697 hflush(hout);
698 return 0;
699 }
700
701 static int
702 hdcacheflush(HConnect *c)
703 {
704 Hio *hout;
705 int r;
706
707 r = hsettext(c);
708 if(r < 0)
709 return r;
710 hout = &c->hout;
711
712 flushdcache();
713 hprint(hout, "flushed dcache\n");
714 hflush(hout);
715 return 0;
716 }
717
718 static int
719 dindex(HConnect *c)
720 {
721 Hio *hout;
722 Index *ix;
723 int i, r;
724
725 r = hsettext(c);
726 if(r < 0)
727 return r;
728 hout = &c->hout;
729
730
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]);
741 }
742 }
743 hflush(hout);
744 return 0;
745 }
746
747 typedef struct Arg Arg;
748 struct Arg
749 {
750 int index;
751 int index2;
752 };
753
754 static long
755 rawgraph(Stats *s, Stats *t, void *va)
756 {
757 Arg *a;
758
759 USED(s);
760 a = va;
761 return t->n[a->index];
762 }
763
764 static long
765 diffgraph(Stats *s, Stats *t, void *va)
766 {
767 Arg *a;
768
769 a = va;
770 return t->n[a->index] - s->n[a->index];
771 }
772
773 static long
774 pctgraph(Stats *s, Stats *t, void *va)
775 {
776 Arg *a;
777
778 USED(s);
779 a = va;
780 return percent(t->n[a->index], t->n[a->index2]);
781 }
782
783 static long
784 pctdiffgraph(Stats *s, Stats *t, void *va)
785 {
786 Arg *a;
787
788 a = va;
789 return percent(t->n[a->index]-s->n[a->index], t->n[a->index2]-s->n[a->index2]);
790 }
791
792 static long
793 xdiv(long a, long b)
794 {
795 if(b == 0)
796 b++;
797 return a/b;
798 }
799
800 static long
801 divdiffgraph(Stats *s, Stats *t, void *va)
802 {
803 Arg *a;
804
805 a = va;
806 return xdiv(t->n[a->index] - s->n[a->index], t->n[a->index2] - s->n[a->index2]);
807 }
808
809 static long
810 netbw(Stats *s)
811 {
812 ulong *n;
813
814 n = s->n;
815 return n[StatRpcReadBytes]+n[StatRpcWriteBytes]; /* not exactly right */
816 }
817
818 static long
819 diskbw(Stats *s)
820 {
821 ulong *n;
822
823 n = s->n;
824 return n[StatApartReadBytes]+n[StatApartWriteBytes]
825 + n[StatIsectReadBytes]+n[StatIsectWriteBytes]
826 + n[StatSumReadBytes];
827 }
828
829 static long
830 iobw(Stats *s)
831 {
832 return netbw(s)+diskbw(s);
833 }
834
835 static long
836 diskgraph(Stats *s, Stats *t, void *va)
837 {
838 USED(va);
839 return diskbw(t)-diskbw(s);
840 }
841
842 static long
843 netgraph(Stats *s, Stats *t, void *va)
844 {
845 USED(va);
846 return netbw(t)-netbw(s);
847 }
848
849 static long
850 iograph(Stats *s, Stats *t, void *va)
851 {
852 USED(va);
853 return iobw(t)-iobw(s);
854 }
855
856
857 static char* graphname[] =
858 {
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",
877
878 "lcachehit",
879 "lcachemiss",
880 "lcachelookup",
881 "lcachewrite",
882 "lcachesize",
883 "lcachestall",
884 "lcachelookuptime",
885
886 "dcachehit",
887 "dcachemiss",
888 "dcachelookup",
889 "dcacheread",
890 "dcachewrite",
891 "dcachedirty",
892 "dcachesize",
893 "dcacheflush",
894 "dcachestall",
895 "dcachelookuptime",
896
897 "dblockstall",
898 "lumpstall",
899
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",
914
915 "bloomhit",
916 "bloommiss",
917 "bloomfalsemiss",
918 "bloomlookup",
919 "bloomones",
920 "bloombits",
921
922 "apartread",
923 "apartreadbyte",
924 "apartwrite",
925 "apartwritebyte",
926
927 "isectread",
928 "isectreadbyte",
929 "isectwrite",
930 "isectwritebyte",
931
932 "sumread",
933 "sumreadbyte",
934
935 "cigload",
936 "cigloadtime",
937 };
938
939 static int
940 findname(char *s)
941 {
942 int i;
943
944 for(i=0; ifn, g->arg, g->t0, g->t1, bin, nbin);
959
960 hprint(io, "stats\n\n");
961 for(i=0; insamp, b->min, b->max, b->avg);
965 }
966 }
967
968 static int
969 xgraph(HConnect *c)
970 {
971 char *name;
972 Hio *hout;
973 Memimage *m;
974 int dotext;
975 Graph g;
976 Arg arg;
977 char *graph, *a;
978
979 name = hargstr(c, "arg", "");
980 if((arg.index = findname(name)) == -1 && strcmp(name, "*") != 0){
981 werrstr("unknown name %s", name);
982 goto error;
983 }
984 a = hargstr(c, "arg2", "");
985 if(a[0] && (arg.index2 = findname(a)) == -1){
986 werrstr("unknown name %s", a);
987 goto error;
988 }
989
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);
999
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;
1020 }
1021
1022 if(dotext){
1023 hsettype(c, "text/plain");
1024 dotextbin(&c->hout, &g);
1025 hflush(&c->hout);
1026 return 0;
1027 }
1028
1029 m = statgraph(&g);
1030 if(m == nil)
1031 goto error;
1032
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;
1042
1043 error:
1044 return herror(c);
1045 }
1046
1047 static int
1048 xloglist(HConnect *c)
1049 {
1050 if(hsettype(c, "text/html") < 0)
1051 return -1;
1052 vtloghlist(&c->hout);
1053 hflush(&c->hout);
1054 return 0;
1055 }
1056
1057 static int
1058 xlog(HConnect *c)
1059 {
1060 char *name;
1061 VtLog *l;
1062
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;
1072 }
1073 vtloghdump(&c->hout, l);
1074 vtlogclose(l);
1075 hflush(&c->hout);
1076 return 0;
1077 }
1078
1079 static int
1080 xindex(HConnect *c)
1081 {
1082 if(hsettype(c, "text/xml") < 0)
1083 return -1;
1084 xmlindex(&c->hout, mainindex, "index", 0);
1085 hflush(&c->hout);
1086 return 0;
1087 }
1088
1089 void
1090 xmlindent(Hio *hout, int indent)
1091 {
1092 int i;
1093
1094 for(i = 0; i < indent; i++)
1095 hputc(hout, '\t');
1096 }
1097
1098 void
1099 xmlaname(Hio *hout, char *v, char *tag)
1100 {
1101 hprint(hout, " %s=\"%s\"", tag, v);
1102 }
1103
1104 void
1105 xmlscore(Hio *hout, u8int *v, char *tag)
1106 {
1107 if(scorecmp(zeroscore, v) == 0)
1108 return;
1109 hprint(hout, " %s=\"%V\"", tag, v);
1110 }
1111
1112 void
1113 xmlsealed(Hio *hout, int v, char *tag)
1114 {
1115 if(!v)
1116 return;
1117 hprint(hout, " %s=\"yes\"", tag);
1118 }
1119
1120 void
1121 xmlu32int(Hio *hout, u32int v, char *tag)
1122 {
1123 hprint(hout, " %s=\"%ud\"", tag, v);
1124 }
1125
1126 void
1127 xmlu64int(Hio *hout, u64int v, char *tag)
1128 {
1129 hprint(hout, " %s=\"%llud\"", tag, v);
1130 }
1131
1132 void
1133 vtloghdump(Hio *h, VtLog *l)
1134 {
1135 int i;
1136 VtLogChunk *c;
1137 char *name;
1138
1139 name = l ? l->name : "<nil>";
1140
1141 hprint(h, "\n");
1142 hprint(h, "Venti Server Log: %s\n", name);
1143 hprint(h, "\n");
1144 hprint(h, "Venti Server Log: %s\n\n", name);
1145
1146 if(l){
1147 c = l->w;
1148 for(i=0; inchunk; i++){
1149 if(++c == l->chunk+l->nchunk)
1150 c = l->chunk;
1151 hwrite(h, c->p, c->wp-c->p);
1152 }
1153 }
1154 hprint(h, "\n");
1155 }
1156
1157 static int
1158 strpcmp(const void *va, const void *vb)
1159 {
1160 return strcmp(*(char**)va, *(char**)vb);
1161 }
1162
1163 void
1164 vtloghlist(Hio *h)
1165 {
1166 char **p;
1167 int i, n;
1168
1169 hprint(h, "\n");
1170 hprint(h, "Venti Server Logs\n");
1171 hprint(h, "\n");
1172 hprint(h, "Venti Server Logs\n\n");
1173
1174 p = vtlognames(&n);
1175 qsort(p, n, sizeof(p[0]), strpcmp);
1176 for(i=0; i%s \n", p[i], p[i]);
1178 vtfree(p);
1179 hprint(h, "\n");
1180 } |