xref: /plan9/sys/src/libventi/log.c (revision 9ba92a1a1d8a653f6050241dbdbd039f2ecb1dc2)
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