Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

- #PXC-393: Optimized and accurate way to get mmap file gcache size using mincore syscall #100

Open
wants to merge 1 commit into
base: 3.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions common/wsrep_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,15 @@ struct wsrep {
*/
struct wsrep_stats_var* (*stats_get) (wsrep_t* wsrep);

/*!
* @brief Returns an array of extended status variables.
* Array is terminated by Null variable name.
*
* @param wsrep provider handle
* @return array of struct wsrep_status_var.
*/
struct wsrep_stats_var* (*stats_ext_get) (wsrep_t* wsrep);

/*!
* @brief Release resources that might be associated with the array.
*
Expand Down
1 change: 1 addition & 0 deletions galera/src/replicator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ namespace galera
virtual void process_sync(wsrep_seqno_t seqno_l) = 0;

virtual const struct wsrep_stats_var* stats_get() = 0;
virtual const struct wsrep_stats_var* stats_ext_get() = 0;
virtual void stats_reset() = 0;
// static void stats_free(struct wsrep_stats_var*) must be declared in
// the child class
Expand Down
4 changes: 3 additions & 1 deletion galera/src/replicator_smm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,8 @@ galera::ReplicatorSMM::ReplicatorSMM(const struct wsrep_init_args* args)
preordered_id_ (),
incoming_list_ (""),
incoming_mutex_ (),
wsrep_stats_ ()
wsrep_stats_ (),
wsrep_stats_ext_ ()
{
/*
Register the application callback that should be called
Expand Down Expand Up @@ -278,6 +279,7 @@ galera::ReplicatorSMM::ReplicatorSMM(const struct wsrep_init_args* args)
cert_.assign_initial_position(seqno, trx_proto_ver());

build_stats_vars(wsrep_stats_);
build_stats_ext_vars(wsrep_stats_ext_);
}

galera::ReplicatorSMM::~ReplicatorSMM()
Expand Down
3 changes: 3 additions & 0 deletions galera/src/replicator_smm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ namespace galera
void process_sync(wsrep_seqno_t seqno_l);

const struct wsrep_stats_var* stats_get();
const struct wsrep_stats_var* stats_ext_get();
void stats_reset();
void stats_free(struct wsrep_stats_var*);

Expand Down Expand Up @@ -457,6 +458,7 @@ namespace galera
};

void build_stats_vars (std::vector<struct wsrep_stats_var>& stats);
void build_stats_ext_vars (std::vector<struct wsrep_stats_var>& stats);

void establish_protocol_versions (int version);

Expand Down Expand Up @@ -616,6 +618,7 @@ namespace galera
mutable gu::Mutex incoming_mutex_;

mutable std::vector<struct wsrep_stats_var> wsrep_stats_;
mutable std::vector<struct wsrep_stats_var> wsrep_stats_ext_;
};

std::ostream& operator<<(std::ostream& os, ReplicatorSMM::State state);
Expand Down
70 changes: 70 additions & 0 deletions galera/src/replicator_smm_stats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,77 @@ galera::ReplicatorSMM::stats_get()
log_warn << "Failed to allocate stats vars buffer to "
<< (vec_size + tail_size)
<< " bytes. System is running out of memory.";
}

return buf;
}

typedef enum status_vars_ext
{
STATS_EXT_GCACHE_ACTUAL_POOL_SIZE = 0,
STATS_EXT_MAX
} StatusExtVars;

static const struct wsrep_stats_var wsrep_stats_ext[STATS_EXT_MAX + 1] =
{
{ "gcache_actual_pool_size", WSREP_VAR_INT64, { 0 } },
{ 0, WSREP_VAR_STRING, { 0 } }
};

void
galera::ReplicatorSMM::build_stats_ext_vars (
std::vector<struct wsrep_stats_var>& stats)
{
const struct wsrep_stats_var* ptr(wsrep_stats_ext);

do
{
stats.push_back(*ptr);
}
while (ptr++->name != 0);

stats[STATS_EXT_GCACHE_ACTUAL_POOL_SIZE].value._int64 = 0;
}

const struct wsrep_stats_var*
galera::ReplicatorSMM::stats_ext_get()
{
if (S_DESTROYED == state_()) return 0;

std::vector<struct wsrep_stats_var> sv(wsrep_stats_ext_);

sv[STATS_EXT_GCACHE_ACTUAL_POOL_SIZE].value._int64 =
gcache_.actual_pool_size();

/* Create a buffer to be passed to the caller. */
// The buffer size needed:
// * Space for wsrep_stats_ext_ array
// * Trailing space for string store
size_t const vec_size(
(sv.size())*sizeof(struct wsrep_stats_var));
struct wsrep_stats_var* const buf(
reinterpret_cast<struct wsrep_stats_var*>(
gu_malloc(vec_size)));

if (buf)
{
size_t sv_pos(STATS_EXT_MAX);

assert(sv_pos == sv.size() - 1);

// NULL terminate
sv[sv_pos].name = 0;
sv[sv_pos].type = WSREP_VAR_STRING;
sv[sv_pos].value._string = 0;

// Finally copy sv vector to buf
memcpy(buf, &sv[0], vec_size);
}
else
{
log_warn << "Failed to allocate extended stats vars buffer to "
<< (vec_size)
<< " bytes. System is running out of memory.";
}

return buf;
Expand Down
12 changes: 12 additions & 0 deletions galera/src/wsrep_provider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,17 @@ struct wsrep_stats_var* galera_stats_get (wsrep_t* gh)
}


struct wsrep_stats_var* galera_stats_ext_get (wsrep_t* gh)
{
assert(gh != 0);
assert(gh->ctx != 0);

REPL_CLASS* repl(reinterpret_cast< REPL_CLASS * >(gh->ctx));

return const_cast<struct wsrep_stats_var*>(repl->stats_ext_get());
}


extern "C"
void galera_stats_free (wsrep_t* gh, struct wsrep_stats_var* s)
{
Expand Down Expand Up @@ -1095,6 +1106,7 @@ static wsrep_t galera_str = {
&galera_sst_received,
&galera_snapshot,
&galera_stats_get,
&galera_stats_ext_get,
&galera_stats_free,
&galera_stats_reset,
&galera_pause,
Expand Down
97 changes: 97 additions & 0 deletions galerautils/src/gu_mmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,100 @@ namespace gu
}
}
}

/** Returns actual memory usage by allocated page range: **/

/*
* Verify test macros to make sure we have mincore syscall:
*/
#if defined(_BSD_SOURCE) || defined(_SVID_SOURCE)

/*
* The buffer size for mincore. 256 kilobytes is enough to request
* information on the status of 1GB memory map (256K * 4096 bytes per
* page = 1GB) in one syscall (when a 4096-byte pages). Increasing this
* parameter allows us to save a few syscalls (when huge amounts of mmap),
* but it also raises the memory requirements for temporary buffer:
*/
#define GU_AMU_CHUNK 0x40000 /* Currently 256K, must be power of two. */

size_t gu_actual_memory_usage (const void * const ptr, const size_t length)
{
size_t size= 0;
if (length)
{
/*
* -PAGE_SIZE is same as ~(PAGE_SIZE-1), but creates less
* potential problems due to implicit type cast in expressions:
*/
uintptr_t first=
reinterpret_cast<uintptr_t> (ptr) & -GU_PAGE_SIZE;
const uintptr_t last=
(reinterpret_cast<uintptr_t> (ptr) + length - 1) & -GU_PAGE_SIZE;
const ptrdiff_t total= last - first + GU_PAGE_SIZE;
size_t pages= total / GU_PAGE_SIZE;
size_t chunks= pages / GU_AMU_CHUNK;
unsigned char * const map=
reinterpret_cast<unsigned char *> (malloc(chunks ? GU_AMU_CHUNK : pages));
if (map)
{
while (chunks--)
{
if (mincore(reinterpret_cast<void *> (first),
(size_t) GU_AMU_CHUNK * GU_PAGE_SIZE, map) == 0)
{
for (size_t i = 0; i < GU_AMU_CHUNK; i++)
{
if (map[i])
{
size += GU_PAGE_SIZE;
}
}
}
else
{
log_fatal << "Unable to get in-core state vector "
"for page range. Aborting.";
abort();
}
first += (size_t) GU_AMU_CHUNK * GU_PAGE_SIZE;
}
pages &= GU_AMU_CHUNK - 1;
if (mincore(reinterpret_cast<void *> (first),
pages * GU_PAGE_SIZE, map) == 0)
{
for (size_t i = 0; i < pages; i++)
{
if (map[i]) size += GU_PAGE_SIZE;
}
}
else
{
log_fatal << "Unable to get in-core state vector "
"for page range. Aborting.";
abort();
}
free(map);
}
else
{
log_fatal << "Unable to allocate memory for in-core state vector. "
<< "Aborting.";
abort();
}
}
return size;
}

#else

/*
* In case of absence mincore syscall we simply return the total size
* of memory-mapped region:
*/
size_t gu_actual_memory_usage (const void * const ptr, const size_t length)
{
return length;
}

#endif
3 changes: 3 additions & 0 deletions galerautils/src/gu_mmap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,7 @@ class MMap

} /* namespace gu */

/** Returns actual memory usage by allocated page range: **/
size_t gu_actual_memory_usage (const void * const ptr, const size_t length);

#endif /* __GCACHE_MMAP__ */
8 changes: 8 additions & 0 deletions gcache/src/GCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ namespace gcache
<< "\n" << "GCache frees : " << frees;
}

size_t GCache::actual_pool_size ()
{
gu::Lock lock(mtx);
return mem.actual_pool_size() +
rb.actual_pool_size(&mtx) +
ps.actual_pool_size(&mtx);
}

size_t GCache::allocated_pool_size ()
{
gu::Lock lock(mtx);
Expand Down
5 changes: 5 additions & 0 deletions gcache/src/GCache.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ namespace gcache
int64_t& seqno_d,
ssize_t& size);

/*!
* Returns actual gcache memory pool size (in bytes).
*/
size_t actual_pool_size ();

/*!
* Returns allocated gcache memory pool size (in bytes).
*/
Expand Down
5 changes: 5 additions & 0 deletions gcache/src/gcache_mem_store.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ MemStore::seqno_reset()
}
}

size_t MemStore::actual_pool_size ()
{
return size_;
}

size_t MemStore::allocated_pool_size ()
{
return size_;
Expand Down
1 change: 1 addition & 0 deletions gcache/src/gcache_mem_store.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ namespace gcache
// for unit tests only
size_t _allocd () const { return size_; }

size_t actual_pool_size ();
size_t allocated_pool_size ();

private:
Expand Down
11 changes: 11 additions & 0 deletions gcache/src/gcache_page.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,17 @@ gcache::Page::realloc (void* ptr, size_type size)
}
}

size_t gcache::Page::actual_pool_size (gu::Mutex * mtx)
{
void* ptr= reinterpret_cast<void *> (mmap_.ptr);
size_t used= mmap_.size - min_space_;
size_t size;
mtx->unlock();
size = gu_actual_memory_usage(ptr, used);
mtx->lock();
return size;
}

size_t gcache::Page::allocated_pool_size ()
{
return mmap_.size - min_space_;
Expand Down
6 changes: 4 additions & 2 deletions gcache/src/gcache_page.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
#include "gcache_memops.hpp"
#include "gcache_bh.hpp"

#include "gu_fdesc.hpp"
#include "gu_mmap.hpp"
#include <gu_fdesc.hpp>
#include <gu_mmap.hpp>
#include <gu_lock.hpp>

#include <string>

Expand Down Expand Up @@ -53,6 +54,7 @@ namespace gcache

void* parent() const { return ps_; }

size_t actual_pool_size (gu::Mutex * mtx);
size_t allocated_pool_size ();

private:
Expand Down
Loading