/* Copyright (c) 2025, 2026, MariaDB plc.
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; version 2 of the License .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
#include <my_global.h>
#include <my_sys.h>
#include <mysys_err.h>
#include <my_virtual_mem.h>
#ifdef _AIX
# include <sys/shm.h>
#endif
/*
Functionality for handling virtual memory
- reserve range - memory is reserved , not allocated .
- commit memory ( within reserved range ) - memory is allocated
- decommit previously commited memory - memory is deallocated , stays reserved
- release range - reserved range is released to OS
Not every OS has a " reserve " functionality , i . e it is not always
possible to reserve memory larger than swap or RAM for example .
The unfortunate terminology comes from WinAPI , see MEM_ * flags below .
It ' s rather confusing in the context of a database ( and specifically ,
InnoDB , the only user of this functionality ) , but it ' s the established
terminology .
We try to respect use_large_pages setting , both on Windows and Linux
*/
char *my_virtual_mem_reserve(size_t *size)
{
#ifdef _WIN32
DWORD flags= my_use_large_pages
? MEM_LARGE_PAGES | MEM_RESERVE | MEM_COMMIT
: MEM_RESERVE;
char *ptr= VirtualAlloc(NULL, *size, flags, PAGE_READWRITE);
if (!ptr && (flags & MEM_LARGE_PAGES))
{
/* Try without large pages */
ptr= VirtualAlloc(NULL, *size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (!ptr)
my_error(EE_OUTOFMEMORY, MYF(ME_BELL + ME_ERROR_LOG), *size);
}
return ptr;
#else
return my_large_virtual_alloc(size);
#endif
}
#if defined _WIN32 && !defined DBUG_OFF
static my_bool is_memory_committed(char *ptr, size_t size)
{
MEMORY_BASIC_INFORMATION mbi;
if (VirtualQuery(ptr, &mbi, sizeof mbi) == 0 )
DBUG_ASSERT(0 );
return !!(mbi.State & MEM_COMMIT);
}
#endif
/*
" commit " - in other words , allocate - memory .
ptr must lie within a previously reserved range or be NULL .
in the latter case new memory is reserved and committed .
This is compatible with the mmap / VirtualAlloc semantics .
*/
char *my_virtual_mem_commit(char *ptr, size_t size)
{
#ifdef _WIN32
if (!ptr)
return VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (my_use_large_pages)
{
DBUG_ASSERT(is_memory_committed(ptr, size));
}
else
{
void *p= VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE);
DBUG_ASSERT(p == ptr);
if (!p)
{
my_error(EE_OUTOFMEMORY, MYF(ME_BELL + ME_ERROR_LOG), size);
return NULL;
}
}
#else
if (!ptr)
{
void *p= mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1 , 0 );
return p == MAP_FAILED ? NULL : p;
}
if (my_use_large_pages)
/* my_large_virtual_alloc() already created a read/write mapping. */;
else
{
# ifdef _AIX
/*
MAP_FIXED does not not work on IBM AIX in the way does works elsewhere .
Apparently , it is not possible to mmap ( 2 ) a range that is already in use ,
at least not by default .
mprotect ( 2 ) is the fallback , it can ' t communicate out - of - memory
conditions , but it looks like overcommitting is not possible on
AIX anyway .
*/
if (mprotect(ptr, size, PROT_READ | PROT_WRITE))
{
my_error(EE_OUTOFMEMORY, MYF(ME_BELL + ME_ERROR_LOG), size);
return NULL;
}
# else
void *p= 0 ;
const int flags=
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
p= mmap(ptr, size, PROT_READ | PROT_WRITE, flags, -1 , 0 );
if (p == MAP_FAILED)
{
my_error(EE_OUTOFMEMORY, MYF(ME_BELL + ME_ERROR_LOG), size);
return NULL;
}
DBUG_ASSERT(p == ptr);
# if defined MADV_FREE_REUSABLE && defined MADV_FREE_REUSE /* Apple macOS */
madvise(ptr, size, MADV_FREE_REUSE); /* cancel MADV_FREE_REUSABLE */
# endif
# endif
}
#endif
update_malloc_size(size, 0 );
return ptr;
}
void my_virtual_mem_decommit(char *ptr, size_t size)
{
#ifdef _WIN32
DBUG_ASSERT(is_memory_committed(ptr, size));
if (!my_use_large_pages)
{
if (!VirtualFree(ptr, size, MEM_DECOMMIT))
{
my_error(EE_BADMEMORYRELEASE, MYF(ME_ERROR_LOG_ONLY), ptr, size,
GetLastError());
DBUG_ASSERT(0 );
}
}
#else
# ifdef _AIX
disclaim(ptr, size, DISCLAIM_ZEROMEM);
# elif defined __linux__ || defined __osf__
madvise(ptr, size, MADV_DONTNEED); /* OSF/1, Linux mimicing AIX disclaim() */
# elif defined MADV_FREE_REUSABLE && defined MADV_FREE_REUSE
/* Mac OS X 10.9; undocumented in Apple macOS */
madvise(ptr, size, MADV_FREE_REUSABLE); /* macOS mimicing AIX disclaim() */
# elif defined MADV_PURGE /* Illumos */
madvise(ptr, size, MADV_PURGE); /* Illumos mimicing AIX disclaim() */
# elif defined MADV_FREE
/* FreeBSD, NetBSD, OpenBSD, Dragonfly BSD, OpenSolaris, Apple macOS */
madvise(ptr, size, MADV_FREE); /* allow lazy zeroing out */
# elif defined MADV_DONTNEED
# warning "It is unclear if madvise(MADV_DONTNEED) works as intended"
madvise(ptr, size, MADV_DONTNEED);
# else
# warning "Do not know how to decommit memory"
# endif
if (mprotect(ptr, size, PROT_NONE))
{
my_error(EE_BADMEMORYRELEASE, MYF(ME_ERROR_LOG_ONLY), ptr, size, errno);
DBUG_ASSERT(0 );
}
#endif
update_malloc_size(-(longlong) size, 0 );
}
void my_virtual_mem_release(char *ptr, size_t size)
{
#ifdef _WIN32
if (!VirtualFree(ptr, 0 , MEM_RELEASE))
{
my_error(EE_BADMEMORYRELEASE, MYF(ME_ERROR_LOG_ONLY), ptr, size,
GetLastError());
DBUG_ASSERT(0 );
}
#else
if (munmap(ptr, size))
{
my_error(EE_BADMEMORYRELEASE, MYF(ME_ERROR_LOG_ONLY), ptr, size, errno);
DBUG_ASSERT(0 );
}
#endif
}
void my_virtual_mem_protect(void *ptr, size_t size, enum my_vmem_prot prot)
{
int res __attribute__((unused));
#ifdef _WIN32
DWORD old_prot;
res= !VirtualProtect(ptr, size, prot ? PAGE_READWRITE : PAGE_READONLY, &old_prot);
#else
res= mprotect(ptr, size, prot ? PROT_READ | PROT_WRITE : PROT_READ);
#endif
DBUG_ASSERT(res == 0 ); // bad ptr or size alignment, neither should be possible
}
Messung V0.5 in Prozent C=93 H=100 G=96
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet am 2026-10-08)
¤
*© Formatika GbR, Deutschland