/[hydra]/hydra/src/mmap_cache.c
ViewVC logotype

Contents of /hydra/src/mmap_cache.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.6 - (show annotations)
Sun Sep 22 15:12:03 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
CVS Tags: BOAS_WITH_RANGES_AND_CGI
Changes since 1.5: +2 -2 lines
File MIME type: text/plain
The mmap_list cleanup function, now resets usage statistics.

1 /*
2 * Boa, an http server
3 * Copyright (C) 1999 Larry Doolittle <ldoolitt@boa.org>
4 * Portions Copyright (C) 2002 Nikos Mavroyanopoulos <nmav@gnutls.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 1, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 */
21
22 /* $Id: mmap_cache.c,v 1.5 2002/09/22 09:31:52 nmav Exp $*/
23
24 #include "boa.h"
25
26 #ifdef ENABLE_SMP
27 # include <pthread.h>
28 pthread_mutex_t mmap_lock = PTHREAD_MUTEX_INITIALIZER;
29 #endif
30
31 static int cleanup_mmap_list(void);
32
33 int mmap_list_entries_used = 0;
34 int mmap_list_total_requests = 0;
35 int mmap_list_hash_bounces = 0;
36
37 #ifdef USE_MMAP_LIST
38
39 /* define local table variable */
40 static struct mmap_entry mmap_list[MMAP_LIST_SIZE];
41
42 struct mmap_entry *find_mmap(int data_fd, struct stat *s)
43 {
44 char *m;
45 int i, start;
46
47 #ifdef ENABLE_SMP
48 pthread_mutex_lock(&mmap_lock);
49 #endif
50 mmap_list_total_requests++;
51 i = start = MMAP_LIST_HASH(s->st_dev, s->st_ino, s->st_size);
52
53 for (;mmap_list[i].available;) {
54 if (mmap_list[i].dev == s->st_dev && mmap_list[i].ino == s->st_ino
55 && mmap_list[i].len == s->st_size) {
56 mmap_list[i].use_count++;
57 mmap_list[i].times_used++;
58
59 #ifdef DEBUG0
60 fprintf(stderr,
61 "Old mmap_list entry %d use_count now %d (hash was %d)\n",
62 i, mmap_list[i].use_count, start);
63 #endif
64 #ifdef ENABLE_SMP
65 pthread_mutex_unlock(&mmap_lock);
66 #endif
67 return &mmap_list[i];
68 }
69 mmap_list_hash_bounces++;
70 i = MMAP_LIST_NEXT(i);
71
72 if (i == start) {
73 i = cleanup_mmap_list();
74 if (i != -1) break; /* if we found an empty index */
75 /* otherwise no space could be cleaned. So say bye!!
76 */
77 #ifdef ENABLE_SMP
78 pthread_mutex_unlock(&mmap_lock);
79 #endif
80 return NULL;
81 }
82
83 }
84
85 /* didn't find an entry that matches our dev/inode/size.
86 There might be an entry that matches later in the table,
87 but that _should_ be rare. The worst case is that we
88 needlessly mmap() a file that is already mmap'd, but we
89 did that all the time before this code was written,
90 so it shouldn't be _too_ bad.
91 */
92
93 m = mmap(0, s->st_size, PROT_READ, MAP_OPTIONS, data_fd, 0);
94
95 if ( m == MAP_FAILED) {
96 /* boa_perror(req,"mmap"); */
97 return NULL;
98 }
99 #ifdef DEBUG0
100 fprintf(stderr,
101 "New mmap_list entry %d (hash was %d) [ino: %u size: %u]\n", i,
102 start, s->st_ino, s->st_size);
103 #endif
104 mmap_list_entries_used++;
105 mmap_list[i].dev = s->st_dev;
106 mmap_list[i].ino = s->st_ino;
107 mmap_list[i].len = s->st_size;
108 mmap_list[i].mmap = m;
109 mmap_list[i].use_count = 1;
110 mmap_list[i].available = 1;
111 mmap_list[i].times_used = 1;
112
113 #ifdef ENABLE_SMP
114 pthread_mutex_unlock(&mmap_lock);
115 #endif
116 return &mmap_list[i];
117 }
118
119 /* Removes all entries in the mmap list that are not used and
120 * have been used less times than the average of all.
121 * No locking here. The caller has to do the proper locking.
122 *
123 * Return values:
124 * -1 failed. Could not make any space on the list
125 * >=0 an index number, of an empty element in the list.
126 *
127 */
128 static int cleanup_mmap_list()
129 {
130 int i, avg = 0;
131 int ret = -1;
132 #ifdef DEBUG
133 int count = 0;
134
135 fprintf(stderr, "Cleaning up mmap_list. Entries: %d.\n", mmap_list_entries_used);
136 #endif
137
138 /* The algorithm here is:
139 * 1. Calculate the average of all times used
140 * 2. Remove all entries that have been used less than
141 * 'average' times. Also remove entries that their hash does not
142 * equal their index. This is to avoid duplicate entries.
143 */
144 for (i = 0; i < MMAP_LIST_SIZE; i++) {
145 if (mmap_list[i].available) {
146 avg += mmap_list[i].times_used;
147 }
148 }
149
150 avg /= i;
151
152 for (i = 0; i < MMAP_LIST_SIZE; i++) {
153 if (mmap_list[i].available && (mmap_list[i].use_count == 0) &&
154 (mmap_list[i].times_used < avg || MMAP_LIST_HASH(mmap_list[i].dev,
155 mmap_list[i].ino, mmap_list[i].len) != i)) {
156
157 ret = i;
158 munmap(mmap_list[i].mmap, mmap_list[i].len);
159 mmap_list[i].available = 0;
160 mmap_list_entries_used--;
161 #ifdef DEBUG
162 count++;
163 #endif
164 } else mmap_list[i].times_used = 0; /* zero all counters. */
165 }
166 #ifdef DEBUG
167 fprintf(stderr, "Removed %d entries from the mmap_hashtable (clean stage1)\n", count);
168 count = 0;
169 #endif
170
171 /* If no list elements were removed, then remove all that
172 * are not used. This is our last resort! We shouldn't have
173 * come here.
174 */
175 if (mmap_list_entries_used >= MMAP_LIST_SIZE) {
176 for (i = 0; i < MMAP_LIST_SIZE; i++) {
177 if (mmap_list[i].available && mmap_list[i].use_count == 0) {
178
179 ret = i;
180 munmap(mmap_list[i].mmap, mmap_list[i].len);
181 mmap_list[i].available = 0;
182 mmap_list_entries_used--;
183 #ifdef DEBUG
184 count++;
185 #endif
186 }
187 }
188 #ifdef DEBUG
189 fprintf(stderr, "Removed %d entries from the mmap_hashtable (clean stage2)\n", count);
190 #endif
191
192 }
193
194 /* If we have come here and we didn't remove any list entries,
195 * then all list entries are used or there is a bug above.
196 */
197
198 #ifdef DEBUG
199 fprintf(stderr, "Cleaned up mmap_list. Entries: %d.\n", mmap_list_entries_used);
200 #endif
201
202 return ret;
203 }
204
205 void release_mmap(struct mmap_entry *e)
206 {
207 if (!e)
208 return;
209
210 #ifdef ENABLE_SMP
211 pthread_mutex_lock(&mmap_lock);
212 #endif
213
214 if (!e->use_count) {
215 #ifdef DEBUG
216 fprintf(stderr, "mmap_list(%p)->use_count already zero!\n", e);
217 #endif
218 goto finish;
219 }
220
221 e->use_count--;
222
223
224 finish:
225 #ifdef ENABLE_SMP
226 pthread_mutex_unlock(&mmap_lock);
227 #endif
228 return;
229 }
230
231 struct mmap_entry *find_named_mmap(char *fname)
232 {
233 int data_fd;
234 struct stat statbuf;
235 struct mmap_entry *e;
236 data_fd = open(fname, O_RDONLY);
237 if (data_fd == -1) {
238 perror(fname);
239 return NULL;
240 }
241 fstat(data_fd, &statbuf);
242 if (S_ISDIR(statbuf.st_mode)) {
243 #ifdef DEBUG
244 fprintf(stderr, "%s is a directory\n", fname);
245 #endif
246 return NULL;
247 }
248
249 e = find_mmap(data_fd, &statbuf);
250 close(data_fd);
251 return e;
252 }
253
254 /*
255 int main(int argc, char *argv[])
256 {
257 #define MAXTEST 2048
258 struct mmap_entry *mlist[MAXTEST];
259 char name[1024], *s;
260 int i, tests=0;
261 while (fgets(name,sizeof(name),stdin) && tests < MAXTEST) {
262 if (name[0]=='-') {
263 i=atoi(name+1);
264 release_mmap(mlist[i]);
265 mlist[i]=NULL;
266 } else {
267 if ((s=strchr(name,'\n'))) *s='\0';
268 mlist[tests] = find_named_mmap(name);
269 if (mlist[tests]) tests++;
270 else fprintf(stderr, "find_named_mmap(%s) failed\n",name);
271 }
272 }
273 fprintf(stderr, "mmap_list entries_used=%d ",mmap_list_entries_used);
274 fprintf(stderr, "total_requests=%d ",mmap_list_total_requests);
275 fprintf(stderr, "hash_bounces=%d\n",mmap_list_hash_bounces);
276 for (i=0; i<tests; i++) release_mmap(mlist[i]);
277 fprintf(stderr, "mmap_list entries_used=%d ",mmap_list_entries_used);
278 fprintf(stderr, "total_requests=%d ",mmap_list_total_requests);
279 fprintf(stderr, "hash_bounces=%d\n",mmap_list_hash_bounces);
280
281 */
282
283 #endif /* USE_MMAP_LIST */

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26