/[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.11 - (show annotations)
Fri Oct 4 09:11:43 2002 UTC (21 years, 5 months ago) by nmav
Branch: MAIN
CVS Tags: hydra_0_0_8, hydra_0_0_7
Changes since 1.10: +3 -3 lines
File MIME type: text/plain
Added support for large files in 32 bit systems.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26