log.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <venti.h>
  4. char *VtServerLog = "libventi/server";
  5. int ventilogging;
  6. #define log not_the_log_library_call
  7. static char Eremoved[] = "[removed]";
  8. enum
  9. { /* defaults */
  10. LogChunkSize = 8192,
  11. LogSize = 65536
  12. };
  13. static struct {
  14. QLock lk;
  15. VtLog *hash[1024];
  16. } vl;
  17. static uint
  18. hash(char *s)
  19. {
  20. uint h;
  21. uchar *p;
  22. h = 0;
  23. for(p=(uchar*)s; *p; p++)
  24. h = h*37 + *p;
  25. return h;
  26. }
  27. char**
  28. vtlognames(int *pn)
  29. {
  30. int i, nname, size;
  31. VtLog *l;
  32. char **s, *a, *e;
  33. qlock(&vl.lk);
  34. size = 0;
  35. nname = 0;
  36. for(i=0; i<nelem(vl.hash); i++)
  37. for(l=vl.hash[i]; l; l=l->next){
  38. nname++;
  39. size += strlen(l->name)+1;
  40. }
  41. s = vtmalloc(nname*sizeof(char*)+size);
  42. a = (char*)(s+nname);
  43. e = (char*)s+nname*sizeof(char*)+size;
  44. nname = 0;
  45. for(i=0; i<nelem(vl.hash); i++)
  46. for(l=vl.hash[i]; l; l=l->next){
  47. strcpy(a, l->name);
  48. s[nname++] = a;
  49. a += strlen(a)+1;
  50. }
  51. *pn = nname;
  52. assert(a == e);
  53. qunlock(&vl.lk);
  54. return s;
  55. }
  56. VtLog*
  57. vtlogopen(char *name, uint size)
  58. {
  59. uint h;
  60. int i, nc;
  61. char *p;
  62. VtLog *l, *last;
  63. if(!ventilogging)
  64. return nil;
  65. h = hash(name)%nelem(vl.hash);
  66. qlock(&vl.lk);
  67. last = nil;
  68. for(l=vl.hash[h]; l; last=l, l=l->next)
  69. if(strcmp(l->name, name) == 0){
  70. if(last){ /* move to front */
  71. last->next = l->next;
  72. l->next = vl.hash[h];
  73. vl.hash[h] = l;
  74. }
  75. l->ref++;
  76. qunlock(&vl.lk);
  77. return l;
  78. }
  79. if(size == 0){
  80. qunlock(&vl.lk);
  81. return nil;
  82. }
  83. /* allocate */
  84. nc = (size+LogChunkSize-1)/LogChunkSize;
  85. l = vtmalloc(sizeof *l + nc*(sizeof(*l->chunk)+LogChunkSize) + strlen(name)+1);
  86. memset(l, 0, sizeof *l);
  87. l->chunk = (VtLogChunk*)(l+1);
  88. l->nchunk = nc;
  89. l->w = l->chunk;
  90. p = (char*)(l->chunk+nc);
  91. for(i=0; i<nc; i++){
  92. l->chunk[i].p = p;
  93. l->chunk[i].wp = p;
  94. p += LogChunkSize;
  95. l->chunk[i].ep = p;
  96. }
  97. strcpy(p, name);
  98. l->name = p;
  99. /* insert */
  100. l->next = vl.hash[h];
  101. vl.hash[h] = l;
  102. l->ref++;
  103. l->ref++;
  104. qunlock(&vl.lk);
  105. return l;
  106. }
  107. void
  108. vtlogclose(VtLog *l)
  109. {
  110. if(l == nil)
  111. return;
  112. qlock(&vl.lk);
  113. if(--l->ref == 0){
  114. /* must not be in hash table */
  115. assert(l->name == Eremoved);
  116. free(l);
  117. }else
  118. assert(l->ref > 0);
  119. qunlock(&vl.lk);
  120. }
  121. void
  122. vtlogremove(char *name)
  123. {
  124. uint h;
  125. VtLog *last, *l;
  126. h = hash(name)%nelem(vl.hash);
  127. qlock(&vl.lk);
  128. last = nil;
  129. for(l=vl.hash[h]; l; last=l, l=l->next)
  130. if(strcmp(l->name, name) == 0){
  131. if(last)
  132. last->next = l->next;
  133. else
  134. vl.hash[h] = l->next;
  135. l->name = Eremoved;
  136. l->next = nil;
  137. qunlock(&vl.lk);
  138. vtlogclose(l);
  139. return;
  140. }
  141. qunlock(&vl.lk);
  142. }
  143. static int
  144. timefmt(Fmt *fmt)
  145. {
  146. static uvlong t0;
  147. uvlong t;
  148. if(t0 == 0)
  149. t0 = nsec();
  150. t = nsec()-t0;
  151. return fmtprint(fmt, "T+%d.%04d", (uint)(t/1000000000), (uint)(t%1000000000)/100000);
  152. }
  153. void
  154. vtlogvprint(VtLog *l, char *fmt, va_list arg)
  155. {
  156. int n;
  157. char *p;
  158. VtLogChunk *c;
  159. static int first = 1;
  160. if(l == nil)
  161. return;
  162. if(first){
  163. fmtinstall('T', timefmt);
  164. first = 0;
  165. }
  166. qlock(&l->lk);
  167. c = l->w;
  168. n = c->ep - c->wp;
  169. if(n < 512){
  170. c++;
  171. if(c == l->chunk+l->nchunk)
  172. c = l->chunk;
  173. c->wp = c->p;
  174. l->w = c;
  175. }
  176. p = vseprint(c->wp, c->ep, fmt, arg);
  177. if(p)
  178. c->wp = p;
  179. qunlock(&l->lk);
  180. }
  181. void
  182. vtlogprint(VtLog *l, char *fmt, ...)
  183. {
  184. va_list arg;
  185. if(l == nil)
  186. return;
  187. va_start(arg, fmt);
  188. vtlogvprint(l, fmt, arg);
  189. va_end(arg);
  190. }
  191. void
  192. vtlog(char *name, char *fmt, ...)
  193. {
  194. VtLog *l;
  195. va_list arg;
  196. l = vtlogopen(name, LogSize);
  197. if(l == nil)
  198. return;
  199. va_start(arg, fmt);
  200. vtlogvprint(l, fmt, arg);
  201. va_end(arg);
  202. vtlogclose(l);
  203. }
  204. void
  205. vtlogdump(int fd, VtLog *l)
  206. {
  207. int i;
  208. VtLogChunk *c;
  209. if(l == nil)
  210. return;
  211. c = l->w;
  212. for(i=0; i<l->nchunk; i++){
  213. if(++c == l->chunk+l->nchunk)
  214. c = l->chunk;
  215. write(fd, c->p, c->wp-c->p);
  216. }
  217. }