httpd.c 22 KB

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