mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 20:03:02 +01:00
Merge pull request #6991 from FirebirdSQL/work/external-pool
Introduce the external memory pool.
This commit is contained in:
commit
e64c3aacad
@ -21,7 +21,7 @@
|
|||||||
# Notes:
|
# Notes:
|
||||||
|
|
||||||
# Firebird requires the HP-UX Atomic APIs ("AtomicAPI" bundle), released as an
|
# Firebird requires the HP-UX Atomic APIs ("AtomicAPI" bundle), released as an
|
||||||
# optional Software Pack (SPK) for HP-UX 11i v2 or v3.
|
# optional Software Pack (SPK) for HP-UX 11i v2 or v3.
|
||||||
|
|
||||||
# Before attempting the HPUX build, you must export necessary
|
# Before attempting the HPUX build, you must export necessary
|
||||||
# CFLAGS and CXXFLAGS to be picked up by the configure process and
|
# CFLAGS and CXXFLAGS to be picked up by the configure process and
|
||||||
@ -60,15 +60,12 @@ COMMON_FLAGS= -DHP11 -DHPUX -D_XOPEN_SOURCE_EXTENDED -D_HP_ATOMIC_INLINE \
|
|||||||
|
|
||||||
# Flags specific to production or debug build...
|
# Flags specific to production or debug build...
|
||||||
# -z, disallow dereferencing of null pointers at runtime
|
# -z, disallow dereferencing of null pointers at runtime
|
||||||
# -DLIBC_CALLS_NEW, Firebird macro, used when C++ runtime can call
|
|
||||||
# redefined by us operator new before initialization of global variables.
|
|
||||||
# Required on IA-64, but evidently only by debug build!?
|
|
||||||
|
|
||||||
ifeq ($(shell uname -m),ia64)
|
ifeq ($(shell uname -m),ia64)
|
||||||
# ...for IA-64
|
# ...for IA-64
|
||||||
PROD_FLAGS= +O2 +Onolimit +Ofltacc=strict +Ofenvaccess \
|
PROD_FLAGS= +O2 +Onolimit +Ofltacc=strict +Ofenvaccess \
|
||||||
$(COMMON_FLAGS)
|
$(COMMON_FLAGS)
|
||||||
DEV_FLAGS= -g -z -DLIBC_CALLS_NEW \
|
DEV_FLAGS= -g -z \
|
||||||
$(COMMON_FLAGS)
|
$(COMMON_FLAGS)
|
||||||
else
|
else
|
||||||
# ...for PA-RISC
|
# ...for PA-RISC
|
||||||
|
25
extern/re2/re2/re2.cc
vendored
25
extern/re2/re2/re2.cc
vendored
@ -21,6 +21,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -60,9 +61,9 @@ RE2::Options::Options(RE2::CannedOptions opt)
|
|||||||
|
|
||||||
// static empty objects for use as const references.
|
// static empty objects for use as const references.
|
||||||
// To avoid global constructors, allocated in RE2::Init().
|
// To avoid global constructors, allocated in RE2::Init().
|
||||||
static const std::string* empty_string;
|
static std::unique_ptr<const std::string> empty_string;
|
||||||
static const std::map<std::string, int>* empty_named_groups;
|
static std::unique_ptr<const std::map<std::string, int>> empty_named_groups;
|
||||||
static const std::map<int, std::string>* empty_group_names;
|
static std::unique_ptr<const std::map<int, std::string>> empty_group_names;
|
||||||
|
|
||||||
// Converts from Regexp error code to RE2 error code.
|
// Converts from Regexp error code to RE2 error code.
|
||||||
// Maybe some day they will diverge. In any event, this
|
// Maybe some day they will diverge. In any event, this
|
||||||
@ -173,15 +174,15 @@ int RE2::Options::ParseFlags() const {
|
|||||||
void RE2::Init(const StringPiece& pattern, const Options& options) {
|
void RE2::Init(const StringPiece& pattern, const Options& options) {
|
||||||
static std::once_flag empty_once;
|
static std::once_flag empty_once;
|
||||||
std::call_once(empty_once, []() {
|
std::call_once(empty_once, []() {
|
||||||
empty_string = new std::string;
|
empty_string.reset(new std::string);
|
||||||
empty_named_groups = new std::map<std::string, int>;
|
empty_named_groups.reset(new std::map<std::string, int>);
|
||||||
empty_group_names = new std::map<int, std::string>;
|
empty_group_names.reset(new std::map<int, std::string>);
|
||||||
});
|
});
|
||||||
|
|
||||||
pattern_.assign(pattern.data(), pattern.size());
|
pattern_.assign(pattern.data(), pattern.size());
|
||||||
options_.Copy(options);
|
options_.Copy(options);
|
||||||
entire_regexp_ = NULL;
|
entire_regexp_ = NULL;
|
||||||
error_ = empty_string;
|
error_ = empty_string.get();
|
||||||
error_code_ = NoError;
|
error_code_ = NoError;
|
||||||
error_arg_.clear();
|
error_arg_.clear();
|
||||||
prefix_.clear();
|
prefix_.clear();
|
||||||
@ -267,11 +268,11 @@ RE2::~RE2() {
|
|||||||
entire_regexp_->Decref();
|
entire_regexp_->Decref();
|
||||||
delete prog_;
|
delete prog_;
|
||||||
delete rprog_;
|
delete rprog_;
|
||||||
if (error_ != empty_string)
|
if (error_ != empty_string.get())
|
||||||
delete error_;
|
delete error_;
|
||||||
if (named_groups_ != NULL && named_groups_ != empty_named_groups)
|
if (named_groups_ != NULL && named_groups_ != empty_named_groups.get())
|
||||||
delete named_groups_;
|
delete named_groups_;
|
||||||
if (group_names_ != NULL && group_names_ != empty_group_names)
|
if (group_names_ != NULL && group_names_ != empty_group_names.get())
|
||||||
delete group_names_;
|
delete group_names_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,7 +353,7 @@ const std::map<std::string, int>& RE2::NamedCapturingGroups() const {
|
|||||||
if (re->suffix_regexp_ != NULL)
|
if (re->suffix_regexp_ != NULL)
|
||||||
re->named_groups_ = re->suffix_regexp_->NamedCaptures();
|
re->named_groups_ = re->suffix_regexp_->NamedCaptures();
|
||||||
if (re->named_groups_ == NULL)
|
if (re->named_groups_ == NULL)
|
||||||
re->named_groups_ = empty_named_groups;
|
re->named_groups_ = empty_named_groups.get();
|
||||||
}, this);
|
}, this);
|
||||||
return *named_groups_;
|
return *named_groups_;
|
||||||
}
|
}
|
||||||
@ -363,7 +364,7 @@ const std::map<int, std::string>& RE2::CapturingGroupNames() const {
|
|||||||
if (re->suffix_regexp_ != NULL)
|
if (re->suffix_regexp_ != NULL)
|
||||||
re->group_names_ = re->suffix_regexp_->CaptureNames();
|
re->group_names_ = re->suffix_regexp_->CaptureNames();
|
||||||
if (re->group_names_ == NULL)
|
if (re->group_names_ == NULL)
|
||||||
re->group_names_ = empty_group_names;
|
re->group_names_ = empty_group_names.get();
|
||||||
}, this);
|
}, this);
|
||||||
return *group_names_;
|
return *group_names_;
|
||||||
}
|
}
|
||||||
|
@ -234,7 +234,7 @@ private:
|
|||||||
{
|
{
|
||||||
unsigned l = aMeta->getMessageLength(&statusWrapper);
|
unsigned l = aMeta->getMessageLength(&statusWrapper);
|
||||||
check(&statusWrapper);
|
check(&statusWrapper);
|
||||||
buffer = new unsigned char[l];
|
buffer = FB_NEW unsigned char[l];
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -336,7 +336,7 @@ public:
|
|||||||
|
|
||||||
if (!charBuffer)
|
if (!charBuffer)
|
||||||
{
|
{
|
||||||
charBuffer = new char[size + 1];
|
charBuffer = FB_NEW char[size + 1];
|
||||||
}
|
}
|
||||||
getStrValue(charBuffer);
|
getStrValue(charBuffer);
|
||||||
return charBuffer;
|
return charBuffer;
|
||||||
|
@ -40,12 +40,22 @@
|
|||||||
#include "firebird.h"
|
#include "firebird.h"
|
||||||
#include "../common/classes/alloc.h"
|
#include "../common/classes/alloc.h"
|
||||||
|
|
||||||
#ifndef WIN_NT
|
#ifdef WIN_NT
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#ifndef PATH_MAX
|
||||||
|
#define PATH_MAX MAX_PATH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "../common/classes/fb_tls.h"
|
#include "../common/classes/fb_tls.h"
|
||||||
@ -68,25 +78,10 @@
|
|||||||
#define VALGRIND_FIX_IT // overrides suspicious valgrind behavior
|
#define VALGRIND_FIX_IT // overrides suspicious valgrind behavior
|
||||||
#endif // USE_VALGRIND
|
#endif // USE_VALGRIND
|
||||||
|
|
||||||
void* operator new(size_t s ALLOC_PARAMS)
|
|
||||||
{
|
|
||||||
return MemoryPool::globalAlloc(s ALLOC_PASS_ARGS);
|
|
||||||
}
|
|
||||||
void* operator new[](size_t s ALLOC_PARAMS)
|
|
||||||
{
|
|
||||||
return MemoryPool::globalAlloc(s ALLOC_PASS_ARGS);
|
|
||||||
}
|
|
||||||
void operator delete(void* mem ALLOC_PARAMS) noexcept
|
|
||||||
{
|
|
||||||
MemoryPool::globalFree(mem);
|
|
||||||
}
|
|
||||||
void operator delete[](void* mem ALLOC_PARAMS) noexcept
|
|
||||||
{
|
|
||||||
MemoryPool::globalFree(mem);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
///#define MEM_DEBUG_EXTERNAL
|
||||||
|
|
||||||
/*** emergency debugging stuff
|
/*** emergency debugging stuff
|
||||||
static const char* lastFileName;
|
static const char* lastFileName;
|
||||||
static int lastLine;
|
static int lastLine;
|
||||||
@ -147,7 +142,14 @@ typedef Firebird::AtomicCounter::counter_type StatInt;
|
|||||||
const int MAP_CACHE_SIZE = 16; // == 1 MB
|
const int MAP_CACHE_SIZE = 16; // == 1 MB
|
||||||
const size_t DEFAULT_ALLOCATION = 65536;
|
const size_t DEFAULT_ALLOCATION = 65536;
|
||||||
|
|
||||||
Firebird::Vector<void*, MAP_CACHE_SIZE> extents_cache;
|
struct ExtentsCache // C++ aggregate - members are statically initialized to zeros
|
||||||
|
{
|
||||||
|
unsigned count;
|
||||||
|
void* data[MAP_CACHE_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
ExtentsCache defaultExtentsCache;
|
||||||
|
ExtentsCache externalExtentsCache;
|
||||||
|
|
||||||
#ifndef WIN_NT
|
#ifndef WIN_NT
|
||||||
struct FailedBlock
|
struct FailedBlock
|
||||||
@ -191,7 +193,7 @@ inline size_t get_map_page_size()
|
|||||||
static volatile size_t map_page_size = 0;
|
static volatile size_t map_page_size = 0;
|
||||||
if (!map_page_size)
|
if (!map_page_size)
|
||||||
{
|
{
|
||||||
Firebird::MutexLockGuard guard(*cache_mutex, "get_map_page_size");
|
Firebird::MutexLockGuard guard(cache_mutex, "get_map_page_size");
|
||||||
if (!map_page_size)
|
if (!map_page_size)
|
||||||
map_page_size = get_page_size();
|
map_page_size = get_page_size();
|
||||||
}
|
}
|
||||||
@ -1731,10 +1733,22 @@ private:
|
|||||||
public:
|
public:
|
||||||
static MemPool* defaultMemPool;
|
static MemPool* defaultMemPool;
|
||||||
|
|
||||||
MemPool();
|
MemPool(MemoryStats& stats, ExtentsCache* extentsCache);
|
||||||
MemPool(MemPool& parent, MemoryStats& stats);
|
MemPool(MemPool& parent, MemoryStats& stats, ExtentsCache* extentsCache);
|
||||||
virtual ~MemPool(void);
|
virtual ~MemPool(void);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static inline constexpr MemPool* getPoolFromPointer(void* ptr) noexcept
|
||||||
|
{
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
auto block = (MemBlock*) ((UCHAR*) ptr - offsetof(MemBlock, body));
|
||||||
|
return block->pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const size_t minAllocation = 65536;
|
static const size_t minAllocation = 65536;
|
||||||
static const size_t roundingSize = ALLOC_ALIGNMENT;
|
static const size_t roundingSize = ALLOC_ALIGNMENT;
|
||||||
@ -1749,12 +1763,10 @@ private:
|
|||||||
int blocksActive;
|
int blocksActive;
|
||||||
bool pool_destroying, parent_redirect;
|
bool pool_destroying, parent_redirect;
|
||||||
|
|
||||||
// Statistics group for the pool
|
MemoryStats* stats; // Statistics group for the pool
|
||||||
MemoryStats* stats;
|
MemPool* parent; // Parent pool if present
|
||||||
// Parent pool if present
|
ExtentsCache* extentsCache;
|
||||||
MemPool* parent;
|
AtomicCounter used_memory, mapped_memory; // Memory used
|
||||||
// Memory used
|
|
||||||
AtomicCounter used_memory, mapped_memory;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -1810,7 +1822,7 @@ private:
|
|||||||
virtual void memoryIsExhausted(void);
|
virtual void memoryIsExhausted(void);
|
||||||
void* allocRaw(size_t length);
|
void* allocRaw(size_t length);
|
||||||
static void releaseMemory(void* block, bool flagExtent) noexcept;
|
static void releaseMemory(void* block, bool flagExtent) noexcept;
|
||||||
static void releaseRaw(bool destroying, void *block, size_t size, bool use_cache = true) noexcept;
|
static void releaseRaw(bool destroying, void *block, size_t size, ExtentsCache* extentsCache) noexcept;
|
||||||
void* getExtent(size_t from, size_t& to);
|
void* getExtent(size_t from, size_t& to);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -1843,23 +1855,36 @@ public:
|
|||||||
void setStatsGroup(MemoryStats& stats) noexcept;
|
void setStatsGroup(MemoryStats& stats) noexcept;
|
||||||
|
|
||||||
// Initialize and finalize global memory pool
|
// Initialize and finalize global memory pool
|
||||||
static MemPool* init()
|
static MemPool* initDefaultPool()
|
||||||
{
|
{
|
||||||
fb_assert(!defaultMemPool);
|
fb_assert(!defaultMemPool);
|
||||||
|
|
||||||
static char mpBuffer[sizeof(MemPool) + ALLOC_ALIGNMENT];
|
alignas(alignof(MemPool)) static char mpBuffer[sizeof(MemPool)];
|
||||||
defaultMemPool = new((void*)(IPTR) MEM_ALIGN((size_t)(IPTR) mpBuffer)) MemPool();
|
defaultMemPool = new(mpBuffer) MemPool(*MemoryPool::default_stats_group, &defaultExtentsCache);
|
||||||
return defaultMemPool;
|
return defaultMemPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cleanup()
|
static void cleanupDefaultPool()
|
||||||
{
|
{
|
||||||
defaultMemPool->~MemPool();
|
defaultMemPool->~MemPool();
|
||||||
defaultMemPool = NULL;
|
defaultMemPool = NULL;
|
||||||
|
|
||||||
while (extents_cache.getCount())
|
while (defaultExtentsCache.count)
|
||||||
releaseRaw(true, extents_cache.pop(), DEFAULT_ALLOCATION, false);
|
releaseRaw(true, defaultExtentsCache.data[--defaultExtentsCache.count], DEFAULT_ALLOCATION, nullptr);
|
||||||
|
|
||||||
|
cleanupFailedList();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cleanupExternalPool()
|
||||||
|
{
|
||||||
|
while (externalExtentsCache.count)
|
||||||
|
releaseRaw(true, externalExtentsCache.data[--externalExtentsCache.count], DEFAULT_ALLOCATION, nullptr);
|
||||||
|
|
||||||
|
cleanupFailedList();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cleanupFailedList()
|
||||||
|
{
|
||||||
#ifndef WIN_NT
|
#ifndef WIN_NT
|
||||||
unsigned oldCount = 0;
|
unsigned oldCount = 0;
|
||||||
|
|
||||||
@ -1880,7 +1905,7 @@ public:
|
|||||||
++newCount;
|
++newCount;
|
||||||
FailedBlock* fb = oldList;
|
FailedBlock* fb = oldList;
|
||||||
SemiDoubleLink::pop(oldList);
|
SemiDoubleLink::pop(oldList);
|
||||||
releaseRaw(true, fb, fb->blockSize, false);
|
releaseRaw(true, fb, fb->blockSize, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newCount == oldCount)
|
if (newCount == oldCount)
|
||||||
@ -1889,7 +1914,6 @@ public:
|
|||||||
oldCount = newCount;
|
oldCount = newCount;
|
||||||
}
|
}
|
||||||
#endif // WIN_NT
|
#endif // WIN_NT
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Statistics
|
// Statistics
|
||||||
@ -2012,28 +2036,28 @@ GlobalPtr<Mutex> forceCreationOfDefaultMemoryPool;
|
|||||||
|
|
||||||
MemoryPool* MemoryPool::defaultMemoryManager = NULL;
|
MemoryPool* MemoryPool::defaultMemoryManager = NULL;
|
||||||
MemoryStats* MemoryPool::default_stats_group = NULL;
|
MemoryStats* MemoryPool::default_stats_group = NULL;
|
||||||
|
MemoryPool* MemoryPool::externalMemoryManager = NULL;
|
||||||
MemPool* MemPool::defaultMemPool = NULL;
|
MemPool* MemPool::defaultMemPool = NULL;
|
||||||
|
|
||||||
|
|
||||||
// Initialize process memory pool (called from InstanceControl).
|
// Initialize process memory pool (called from InstanceControl).
|
||||||
|
|
||||||
void MemoryPool::init()
|
void MemoryPool::initDefaultPool()
|
||||||
{
|
{
|
||||||
static char mtxBuffer[sizeof(Mutex) + ALLOC_ALIGNMENT];
|
alignas(alignof(Mutex)) static char mtxBuffer[sizeof(Mutex)];
|
||||||
cache_mutex = new((void*)(IPTR) MEM_ALIGN((size_t)(IPTR) mtxBuffer)) Mutex;
|
cache_mutex = new(mtxBuffer) Mutex;
|
||||||
|
|
||||||
static char msBuffer[sizeof(MemoryStats) + ALLOC_ALIGNMENT];
|
alignas(alignof(MemoryStats)) static char msBuffer[sizeof(MemoryStats)];
|
||||||
default_stats_group =
|
default_stats_group = new(msBuffer) MemoryStats;
|
||||||
new((void*)(IPTR) MEM_ALIGN((size_t)(IPTR) msBuffer)) MemoryStats;
|
|
||||||
|
|
||||||
static char mpBuffer[sizeof(MemoryPool) + ALLOC_ALIGNMENT];
|
alignas(alignof(MemoryPool)) static char mpBuffer[sizeof(MemoryPool)];
|
||||||
defaultMemoryManager = new((void*)(IPTR) MEM_ALIGN((size_t)(IPTR) mpBuffer)) MemoryPool(MemPool::init());
|
defaultMemoryManager = new(mpBuffer) MemoryPool(MemPool::initDefaultPool());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should be last routine, called by InstanceControl,
|
// Should be last routine, called by InstanceControl,
|
||||||
// being therefore the very last routine in firebird module.
|
// being therefore the very last routine in firebird module.
|
||||||
|
|
||||||
void MemoryPool::cleanup()
|
void MemoryPool::cleanupDefaultPool()
|
||||||
{
|
{
|
||||||
#ifdef VALGRIND_FIX_IT
|
#ifdef VALGRIND_FIX_IT
|
||||||
VALGRIND_DISCARD(
|
VALGRIND_DISCARD(
|
||||||
@ -2047,7 +2071,7 @@ void MemoryPool::cleanup()
|
|||||||
if (defaultMemoryManager)
|
if (defaultMemoryManager)
|
||||||
{
|
{
|
||||||
//defaultMemoryManager->~MemoryPool();
|
//defaultMemoryManager->~MemoryPool();
|
||||||
MemPool::cleanup();
|
MemPool::cleanupDefaultPool();
|
||||||
defaultMemoryManager = NULL;
|
defaultMemoryManager = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2065,15 +2089,23 @@ void MemoryPool::cleanup()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MemPool::MemPool()
|
MemPool::MemPool(MemoryStats& s, ExtentsCache* cache)
|
||||||
: pool_destroying(false), parent_redirect(false), stats(MemoryPool::default_stats_group), parent(NULL)
|
: pool_destroying(false),
|
||||||
|
parent_redirect(false),
|
||||||
|
stats(&s),
|
||||||
|
parent(NULL),
|
||||||
|
extentsCache(cache)
|
||||||
{
|
{
|
||||||
fb_assert(offsetof(MemBlock, body) == MEM_ALIGN(offsetof(MemBlock, body)));
|
fb_assert(offsetof(MemBlock, body) == MEM_ALIGN(offsetof(MemBlock, body)));
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
MemPool::MemPool(MemPool& p, MemoryStats& s)
|
MemPool::MemPool(MemPool& p, MemoryStats& s, ExtentsCache* cache)
|
||||||
: pool_destroying(false), parent_redirect(true), stats(&s), parent(&p)
|
: pool_destroying(false),
|
||||||
|
parent_redirect(true),
|
||||||
|
stats(&s),
|
||||||
|
parent(&p),
|
||||||
|
extentsCache(cache)
|
||||||
{
|
{
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
@ -2133,7 +2165,7 @@ MemPool::~MemPool(void)
|
|||||||
{
|
{
|
||||||
MemBigHunk* hunk = bigHunks;
|
MemBigHunk* hunk = bigHunks;
|
||||||
bigHunks = hunk->next;
|
bigHunks = hunk->next;
|
||||||
releaseRaw(pool_destroying, hunk, hunk->length);
|
releaseRaw(pool_destroying, hunk, hunk->length, extentsCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent)
|
if (parent)
|
||||||
@ -2210,7 +2242,7 @@ MemoryPool* MemoryPool::createPool(MemoryPool* parentPool, MemoryStats& stats)
|
|||||||
if (!parentPool)
|
if (!parentPool)
|
||||||
parentPool = getDefaultMemoryPool();
|
parentPool = getDefaultMemoryPool();
|
||||||
|
|
||||||
MemPool* p = FB_NEW_POOL(*parentPool) MemPool(*(parentPool->pool), stats);
|
MemPool* p = FB_NEW_POOL(*parentPool) MemPool(*(parentPool->pool), stats, &defaultExtentsCache);
|
||||||
return FB_NEW_POOL(*parentPool) MemoryPool(p);
|
return FB_NEW_POOL(*parentPool) MemoryPool(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2461,7 +2493,7 @@ void MemPool::releaseBlock(MemBlock* block, bool decrUsage) noexcept
|
|||||||
MemBigHunk* hunk = (MemBigHunk*)(((UCHAR*)block) - MemBigHunk::hdrSize());
|
MemBigHunk* hunk = (MemBigHunk*)(((UCHAR*)block) - MemBigHunk::hdrSize());
|
||||||
SemiDoubleLink::remove(hunk);
|
SemiDoubleLink::remove(hunk);
|
||||||
decrement_mapping(FB_ALIGN(hunk->length, get_map_page_size()));
|
decrement_mapping(FB_ALIGN(hunk->length, get_map_page_size()));
|
||||||
releaseRaw(pool_destroying, hunk, hunk->length, false);
|
releaseRaw(pool_destroying, hunk, hunk->length, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemPool::memoryIsExhausted(void)
|
void MemPool::memoryIsExhausted(void)
|
||||||
@ -2474,12 +2506,12 @@ void* MemPool::allocRaw(size_t size)
|
|||||||
#ifndef USE_VALGRIND
|
#ifndef USE_VALGRIND
|
||||||
if (size == DEFAULT_ALLOCATION)
|
if (size == DEFAULT_ALLOCATION)
|
||||||
{
|
{
|
||||||
MutexLockGuard guard(*cache_mutex, "MemPool::allocRaw");
|
MutexLockGuard guard(cache_mutex, "MemPool::allocRaw");
|
||||||
if (extents_cache.hasData())
|
if (extentsCache->count)
|
||||||
{
|
{
|
||||||
// Use most recently used object to encourage caching
|
// Use most recently used object to encourage caching
|
||||||
increment_mapping(size);
|
increment_mapping(size);
|
||||||
return extents_cache.pop();
|
return extentsCache->data[--extentsCache->count];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -2497,7 +2529,7 @@ void* MemPool::allocRaw(size_t size)
|
|||||||
void* result = NULL;
|
void* result = NULL;
|
||||||
if (failedList)
|
if (failedList)
|
||||||
{
|
{
|
||||||
MutexLockGuard guard(*cache_mutex, "MemPool::allocRaw");
|
MutexLockGuard guard(cache_mutex, "MemPool::allocRaw");
|
||||||
for (FailedBlock* fb = failedList; fb; fb = fb->next)
|
for (FailedBlock* fb = failedList; fb; fb = fb->next)
|
||||||
{
|
{
|
||||||
if (fb->blockSize == size)
|
if (fb->blockSize == size)
|
||||||
@ -2568,20 +2600,20 @@ void MemPool::releaseExtent(bool destroying, void* block, size_t size, MemPool*
|
|||||||
{
|
{
|
||||||
if (pool)
|
if (pool)
|
||||||
pool->decrement_mapping(size);
|
pool->decrement_mapping(size);
|
||||||
releaseRaw(true, block, size, pool);
|
releaseRaw(true, block, size, (pool ? pool->extentsCache : nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MemPool::releaseRaw(bool destroying, void* block, size_t size, bool use_cache) noexcept
|
void MemPool::releaseRaw(bool destroying, void* block, size_t size, ExtentsCache* extentsCache) noexcept
|
||||||
{
|
{
|
||||||
#ifndef USE_VALGRIND
|
#ifndef USE_VALGRIND
|
||||||
if (use_cache && (size == DEFAULT_ALLOCATION))
|
if (extentsCache && (size == DEFAULT_ALLOCATION))
|
||||||
{
|
{
|
||||||
MutexLockGuard guard(*cache_mutex, "MemPool::releaseRaw");
|
MutexLockGuard guard(cache_mutex, "MemPool::releaseRaw");
|
||||||
if (extents_cache.getCount() < extents_cache.getCapacity())
|
if (extentsCache->count < MAP_CACHE_SIZE)
|
||||||
{
|
{
|
||||||
extents_cache.push(block);
|
extentsCache->data[extentsCache->count++] = block;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2599,7 +2631,7 @@ void MemPool::releaseRaw(bool destroying, void* block, size_t size, bool use_cac
|
|||||||
if (destroying)
|
if (destroying)
|
||||||
{
|
{
|
||||||
// Synchronize delayed free queue using extents mutex
|
// Synchronize delayed free queue using extents mutex
|
||||||
MutexLockGuard guard(*cache_mutex, "MemPool::releaseRaw");
|
MutexLockGuard guard(cache_mutex, "MemPool::releaseRaw");
|
||||||
|
|
||||||
// Extend circular buffer if possible
|
// Extend circular buffer if possible
|
||||||
if (delayedExtentCount < FB_NELEM(delayedExtents))
|
if (delayedExtentCount < FB_NELEM(delayedExtents))
|
||||||
@ -2656,7 +2688,7 @@ void MemPool::releaseRaw(bool destroying, void* block, size_t size, bool use_cac
|
|||||||
FailedBlock* failed = (FailedBlock*) block;
|
FailedBlock* failed = (FailedBlock*) block;
|
||||||
failed->blockSize = size;
|
failed->blockSize = size;
|
||||||
|
|
||||||
MutexLockGuard guard(*cache_mutex, "MemPool::releaseRaw");
|
MutexLockGuard guard(cache_mutex, "MemPool::releaseRaw");
|
||||||
SemiDoubleLink::push(&failedList, failed);
|
SemiDoubleLink::push(&failedList, failed);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -2817,25 +2849,6 @@ MemoryPool& AutoStorage::getAutoMemoryPool()
|
|||||||
return *p;
|
return *p;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LIBC_CALLS_NEW
|
|
||||||
void* MemoryPool::globalAlloc(size_t s ALLOC_PARAMS)
|
|
||||||
{
|
|
||||||
if (!defaultMemoryManager)
|
|
||||||
{
|
|
||||||
// this will do all required init, including processMemoryPool creation
|
|
||||||
static Firebird::InstanceControl dummy;
|
|
||||||
fb_assert(defaultMemoryManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultMemoryManager->allocate(s ALLOC_PASS_ARGS);
|
|
||||||
}
|
|
||||||
#endif // LIBC_CALLS_NEW
|
|
||||||
|
|
||||||
void MemoryPool::globalFree(void* block) noexcept
|
|
||||||
{
|
|
||||||
MemPool::globalFree(block);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* MemoryPool::allocate(size_t size ALLOC_PARAMS)
|
void* MemoryPool::allocate(size_t size ALLOC_PARAMS)
|
||||||
{
|
{
|
||||||
return pool->allocate(size ALLOC_PASS_ARGS);
|
return pool->allocate(size ALLOC_PASS_ARGS);
|
||||||
@ -2924,6 +2937,159 @@ void MemoryPool::unregisterFinalizer(Finalizer*& finalizer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ExternalMemoryHandler
|
||||||
|
{
|
||||||
|
friend class MemoryPool;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Objects
|
||||||
|
{
|
||||||
|
MemoryStats memoryStats;
|
||||||
|
MemPool memPool{memoryStats, &externalExtentsCache};
|
||||||
|
MemoryPool memoryPool{&memPool};
|
||||||
|
};
|
||||||
|
|
||||||
|
static ExternalMemoryHandler* instance;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum class State : UCHAR
|
||||||
|
{
|
||||||
|
ALIVE,
|
||||||
|
DEAD,
|
||||||
|
DYING
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
ExternalMemoryHandler()
|
||||||
|
{
|
||||||
|
Mutex::initMutexes();
|
||||||
|
|
||||||
|
#ifdef MEM_DEBUG_EXTERNAL
|
||||||
|
printf("ExternalMemoryHandler::ExternalMemoryHandler()\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
instance = this;
|
||||||
|
|
||||||
|
new(objectsBuffer) Objects();
|
||||||
|
|
||||||
|
MemoryPool::externalMemoryManager = &objects().memoryPool;
|
||||||
|
|
||||||
|
atexit([] {
|
||||||
|
const auto currentUsage = instance->objects().memoryStats.getCurrentUsage();
|
||||||
|
|
||||||
|
#ifdef MEM_DEBUG_EXTERNAL
|
||||||
|
printf("ExternalMemoryHandler atexit: %" SIZEFORMAT "\n", currentUsage);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ExternalMemoryHandler::printContents("atexit");
|
||||||
|
|
||||||
|
if (currentUsage == 0)
|
||||||
|
ExternalMemoryHandler::free();
|
||||||
|
else
|
||||||
|
instance->state = State::DYING;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void revive()
|
||||||
|
{
|
||||||
|
#ifdef MEM_DEBUG_EXTERNAL
|
||||||
|
printf("ExternalMemoryHandler::revive()\n");
|
||||||
|
#endif
|
||||||
|
new(this) ExternalMemoryHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printContents(const char* moment)
|
||||||
|
{
|
||||||
|
#if defined(MEM_DEBUG) && defined(DEBUG_GDS_ALLOC)
|
||||||
|
if (!MemoryPool::externalMemoryManager)
|
||||||
|
return;
|
||||||
|
|
||||||
|
static bool alreadyPrinted = false;
|
||||||
|
Firebird::AutoPtr<FILE> file;
|
||||||
|
|
||||||
|
{ // scope
|
||||||
|
char name[PATH_MAX];
|
||||||
|
|
||||||
|
if (os_utils::getCurrentModulePath(name, sizeof(name)))
|
||||||
|
strncat(name, ".memdebug.external.log", sizeof(name) - 1);
|
||||||
|
else
|
||||||
|
strcpy(name, "memdebug.external.log");
|
||||||
|
|
||||||
|
file = os_utils::fopen(name, alreadyPrinted ? "at" : "w+t");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file)
|
||||||
|
{
|
||||||
|
fprintf(file, "********* Moment: %s\n", moment);
|
||||||
|
|
||||||
|
MemoryPool::externalMemoryManager->print_contents(file,
|
||||||
|
Firebird::MemoryPool::PRINT_USED_ONLY | Firebird::MemoryPool::PRINT_RECURSIVE);
|
||||||
|
file = NULL;
|
||||||
|
alreadyPrinted = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free()
|
||||||
|
{
|
||||||
|
if (instance->state != State::DEAD)
|
||||||
|
{
|
||||||
|
instance->state = State::DEAD;
|
||||||
|
instance->objects().~Objects();
|
||||||
|
instance->~ExternalMemoryHandler();
|
||||||
|
instance = nullptr;
|
||||||
|
|
||||||
|
MemPool::cleanupExternalPool();
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryPool::externalMemoryManager = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Objects& objects()
|
||||||
|
{
|
||||||
|
return *(Objects*) objectsBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
alignas(alignof(Objects)) char objectsBuffer[sizeof(Objects)];
|
||||||
|
State state = State::ALIVE;
|
||||||
|
};
|
||||||
|
|
||||||
|
ExternalMemoryHandler* ExternalMemoryHandler::instance = nullptr;
|
||||||
|
|
||||||
|
void initExternalMemoryPool()
|
||||||
|
{
|
||||||
|
static ExternalMemoryHandler handler;
|
||||||
|
|
||||||
|
if (handler.state == ExternalMemoryHandler::State::DEAD)
|
||||||
|
handler.revive();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MemoryPool::globalFree(void* block) noexcept
|
||||||
|
{
|
||||||
|
auto pool = MemPool::getPoolFromPointer(block);
|
||||||
|
|
||||||
|
MemPool::globalFree(block);
|
||||||
|
|
||||||
|
if (auto externalMemoryHandler = ExternalMemoryHandler::instance;
|
||||||
|
externalMemoryHandler &&
|
||||||
|
externalMemoryHandler->state == ExternalMemoryHandler::State::DYING &&
|
||||||
|
pool == &externalMemoryHandler->objects().memPool)
|
||||||
|
{
|
||||||
|
const auto currentUsage = externalMemoryHandler->objects().memoryStats.getCurrentUsage();
|
||||||
|
|
||||||
|
#ifdef MEM_DEBUG_EXTERNAL
|
||||||
|
printf("MemoryPool::globalFree() - dying ExternalMemoryHandler: %" SIZEFORMAT "\n", currentUsage);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ExternalMemoryHandler::printContents("globalFree");
|
||||||
|
|
||||||
|
if (currentUsage == 0)
|
||||||
|
ExternalMemoryHandler::free();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(DEV_BUILD)
|
#if defined(DEV_BUILD)
|
||||||
void AutoStorage::ProbeStack() const
|
void AutoStorage::ProbeStack() const
|
||||||
{
|
{
|
||||||
@ -2949,14 +3115,15 @@ void AutoStorage::ProbeStack() const
|
|||||||
// Global operator "delete" is always redefined by firebird,
|
// Global operator "delete" is always redefined by firebird,
|
||||||
// in a case when we actually need "new" only with file/line information
|
// in a case when we actually need "new" only with file/line information
|
||||||
// this version should be also present as a pair for "delete".
|
// this version should be also present as a pair for "delete".
|
||||||
#ifdef DEBUG_GDS_ALLOC
|
|
||||||
void* operator new(size_t s)
|
void* operator new(size_t s)
|
||||||
{
|
{
|
||||||
return MemoryPool::globalAlloc(s ALLOC_ARGS);
|
return getExternalMemoryPool()->allocate(s ALLOC_ARGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* operator new[](size_t s)
|
void* operator new[](size_t s)
|
||||||
{
|
{
|
||||||
return MemoryPool::globalAlloc(s ALLOC_ARGS);
|
return getExternalMemoryPool()->allocate(s ALLOC_ARGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator delete(void* mem) noexcept
|
void operator delete(void* mem) noexcept
|
||||||
@ -2968,5 +3135,3 @@ void operator delete[](void* mem) noexcept
|
|||||||
{
|
{
|
||||||
MemoryPool::globalFree(mem);
|
MemoryPool::globalFree(mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // DEBUG_GDS_ALLOC
|
|
||||||
|
@ -59,11 +59,11 @@
|
|||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
|
|
||||||
#ifdef DEBUG_GDS_ALLOC
|
#ifdef DEBUG_GDS_ALLOC
|
||||||
#define FB_NEW new(__FILE__, __LINE__)
|
#define FB_NEW new(*getDefaultMemoryPool(), __FILE__, __LINE__)
|
||||||
#define FB_NEW_POOL(pool) new(pool, __FILE__, __LINE__)
|
#define FB_NEW_POOL(pool) new(pool, __FILE__, __LINE__)
|
||||||
#define FB_NEW_RPT(pool, count) new(pool, count, __FILE__, __LINE__)
|
#define FB_NEW_RPT(pool, count) new(pool, count, __FILE__, __LINE__)
|
||||||
#else // DEBUG_GDS_ALLOC
|
#else // DEBUG_GDS_ALLOC
|
||||||
#define FB_NEW new
|
#define FB_NEW new(*getDefaultMemoryPool())
|
||||||
#define FB_NEW_POOL(pool) new(pool)
|
#define FB_NEW_POOL(pool) new(pool)
|
||||||
#define FB_NEW_RPT(pool, count) new(pool, count)
|
#define FB_NEW_RPT(pool, count) new(pool, count)
|
||||||
#endif // DEBUG_GDS_ALLOC
|
#endif // DEBUG_GDS_ALLOC
|
||||||
@ -159,6 +159,8 @@ private:
|
|||||||
|
|
||||||
class MemoryPool
|
class MemoryPool
|
||||||
{
|
{
|
||||||
|
friend class ExternalMemoryHandler;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MemPool* pool;
|
MemPool* pool;
|
||||||
|
|
||||||
@ -174,6 +176,7 @@ public:
|
|||||||
enum RecommendedBufferSize { MAX_MEDIUM_BLOCK_SIZE = 64384 }; // MediumLimits::TOP_LIMIT - 128
|
enum RecommendedBufferSize { MAX_MEDIUM_BLOCK_SIZE = 64384 }; // MediumLimits::TOP_LIMIT - 128
|
||||||
|
|
||||||
static MemoryPool* defaultMemoryManager;
|
static MemoryPool* defaultMemoryManager;
|
||||||
|
static MemoryPool* externalMemoryManager;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Create memory pool instance
|
// Create memory pool instance
|
||||||
@ -193,14 +196,10 @@ public:
|
|||||||
|
|
||||||
void* calloc(size_t size ALLOC_PARAMS);
|
void* calloc(size_t size ALLOC_PARAMS);
|
||||||
|
|
||||||
#ifdef LIBC_CALLS_NEW
|
|
||||||
static void* globalAlloc(size_t s ALLOC_PARAMS);
|
|
||||||
#else
|
|
||||||
static void* globalAlloc(size_t s ALLOC_PARAMS)
|
static void* globalAlloc(size_t s ALLOC_PARAMS)
|
||||||
{
|
{
|
||||||
return defaultMemoryManager->allocate(s ALLOC_PASS_ARGS);
|
return defaultMemoryManager->allocate(s ALLOC_PASS_ARGS);
|
||||||
}
|
}
|
||||||
#endif // LIBC_CALLS_NEW
|
|
||||||
|
|
||||||
void* allocate(size_t size ALLOC_PARAMS);
|
void* allocate(size_t size ALLOC_PARAMS);
|
||||||
|
|
||||||
@ -218,8 +217,8 @@ public:
|
|||||||
void setStatsGroup(MemoryStats& stats) noexcept;
|
void setStatsGroup(MemoryStats& stats) noexcept;
|
||||||
|
|
||||||
// Initialize and finalize global memory pool
|
// Initialize and finalize global memory pool
|
||||||
static void init();
|
static void initDefaultPool();
|
||||||
static void cleanup();
|
static void cleanupDefaultPool();
|
||||||
|
|
||||||
// Initialize context pool
|
// Initialize context pool
|
||||||
static void contextPoolInit();
|
static void contextPoolInit();
|
||||||
@ -282,6 +281,8 @@ private:
|
|||||||
friend class MemPool;
|
friend class MemPool;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void initExternalMemoryPool();
|
||||||
|
|
||||||
} // namespace Firebird
|
} // namespace Firebird
|
||||||
|
|
||||||
static inline Firebird::MemoryPool* getDefaultMemoryPool() noexcept
|
static inline Firebird::MemoryPool* getDefaultMemoryPool() noexcept
|
||||||
@ -290,6 +291,16 @@ static inline Firebird::MemoryPool* getDefaultMemoryPool() noexcept
|
|||||||
return Firebird::MemoryPool::defaultMemoryManager;
|
return Firebird::MemoryPool::defaultMemoryManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline Firebird::MemoryPool* getExternalMemoryPool() noexcept
|
||||||
|
{
|
||||||
|
using namespace Firebird;
|
||||||
|
|
||||||
|
if (!MemoryPool::externalMemoryManager)
|
||||||
|
initExternalMemoryPool();
|
||||||
|
|
||||||
|
return MemoryPool::externalMemoryManager;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Firebird {
|
namespace Firebird {
|
||||||
|
|
||||||
// Class intended to manage execution context pool stack
|
// Class intended to manage execution context pool stack
|
||||||
@ -341,16 +352,12 @@ private:
|
|||||||
using Firebird::MemoryPool;
|
using Firebird::MemoryPool;
|
||||||
|
|
||||||
// operators new and delete
|
// operators new and delete
|
||||||
extern void* operator new(size_t s ALLOC_PARAMS);
|
|
||||||
extern void* operator new[](size_t s ALLOC_PARAMS);
|
|
||||||
extern void operator delete(void* mem ALLOC_PARAMS) noexcept;
|
|
||||||
extern void operator delete[](void* mem ALLOC_PARAMS) noexcept;
|
|
||||||
|
|
||||||
|
|
||||||
inline void* operator new(size_t s, Firebird::MemoryPool& pool ALLOC_PARAMS)
|
inline void* operator new(size_t s, Firebird::MemoryPool& pool ALLOC_PARAMS)
|
||||||
{
|
{
|
||||||
return pool.allocate(s ALLOC_PASS_ARGS);
|
return pool.allocate(s ALLOC_PASS_ARGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void* operator new[](size_t s, Firebird::MemoryPool& pool ALLOC_PARAMS)
|
inline void* operator new[](size_t s, Firebird::MemoryPool& pool ALLOC_PARAMS)
|
||||||
{
|
{
|
||||||
return pool.allocate(s ALLOC_PASS_ARGS);
|
return pool.allocate(s ALLOC_PASS_ARGS);
|
||||||
@ -360,6 +367,7 @@ inline void operator delete(void* mem, Firebird::MemoryPool& pool ALLOC_PARAMS)
|
|||||||
{
|
{
|
||||||
MemoryPool::globalFree(mem);
|
MemoryPool::globalFree(mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void operator delete[](void* mem, Firebird::MemoryPool& pool ALLOC_PARAMS) noexcept
|
inline void operator delete[](void* mem, Firebird::MemoryPool& pool ALLOC_PARAMS) noexcept
|
||||||
{
|
{
|
||||||
MemoryPool::globalFree(mem);
|
MemoryPool::globalFree(mem);
|
||||||
@ -370,6 +378,7 @@ inline void operator delete(void* mem, std::size_t s ALLOC_PARAMS) noexcept
|
|||||||
{
|
{
|
||||||
MemoryPool::globalFree(mem);
|
MemoryPool::globalFree(mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void operator delete[](void* mem, std::size_t s ALLOC_PARAMS) noexcept
|
inline void operator delete[](void* mem, std::size_t s ALLOC_PARAMS) noexcept
|
||||||
{
|
{
|
||||||
MemoryPool::globalFree(mem);
|
MemoryPool::globalFree(mem);
|
||||||
@ -390,16 +399,6 @@ namespace Firebird
|
|||||||
class GlobalStorage
|
class GlobalStorage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void* operator new(size_t size ALLOC_PARAMS)
|
|
||||||
{
|
|
||||||
return getDefaultMemoryPool()->allocate(size ALLOC_PASS_ARGS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator delete(void* mem)
|
|
||||||
{
|
|
||||||
getDefaultMemoryPool()->deallocate(mem);
|
|
||||||
}
|
|
||||||
|
|
||||||
MemoryPool& getPool() const
|
MemoryPool& getPool() const
|
||||||
{
|
{
|
||||||
return *getDefaultMemoryPool();
|
return *getDefaultMemoryPool();
|
||||||
|
@ -31,12 +31,13 @@
|
|||||||
#include "../common/dllinst.h"
|
#include "../common/dllinst.h"
|
||||||
#include "../common/os/os_utils.h"
|
#include "../common/os/os_utils.h"
|
||||||
|
|
||||||
#ifdef HAVE_DLADDR
|
#ifdef WIN_NT
|
||||||
#ifndef _GNU_SOURCE
|
#include <windows.h>
|
||||||
#define _GNU_SOURCE
|
|
||||||
|
#ifndef PATH_MAX
|
||||||
|
#define PATH_MAX MAX_PATH
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#include <dlfcn.h>
|
|
||||||
#endif // HAVE_DLADDR
|
|
||||||
|
|
||||||
// Setting this define helps (with AV at exit time) detect globals
|
// Setting this define helps (with AV at exit time) detect globals
|
||||||
// with destructors, declared not using InstanceControl.
|
// with destructors, declared not using InstanceControl.
|
||||||
@ -96,36 +97,14 @@ namespace
|
|||||||
Firebird::AutoPtr<FILE> file;
|
Firebird::AutoPtr<FILE> file;
|
||||||
|
|
||||||
{ // scope
|
{ // scope
|
||||||
Firebird::PathName name = "memdebug.log";
|
char name[PATH_MAX];
|
||||||
#ifdef HAVE_DLADDR
|
|
||||||
Dl_info path;
|
|
||||||
if (dladdr((void*) &allClean, &path))
|
|
||||||
{
|
|
||||||
name = path.dli_fname;
|
|
||||||
name += ".memdebug.log";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf(stderr, "dladdr: %s\n", dlerror());
|
|
||||||
}
|
|
||||||
#elif defined(WIN_NT)
|
|
||||||
HMODULE hmod = 0;
|
|
||||||
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
|
||||||
(LPCTSTR) &allClean,
|
|
||||||
&hmod);
|
|
||||||
|
|
||||||
if (hmod)
|
if (os_utils::getCurrentModulePath(name, sizeof(name)))
|
||||||
{
|
strncat(name, ".memdebug.log", sizeof(name) - 1);
|
||||||
char moduleName[MAX_PATH];
|
else
|
||||||
DWORD len = GetModuleFileName(hmod, moduleName, MAX_PATH);
|
strcpy(name, "memdebug.log");
|
||||||
if (len < MAX_PATH)
|
|
||||||
{
|
file = os_utils::fopen(name, "w+t");
|
||||||
name = moduleName;
|
|
||||||
name += ".memdebug.log";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // HAVE_DLADDR
|
|
||||||
file = os_utils::fopen(name.c_str(), "w+t");
|
|
||||||
}
|
}
|
||||||
#endif // DEBUG_GDS_ALLOC
|
#endif // DEBUG_GDS_ALLOC
|
||||||
|
|
||||||
@ -154,7 +133,7 @@ namespace
|
|||||||
file = NULL;
|
file = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
Firebird::MemoryPool::cleanup();
|
Firebird::MemoryPool::cleanupDefaultPool();
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
@ -193,7 +172,7 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
Firebird::Mutex::initMutexes();
|
Firebird::Mutex::initMutexes();
|
||||||
Firebird::MemoryPool::init();
|
Firebird::MemoryPool::initDefaultPool();
|
||||||
Firebird::StaticMutex::create();
|
Firebird::StaticMutex::create();
|
||||||
|
|
||||||
#ifdef DEBUG_INIT
|
#ifdef DEBUG_INIT
|
||||||
|
@ -304,12 +304,12 @@ template <typename T>
|
|||||||
class StaticInstanceAllocator
|
class StaticInstanceAllocator
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
char buf[sizeof(T) + FB_ALIGNMENT];
|
alignas(alignof(T)) char buf[sizeof(T)];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
T* create()
|
T* create()
|
||||||
{
|
{
|
||||||
return new((void*) FB_ALIGN(buf, FB_ALIGNMENT)) T();
|
return new(buf) T();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy(T*)
|
static void destroy(T*)
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include "../../common/classes/locks.h"
|
#include "../../common/classes/locks.h"
|
||||||
#include "../../common/ThreadStart.h"
|
#include "../../common/ThreadStart.h"
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
|
||||||
namespace Firebird {
|
namespace Firebird {
|
||||||
@ -50,15 +51,18 @@ pthread_mutexattr_t Mutex::attr;
|
|||||||
|
|
||||||
void Mutex::initMutexes()
|
void Mutex::initMutexes()
|
||||||
{
|
{
|
||||||
// Throw exceptions on errors, but they will not be processed in init
|
static std::once_flag onceFlag;
|
||||||
// (first constructor). Better logging facilities are required here.
|
std::call_once(onceFlag, [] {
|
||||||
int rc = pthread_mutexattr_init(&attr);
|
// Throw exceptions on errors, but they will not be processed in init
|
||||||
if (rc < 0)
|
// (first constructor). Better logging facilities are required here.
|
||||||
system_call_failed::raise("pthread_mutexattr_init", rc);
|
int rc = pthread_mutexattr_init(&attr);
|
||||||
|
if (rc < 0)
|
||||||
|
system_call_failed::raise("pthread_mutexattr_init", rc);
|
||||||
|
|
||||||
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
system_call_failed::raise("pthread_mutexattr_settype", rc);
|
system_call_failed::raise("pthread_mutexattr_settype", rc);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -331,6 +331,13 @@ public:
|
|||||||
lock->enter(aReason);
|
lock->enter(aReason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RaiiLockGuard(M* aLock, const char* aReason)
|
||||||
|
: lock(aLock)
|
||||||
|
{
|
||||||
|
if (lock)
|
||||||
|
lock->enter(aReason);
|
||||||
|
}
|
||||||
|
|
||||||
~RaiiLockGuard()
|
~RaiiLockGuard()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -81,6 +81,8 @@ namespace os_utils
|
|||||||
|
|
||||||
bool isIPv6supported();
|
bool isIPv6supported();
|
||||||
|
|
||||||
|
bool getCurrentModulePath(char* buffer, size_t bufferSize);
|
||||||
|
|
||||||
// force descriptor to have O_CLOEXEC set
|
// force descriptor to have O_CLOEXEC set
|
||||||
int open(const char* pathname, int flags, mode_t mode = DEFAULT_OPEN_MODE);
|
int open(const char* pathname, int flags, mode_t mode = DEFAULT_OPEN_MODE);
|
||||||
void setCloseOnExec(int fd); // posix only
|
void setCloseOnExec(int fd); // posix only
|
||||||
|
@ -43,6 +43,14 @@
|
|||||||
#ifdef HAVE_SYS_STAT_H
|
#ifdef HAVE_SYS_STAT_H
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_DLADDR
|
||||||
|
#ifndef _GNU_SOURCE
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#endif // HAVE_DLADDR
|
||||||
|
|
||||||
#ifdef HAVE_FCNTL_H
|
#ifdef HAVE_FCNTL_H
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#endif
|
#endif
|
||||||
@ -335,6 +343,21 @@ bool isIPv6supported()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool getCurrentModulePath(char* buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_DLADDR
|
||||||
|
Dl_info path;
|
||||||
|
|
||||||
|
if (dladdr((void*) &getCurrentModulePath, &path))
|
||||||
|
{
|
||||||
|
strncpy(buffer, path.dli_fname, bufferSize);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// setting flag is not absolutely required, therefore ignore errors here
|
// setting flag is not absolutely required, therefore ignore errors here
|
||||||
void setCloseOnExec(int fd)
|
void setCloseOnExec(int fd)
|
||||||
{
|
{
|
||||||
|
@ -380,6 +380,23 @@ bool isIPv6supported()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool getCurrentModulePath(char* buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
HMODULE hmod = 0;
|
||||||
|
|
||||||
|
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||||
|
(LPCTSTR) &getCurrentModulePath,
|
||||||
|
&hmod);
|
||||||
|
|
||||||
|
if (hmod)
|
||||||
|
{
|
||||||
|
GetModuleFileName(hmod, buffer, bufferSize);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int open(const char* pathname, int flags, mode_t mode)
|
int open(const char* pathname, int flags, mode_t mode)
|
||||||
{
|
{
|
||||||
return ::_open(pathname, flags, mode);
|
return ::_open(pathname, flags, mode);
|
||||||
|
@ -11519,7 +11519,7 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G
|
|||||||
const MetaName objName(object ? object->second : "");
|
const MetaName objName(object ? object->second : "");
|
||||||
bool crdb = false;
|
bool crdb = false;
|
||||||
|
|
||||||
AutoPtr<char, ArrayDelete> privileges(new char[MAX(strlen(ALL_PRIVILEGES), strlen(privs ? privs : "")) + 1]);
|
AutoPtr<char, ArrayDelete> privileges(FB_NEW char[MAX(strlen(ALL_PRIVILEGES), strlen(privs ? privs : "")) + 1]);
|
||||||
strcpy(privileges, privs ? privs : "");
|
strcpy(privileges, privs ? privs : "");
|
||||||
|
|
||||||
if (strcmp(privileges, "A") == 0)
|
if (strcmp(privileges, "A") == 0)
|
||||||
|
@ -137,12 +137,8 @@ private:
|
|||||||
|
|
||||||
// Fool-proof requested by Alex
|
// Fool-proof requested by Alex
|
||||||
// Private memory operators to be sure that this class is used in heap only with launcher
|
// Private memory operators to be sure that this class is used in heap only with launcher
|
||||||
#ifdef DEBUG_GDS_ALLOC
|
void* operator new (size_t s, Firebird::MemoryPool& pool ALLOC_PARAMS) { return pool.allocate(s ALLOC_PASS_ARGS); }
|
||||||
void* operator new (size_t s, const char* file, int line) { return MemoryPool::globalAlloc(s, file, line); }
|
void operator delete (void* mem, Firebird::MemoryPool& ALLOC_PARAMS) { MemoryPool::globalFree(mem); }
|
||||||
void operator delete (void* mem, const char* file, int line) { MemoryPool::globalFree(mem); }
|
|
||||||
#else
|
|
||||||
void* operator new (size_t s) { return MemoryPool::globalAlloc(s); }
|
|
||||||
#endif
|
|
||||||
void operator delete (void* mem) { MemoryPool::globalFree(mem); }
|
void operator delete (void* mem) { MemoryPool::globalFree(mem); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Loading…
Reference in New Issue
Block a user