summaryrefslogtreecommitdiff
path: root/storage/xtradb/os/os0proc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/xtradb/os/os0proc.cc')
-rw-r--r--storage/xtradb/os/os0proc.cc63
1 files changed, 59 insertions, 4 deletions
diff --git a/storage/xtradb/os/os0proc.cc b/storage/xtradb/os/os0proc.cc
index ff6d65e4ae6..6c9116e1397 100644
--- a/storage/xtradb/os/os0proc.cc
+++ b/storage/xtradb/os/os0proc.cc
@@ -32,6 +32,14 @@ Created 9/30/1995 Heikki Tuuri
#include "ut0mem.h"
#include "ut0byte.h"
+/* Linux release version */
+#if defined(UNIV_LINUX) && defined(_GNU_SOURCE)
+#include <string.h> /* strverscmp() */
+#include <sys/utsname.h> /* uname() */
+#endif
+
+#include "ha_prototypes.h"
+
/* FreeBSD for example has only MAP_ANON, Linux has MAP_ANONYMOUS and
MAP_ANON but MAP_ANON is marked as deprecated */
#if defined(MAP_ANONYMOUS)
@@ -40,10 +48,36 @@ MAP_ANON but MAP_ANON is marked as deprecated */
#define OS_MAP_ANON MAP_ANON
#endif
+/* Linux's MAP_POPULATE */
+#if defined(MAP_POPULATE)
+#define OS_MAP_POPULATE MAP_POPULATE
+#else
+#define OS_MAP_POPULATE 0
+#endif
+
UNIV_INTERN ibool os_use_large_pages;
/* Large page size. This may be a boot-time option on some platforms */
UNIV_INTERN ulint os_large_page_size;
+
+/****************************************************************//**
+Retrieve and compare operating system release.
+@return TRUE if the OS release is equal to, or later than release. */
+UNIV_INTERN
+bool
+os_compare_release(
+/*===============*/
+ const char* release /*!< in: OS release */
+ MY_ATTRIBUTE((unused)))
+{
+#if defined(UNIV_LINUX) && defined(_GNU_SOURCE)
+ struct utsname name;
+ return uname(&name) == 0 && strverscmp(name.release, release) >= 0;
+#else
+ return false;
+#endif
+}
+
/****************************************************************//**
Converts the current process id to a number. It is not guaranteed that the
number is unique. In Linux returns the 'process number' of the current
@@ -69,7 +103,8 @@ UNIV_INTERN
void*
os_mem_alloc_large(
/*===============*/
- ulint* n) /*!< in/out: number of bytes */
+ ulint* n, /*!< in/out: number of bytes */
+ bool populate) /*!< in: virtual page preallocation */
{
void* ptr;
ulint size;
@@ -155,12 +190,13 @@ skip:
ut_ad(ut_is_2pow(size));
size = *n = ut_2pow_round(*n + (size - 1), size);
ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | OS_MAP_ANON, -1, 0);
- if (UNIV_UNLIKELY(ptr == (void*) -1)) {
+ MAP_PRIVATE | OS_MAP_ANON |
+ (populate ? OS_MAP_POPULATE : 0), -1, 0);
+ if (UNIV_UNLIKELY(ptr == MAP_FAILED)) {
fprintf(stderr, "InnoDB: mmap(%lu bytes) failed;"
" errno %lu\n",
(ulong) size, (ulong) errno);
- ptr = NULL;
+ return NULL;
} else {
os_fast_mutex_lock(&ut_list_mutex);
ut_total_allocated_memory += size;
@@ -168,6 +204,25 @@ skip:
UNIV_MEM_ALLOC(ptr, size);
}
#endif
+
+#if OS_MAP_ANON && OS_MAP_POPULATE
+ /* MAP_POPULATE is only supported for private mappings
+ since Linux 2.6.23. */
+ populate = populate && !os_compare_release("2.6.23");
+
+ if (populate) {
+ ib_logf(IB_LOG_LEVEL_WARN, "InnoDB: Warning: mmap(MAP_POPULATE) "
+ "is not supported for private mappings. "
+ "Forcing preallocation by faulting in pages.\n");
+ }
+#endif
+
+ /* Initialize the entire buffer to force the allocation
+ of physical memory page frames. */
+ if (populate) {
+ memset(ptr, '\0', size);
+ }
+
return(ptr);
}