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