/[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.7 - (show annotations)
Wed Sep 25 10:33:19 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
CVS Tags: hydra_0_0_2
Changes since 1.6: +48 -33 lines
File MIME type: text/plain
The file caching layer (mmap), can now be accessed by the configuration file.

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.6 2002/09/22 15:12:03 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 static int previous_max_files_cache = 0;
40
41 /* define local table variable */
42 static struct mmap_entry* mmap_list;
43
44
45 struct mmap_entry *find_mmap(int data_fd, struct stat *s)
46 {
47 char *m;
48 int i, start;
49
50 if ( max_files_cache == 0) return NULL;
51
52 #ifdef ENABLE_SMP
53 pthread_mutex_lock(&mmap_lock);
54 #endif
55 mmap_list_total_requests++;
56 i = start = MMAP_LIST_HASH(s->st_dev, s->st_ino, s->st_size);
57
58 for (;mmap_list[i].available;) {
59 if (mmap_list[i].dev == s->st_dev && mmap_list[i].ino == s->st_ino
60 && mmap_list[i].len == s->st_size) {
61 mmap_list[i].use_count++;
62 mmap_list[i].times_used++;
63
64 #ifdef DEBUG0
65 fprintf(stderr,
66 "Old mmap_list entry %d use_count now %d (hash was %d)\n",
67 i, mmap_list[i].use_count, start);
68 #endif
69 #ifdef ENABLE_SMP
70 pthread_mutex_unlock(&mmap_lock);
71 #endif
72 return &mmap_list[i];
73 }
74 mmap_list_hash_bounces++;
75 i = MMAP_LIST_NEXT(i);
76
77 if (i == start) {
78 i = cleanup_mmap_list();
79 if (i != -1) break; /* if we found an empty index */
80 /* otherwise no space could be cleaned. So say bye!!
81 */
82 #ifdef ENABLE_SMP
83 pthread_mutex_unlock(&mmap_lock);
84 #endif
85 return NULL;
86 }
87
88 }
89
90 /* didn't find an entry that matches our dev/inode/size.
91 There might be an entry that matches later in the table,
92 but that _should_ be rare. The worst case is that we
93 needlessly mmap() a file that is already mmap'd, but we
94 did that all the time before this code was written,
95 so it shouldn't be _too_ bad.
96 */
97
98 m = mmap(0, s->st_size, PROT_READ, MAP_OPTIONS, data_fd, 0);
99
100 if ( m == MAP_FAILED) {
101 /* boa_perror(req,"mmap"); */
102 return NULL;
103 }
104 #ifdef DEBUG0
105 fprintf(stderr,
106 "New mmap_list entry %d (hash was %d) [ino: %u size: %u]\n", i,
107 start, s->st_ino, s->st_size);
108 #endif
109 mmap_list_entries_used++;
110 mmap_list[i].dev = s->st_dev;
111 mmap_list[i].ino = s->st_ino;
112 mmap_list[i].len = s->st_size;
113 mmap_list[i].mmap = m;
114 mmap_list[i].use_count = 1;
115 mmap_list[i].available = 1;
116 mmap_list[i].times_used = 1;
117
118 #ifdef ENABLE_SMP
119 pthread_mutex_unlock(&mmap_lock);
120 #endif
121 return &mmap_list[i];
122 }
123
124 /* Removes all entries in the mmap list that are not used and
125 * have been used less times than the average of all.
126 * No locking here. The caller has to do the proper locking.
127 *
128 * Return values:
129 * -1 failed. Could not make any space on the list
130 * >=0 an index number, of an empty element in the list.
131 *
132 */
133 static int cleanup_mmap_list()
134 {
135 int i, avg = 0;
136 int ret = -1;
137 #ifdef DEBUG
138 int count = 0;
139
140 fprintf(stderr, "Cleaning up mmap_list. Entries: %d.\n", mmap_list_entries_used);
141 #endif
142
143 /* The algorithm here is:
144 * 1. Calculate the average of all times used
145 * 2. Remove all entries that have been used less than
146 * 'average' times. Also remove entries that their hash does not
147 * equal their index. This is to avoid duplicate entries.
148 */
149 for (i = 0; i < max_files_cache; i++) {
150 if (mmap_list[i].available) {
151 avg += mmap_list[i].times_used;
152 }
153 }
154
155 avg /= i;
156
157 for (i = 0; i < max_files_cache; i++) {
158 if (mmap_list[i].available && (mmap_list[i].use_count == 0) &&
159 (mmap_list[i].times_used < avg || MMAP_LIST_HASH(mmap_list[i].dev,
160 mmap_list[i].ino, mmap_list[i].len) != i)) {
161
162 ret = i;
163 munmap(mmap_list[i].mmap, mmap_list[i].len);
164 mmap_list[i].available = 0;
165 mmap_list_entries_used--;
166 #ifdef DEBUG
167 count++;
168 #endif
169 } else mmap_list[i].times_used = 0; /* zero all counters. */
170 }
171 #ifdef DEBUG
172 fprintf(stderr, "Removed %d entries from the mmap_hashtable (clean stage1)\n", count);
173 count = 0;
174 #endif
175
176 /* If no list elements were removed, then remove all that
177 * are not used. This is our last resort! We shouldn't have
178 * come here.
179 */
180 if (mmap_list_entries_used >= max_files_cache) {
181 for (i = 0; i < max_files_cache; i++) {
182 if (mmap_list[i].available && mmap_list[i].use_count == 0) {
183
184 ret = i;
185 munmap(mmap_list[i].mmap, mmap_list[i].len);
186 mmap_list[i].available = 0;
187 mmap_list_entries_used--;
188 #ifdef DEBUG
189 count++;
190 #endif
191 }
192 }
193 #ifdef DEBUG
194 fprintf(stderr, "Removed %d entries from the mmap_hashtable (clean stage2)\n", count);
195 #endif
196
197 }
198
199 /* If we have come here and we didn't remove any list entries,
200 * then all list entries are used or there is a bug above.
201 */
202
203 #ifdef DEBUG
204 fprintf(stderr, "Cleaned up mmap_list. Entries: %d.\n", mmap_list_entries_used);
205 #endif
206
207 return ret;
208 }
209
210 void release_mmap(struct mmap_entry *e)
211 {
212 if (!e)
213 return;
214
215 #ifdef ENABLE_SMP
216 pthread_mutex_lock(&mmap_lock);
217 #endif
218
219 if (!e->use_count) {
220 #ifdef DEBUG
221 fprintf(stderr, "mmap_list(%p)->use_count already zero!\n", e);
222 #endif
223 goto finish;
224 }
225
226 e->use_count--;
227
228
229 finish:
230 #ifdef ENABLE_SMP
231 pthread_mutex_unlock(&mmap_lock);
232 #endif
233 return;
234 }
235
236 struct mmap_entry *find_named_mmap(char *fname)
237 {
238 int data_fd;
239 struct stat statbuf;
240 struct mmap_entry *e;
241 data_fd = open(fname, O_RDONLY);
242 if (data_fd == -1) {
243 perror(fname);
244 return NULL;
245 }
246 fstat(data_fd, &statbuf);
247 if (S_ISDIR(statbuf.st_mode)) {
248 #ifdef DEBUG
249 fprintf(stderr, "%s is a directory\n", fname);
250 #endif
251 return NULL;
252 }
253
254 e = find_mmap(data_fd, &statbuf);
255 close(data_fd);
256 return e;
257 }
258
259 void mmap_reinit()
260 {
261
262 if (max_files_cache > previous_max_files_cache) {
263 mmap_list = realloc( mmap_list, sizeof(struct mmap_entry)*max_files_cache);
264 if (mmap_list == NULL) {
265 log_error_time();
266 fprintf(stderr, "Could not allocate mmap list\n");
267 exit(1);
268 }
269 memset( &mmap_list[previous_max_files_cache], 0, sizeof(struct mmap_entry)*
270 (max_files_cache-previous_max_files_cache));
271 } else {
272 /* we cannot make the max file cache less than
273 * the previous one, or we risk having some stray mmaped
274 * stuff, in memory we cannot access.
275 */
276 max_files_cache = previous_max_files_cache;
277 log_error_time();
278 fprintf(stderr, "Cannot not decrease the maximum files cache value, on runtime.\n");
279 }
280 previous_max_files_cache = max_files_cache;
281
282 }
283
284 void initialize_mmap()
285 {
286 /* initialize the list array */
287 mmap_list = calloc( 1, sizeof(struct mmap_entry)*max_files_cache);
288 if (mmap_list == NULL) {
289 log_error_time();
290 fprintf(stderr, "Could not allocate mmap list\n");
291 exit(1);
292 }
293
294 previous_max_files_cache = max_files_cache;
295 return;
296 }
297
298 #endif /* USE_MMAP_LIST */

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26