httpd.c 22 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177
  1. #include "stdinc.h"
  2. #include "dat.h"
  3. #include "fns.h"
  4. #include "xml.h"
  5. typedef struct HttpObj HttpObj;
  6. extern QLock memdrawlock;
  7. enum
  8. {
  9. ObjNameSize = 64,
  10. MaxObjs = 64
  11. };
  12. struct HttpObj
  13. {
  14. char name[ObjNameSize];
  15. int (*f)(HConnect*);
  16. };
  17. static HttpObj objs[MaxObjs];
  18. static char *webroot;
  19. static void listenproc(void*);
  20. static int estats(HConnect *c);
  21. static int dindex(HConnect *c);
  22. static int xindex(HConnect *c);
  23. static int xlog(HConnect *c);
  24. static int sindex(HConnect *c);
  25. static int hempty(HConnect *c);
  26. static int hlcacheempty(HConnect *c);
  27. static int hdcacheempty(HConnect *c);
  28. static int hicacheempty(HConnect *c);
  29. static int hicachekick(HConnect *c);
  30. static int hdcachekick(HConnect *c);
  31. static int hicacheflush(HConnect *c);
  32. static int hdcacheflush(HConnect *c);
  33. static int httpdobj(char *name, int (*f)(HConnect*));
  34. static int xgraph(HConnect *c);
  35. static int xset(HConnect *c);
  36. static int fromwebdir(HConnect *c);
  37. int
  38. httpdinit(char *address, char *dir)
  39. {
  40. fmtinstall('D', hdatefmt);
  41. /* fmtinstall('H', httpfmt); */
  42. fmtinstall('U', hurlfmt);
  43. if(address == nil)
  44. address = "tcp!*!http";
  45. webroot = dir;
  46. httpdobj("/stats", estats);
  47. httpdobj("/index", dindex);
  48. httpdobj("/storage", sindex);
  49. httpdobj("/xindex", xindex);
  50. httpdobj("/flushicache", hicacheflush);
  51. httpdobj("/flushdcache", hdcacheflush);
  52. httpdobj("/kickicache", hicachekick);
  53. httpdobj("/kickdcache", hdcachekick);
  54. httpdobj("/graph", xgraph);
  55. httpdobj("/set", xset);
  56. httpdobj("/log", xlog);
  57. httpdobj("/empty", hempty);
  58. httpdobj("/emptyicache", hicacheempty);
  59. httpdobj("/emptylumpcache", hlcacheempty);
  60. httpdobj("/emptydcache", hdcacheempty);
  61. httpdobj("/disk", hdisk);
  62. httpdobj("/debug", hdebug);
  63. if(vtproc(listenproc, address) < 0)
  64. return -1;
  65. return 0;
  66. }
  67. static int
  68. httpdobj(char *name, int (*f)(HConnect*))
  69. {
  70. int i;
  71. if(name == nil || strlen(name) >= ObjNameSize)
  72. return -1;
  73. for(i = 0; i < MaxObjs; i++){
  74. if(objs[i].name[0] == '\0'){
  75. strcpy(objs[i].name, name);
  76. objs[i].f = f;
  77. return 0;
  78. }
  79. if(strcmp(objs[i].name, name) == 0)
  80. return -1;
  81. }
  82. return -1;
  83. }
  84. static HConnect*
  85. mkconnect(void)
  86. {
  87. HConnect *c;
  88. c = mallocz(sizeof(HConnect), 1);
  89. if(c == nil)
  90. sysfatal("out of memory");
  91. c->replog = nil;
  92. c->hpos = c->header;
  93. c->hstop = c->header;
  94. return c;
  95. }
  96. void httpproc(void*);
  97. static void
  98. listenproc(void *vaddress)
  99. {
  100. HConnect *c;
  101. char *address, ndir[NETPATHLEN], dir[NETPATHLEN];
  102. int ctl, nctl, data;
  103. address = vaddress;
  104. ctl = announce(address, dir);
  105. if(ctl < 0){
  106. fprint(2, "venti: httpd can't announce on %s: %r\n", address);
  107. return;
  108. }
  109. if(0) print("announce ctl %d dir %s\n", ctl, dir);
  110. for(;;){
  111. /*
  112. * wait for a call (or an error)
  113. */
  114. nctl = listen(dir, ndir);
  115. if(0) print("httpd listen %d %s...\n", nctl, ndir);
  116. if(nctl < 0){
  117. fprint(2, "venti: httpd can't listen on %s: %r\n", address);
  118. return;
  119. }
  120. data = accept(ctl, ndir);
  121. if(0) print("httpd accept %d...\n", data);
  122. if(data < 0){
  123. fprint(2, "venti: httpd accept: %r\n");
  124. close(nctl);
  125. continue;
  126. }
  127. if(0) print("httpd close nctl %d\n", nctl);
  128. close(nctl);
  129. c = mkconnect();
  130. hinit(&c->hin, data, Hread);
  131. hinit(&c->hout, data, Hwrite);
  132. vtproc(httpproc, c);
  133. }
  134. }
  135. void
  136. httpproc(void *v)
  137. {
  138. HConnect *c;
  139. int ok, i, n;
  140. c = v;
  141. for(;;){
  142. /*
  143. * No timeout because the signal appears to hit every
  144. * proc, not just us.
  145. */
  146. if(hparsereq(c, 0) < 0)
  147. break;
  148. for(i = 0; i < MaxObjs && objs[i].name[0]; i++){
  149. n = strlen(objs[i].name);
  150. if((objs[i].name[n-1] == '/' && strncmp(c->req.uri, objs[i].name, n) == 0)
  151. || (objs[i].name[n-1] != '/' && strcmp(c->req.uri, objs[i].name) == 0)){
  152. ok = (*objs[i].f)(c);
  153. goto found;
  154. }
  155. }
  156. ok = fromwebdir(c);
  157. found:
  158. hflush(&c->hout);
  159. if(c->head.closeit)
  160. ok = -1;
  161. hreqcleanup(c);
  162. if(ok < 0)
  163. break;
  164. }
  165. hreqcleanup(c);
  166. close(c->hin.fd);
  167. free(c);
  168. }
  169. char*
  170. hargstr(HConnect *c, char *name, char *def)
  171. {
  172. HSPairs *p;
  173. for(p=c->req.searchpairs; p; p=p->next)
  174. if(strcmp(p->s, name) == 0)
  175. return p->t;
  176. return def;
  177. }
  178. vlong
  179. hargint(HConnect *c, char *name, vlong def)
  180. {
  181. char *a;
  182. if((a = hargstr(c, name, nil)) == nil)
  183. return def;
  184. return atoll(a);
  185. }
  186. static int
  187. percent(ulong v, ulong total)
  188. {
  189. if(total == 0)
  190. total = 1;
  191. if(v < 1000*1000)
  192. return (v * 100) / total;
  193. total /= 100;
  194. if(total == 0)
  195. total = 1;
  196. return v / total;
  197. }
  198. static int
  199. preq(HConnect *c)
  200. {
  201. if(hparseheaders(c, 0) < 0)
  202. return -1;
  203. if(strcmp(c->req.meth, "GET") != 0
  204. && strcmp(c->req.meth, "HEAD") != 0)
  205. return hunallowed(c, "GET, HEAD");
  206. if(c->head.expectother || c->head.expectcont)
  207. return hfail(c, HExpectFail, nil);
  208. return 0;
  209. }
  210. int
  211. hsettype(HConnect *c, char *type)
  212. {
  213. Hio *hout;
  214. int r;
  215. r = preq(c);
  216. if(r < 0)
  217. return r;
  218. hout = &c->hout;
  219. if(c->req.vermaj){
  220. hokheaders(c);
  221. hprint(hout, "Content-type: %s\r\n", type);
  222. if(http11(c))
  223. hprint(hout, "Transfer-Encoding: chunked\r\n");
  224. hprint(hout, "\r\n");
  225. }
  226. if(http11(c))
  227. hxferenc(hout, 1);
  228. else
  229. c->head.closeit = 1;
  230. return 0;
  231. }
  232. int
  233. hsethtml(HConnect *c)
  234. {
  235. return hsettype(c, "text/html; charset=utf-8");
  236. }
  237. int
  238. hsettext(HConnect *c)
  239. {
  240. return hsettype(c, "text/plain; charset=utf-8");
  241. }
  242. static int
  243. herror(HConnect *c)
  244. {
  245. int n;
  246. Hio *hout;
  247. hout = &c->hout;
  248. n = snprint(c->xferbuf, HBufSize, "<html><head><title>Error</title></head>\n<body><h1>Error</h1>\n<pre>%r</pre>\n</body></html>");
  249. hprint(hout, "%s %s\r\n", hversion, "400 Bad Request");
  250. hprint(hout, "Date: %D\r\n", time(nil));
  251. hprint(hout, "Server: Venti\r\n");
  252. hprint(hout, "Content-Type: text/html\r\n");
  253. hprint(hout, "Content-Length: %d\r\n", n);
  254. if(c->head.closeit)
  255. hprint(hout, "Connection: close\r\n");
  256. else if(!http11(c))
  257. hprint(hout, "Connection: Keep-Alive\r\n");
  258. hprint(hout, "\r\n");
  259. if(c->req.meth == nil || strcmp(c->req.meth, "HEAD") != 0)
  260. hwrite(hout, c->xferbuf, n);
  261. return hflush(hout);
  262. }
  263. int
  264. hnotfound(HConnect *c)
  265. {
  266. int r;
  267. r = preq(c);
  268. if(r < 0)
  269. return r;
  270. return hfail(c, HNotFound, c->req.uri);
  271. }
  272. struct {
  273. char *ext;
  274. char *type;
  275. } exttab[] = {
  276. ".html", "text/html",
  277. ".txt", "text/plain",
  278. ".xml", "text/xml",
  279. ".png", "image/png",
  280. ".gif", "image/gif",
  281. 0
  282. };
  283. static int
  284. fromwebdir(HConnect *c)
  285. {
  286. char buf[4096], *p, *ext, *type;
  287. int i, fd, n, defaulted;
  288. Dir *d;
  289. if(webroot == nil || strstr(c->req.uri, ".."))
  290. return hnotfound(c);
  291. snprint(buf, sizeof buf-20, "%s/%s", webroot, c->req.uri+1);
  292. defaulted = 0;
  293. reopen:
  294. if((fd = open(buf, OREAD)) < 0)
  295. return hnotfound(c);
  296. d = dirfstat(fd);
  297. if(d == nil){
  298. close(fd);
  299. return hnotfound(c);
  300. }
  301. if(d->mode&DMDIR){
  302. if(!defaulted){
  303. defaulted = 1;
  304. strcat(buf, "/index.html");
  305. free(d);
  306. close(fd);
  307. goto reopen;
  308. }
  309. free(d);
  310. return hnotfound(c);
  311. }
  312. free(d);
  313. p = buf+strlen(buf);
  314. type = "application/octet-stream";
  315. for(i=0; exttab[i].ext; i++){
  316. ext = exttab[i].ext;
  317. if(p-strlen(ext) >= buf && strcmp(p-strlen(ext), ext) == 0){
  318. type = exttab[i].type;
  319. break;
  320. }
  321. }
  322. if(hsettype(c, type) < 0){
  323. close(fd);
  324. return 0;
  325. }
  326. while((n = read(fd, buf, sizeof buf)) > 0)
  327. if(hwrite(&c->hout, buf, n) < 0)
  328. break;
  329. close(fd);
  330. hflush(&c->hout);
  331. return 0;
  332. }
  333. static struct
  334. {
  335. char *name;
  336. int *p;
  337. } namedints[] =
  338. {
  339. "compress", &compressblocks,
  340. "devnull", &writestodevnull,
  341. "logging", &ventilogging,
  342. "stats", &collectstats,
  343. "icachesleeptime", &icachesleeptime,
  344. "minicachesleeptime", &minicachesleeptime,
  345. "arenasumsleeptime", &arenasumsleeptime,
  346. "l0quantum", &l0quantum,
  347. "l1quantum", &l1quantum,
  348. "manualscheduling", &manualscheduling,
  349. "ignorebloom", &ignorebloom,
  350. "syncwrites", &syncwrites,
  351. "icacheprefetch", &icacheprefetch,
  352. 0
  353. };
  354. static int
  355. xset(HConnect *c)
  356. {
  357. int i, old;
  358. char *name, *value;
  359. if(hsettext(c) < 0)
  360. return -1;
  361. if((name = hargstr(c, "name", nil)) == nil || name[0] == 0){
  362. for(i=0; namedints[i].name; i++)
  363. hprint(&c->hout, "%s = %d\n", namedints[i].name, *namedints[i].p);
  364. hflush(&c->hout);
  365. return 0;
  366. }
  367. for(i=0; namedints[i].name; i++)
  368. if(strcmp(name, namedints[i].name) == 0)
  369. break;
  370. if(!namedints[i].name){
  371. hprint(&c->hout, "%s not found\n", name);
  372. hflush(&c->hout);
  373. return 0;
  374. }
  375. if((value = hargstr(c, "value", nil)) == nil || value[0] == 0){
  376. hprint(&c->hout, "%s = %d\n", namedints[i].name, *namedints[i].p);
  377. hflush(&c->hout);
  378. return 0;
  379. }
  380. old = *namedints[i].p;
  381. *namedints[i].p = atoll(value);
  382. hprint(&c->hout, "%s = %d (was %d)\n", name, *namedints[i].p, old);
  383. hflush(&c->hout);
  384. return 0;
  385. }
  386. static int
  387. estats(HConnect *c)
  388. {
  389. Hio *hout;
  390. int r;
  391. r = hsettext(c);
  392. if(r < 0)
  393. return r;
  394. hout = &c->hout;
  395. /*
  396. hprint(hout, "lump writes=%,ld\n", stats.lumpwrites);
  397. hprint(hout, "lump reads=%,ld\n", stats.lumpreads);
  398. hprint(hout, "lump cache read hits=%,ld\n", stats.lumphit);
  399. hprint(hout, "lump cache read misses=%,ld\n", stats.lumpmiss);
  400. hprint(hout, "clump disk writes=%,ld\n", stats.clumpwrites);
  401. hprint(hout, "clump disk bytes written=%,lld\n", stats.clumpbwrites);
  402. hprint(hout, "clump disk bytes compressed=%,lld\n", stats.clumpbcomp);
  403. hprint(hout, "clump disk reads=%,ld\n", stats.clumpreads);
  404. hprint(hout, "clump disk bytes read=%,lld\n", stats.clumpbreads);
  405. hprint(hout, "clump disk bytes uncompressed=%,lld\n", stats.clumpbuncomp);
  406. hprint(hout, "clump directory disk writes=%,ld\n", stats.ciwrites);
  407. hprint(hout, "clump directory disk reads=%,ld\n", stats.cireads);
  408. hprint(hout, "index disk writes=%,ld\n", stats.indexwrites);
  409. hprint(hout, "index disk reads=%,ld\n", stats.indexreads);
  410. hprint(hout, "index disk bloom filter hits=%,ld %d%% falsemisses=%,ld %d%%\n",
  411. stats.indexbloomhits,
  412. percent(stats.indexbloomhits, stats.indexreads),
  413. stats.indexbloomfalsemisses,
  414. percent(stats.indexbloomfalsemisses, stats.indexreads));
  415. hprint(hout, "bloom filter bits=%,ld of %,ld %d%%\n",
  416. stats.bloomones, stats.bloombits, percent(stats.bloomones, stats.bloombits));
  417. hprint(hout, "index disk reads for modify=%,ld\n", stats.indexwreads);
  418. hprint(hout, "index disk reads for allocation=%,ld\n", stats.indexareads);
  419. hprint(hout, "index block splits=%,ld\n", stats.indexsplits);
  420. hprint(hout, "index cache lookups=%,ld\n", stats.iclookups);
  421. hprint(hout, "index cache hits=%,ld %d%%\n", stats.ichits,
  422. percent(stats.ichits, stats.iclookups));
  423. hprint(hout, "index cache fills=%,ld %d%%\n", stats.icfills,
  424. percent(stats.icfills, stats.iclookups));
  425. hprint(hout, "index cache inserts=%,ld\n", stats.icinserts);
  426. hprint(hout, "disk cache hits=%,ld\n", stats.pchit);
  427. hprint(hout, "disk cache misses=%,ld\n", stats.pcmiss);
  428. hprint(hout, "disk cache reads=%,ld\n", stats.pcreads);
  429. hprint(hout, "disk cache bytes read=%,lld\n", stats.pcbreads);
  430. hprint(hout, "disk cache writes=%,ld\n", stats.dirtydblocks);
  431. hprint(hout, "disk cache writes absorbed=%,ld %d%%\n", stats.absorbedwrites,
  432. percent(stats.absorbedwrites, stats.dirtydblocks));
  433. hprint(hout, "disk cache flushes=%,ld\n", stats.dcacheflushes);
  434. hprint(hout, "disk cache flush writes=%,ld (%,ld per flush)\n",
  435. stats.dcacheflushwrites,
  436. stats.dcacheflushwrites/(stats.dcacheflushes ? stats.dcacheflushes : 1));
  437. hprint(hout, "disk writes=%,ld\n", stats.diskwrites);
  438. hprint(hout, "disk bytes written=%,lld\n", stats.diskbwrites);
  439. hprint(hout, "disk reads=%,ld\n", stats.diskreads);
  440. hprint(hout, "disk bytes read=%,lld\n", stats.diskbreads);
  441. */
  442. hflush(hout);
  443. return 0;
  444. }
  445. static int
  446. sindex(HConnect *c)
  447. {
  448. Hio *hout;
  449. Index *ix;
  450. Arena *arena;
  451. vlong clumps, cclumps, uncsize, used, size;
  452. int i, r, active;
  453. r = hsettext(c);
  454. if(r < 0)
  455. return r;
  456. hout = &c->hout;
  457. ix = mainindex;
  458. hprint(hout, "index=%s\n", ix->name);
  459. active = 0;
  460. clumps = 0;
  461. cclumps = 0;
  462. uncsize = 0;
  463. used = 0;
  464. size = 0;
  465. for(i = 0; i < ix->narenas; i++){
  466. arena = ix->arenas[i];
  467. if(arena != nil && arena->memstats.clumps != 0){
  468. active++;
  469. clumps += arena->memstats.clumps;
  470. cclumps += arena->memstats.cclumps;
  471. uncsize += arena->memstats.uncsize;
  472. used += arena->memstats.used;
  473. }
  474. size += arena->size;
  475. }
  476. hprint(hout, "total arenas=%,d active=%,d\n", ix->narenas, active);
  477. hprint(hout, "total space=%,lld used=%,lld\n", size, used + clumps * ClumpInfoSize);
  478. hprint(hout, "clumps=%,lld compressed clumps=%,lld data=%,lld compressed data=%,lld\n",
  479. clumps, cclumps, uncsize, used - clumps * ClumpSize);
  480. hflush(hout);
  481. return 0;
  482. }
  483. static void
  484. darena(Hio *hout, Arena *arena)
  485. {
  486. hprint(hout, "arena='%s' on %s at [%lld,%lld)\n\tversion=%d created=%d modified=%d",
  487. arena->name, arena->part->name, arena->base, arena->base + arena->size + 2 * arena->blocksize,
  488. arena->version, arena->ctime, arena->wtime);
  489. if(arena->memstats.sealed)
  490. hprint(hout, " mem=sealed");
  491. if(arena->diskstats.sealed)
  492. hprint(hout, " disk=sealed");
  493. hprint(hout, "\n");
  494. if(scorecmp(zeroscore, arena->score) != 0)
  495. hprint(hout, "\tscore=%V\n", arena->score);
  496. hprint(hout, "\twritten: clumps=%d compressed clumps=%d data=%,lld compressed data=%,lld storage=%,lld\n",
  497. arena->memstats.clumps, arena->memstats.cclumps, arena->memstats.uncsize,
  498. arena->memstats.used - arena->memstats.clumps * ClumpSize,
  499. arena->memstats.used + arena->memstats.clumps * ClumpInfoSize);
  500. hprint(hout, "\tindexed: clumps=%d compressed clumps=%d data=%,lld compressed data=%,lld storage=%,lld\n",
  501. arena->diskstats.clumps, arena->diskstats.cclumps, arena->diskstats.uncsize,
  502. arena->diskstats.used - arena->diskstats.clumps * ClumpSize,
  503. arena->diskstats.used + arena->diskstats.clumps * ClumpInfoSize);
  504. }
  505. static int
  506. hempty(HConnect *c)
  507. {
  508. Hio *hout;
  509. int r;
  510. r = hsettext(c);
  511. if(r < 0)
  512. return r;
  513. hout = &c->hout;
  514. emptylumpcache();
  515. emptydcache();
  516. emptyicache();
  517. hprint(hout, "emptied all caches\n");
  518. hflush(hout);
  519. return 0;
  520. }
  521. static int
  522. hlcacheempty(HConnect *c)
  523. {
  524. Hio *hout;
  525. int r;
  526. r = hsettext(c);
  527. if(r < 0)
  528. return r;
  529. hout = &c->hout;
  530. emptylumpcache();
  531. hprint(hout, "emptied lumpcache\n");
  532. hflush(hout);
  533. return 0;
  534. }
  535. static int
  536. hicacheempty(HConnect *c)
  537. {
  538. Hio *hout;
  539. int r;
  540. r = hsettext(c);
  541. if(r < 0)
  542. return r;
  543. hout = &c->hout;
  544. emptyicache();
  545. hprint(hout, "emptied icache\n");
  546. hflush(hout);
  547. return 0;
  548. }
  549. static int
  550. hdcacheempty(HConnect *c)
  551. {
  552. Hio *hout;
  553. int r;
  554. r = hsettext(c);
  555. if(r < 0)
  556. return r;
  557. hout = &c->hout;
  558. emptydcache();
  559. hprint(hout, "emptied dcache\n");
  560. hflush(hout);
  561. return 0;
  562. }
  563. static int
  564. hicachekick(HConnect *c)
  565. {
  566. Hio *hout;
  567. int r;
  568. r = hsettext(c);
  569. if(r < 0)
  570. return r;
  571. hout = &c->hout;
  572. kickicache();
  573. hprint(hout, "kicked icache\n");
  574. hflush(hout);
  575. return 0;
  576. }
  577. static int
  578. hdcachekick(HConnect *c)
  579. {
  580. Hio *hout;
  581. int r;
  582. r = hsettext(c);
  583. if(r < 0)
  584. return r;
  585. hout = &c->hout;
  586. kickdcache();
  587. hprint(hout, "kicked dcache\n");
  588. hflush(hout);
  589. return 0;
  590. }
  591. static int
  592. hicacheflush(HConnect *c)
  593. {
  594. Hio *hout;
  595. int r;
  596. r = hsettext(c);
  597. if(r < 0)
  598. return r;
  599. hout = &c->hout;
  600. flushicache();
  601. hprint(hout, "flushed icache\n");
  602. hflush(hout);
  603. return 0;
  604. }
  605. static int
  606. hdcacheflush(HConnect *c)
  607. {
  608. Hio *hout;
  609. int r;
  610. r = hsettext(c);
  611. if(r < 0)
  612. return r;
  613. hout = &c->hout;
  614. flushdcache();
  615. hprint(hout, "flushed dcache\n");
  616. hflush(hout);
  617. return 0;
  618. }
  619. static int
  620. dindex(HConnect *c)
  621. {
  622. Hio *hout;
  623. Index *ix;
  624. int i, r;
  625. r = hsettext(c);
  626. if(r < 0)
  627. return r;
  628. hout = &c->hout;
  629. ix = mainindex;
  630. hprint(hout, "index=%s version=%d blocksize=%d tabsize=%d\n",
  631. ix->name, ix->version, ix->blocksize, ix->tabsize);
  632. hprint(hout, "\tbuckets=%d div=%d\n", ix->buckets, ix->div);
  633. for(i = 0; i < ix->nsects; i++)
  634. 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);
  635. for(i = 0; i < ix->narenas; i++){
  636. if(ix->arenas[i] != nil && ix->arenas[i]->memstats.clumps != 0){
  637. hprint(hout, "arena=%s at index [%lld,%lld)\n\t", ix->amap[i].name, ix->amap[i].start, ix->amap[i].stop);
  638. darena(hout, ix->arenas[i]);
  639. }
  640. }
  641. hflush(hout);
  642. return 0;
  643. }
  644. typedef struct Arg Arg;
  645. struct Arg
  646. {
  647. int index;
  648. int index2;
  649. };
  650. static long
  651. rawgraph(Stats *s, Stats *t, void *va)
  652. {
  653. Arg *a;
  654. USED(s);
  655. a = va;
  656. return t->n[a->index];
  657. }
  658. static long
  659. diffgraph(Stats *s, Stats *t, void *va)
  660. {
  661. Arg *a;
  662. a = va;
  663. return t->n[a->index] - s->n[a->index];
  664. }
  665. static long
  666. pctgraph(Stats *s, Stats *t, void *va)
  667. {
  668. Arg *a;
  669. USED(s);
  670. a = va;
  671. return percent(t->n[a->index], t->n[a->index2]);
  672. }
  673. static long
  674. pctdiffgraph(Stats *s, Stats *t, void *va)
  675. {
  676. Arg *a;
  677. a = va;
  678. return percent(t->n[a->index]-s->n[a->index], t->n[a->index2]-s->n[a->index2]);
  679. }
  680. static long
  681. xdiv(long a, long b)
  682. {
  683. if(b == 0)
  684. b++;
  685. return a/b;
  686. }
  687. static long
  688. divdiffgraph(Stats *s, Stats *t, void *va)
  689. {
  690. Arg *a;
  691. a = va;
  692. return xdiv(t->n[a->index] - s->n[a->index], t->n[a->index2] - s->n[a->index2]);
  693. }
  694. static long
  695. netbw(Stats *s)
  696. {
  697. ulong *n;
  698. n = s->n;
  699. return n[StatRpcReadBytes]+n[StatRpcWriteBytes]; /* not exactly right */
  700. }
  701. static long
  702. diskbw(Stats *s)
  703. {
  704. ulong *n;
  705. n = s->n;
  706. return n[StatApartReadBytes]+n[StatApartWriteBytes]
  707. + n[StatIsectReadBytes]+n[StatIsectWriteBytes]
  708. + n[StatSumReadBytes];
  709. }
  710. static long
  711. iobw(Stats *s)
  712. {
  713. return netbw(s)+diskbw(s);
  714. }
  715. static long
  716. diskgraph(Stats *s, Stats *t, void *va)
  717. {
  718. USED(va);
  719. return diskbw(t)-diskbw(s);
  720. }
  721. static long
  722. netgraph(Stats *s, Stats *t, void *va)
  723. {
  724. USED(va);
  725. return netbw(t)-netbw(s);
  726. }
  727. static long
  728. iograph(Stats *s, Stats *t, void *va)
  729. {
  730. USED(va);
  731. return iobw(t)-iobw(s);
  732. }
  733. static char* graphname[] =
  734. {
  735. "rpctotal",
  736. "rpcread",
  737. "rpcreadok",
  738. "rpcreadfail",
  739. "rpcreadbyte",
  740. "rpcreadtime",
  741. "rpcreadcached",
  742. "rpcreadcachedtime",
  743. "rpcreaduncached",
  744. "rpcreaduncachedtime",
  745. "rpcwrite",
  746. "rpcwritenew",
  747. "rpcwriteold",
  748. "rpcwritefail",
  749. "rpcwritebyte",
  750. "rpcwritetime",
  751. "rpcwritenewtime",
  752. "rpcwriteoldtime",
  753. "lcachehit",
  754. "lcachemiss",
  755. "lcachelookup",
  756. "lcachewrite",
  757. "lcachesize",
  758. "lcachestall",
  759. "lcachelookuptime",
  760. "dcachehit",
  761. "dcachemiss",
  762. "dcachelookup",
  763. "dcacheread",
  764. "dcachewrite",
  765. "dcachedirty",
  766. "dcachesize",
  767. "dcacheflush",
  768. "dcachestall",
  769. "dcachelookuptime",
  770. "dblockstall",
  771. "lumpstall",
  772. "icachehit",
  773. "icachemiss",
  774. "icacheread",
  775. "icachewrite",
  776. "icachefill",
  777. "icacheprefetch",
  778. "icachedirty",
  779. "icachesize",
  780. "icacheflush",
  781. "icachestall",
  782. "icachelookuptime",
  783. "icachelookup",
  784. "scachehit",
  785. "scacheprefetch",
  786. "bloomhit",
  787. "bloommiss",
  788. "bloomfalsemiss",
  789. "bloomlookup",
  790. "bloomones",
  791. "bloombits",
  792. "bloomlookuptime",
  793. "apartread",
  794. "apartreadbyte",
  795. "apartwrite",
  796. "apartwritebyte",
  797. "isectread",
  798. "isectreadbyte",
  799. "isectwrite",
  800. "isectwritebyte",
  801. "sumread",
  802. "sumreadbyte",
  803. "cigload",
  804. "cigloadtime",
  805. };
  806. static int
  807. findname(char *s)
  808. {
  809. int i;
  810. for(i=0; i<nelem(graphname); i++)
  811. if(strcmp(graphname[i], s) == 0)
  812. return i;
  813. return -1;
  814. }
  815. static void
  816. dotextbin(Hio *io, Graph *g)
  817. {
  818. int i, nbin;
  819. Statbin *b, bin[2000]; /* 32 kB, but whack is worse */
  820. needstack(8192); /* double check that bin didn't kill us */
  821. nbin = 100;
  822. binstats(g->fn, g->arg, g->t0, g->t1, bin, nbin);
  823. hprint(io, "stats\n\n");
  824. for(i=0; i<nbin; i++){
  825. b = &bin[i];
  826. hprint(io, "%d: nsamp=%d min=%d max=%d avg=%d\n",
  827. i, b->nsamp, b->min, b->max, b->avg);
  828. }
  829. }
  830. static int
  831. xgraph(HConnect *c)
  832. {
  833. char *name;
  834. Hio *hout;
  835. Memimage *m;
  836. int dotext;
  837. Graph g;
  838. Arg arg;
  839. char *graph, *a;
  840. name = hargstr(c, "arg", "");
  841. if((arg.index = findname(name)) == -1 && strcmp(name, "*") != 0){
  842. werrstr("unknown name %s", name);
  843. goto error;
  844. }
  845. a = hargstr(c, "arg2", "");
  846. if(a[0] && (arg.index2 = findname(a)) == -1){
  847. werrstr("unknown name %s", a);
  848. goto error;
  849. }
  850. g.arg = &arg;
  851. g.t0 = hargint(c, "t0", -120);
  852. g.t1 = hargint(c, "t1", 0);
  853. g.min = hargint(c, "min", -1);
  854. g.max = hargint(c, "max", -1);
  855. g.wid = hargint(c, "wid", -1);
  856. g.ht = hargint(c, "ht", -1);
  857. dotext = hargstr(c, "text", "")[0] != 0;
  858. g.fill = hargint(c, "fill", -1);
  859. graph = hargstr(c, "graph", "raw");
  860. if(strcmp(graph, "raw") == 0)
  861. g.fn = rawgraph;
  862. else if(strcmp(graph, "diskbw") == 0)
  863. g.fn = diskgraph;
  864. else if(strcmp(graph, "iobw") == 0)
  865. g.fn = iograph;
  866. else if(strcmp(graph, "netbw") == 0)
  867. g.fn = netgraph;
  868. else if(strcmp(graph, "diff") == 0)
  869. g.fn = diffgraph;
  870. else if(strcmp(graph, "pct") == 0)
  871. g.fn = pctgraph;
  872. else if(strcmp(graph, "pctdiff") == 0)
  873. g.fn = pctdiffgraph;
  874. else if(strcmp(graph, "divdiff") == 0)
  875. g.fn = divdiffgraph;
  876. else{
  877. werrstr("unknown graph %s", graph);
  878. goto error;
  879. }
  880. if(dotext){
  881. hsettype(c, "text/plain");
  882. dotextbin(&c->hout, &g);
  883. hflush(&c->hout);
  884. return 0;
  885. }
  886. m = statgraph(&g);
  887. if(m == nil)
  888. goto error;
  889. if(hsettype(c, "image/png") < 0)
  890. return -1;
  891. hout = &c->hout;
  892. writepng(hout, m);
  893. qlock(&memdrawlock);
  894. freememimage(m);
  895. qunlock(&memdrawlock);
  896. hflush(hout);
  897. return 0;
  898. error:
  899. return herror(c);
  900. }
  901. static int
  902. xloglist(HConnect *c)
  903. {
  904. if(hsettype(c, "text/html") < 0)
  905. return -1;
  906. vtloghlist(&c->hout);
  907. hflush(&c->hout);
  908. return 0;
  909. }
  910. static int
  911. xlog(HConnect *c)
  912. {
  913. char *name;
  914. VtLog *l;
  915. name = hargstr(c, "log", "");
  916. if(!name[0])
  917. return xloglist(c);
  918. l = vtlogopen(name, 0);
  919. if(l == nil)
  920. return hnotfound(c);
  921. if(hsettype(c, "text/html") < 0){
  922. vtlogclose(l);
  923. return -1;
  924. }
  925. vtloghdump(&c->hout, l);
  926. vtlogclose(l);
  927. hflush(&c->hout);
  928. return 0;
  929. }
  930. static int
  931. xindex(HConnect *c)
  932. {
  933. if(hsettype(c, "text/xml") < 0)
  934. return -1;
  935. xmlindex(&c->hout, mainindex, "index", 0);
  936. hflush(&c->hout);
  937. return 0;
  938. }
  939. void
  940. xmlindent(Hio *hout, int indent)
  941. {
  942. int i;
  943. for(i = 0; i < indent; i++)
  944. hputc(hout, '\t');
  945. }
  946. void
  947. xmlaname(Hio *hout, char *v, char *tag)
  948. {
  949. hprint(hout, " %s=\"%s\"", tag, v);
  950. }
  951. void
  952. xmlscore(Hio *hout, u8int *v, char *tag)
  953. {
  954. if(scorecmp(zeroscore, v) == 0)
  955. return;
  956. hprint(hout, " %s=\"%V\"", tag, v);
  957. }
  958. void
  959. xmlsealed(Hio *hout, int v, char *tag)
  960. {
  961. if(!v)
  962. return;
  963. hprint(hout, " %s=\"yes\"", tag);
  964. }
  965. void
  966. xmlu32int(Hio *hout, u32int v, char *tag)
  967. {
  968. hprint(hout, " %s=\"%ud\"", tag, v);
  969. }
  970. void
  971. xmlu64int(Hio *hout, u64int v, char *tag)
  972. {
  973. hprint(hout, " %s=\"%llud\"", tag, v);
  974. }
  975. void
  976. vtloghdump(Hio *h, VtLog *l)
  977. {
  978. int i;
  979. VtLogChunk *c;
  980. char *name;
  981. name = l ? l->name : "&lt;nil&gt;";
  982. hprint(h, "<html><head>\n");
  983. hprint(h, "<title>Venti Server Log: %s</title>\n", name);
  984. hprint(h, "</head><body>\n");
  985. hprint(h, "<b>Venti Server Log: %s</b>\n<p>\n", name);
  986. if(l){
  987. c = l->w;
  988. for(i=0; i<l->nchunk; i++){
  989. if(++c == l->chunk+l->nchunk)
  990. c = l->chunk;
  991. hwrite(h, c->p, c->wp-c->p);
  992. }
  993. }
  994. hprint(h, "</body></html>\n");
  995. }
  996. static int
  997. strpcmp(const void *va, const void *vb)
  998. {
  999. return strcmp(*(char**)va, *(char**)vb);
  1000. }
  1001. void
  1002. vtloghlist(Hio *h)
  1003. {
  1004. char **p;
  1005. int i, n;
  1006. hprint(h, "<html><head>\n");
  1007. hprint(h, "<title>Venti Server Logs</title>\n");
  1008. hprint(h, "</head><body>\n");
  1009. hprint(h, "<b>Venti Server Logs</b>\n<p>\n");
  1010. p = vtlognames(&n);
  1011. qsort(p, n, sizeof(p[0]), strpcmp);
  1012. for(i=0; i<n; i++)
  1013. hprint(h, "<a href=\"/log?log=%s\">%s</a><br>\n", p[i], p[i]);
  1014. vtfree(p);
  1015. hprint(h, "</body></html>\n");
  1016. }