]>
git.proxmox.com Git - libgit2.git/blob - src/mwindow.c
2 * Copyright (C) 2009-2012 the libgit2 contributors
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
15 #define DEFAULT_WINDOW_SIZE \
17 ? 1 * 1024 * 1024 * 1024 \
20 #define DEFAULT_MAPPED_LIMIT \
21 ((1024 * 1024) * (sizeof(void*) >= 8 ? 8192ULL : 256UL))
24 * These are the global options for mmmap limits.
25 * TODO: allow the user to change these
35 /* Whenever you want to read or modify this, grab git__mwindow_mutex */
36 static git_mwindow_ctl mem_ctl
;
39 * Free all the windows in a sequence, typically because we're done
42 void git_mwindow_free_all(git_mwindow_file
*mwf
)
44 git_mwindow_ctl
*ctl
= &mem_ctl
;
47 if (git_mutex_lock(&git__mwindow_mutex
)) {
48 giterr_set(GITERR_THREAD
, "unable to lock mwindow mutex");
53 * Remove these windows from the global list
55 for (i
= 0; i
< ctl
->windowfiles
.length
; ++i
){
56 if (git_vector_get(&ctl
->windowfiles
, i
) == mwf
) {
57 git_vector_remove(&ctl
->windowfiles
, i
);
62 if (ctl
->windowfiles
.length
== 0) {
63 git_vector_free(&ctl
->windowfiles
);
64 ctl
->windowfiles
.contents
= NULL
;
67 while (mwf
->windows
) {
68 git_mwindow
*w
= mwf
->windows
;
69 assert(w
->inuse_cnt
== 0);
71 ctl
->mapped
-= w
->window_map
.len
;
74 git_futils_mmap_free(&w
->window_map
);
76 mwf
->windows
= w
->next
;
80 git_mutex_unlock(&git__mwindow_mutex
);
84 * Check if a window 'win' contains the address 'offset'
86 int git_mwindow_contains(git_mwindow
*win
, git_off_t offset
)
88 git_off_t win_off
= win
->offset
;
89 return win_off
<= offset
90 && offset
<= (git_off_t
)(win_off
+ win
->window_map
.len
);
94 * Find the least-recently-used window in a file
96 static void git_mwindow_scan_lru(
97 git_mwindow_file
*mwf
,
101 git_mwindow
*w
, *w_l
;
103 for (w_l
= NULL
, w
= mwf
->windows
; w
; w
= w
->next
) {
106 * If the current one is more recent than the last one,
107 * store it in the output parameter. If lru_w is NULL,
108 * it's the first loop, so store it as well.
110 if (!*lru_w
|| w
->last_used
< (*lru_w
)->last_used
) {
120 * Close the least recently used window. You should check to see if
121 * the file descriptors need closing from time to time. Called under
122 * lock from new_window.
124 static int git_mwindow_close_lru(git_mwindow_file
*mwf
)
126 git_mwindow_ctl
*ctl
= &mem_ctl
;
128 git_mwindow
*lru_w
= NULL
, *lru_l
= NULL
, **list
= &mwf
->windows
;
130 /* FIXME: Does this give us any advantage? */
132 git_mwindow_scan_lru(mwf
, &lru_w
, &lru_l
);
134 for (i
= 0; i
< ctl
->windowfiles
.length
; ++i
) {
135 git_mwindow
*last
= lru_w
;
136 git_mwindow_file
*cur
= git_vector_get(&ctl
->windowfiles
, i
);
137 git_mwindow_scan_lru(cur
, &lru_w
, &lru_l
);
139 list
= &cur
->windows
;
143 giterr_set(GITERR_OS
, "Failed to close memory window. Couldn't find LRU");
147 ctl
->mapped
-= lru_w
->window_map
.len
;
148 git_futils_mmap_free(&lru_w
->window_map
);
151 lru_l
->next
= lru_w
->next
;
161 /* This gets called under lock from git_mwindow_open */
162 static git_mwindow
*new_window(
163 git_mwindow_file
*mwf
,
168 git_mwindow_ctl
*ctl
= &mem_ctl
;
169 size_t walign
= _mw_options
.window_size
/ 2;
173 w
= git__malloc(sizeof(*w
));
178 memset(w
, 0x0, sizeof(*w
));
179 w
->offset
= (offset
/ walign
) * walign
;
181 len
= size
- w
->offset
;
182 if (len
> (git_off_t
)_mw_options
.window_size
)
183 len
= (git_off_t
)_mw_options
.window_size
;
185 ctl
->mapped
+= (size_t)len
;
187 while (_mw_options
.mapped_limit
< ctl
->mapped
&&
188 git_mwindow_close_lru(mwf
) == 0) /* nop */;
191 * We treat _mw_options.mapped_limit as a soft limit. If we can't find a
192 * window to close and are above the limit, we still mmap the new
196 if (git_futils_mmap_ro(&w
->window_map
, fd
, w
->offset
, (size_t)len
) < 0) {
204 if (ctl
->mapped
> ctl
->peak_mapped
)
205 ctl
->peak_mapped
= ctl
->mapped
;
207 if (ctl
->open_windows
> ctl
->peak_open_windows
)
208 ctl
->peak_open_windows
= ctl
->open_windows
;
214 * Open a new window, closing the least recenty used until we have
215 * enough space. Don't forget to add it to your list
217 unsigned char *git_mwindow_open(
218 git_mwindow_file
*mwf
,
219 git_mwindow
**cursor
,
224 git_mwindow_ctl
*ctl
= &mem_ctl
;
225 git_mwindow
*w
= *cursor
;
227 if (git_mutex_lock(&git__mwindow_mutex
)) {
228 giterr_set(GITERR_THREAD
, "unable to lock mwindow mutex");
232 if (!w
|| !(git_mwindow_contains(w
, offset
) && git_mwindow_contains(w
, offset
+ extra
))) {
237 for (w
= mwf
->windows
; w
; w
= w
->next
) {
238 if (git_mwindow_contains(w
, offset
) &&
239 git_mwindow_contains(w
, offset
+ extra
))
244 * If there isn't a suitable window, we need to create a new
248 w
= new_window(mwf
, mwf
->fd
, mwf
->size
, offset
);
250 git_mutex_unlock(&git__mwindow_mutex
);
253 w
->next
= mwf
->windows
;
258 /* If we changed w, store it in the cursor */
260 w
->last_used
= ctl
->used_ctr
++;
268 *left
= (unsigned int)(w
->window_map
.len
- offset
);
270 git_mutex_unlock(&git__mwindow_mutex
);
271 return (unsigned char *) w
->window_map
.data
+ offset
;
274 int git_mwindow_file_register(git_mwindow_file
*mwf
)
276 git_mwindow_ctl
*ctl
= &mem_ctl
;
279 if (git_mutex_lock(&git__mwindow_mutex
)) {
280 giterr_set(GITERR_THREAD
, "unable to lock mwindow mutex");
284 if (ctl
->windowfiles
.length
== 0 &&
285 git_vector_init(&ctl
->windowfiles
, 8, NULL
) < 0) {
286 git_mutex_unlock(&git__mwindow_mutex
);
290 ret
= git_vector_insert(&ctl
->windowfiles
, mwf
);
291 git_mutex_unlock(&git__mwindow_mutex
);
296 int git_mwindow_file_deregister(git_mwindow_file
*mwf
)
298 git_mwindow_ctl
*ctl
= &mem_ctl
;
299 git_mwindow_file
*cur
;
302 if (git_mutex_lock(&git__mwindow_mutex
)) {
303 giterr_set(GITERR_THREAD
, "unable to lock mwindow mutex");
307 git_vector_foreach(&ctl
->windowfiles
, i
, cur
) {
309 git_vector_remove(&ctl
->windowfiles
, i
);
310 git_mutex_unlock(&git__mwindow_mutex
);
314 git_mutex_unlock(&git__mwindow_mutex
);
316 giterr_set(GITERR_ODB
, "Failed to find the memory window file to deregister");
320 void git_mwindow_close(git_mwindow
**window
)
322 git_mwindow
*w
= *window
;
324 if (git_mutex_lock(&git__mwindow_mutex
)) {
325 giterr_set(GITERR_THREAD
, "unable to lock mwindow mutex");
330 git_mutex_unlock(&git__mwindow_mutex
);