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