/[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.14 - (show annotations)
Sun Jan 26 11:25:39 2003 UTC (18 years, 10 months ago) by nmav
Branch: MAIN
CVS Tags: hydra_0_1_6_without_hic, hydra_0_1_7, hydra_0_1_6, hydra_0_1_4, hydra_0_1_8, HEAD
Changes since 1.13: +3 -3 lines
File MIME type: text/plain
Better large file support (now uses the included autoconf macros).
(++some indentation)

1 /*
2 * Hydra, 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.13 2002/10/27 10:46:19 nmav Exp $*/
23
24 #include "boa.h"
25
26 #ifdef ENABLE_SMP
27 pthread_mutex_t mmap_lock = PTHREAD_MUTEX_INITIALIZER;
28 #endif
29
30 int mmap_list_entries_used = 0;
31 int mmap_list_total_requests = 0;
32 int mmap_list_hash_bounces = 0;
33
34 #ifdef USE_MMAP_LIST
35
36 static int previous_max_files_cache = 0;
37
38 /* define local table variable */
39 static struct mmap_entry* mmap_list;
40
41
42 struct mmap_entry *find_mmap(int data_fd, struct stat *s)
43 {
44 char *m;
45 int i, start;
46
47 if ( max_files_cache == 0) return NULL;
48
49 #ifdef ENABLE_SMP
50 pthread_mutex_lock(&mmap_lock);
51 #endif
52 mmap_list_total_requests++;
53 i = start = MMAP_LIST_HASH(s->st_dev, s->st_ino, s->st_size);
54
55 for (;mmap_list[i].available;) {
56 if (mmap_list[i].dev == s->st_dev && mmap_list[i].ino == s->st_ino
57 && mmap_list[i].len == s->st_size) {
58 mmap_list[i].use_count++;
59 mmap_list[i].times_used++;
60
61 #ifdef DEBUG0
62 fprintf(stderr,
63 "Old mmap_list entry %d use_count now %d (hash was %d)\n",
64 i, mmap_list[i].use_count, start);
65 #endif
66 #ifdef ENABLE_SMP
67 pthread_mutex_unlock(&mmap_lock);
68 #endif
69 return &mmap_list[i];
70 }
71 mmap_list_hash_bounces++;
72 i = MMAP_LIST_NEXT(i);
73
74 if (i == start) {
75 i = cleanup_mmap_list(0);
76 if (i != -1) break; /* if we found an empty index */
77 /* otherwise no space could be cleaned. So say bye!!
78 */
79 #ifdef ENABLE_SMP
80 pthread_mutex_unlock(&mmap_lock);
81 #endif
82 return NULL;
83 }
84
85 }
86
87 /* didn't find an entry that matches our dev/inode/size.
88 There might be an entry that matches later in the table,
89 but that _should_ be rare. The worst case is that we
90 needlessly mmap() a file that is already mmap'd, but we
91 did that all the time before this code was written,
92 so it shouldn't be _too_ bad.
93 */
94
95 m = mmap(0, s->st_size, PROT_READ, MAP_OPTIONS, data_fd, 0);
96
97 if ( m == MAP_FAILED) {
98 /* boa_perror(req,"mmap"); */
99 return NULL;
100 }
101 #ifdef DEBUG0
102 fprintf(stderr,
103 "New mmap_list entry %d (hash was %d) [ino: %u size: %u]\n", i,
104 start, s->st_ino, s->st_size);
105 #endif
106 mmap_list_entries_used++;
107 mmap_list[i].dev = s->st_dev;
108 mmap_list[i].ino = s->st_ino;
109 mmap_list[i].len = s->st_size;
110 mmap_list[i].mmap = m;
111 mmap_list[i].use_count = 1;
112 mmap_list[i].available = 1;
113 mmap_list[i].times_used = 1;
114
115 #ifdef ENABLE_SMP
116 pthread_mutex_unlock(&mmap_lock);
117 #endif
118 return &mmap_list[i];
119 }
120
121 /* Removes all entries in the mmap list that are not used and
122 * have been used less times than the average of all.
123 * No locking here. The caller has to do the proper locking.
124 *
125 * Return values:
126 * -1 failed. Could not make any space on the list
127 * >=0 an index number, of an empty element in the list.
128 *
129 */
130 int cleanup_mmap_list(int all)
131 {
132 int i, avg = 0;
133 int ret = -1;
134 #ifdef DEBUG
135 int count = 0;
136
137 fprintf(stderr, "Cleaning up mmap_list. Entries: %d.\n", mmap_list_entries_used);
138 #endif
139
140 if (all != 0) goto remove_all_unused;
141
142 /* The algorithm here is:
143 * 1. Calculate the average of all times used
144 * 2. Remove all entries that have been used less than
145 * 'average' times. Also remove entries that their hash does not
146 * equal their index. This is to avoid duplicate entries.
147 */
148 for (i = 0; i < max_files_cache; i++) {
149 if (mmap_list[i].available) {
150 avg += mmap_list[i].times_used;
151 }
152 }
153
154 avg /= i;
155
156 for (i = 0; i < max_files_cache; i++) {
157 if (mmap_list[i].available && (mmap_list[i].use_count == 0) &&
158 (mmap_list[i].times_used < avg || MMAP_LIST_HASH(mmap_list[i].dev,
159 mmap_list[i].ino, mmap_list[i].len) != i)) {
160
161 ret = i;
162 munmap(mmap_list[i].mmap, mmap_list[i].len);
163 mmap_list[i].available = 0;
164 mmap_list_entries_used--;
165 #ifdef DEBUG
166 count++;
167 #endif
168 } else mmap_list[i].times_used = 0; /* zero all counters. */
169 }
170 #ifdef DEBUG
171 fprintf(stderr, "Removed %d entries from the mmap_hashtable (clean stage1)\n", count);
172 count = 0;
173 #endif
174
175 /* If no list elements were removed, then remove all that
176 * are not used. This is our last resort! We shouldn't have
177 * come here.
178 */
179 if (mmap_list_entries_used >= max_files_cache) {
180 remove_all_unused:
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 if (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
281 max_files_cache = previous_max_files_cache;
282 }
283 previous_max_files_cache = max_files_cache;
284
285 }
286
287 void initialize_mmap()
288 {
289 /* initialize the list array */
290 mmap_list = calloc( 1, sizeof(struct mmap_entry)*max_files_cache);
291 if (mmap_list == NULL) {
292 log_error_time();
293 fprintf(stderr, "Could not allocate mmap list\n");
294 exit(1);
295 }
296
297 previous_max_files_cache = max_files_cache;
298 return;
299 }
300
301 #endif /* USE_MMAP_LIST */

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26