]>
git.proxmox.com Git - libgit2.git/blob - src/mwindow.c
2 * Copyright (C) 2009-2011 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.
14 #define DEFAULT_WINDOW_SIZE \
16 ? 1 * 1024 * 1024 * 1024 \
19 #define DEFAULT_MAPPED_LIMIT \
20 ((1024 * 1024) * (sizeof(void*) >= 8 ? 8192ULL : 256UL))
23 * We need this because each process is only allowed a specific amount
24 * of memory. Making it writable should generate one instance per
25 * process, but we still need to set a couple of variables.
28 static git_mwindow_ctl ctl
= {
41 * Free all the windows in a sequence, typically because we're done
44 void git_mwindow_free_all(git_mwindow_file
*mwf
)
48 * Remove these windows from the global list
50 for (i
= 0; i
< ctl
.windowfiles
.length
; ++i
){
51 if (git_vector_get(&ctl
.windowfiles
, i
) == mwf
) {
52 git_vector_remove(&ctl
.windowfiles
, i
);
57 if (ctl
.windowfiles
.length
== 0) {
58 git_vector_free(&ctl
.windowfiles
);
59 ctl
.windowfiles
.contents
= NULL
;
62 while (mwf
->windows
) {
63 git_mwindow
*w
= mwf
->windows
;
64 assert(w
->inuse_cnt
== 0);
66 ctl
.mapped
-= w
->window_map
.len
;
69 git_futils_mmap_free(&w
->window_map
);
71 mwf
->windows
= w
->next
;
77 * Check if a window 'win' contains the address 'offset'
79 int git_mwindow_contains(git_mwindow
*win
, git_off_t offset
)
81 git_off_t win_off
= win
->offset
;
82 return win_off
<= offset
83 && offset
<= (git_off_t
)(win_off
+ win
->window_map
.len
);
87 * Find the least-recently-used window in a file
89 void git_mwindow_scan_lru(
90 git_mwindow_file
*mwf
,
96 for (w_l
= NULL
, w
= mwf
->windows
; w
; w
= w
->next
) {
99 * If the current one is more recent than the last one,
100 * store it in the output parameter. If lru_w is NULL,
101 * it's the first loop, so store it as well.
103 if (!*lru_w
|| w
->last_used
< (*lru_w
)->last_used
) {
113 * Close the least recently used window. You should check to see if
114 * the file descriptors need closing from time to time.
116 int git_mwindow_close_lru(git_mwindow_file
*mwf
)
119 git_mwindow
*lru_w
= NULL
, *lru_l
= NULL
;
121 /* FIMXE: Does this give us any advantage? */
123 git_mwindow_scan_lru(mwf
, &lru_w
, &lru_l
);
125 for (i
= 0; i
< ctl
.windowfiles
.length
; ++i
) {
126 git_mwindow_scan_lru(git_vector_get(&ctl
.windowfiles
, i
), &lru_w
, &lru_l
);
130 git_mwindow_close(&lru_w
);
131 ctl
.mapped
-= lru_w
->window_map
.len
;
132 git_futils_mmap_free(&lru_w
->window_map
);
135 lru_l
->next
= lru_w
->next
;
137 mwf
->windows
= lru_w
->next
;
145 return git__throw(GIT_ERROR
, "Failed to close memory window. Couln't find LRU");
148 static git_mwindow
*new_window(git_mwindow_file
*mwf
, git_file fd
, git_off_t size
, git_off_t offset
)
150 size_t walign
= ctl
.window_size
/ 2;
154 w
= git__malloc(sizeof(*w
));
158 memset(w
, 0x0, sizeof(*w
));
159 w
->offset
= (offset
/ walign
) * walign
;
161 len
= size
- w
->offset
;
162 if (len
> (git_off_t
)ctl
.window_size
)
163 len
= (git_off_t
)ctl
.window_size
;
165 ctl
.mapped
+= (size_t)len
;
167 while(ctl
.mapped_limit
< ctl
.mapped
&&
168 git_mwindow_close_lru(mwf
) == GIT_SUCCESS
) {}
170 /* FIXME: Shouldn't we error out if there's an error in closing lru? */
172 if (git_futils_mmap_ro(&w
->window_map
, fd
, w
->offset
, (size_t)len
) < GIT_SUCCESS
)
178 if (ctl
.mapped
> ctl
.peak_mapped
)
179 ctl
.peak_mapped
= ctl
.mapped
;
181 if (ctl
.open_windows
> ctl
.peak_open_windows
)
182 ctl
.peak_open_windows
= ctl
.open_windows
;
192 * Open a new window, closing the least recenty used until we have
193 * enough space. Don't forget to add it to your list
195 unsigned char *git_mwindow_open(git_mwindow_file
*mwf
, git_mwindow
**cursor
,
196 git_off_t offset
, int extra
, unsigned int *left
)
198 git_mwindow
*w
= *cursor
;
200 if (!w
|| !git_mwindow_contains(w
, offset
+ extra
)) {
205 for (w
= mwf
->windows
; w
; w
= w
->next
) {
206 if (git_mwindow_contains(w
, offset
+ extra
))
211 * If there isn't a suitable window, we need to create a new
215 w
= new_window(mwf
, mwf
->fd
, mwf
->size
, offset
);
218 w
->next
= mwf
->windows
;
223 /* If we changed w, store it in the cursor */
225 w
->last_used
= ctl
.used_ctr
++;
231 assert(git__is_sizet(offset
));
234 *left
= (unsigned int)(w
->window_map
.len
- offset
);
236 return (unsigned char *) w
->window_map
.data
+ offset
;
239 int git_mwindow_file_register(git_mwindow_file
*mwf
)
243 if (ctl
.windowfiles
.length
== 0 &&
244 (error
= git_vector_init(&ctl
.windowfiles
, 8, NULL
)) < GIT_SUCCESS
)
247 return git_vector_insert(&ctl
.windowfiles
, mwf
);
250 void git_mwindow_close(git_mwindow
**window
)
252 git_mwindow
*w
= *window
;