1 /*-
2 * Copyright (c) 2014-2018 MongoDB, Inc.
3 * Copyright (c) 2008-2014 WiredTiger, Inc.
4 * All rights reserved.
5 *
6 * See the file LICENSE for redistribution information.
7 */
8
9 #include "wt_internal.h"
10
11 /*
12 * __wt_posix_map --
13 * Map a file into memory.
14 */
15 int
__wt_posix_map(WT_FILE_HANDLE * fh,WT_SESSION * wt_session,void * mapped_regionp,size_t * lenp,void * mapped_cookiep)16 __wt_posix_map(WT_FILE_HANDLE *fh, WT_SESSION *wt_session,
17 void *mapped_regionp, size_t *lenp, void *mapped_cookiep)
18 {
19 WT_FILE_HANDLE_POSIX *pfh;
20 WT_SESSION_IMPL *session;
21 wt_off_t file_size;
22 size_t len;
23 void *map;
24
25 WT_UNUSED(mapped_cookiep);
26
27 session = (WT_SESSION_IMPL *)wt_session;
28 pfh = (WT_FILE_HANDLE_POSIX *)fh;
29
30 /*
31 * Mapping isn't possible if direct I/O configured for the file, the
32 * Linux open(2) documentation says applications should avoid mixing
33 * mmap(2) of files with direct I/O to the same files.
34 */
35 if (pfh->direct_io)
36 return (__wt_set_return(session, ENOTSUP));
37
38 /*
39 * There's no locking here to prevent the underlying file from changing
40 * underneath us, our caller needs to ensure consistency of the mapped
41 * region vs. any other file activity.
42 */
43 WT_RET(fh->fh_size(fh, wt_session, &file_size));
44 len = (size_t)file_size;
45
46 __wt_verbose(session, WT_VERB_HANDLEOPS,
47 "%s: memory-map: %" WT_SIZET_FMT " bytes", fh->name, len);
48
49 if ((map = mmap(NULL, len,
50 PROT_READ,
51 #ifdef MAP_NOCORE
52 MAP_NOCORE |
53 #endif
54 MAP_PRIVATE,
55 pfh->fd, (wt_off_t)0)) == MAP_FAILED)
56 WT_RET_MSG(session,
57 __wt_errno(), "%s: memory-map: mmap", fh->name);
58
59 *(void **)mapped_regionp = map;
60 *lenp = len;
61 return (0);
62 }
63
64 #ifdef HAVE_POSIX_MADVISE
65 /*
66 * __wt_posix_map_preload --
67 * Cause a section of a memory map to be faulted in.
68 */
69 int
__wt_posix_map_preload(WT_FILE_HANDLE * fh,WT_SESSION * wt_session,const void * map,size_t length,void * mapped_cookie)70 __wt_posix_map_preload(WT_FILE_HANDLE *fh,
71 WT_SESSION *wt_session, const void *map, size_t length, void *mapped_cookie)
72 {
73 WT_BM *bm;
74 WT_CONNECTION_IMPL *conn;
75 WT_DECL_RET;
76 WT_SESSION_IMPL *session;
77 void *blk;
78
79 WT_UNUSED(mapped_cookie);
80
81 session = (WT_SESSION_IMPL *)wt_session;
82
83 conn = S2C(session);
84 bm = S2BT(session)->bm;
85
86 /* Linux requires the address be aligned to a 4KB boundary. */
87 blk = (void *)((uintptr_t)map & ~(uintptr_t)(conn->page_size - 1));
88 length += WT_PTRDIFF(map, blk);
89
90 /* XXX proxy for "am I doing a scan?" -- manual read-ahead */
91 if (F_ISSET(session, WT_SESSION_READ_WONT_NEED)) {
92 /* Read in 2MB blocks every 1MB of data. */
93 if (((uintptr_t)((uint8_t *)blk + length) &
94 (uintptr_t)((1<<20) - 1)) < (uintptr_t)blk)
95 return (0);
96 length = WT_MIN(WT_MAX(20 * length, 2 << 20),
97 WT_PTRDIFF((uint8_t *)bm->map + bm->maplen, blk));
98 }
99
100 /*
101 * Manual pages aren't clear on whether alignment is required for the
102 * size, so we will be conservative.
103 */
104 length &= ~(size_t)(conn->page_size - 1);
105 if (length <= (size_t)conn->page_size)
106 return (0);
107
108 WT_SYSCALL(posix_madvise(blk, length, POSIX_MADV_WILLNEED), ret);
109 if (ret == 0)
110 return (0);
111
112 WT_RET_MSG(session, ret,
113 "%s: memory-map preload: posix_madvise: POSIX_MADV_WILLNEED",
114 fh->name);
115 }
116 #endif
117
118 #ifdef HAVE_POSIX_MADVISE
119 /*
120 * __wt_posix_map_discard --
121 * Discard a chunk of the memory map.
122 */
123 int
__wt_posix_map_discard(WT_FILE_HANDLE * fh,WT_SESSION * wt_session,void * map,size_t length,void * mapped_cookie)124 __wt_posix_map_discard(WT_FILE_HANDLE *fh,
125 WT_SESSION *wt_session, void *map, size_t length, void *mapped_cookie)
126 {
127 WT_CONNECTION_IMPL *conn;
128 WT_DECL_RET;
129 WT_SESSION_IMPL *session;
130 void *blk;
131
132 WT_UNUSED(mapped_cookie);
133
134 session = (WT_SESSION_IMPL *)wt_session;
135 conn = S2C(session);
136
137 /* Linux requires the address be aligned to a 4KB boundary. */
138 blk = (void *)((uintptr_t)map & ~(uintptr_t)(conn->page_size - 1));
139 length += WT_PTRDIFF(map, blk);
140
141 WT_SYSCALL(posix_madvise(blk, length, POSIX_MADV_DONTNEED), ret);
142 if (ret == 0)
143 return (0);
144
145 WT_RET_MSG(session, ret,
146 "%s: memory-map discard: posix_madvise: POSIX_MADV_DONTNEED",
147 fh->name);
148 }
149 #endif
150
151 /*
152 * __wt_posix_unmap --
153 * Remove a memory mapping.
154 */
155 int
__wt_posix_unmap(WT_FILE_HANDLE * fh,WT_SESSION * wt_session,void * mapped_region,size_t len,void * mapped_cookie)156 __wt_posix_unmap(WT_FILE_HANDLE *fh, WT_SESSION *wt_session,
157 void *mapped_region, size_t len, void *mapped_cookie)
158 {
159 WT_SESSION_IMPL *session;
160
161 WT_UNUSED(mapped_cookie);
162
163 session = (WT_SESSION_IMPL *)wt_session;
164
165 __wt_verbose(session, WT_VERB_HANDLEOPS,
166 "%s: memory-unmap: %" WT_SIZET_FMT " bytes", fh->name, len);
167
168 if (munmap(mapped_region, len) == 0)
169 return (0);
170
171 WT_RET_MSG(session, __wt_errno(), "%s: memory-unmap: munmap", fh->name);
172 }
173