diff --git a/storage/ndb/src/kernel/SimBlockList.cpp b/storage/ndb/src/kernel/SimBlockList.cpp index 0f0439e977341827b4ecca0a98d90bbca6e23977..8467690966c590d350bc233be3c7d2d099ec66d3 100644 --- a/storage/ndb/src/kernel/SimBlockList.cpp +++ b/storage/ndb/src/kernel/SimBlockList.cpp @@ -15,6 +15,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "SimBlockList.hpp" +#include "EmulatorData.hpp" #include <SimulatedBlock.hpp> #include <Cmvmi.hpp> #include <Ndbfs.hpp> @@ -69,7 +70,7 @@ void * operator new (size_t sz, SIMBLOCKLIST_DUMMY dummy){ #endif void -SimBlockList::load(Configuration & conf){ +SimBlockList::load(EmulatorData& data){ noOfBlocks = NO_OF_BLOCKS; theList = new SimulatedBlock * [noOfBlocks]; Dbdict* dbdict = 0; @@ -79,7 +80,7 @@ SimBlockList::load(Configuration & conf){ Tsman* ts = 0; Block_context ctx = - { conf, * (Ndbd_mem_manager*)0 }; + { *data.theConfiguration, *data.m_mem_manager }; SimulatedBlock * fs = 0; { diff --git a/storage/ndb/src/kernel/blocks/record_types.hpp b/storage/ndb/src/kernel/blocks/record_types.hpp index 6d2857bd4e265d7db804a3c574dda0dc6f45ddc5..bb8da685b0502da15eeb138e5a6913adbf6567c2 100644 --- a/storage/ndb/src/kernel/blocks/record_types.hpp +++ b/storage/ndb/src/kernel/blocks/record_types.hpp @@ -17,17 +17,6 @@ #ifndef KERNEL_RECORDS_HPP #define KERNEL_RECORDS_HPP -/** - * Record types - */ -#define PGMAN_PAGE_REQUEST 1 - -#define LGMAN_LOG_BUFFER_WAITER 2 -#define LGMAN_LOG_SYNC_WAITER 3 - -#define DBTUP_PAGE_REQUEST 4 -#define DBTUP_EXTENT_INFO 5 - /** * Resource groups */ @@ -47,4 +36,21 @@ */ #define RG_DISK_RECORDS 2 +/** + * + */ +#define RG_RESERVED 0 +#define RG_COUNT 3 + +/** + * Record types + */ +#define PGMAN_PAGE_REQUEST MAKE_TID(1, RG_DISK_OPERATIONS) + +#define LGMAN_LOG_BUFFER_WAITER MAKE_TID(2, RG_DISK_OPERATIONS) +#define LGMAN_LOG_SYNC_WAITER MAKE_TID(3, RG_DISK_OPERATIONS) + +#define DBTUP_PAGE_REQUEST MAKE_TID(4, RG_DISK_OPERATIONS) +#define DBTUP_EXTENT_INFO MAKE_TID(5, RG_DISK_RECORDS) + #endif diff --git a/storage/ndb/src/kernel/main.cpp b/storage/ndb/src/kernel/main.cpp index 7c1763485ce67f0f82b197ba1dbfb3ff55a49fee..b380a4e74c3cc93f38adbb118ef2fc66568cf664 100644 --- a/storage/ndb/src/kernel/main.cpp +++ b/storage/ndb/src/kernel/main.cpp @@ -406,7 +406,7 @@ int main(int argc, char** argv) systemInfo(* theConfig, * theConfig->m_logLevel); // Load blocks - globalEmulatorData.theSimBlockList->load(* theConfig); + globalEmulatorData.theSimBlockList->load(globalEmulatorData); // Set thread concurrency for Solaris' light weight processes int status; diff --git a/storage/ndb/src/kernel/vm/Emulator.cpp b/storage/ndb/src/kernel/vm/Emulator.cpp index 2105b7ddb5e26730ab732a160f187c2cf75acebe..d05fc5fa97c2c565afca6c80a417f2c0af316494 100644 --- a/storage/ndb/src/kernel/vm/Emulator.cpp +++ b/storage/ndb/src/kernel/vm/Emulator.cpp @@ -28,6 +28,7 @@ #include "SimBlockList.hpp" #include <NodeState.hpp> +#include "ndbd_malloc_impl.hpp" #include <NdbMem.h> #include <NdbMutex.h> @@ -77,6 +78,7 @@ EmulatorData::EmulatorData(){ theSimBlockList = 0; theShutdownMutex = 0; m_socket_server = 0; + m_mem_manager = 0; } void @@ -93,6 +95,7 @@ EmulatorData::create(){ theThreadConfig = new ThreadConfig(); theSimBlockList = new SimBlockList(); m_socket_server = new SocketServer(); + m_mem_manager = new Ndbd_mem_manager(); theShutdownMutex = NdbMutex_Create(); @@ -111,6 +114,9 @@ EmulatorData::destroy(){ delete theSimBlockList; theSimBlockList = 0; if(m_socket_server) delete m_socket_server; m_socket_server = 0; + if (m_mem_manager) + delete m_mem_manager; m_mem_manager = 0; + NdbMem_Destroy(); } diff --git a/storage/ndb/src/kernel/vm/Emulator.hpp b/storage/ndb/src/kernel/vm/Emulator.hpp index cd194202d8531c4a2145199ca03af0fd672e063b..f8f55406ffc60c8052792d9861521b1209325b5e 100644 --- a/storage/ndb/src/kernel/vm/Emulator.hpp +++ b/storage/ndb/src/kernel/vm/Emulator.hpp @@ -56,6 +56,7 @@ struct EmulatorData { class ThreadConfig * theThreadConfig; class SimBlockList * theSimBlockList; class SocketServer * m_socket_server; + class Ndbd_mem_manager * m_mem_manager; /** * Constructor diff --git a/storage/ndb/src/kernel/vm/Makefile.am b/storage/ndb/src/kernel/vm/Makefile.am index 64739b7459e797cc93cf91b94b0f04048f8e0b94..740e6783fcd227efde2c46da75f1ab4e51cdec09 100644 --- a/storage/ndb/src/kernel/vm/Makefile.am +++ b/storage/ndb/src/kernel/vm/Makefile.am @@ -19,7 +19,7 @@ libkernel_a_SOURCES = \ SectionReader.cpp \ Mutex.cpp SafeCounter.cpp \ Rope.cpp \ - ndbd_malloc.cpp ndbd_malloc_impl.cpp + ndbd_malloc.cpp ndbd_malloc_impl.cpp Pool.cpp INCLUDES_LOC = -I$(top_srcdir)/storage/ndb/src/mgmapi diff --git a/storage/ndb/src/kernel/vm/Pool.cpp b/storage/ndb/src/kernel/vm/Pool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e64c18d4b4f69617d4ad93cea159bd7f23feb691 --- /dev/null +++ b/storage/ndb/src/kernel/vm/Pool.cpp @@ -0,0 +1,37 @@ +/* Copyright (C) 2003 MySQL AB + + 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; either version 2 of the License, or + (at your option) any later version. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#include "Pool.hpp" +#include "SimulatedBlock.hpp" + +void* +Pool_context::alloc_page(Uint32 type_id, Uint32 *i) +{ + return m_block->m_ctx.m_mm.alloc_page(type_id, i); +} + +void +Pool_context::release_page(Uint32 type_id, Uint32 i, void* p) +{ + m_block->m_ctx.m_mm.release_page(type_id, i, p); +} + +void +Pool_context::handle_abort(const AbortArg &) +{ + +} diff --git a/storage/ndb/src/kernel/vm/Pool.hpp b/storage/ndb/src/kernel/vm/Pool.hpp index 52f7df0ead026ec2cbff7f387224dc727ecbe005..fb5e2961a99c9ab38cd5f7e66ade302ac19e93de 100644 --- a/storage/ndb/src/kernel/vm/Pool.hpp +++ b/storage/ndb/src/kernel/vm/Pool.hpp @@ -19,6 +19,22 @@ #include <kernel_types.h> +/** + * Type id is 11 bits record type, and 5 bits resource id + * -> 2048 different kind of records and 32 different resource groups + * + * Resource id is used to handle configuration parameters + * + * see blocks/records_types.hpp + */ +#define RG_BITS 5 +#define RG_MASK ((1 << RG_BITS) - 1) +#define MAKE_TID(TID,RG) ((TID << RG_BITS) | RG) + +/** + * Record_info + * + */ struct Record_info { Uint16 m_size; @@ -27,6 +43,9 @@ struct Record_info Uint16 m_offset_magic; }; +/** + * Resource_limit + */ struct Resource_limit { Uint32 m_min; @@ -38,7 +57,6 @@ struct Resource_limit struct Pool_context { class SimulatedBlock* m_block; - struct Resource_limit* m_resource_limit; /** * Alloc consekutive pages @@ -48,7 +66,7 @@ struct Pool_context * * Will handle resource limit */ - void* alloc_page(Uint32 *i); + void* alloc_page(Uint32 type_id, Uint32 *i); /** * Release pages @@ -56,7 +74,7 @@ struct Pool_context * @param i : in : i value of first page * @param p : in : pointer to first page */ - void release_page(Uint32 i, void* p); + void release_page(Uint32 type_id, Uint32 i, void* p); /** * Alloc consekutive pages @@ -70,7 +88,7 @@ struct Pool_context * * Will handle resource limit */ - void* alloc_pages(Uint32 *i, Uint32 *cnt, Uint32 min = 1); + void* alloc_pages(Uint32 type_id, Uint32 *i, Uint32 *cnt, Uint32 min =1); /** * Release pages @@ -79,7 +97,7 @@ struct Pool_context * @param p : in : pointer to first page * @param cnt : in : no of pages to release */ - void release_pages(Uint32 i, void* p, Uint32 cnt); + void release_pages(Uint32 type_id, Uint32 i, void* p, Uint32 cnt); /** * Pool abort diff --git a/storage/ndb/src/kernel/vm/SimBlockList.hpp b/storage/ndb/src/kernel/vm/SimBlockList.hpp index 3204a50b03d3afeaae23723ea34cce0051498585..8ba4ba4e2d13d5e69820ac3770d5c996322929c6 100644 --- a/storage/ndb/src/kernel/vm/SimBlockList.hpp +++ b/storage/ndb/src/kernel/vm/SimBlockList.hpp @@ -19,7 +19,7 @@ #include <SimulatedBlock.hpp> -class Configuration; +class EmulatorData; class SimBlockList { @@ -27,7 +27,7 @@ public: SimBlockList(); ~SimBlockList(); - void load(Configuration & conf); + void load(EmulatorData&); void unload(); private: int noOfBlocks; diff --git a/storage/ndb/src/kernel/vm/SimulatedBlock.hpp b/storage/ndb/src/kernel/vm/SimulatedBlock.hpp index 477e75349ebab4638f842cbbc995a1bdff7ed98f..f71f79b777a05be62bcac5411e84f6bc04f88c4d 100644 --- a/storage/ndb/src/kernel/vm/SimulatedBlock.hpp +++ b/storage/ndb/src/kernel/vm/SimulatedBlock.hpp @@ -91,6 +91,7 @@ class SimulatedBlock { friend class Page_cache_client; friend class Lgman; friend class Logfile_client; + friend struct Pool_context; public: friend class BlockComponent; virtual ~SimulatedBlock(); diff --git a/storage/ndb/src/kernel/vm/ndbd_malloc_impl.cpp b/storage/ndb/src/kernel/vm/ndbd_malloc_impl.cpp index e78a1cc119414a1ad7ca9acfd43b8270f5794cb1..a6067528db8936ade60e049128ef96f2878e0784 100644 --- a/storage/ndb/src/kernel/vm/ndbd_malloc_impl.cpp +++ b/storage/ndb/src/kernel/vm/ndbd_malloc_impl.cpp @@ -18,6 +18,92 @@ #include "ndbd_malloc_impl.hpp" #include <ndb_global.h> +#include <EventLogger.hpp> + +#ifndef UNIT_TEST +extern EventLogger g_eventLogger; +#else +extern EventLogger g_eventLogger; +#endif + +#ifdef NDBD_MALLOC_METHOD +#if NDBD_MALLOC_METHOD == sbrk +static const char * f_method = "sbrk"; +#else +static const char * f_method = "malloc"; +#endif +#elif SIZEOF_CHARP == 8 +static const char * f_method = "sbrk"; +#else +static const char * f_method = "malloc"; +#endif +#define MAX_CHUNKS 10 + +struct InitChunk +{ + Uint32 m_cnt; + Uint32 m_start; + Alloc_page* m_ptr; +}; + +#include <NdbOut.hpp> + +static +bool +do_malloc(Uint32 pages, InitChunk* chunk) +{ + void * ptr; + pages += 1; + Uint32 sz = pages; + if (strcmp(f_method, "sbrk") == 0) + { + ptr = 0; + while (ptr == 0) + { + ptr = sbrk(sizeof(Alloc_page) * sz); + if (ptr == (void*)-1) + { + ptr = 0; + sz = 1 + (9 * sz) / 10; + if (pages >= 32 && sz < 32) + { + sz = pages; + f_method = "malloc"; + g_eventLogger.info("sbrk(%lld) failed, trying malloc", + (Uint64)(sizeof(Alloc_page) * sz)); + break; + } + } + } + } + if (strcmp(f_method, "malloc") == 0) + { + ptr = 0; + while (ptr == 0) + { + ptr = malloc(sizeof(Alloc_page) * sz); + if (ptr == 0) + { + sz = 1 + (9 * sz) / 10; + if (pages >= 32 && sz < 32) + { + return false; + } + } + } + } + + chunk->m_cnt = sz; + chunk->m_ptr = (Alloc_page*)ptr; + const UintPtr align = sizeof(Alloc_page) - 1; + if (UintPtr(ptr) & align) + { + chunk->m_cnt--; + chunk->m_ptr = (Alloc_page*)((UintPtr(ptr) + align) & ~align); + } + + return true; +} Uint32 Ndbd_mem_manager::log2(Uint32 input) @@ -33,67 +119,196 @@ Ndbd_mem_manager::log2(Uint32 input) return output; } -Ndbd_mem_manager::Ndbd_mem_manager(Uint32 default_grow) +Ndbd_mem_manager::Ndbd_mem_manager() { - m_grow_size = default_grow; - bzero(m_buddy_lists, sizeof(m_buddy_lists)); - m_base = 0; m_base_page = 0; - - m_pages_alloc = 0; - m_pages_used = 0; + bzero(m_buddy_lists, sizeof(m_buddy_lists)); + bzero(m_resource_limit, sizeof(m_resource_limit)); if (sizeof(Free_page_data) != (4 * (1 << FPD_2LOG))) { + g_eventLogger.error("Invalid build, ndbd_malloc_impl.cpp:%d", __LINE__); abort(); } } +void +Ndbd_mem_manager::set_resource_limit(const Resource_limit& rl) +{ + Uint32 id = rl.m_resource_id; + assert(id < XX_RL_COUNT); + + Uint32 reserve = id ? rl.m_min : 0; + Uint32 current_reserved = m_resource_limit[0].m_min; + + m_resource_limit[id] = rl; + m_resource_limit[id].m_curr = 0; + m_resource_limit[0].m_min = current_reserved + reserve; +} + bool -Ndbd_mem_manager::init(Uint32 pages) +Ndbd_mem_manager::init(bool alloc_less_memory) { - assert(m_base == 0); assert(m_base_page == 0); - assert(m_pages_alloc == 0); - pages = pages ? pages : m_grow_size; + + Uint32 pages = 0; + Uint32 max_page = 0; + if (m_resource_limit[0].m_max) + { + pages = m_resource_limit[0].m_max; + } + else + { + pages = m_resource_limit[0].m_min; // reserved + } + assert(pages); + + g_eventLogger.info("Ndbd_mem_manager::init(%d) min: %dMb initial: %dMb", + alloc_less_memory, + (sizeof(Alloc_page)*m_resource_limit[0].m_min)>>20, + (sizeof(Alloc_page)*m_resource_limit[0].m_max)>>20); + + /** + * Do malloc + */ + + Uint32 cnt = 0; + struct InitChunk chunks[MAX_CHUNKS]; + bzero(chunks, sizeof(chunks)); + + Uint32 allocated = 0; + while (cnt < MAX_CHUNKS && allocated < pages) + { + InitChunk chunk; + Uint32 remaining = pages - allocated; + + if (do_malloc(pages - allocated, &chunk)) + { + Uint32 i = 0; + for(; i<cnt ; i++) + { + if (chunk.m_ptr < chunks[i].m_ptr) + { + for (Uint32 j = cnt; j > i; j--) + chunks[j] = chunks[j-1]; + break; + } + } + cnt++; + chunks[i] = chunk; + allocated += chunk.m_cnt; + } + else + { + break; + } + } - m_base = malloc((2 + pages) * sizeof(Alloc_page)); - UintPtr ptr = (UintPtr)m_base; - UintPtr rem = ptr % sizeof(Alloc_page); - if (rem) + if (allocated < m_resource_limit[0].m_min) { - ptr += sizeof(Alloc_page) - rem; + g_eventLogger. + error("Unable to alloc min memory from OS: min: %lldMb " + " allocated: %lldMb", + (Uint64)(sizeof(Alloc_page)*m_resource_limit[0].m_min) >> 20, + (Uint64)(sizeof(Alloc_page)*allocated) >> 20); + return false; } - else + else if (allocated < pages) { - pages++; + g_eventLogger. + warning("Unable to alloc requested memory from OS: min: %lldMb" + " requested: %lldMb allocated: %lldMb", + (Uint64)(sizeof(Alloc_page)*m_resource_limit[0].m_min)>>20, + (Uint64)(sizeof(Alloc_page)*m_resource_limit[0].m_max)>>20, + (Uint64)(sizeof(Alloc_page)*allocated)>>20); + if (!alloc_less_memory) + return false; } - m_base_page = (Alloc_page*)ptr; - m_pages_alloc += pages; - m_pages_used += pages; + + m_base_page = chunks[0].m_ptr; + + for (Uint32 i = 0; i<cnt; i++) + { + UintPtr start = UintPtr(chunks[i].m_ptr) - UintPtr(m_base_page); + start >>= (2 + BMW_2LOG); + UintPtr last = start + chunks[i].m_cnt; + chunks[i].m_start = start; + assert((Uint64(start) >> 32) == 0); + + if (last > max_page) + max_page = last; + } + m_resource_limit[0].m_resource_id = max_page; + + for (Uint32 i = 0; i<cnt; i++) + { + grow(chunks[i].m_start, chunks[i].m_cnt); + } + + return true; +} + +#include <NdbOut.hpp> - Uint32 bmp = (pages + (1 << BPP_2LOG) - 1) >> BPP_2LOG; - for(Uint32 i = 0; i < bmp; i++) +void +Ndbd_mem_manager::grow(Uint32 start, Uint32 cnt) +{ + assert(cnt); + Uint32 start_bmp = start >> BPP_2LOG; + Uint32 last_bmp = (start + cnt - 1) >> BPP_2LOG; + +#if SIZEOF_CHARP == 4 + assert(start_bmp == 0 && last_bmp == 0); +#endif + + if (start_bmp != last_bmp) + { + Uint32 tmp = ((start_bmp + 1) << BPP_2LOG) - start; + grow(start, tmp); + grow((start_bmp + 1) << BPP_2LOG, cnt - tmp); + return; + } + + if ((start + cnt) == ((start_bmp + 1) << BPP_2LOG)) + { + cnt--; // last page is always marked as empty + } + + if (!m_used_bitmap_pages.get(start_bmp)) { - Uint32 start = i * (1 << BPP_2LOG); - Uint32 end = start + (1 << BPP_2LOG); - end = end > m_pages_alloc ? m_pages_alloc : end - 1; - Alloc_page *ptr = m_base_page + start; - BitmaskImpl::clear(BITMAP_WORDS, ptr->m_data); + if (start != (start_bmp << BPP_2LOG)) + { + ndbout_c("ndbd_malloc_impl.cpp:%d:grow(%d, %d) %d!=%d" + " - Unable to use due to bitmap pages missaligned!!", + __LINE__, start, cnt, start, (start_bmp << BPP_2LOG)); + g_eventLogger.error("ndbd_malloc_impl.cpp:%d:grow(%d, %d)" + " - Unable to use due to bitmap pages missaligned!!", + __LINE__, start, cnt); + return; + } - release(start+1, end - 1 - start); + Alloc_page* bmp = m_base_page + start; + memset(bmp, 0, sizeof(Alloc_page)); + m_used_bitmap_pages.set(start_bmp); + cnt--; + start++; } - return true; + if (cnt) + { + m_resource_limit[0].m_curr += cnt; + m_resource_limit[0].m_max += cnt; + release(start, cnt); + } } void Ndbd_mem_manager::release(Uint32 start, Uint32 cnt) { - assert(m_pages_used >= cnt); + assert(m_resource_limit[0].m_curr >= cnt); assert(start); - m_pages_used -= cnt; - + m_resource_limit[0].m_curr -= cnt; + set(start, start+cnt-1); release_impl(start, cnt); @@ -131,7 +346,8 @@ Ndbd_mem_manager::release_impl(Uint32 start, Uint32 cnt) void Ndbd_mem_manager::alloc(Uint32* ret, Uint32 *pages, Uint32 min) { - Uint32 start, i; + Int32 i; + Uint32 start; Uint32 cnt = * pages; Uint32 list = log2(cnt - 1); @@ -160,8 +376,8 @@ Ndbd_mem_manager::alloc(Uint32* ret, Uint32 *pages, Uint32 min) clear(start, start+cnt-1); } * ret = start; - m_pages_used += cnt; - assert(m_pages_used <= m_pages_alloc); + m_resource_limit[0].m_curr += cnt; + assert(m_resource_limit[0].m_curr <= m_resource_limit[0].m_max); return; } } @@ -171,7 +387,7 @@ Ndbd_mem_manager::alloc(Uint32* ret, Uint32 *pages, Uint32 min) * search in other lists... */ - Uint32 min_list = log2(min - 1); + Int32 min_list = log2(min - 1); assert(list >= min_list); for (i = list - 1; i >= min_list; i--) { @@ -192,33 +408,14 @@ Ndbd_mem_manager::alloc(Uint32* ret, Uint32 *pages, Uint32 min) * ret = start; * pages = sz; - m_pages_used += sz; - assert(m_pages_used <= m_pages_alloc); + m_resource_limit[0].m_curr += sz; + assert(m_resource_limit[0].m_curr <= m_resource_limit[0].m_max); return; } } * pages = 0; } -void* -Ndbd_mem_manager::alloc(Uint32 *pages, Uint32 min) -{ - Uint32 ret; - alloc(&ret, pages, min); - if (pages) - { - return m_base_page + ret; - } - return 0; -} - -void -Ndbd_mem_manager::release(void* ptr, Uint32 cnt) -{ - Uint32 page = ((Alloc_page*)ptr) - m_base_page; - release(page, cnt); -} - void Ndbd_mem_manager::insert_free_list(Uint32 start, Uint32 size) { @@ -284,25 +481,6 @@ Ndbd_mem_manager::remove_free_list(Uint32 start, Uint32 list) return size; } -Uint32 -Ndbd_mem_manager::get_no_allocated_pages() const -{ - return m_pages_alloc; -} - -Uint32 -Ndbd_mem_manager::get_no_used_pages() const -{ - return m_pages_used; -} - -Uint32 -Ndbd_mem_manager::get_no_free_pages() const -{ - return m_pages_alloc - m_pages_used; -} - - void Ndbd_mem_manager::dump() const { @@ -321,31 +499,105 @@ Ndbd_mem_manager::dump() const } } +void* +Ndbd_mem_manager::alloc_page(Uint32 type, Uint32* i) +{ + Uint32 idx = type & RG_MASK; + assert(idx && idx < XX_RL_COUNT); + Resource_limit tot = m_resource_limit[0]; + Resource_limit rl = m_resource_limit[idx]; + + Uint32 add = (rl.m_curr < rl.m_min) ? 0 : 1; // Over min ? + Uint32 limit = (rl.m_max == 0 || rl.m_curr < rl.m_max) ? 0 : 1; // Over limit + Uint32 free = (tot.m_min + tot.m_curr < tot.m_max) ? 1 : 0; // Has free + + if (likely(add == 0 || (limit == 0 && free == 1))) + { + Uint32 cnt = 1; + alloc(i, &cnt, 1); + assert(cnt); + m_resource_limit[0].m_curr = tot.m_curr + add; + m_resource_limit[idx].m_curr = rl.m_curr + 1; + return m_base_page + *i; + } + return 0; +} + +void +Ndbd_mem_manager::release_page(Uint32 type, Uint32 i, void * p) +{ + Uint32 idx = type & RG_MASK; + assert(idx && idx < XX_RL_COUNT); + Resource_limit tot = m_resource_limit[0]; + Resource_limit rl = m_resource_limit[idx]; + + Uint32 sub = (rl.m_curr < rl.m_min) ? 0 : 1; // Over min ? + release(i, 1); + m_resource_limit[0].m_curr = tot.m_curr - sub; +} + #ifdef UNIT_TEST #include <Vector.hpp> +#include <NdbTick.h> struct Chunk { Uint32 pageId; Uint32 pageCount; }; +struct Timer +{ + Uint64 sum; + Uint32 cnt; + + Timer() { sum = cnt = 0;} + + void add(Uint64 diff) { sum += diff; cnt++;} + + void print(const char * title) const { + printf("%s %lld %d -> %d/s\n", title, sum, cnt, Uint32(1000*cnt/sum)); + } +}; + int main(void) { + char buf[255]; + Timer timer[4]; printf("Startar modul test av Page Manager\n"); + g_eventLogger.createConsoleHandler(); + g_eventLogger.setCategory("keso"); + g_eventLogger.enable(Logger::LL_ON, Logger::LL_INFO); + g_eventLogger.enable(Logger::LL_ON, Logger::LL_CRITICAL); + g_eventLogger.enable(Logger::LL_ON, Logger::LL_ERROR); + g_eventLogger.enable(Logger::LL_ON, Logger::LL_WARNING); + #define DEBUG 0 Ndbd_mem_manager mem; - mem.init(32000); + Resource_limit rl; + rl.m_min = 0; + rl.m_max = 2*32768 + 2*16384; + rl.m_curr = 0; + rl.m_resource_id = 0; + mem.set_resource_limit(rl); + rl.m_min = 32768; + rl.m_max = 0; + rl.m_resource_id = 1; + mem.set_resource_limit(rl); + + mem.init(); + mem.dump(); + printf("pid: %d press enter to continue\n", getpid()); + fgets(buf, sizeof(buf), stdin); Vector<Chunk> chunks; - const Uint32 LOOPS = 100000; + const Uint32 LOOPS = 1000000; for(Uint32 i = 0; i<LOOPS; i++){ //mem.dump(); // Case Uint32 c = (rand() % 100); - const Uint32 free = mem.get_no_allocated_pages() - mem.get_no_used_pages(); if (c < 60) { c = 0; @@ -359,17 +611,8 @@ main(void) c = 2; } - Uint32 alloc = 0; - if(free <= 1) - { - c = 0; - alloc = 1; - } - else - { - alloc = 1 + (rand() % (free - 1)); - } - + Uint32 alloc = 1 + rand() % 3200; + if(chunks.size() == 0 && c == 0) { c = 1 + rand() % 2; @@ -382,38 +625,52 @@ main(void) const int ch = rand() % chunks.size(); Chunk chunk = chunks[ch]; chunks.erase(ch); + Uint64 start = NdbTick_CurrentMillisecond(); mem.release(chunk.pageId, chunk.pageCount); + Uint64 stop = NdbTick_CurrentMillisecond(); + timer[0].add(stop-start); if(DEBUG) printf(" release %d %d\n", chunk.pageId, chunk.pageCount); } break; case 2: { // Seize(n) - fail - alloc += free; + alloc += 32000; // Fall through } case 1: { // Seize(n) (success) Chunk chunk; chunk.pageCount = alloc; + if (DEBUG) + { + printf(" alloc %d -> ", alloc); fflush(stdout); + } + Uint64 start = NdbTick_CurrentMillisecond(); mem.alloc(&chunk.pageId, &chunk.pageCount, 1); + Uint64 stop = NdbTick_CurrentMillisecond(); + if (DEBUG) - printf(" alloc %d -> %d %d", alloc, chunk.pageId, chunk.pageCount); + printf("%d %d", chunk.pageId, chunk.pageCount); assert(chunk.pageCount <= alloc); if(chunk.pageCount != 0){ chunks.push_back(chunk); if(chunk.pageCount != alloc) { + timer[2].add(stop-start); if (DEBUG) printf(" - Tried to allocate %d - only allocated %d - free: %d", - alloc, chunk.pageCount, free); + alloc, chunk.pageCount, 0); + } + else + { + timer[1].add(stop-start); } } else { + timer[3].add(stop-start); if (DEBUG) printf(" Failed to alloc %d pages with %d pages free", - alloc, free); + alloc, 0); } if (DEBUG) printf("\n"); - if(alloc == 1 && free > 0) - assert(chunk.pageCount == alloc); } break; } @@ -424,6 +681,15 @@ main(void) mem.release(chunk.pageId, chunk.pageCount); chunks.erase(chunks.size() - 1); } + + const char *title[] = { + "release ", + "alloc full", + "alloc part", + "alloc fail" + }; + for(Uint32 i = 0; i<4; i++) + timer[i].print(title[i]); } template class Vector<Chunk>; diff --git a/storage/ndb/src/kernel/vm/ndbd_malloc_impl.hpp b/storage/ndb/src/kernel/vm/ndbd_malloc_impl.hpp index 15b5c9c390eb40176406313d91f3193d8bc42967..c1b3985ba428c84803c825d447daad06157846d0 100644 --- a/storage/ndb/src/kernel/vm/ndbd_malloc_impl.hpp +++ b/storage/ndb/src/kernel/vm/ndbd_malloc_impl.hpp @@ -20,6 +20,7 @@ #include <kernel_types.h> #include <Bitmask.hpp> #include <assert.h> +#include "Pool.hpp" /** * 13 -> 8192 words -> 32768 bytes @@ -51,25 +52,22 @@ struct Free_page_data class Ndbd_mem_manager { public: - Ndbd_mem_manager(Uint32 default_grow = 32); - + Ndbd_mem_manager(); + + void set_resource_limit(const Resource_limit& rl); + + bool init(bool allow_alloc_less_than_requested = true); + void grow(Uint32 start, Uint32 cnt); + void* get_memroot() const { return (void*)m_base_page;} + void alloc(Uint32* ret, Uint32 *pages, Uint32 min_requested); void release(Uint32 start, Uint32 cnt); - - Uint32 get_no_allocated_pages() const; - Uint32 get_no_used_pages() const; - Uint32 get_no_free_pages() const; - - bool init(Uint32 pages = 0); - bool grow(Uint32 pages = 0); - + void dump() const ; - - void* get_memroot() const { return (void*)m_base_page;} - - void* alloc(Uint32 * pages, Uint32 min_requested); - void release(void* ptr, Uint32 cnt); - + + void* alloc_page(Uint32 type, Uint32* i); + void release_page(Uint32 type, Uint32 i, void * p); + /** * Compute 2log of size * @note size = 0 -> 0 @@ -78,18 +76,15 @@ public: static Uint32 log2(Uint32 size); private: +#define XX_RL_COUNT 3 /** * Return pointer to free page data on page */ static Free_page_data* get_free_page_data(Alloc_page*, Uint32 idx); + Bitmask<1> m_used_bitmap_pages; - Uint32 m_pages_alloc; - Uint32 m_pages_used; - - Uint32 m_grow_size; Uint32 m_buddy_lists[16]; - - void * m_base; + Resource_limit m_resource_limit[XX_RL_COUNT]; // RG_COUNT in record_types.hpp Alloc_page * m_base_page; void release_impl(Uint32 start, Uint32 cnt); @@ -121,7 +116,7 @@ Ndbd_mem_manager::set(Uint32 first, Uint32 last) #if ((SPACE_PER_BMP_2LOG < 32) && (SIZEOF_CHARP == 4)) || (SIZEOF_CHARP == 8) Uint32 bmp = first & ~((1 << BPP_2LOG) - 1); assert((first >> BPP_2LOG) == (last >> BPP_2LOG)); - assert(bmp < m_pages_alloc); + assert(bmp < m_resource_limit[0].m_resource_id); first -= bmp; last -= bmp; @@ -139,7 +134,7 @@ Ndbd_mem_manager::clear(Uint32 first, Uint32 last) #if ((SPACE_PER_BMP_2LOG < 32) && (SIZEOF_CHARP == 4)) || (SIZEOF_CHARP == 8) Uint32 bmp = first & ~((1 << BPP_2LOG) - 1); assert((first >> BPP_2LOG) == (last >> BPP_2LOG)); - assert(bmp < m_pages_alloc); + assert(bmp < m_resource_limit[0].m_resource_id); first -= bmp; last -= bmp; @@ -157,7 +152,7 @@ Ndbd_mem_manager::clear_and_set(Uint32 first, Uint32 last) #if ((SPACE_PER_BMP_2LOG < 32) && (SIZEOF_CHARP == 4)) || (SIZEOF_CHARP == 8) Uint32 bmp = first & ~((1 << BPP_2LOG) - 1); assert((first >> BPP_2LOG) == (last >> BPP_2LOG)); - assert(bmp < m_pages_alloc); + assert(bmp < m_resource_limit[0].m_resource_id); first -= bmp; last -= bmp; @@ -177,7 +172,7 @@ Ndbd_mem_manager::check(Uint32 first, Uint32 last) #if ((SPACE_PER_BMP_2LOG < 32) && (SIZEOF_CHARP == 4)) || (SIZEOF_CHARP == 8) Uint32 bmp = first & ~((1 << BPP_2LOG) - 1); assert((first >> BPP_2LOG) == (last >> BPP_2LOG)); - assert(bmp < m_pages_alloc); + assert(bmp < m_resource_limit[0].m_resource_id); first -= bmp; last -= bmp;