MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ArenaPool.cpp
1 /* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
15 
16 #include "ArenaPool.hpp"
17 #include <ndbd_exit_codes.h>
18 #include <NdbOut.hpp>
19 
20 static
21 Uint32
22 computeBlockSize(Uint32 blockSz, Uint32 wpp)
23 {
24  Uint32 minspill = wpp % blockSz;
25  Uint32 minspill_bs = blockSz;
26 
27  for (Uint32 i = 16; i<blockSz/4; i += 16)
28  {
29  Uint32 spillsz = wpp % (blockSz - i);
30  if (spillsz == 0)
31  {
32  return blockSz - i;
33  }
34  else if (spillsz < minspill)
35  {
36  minspill = spillsz;
37  minspill_bs = blockSz -i;
38  }
39  }
40  ndbout_c("blockSz: %u, wpp: %u -> %u (%u)",
41  blockSz, wpp, minspill_bs, minspill);
42  return minspill_bs;
43 }
44 
45 void
46 ArenaAllocator::init(Uint32 sz, Uint32 type_id, const Pool_context& pc)
47 {
48  Uint32 blocksz = ArenaBlock::computeBlockSizeInWords(sz);
49  Uint32 wpp = m_pool.WORDS_PER_PAGE;
50 
51  Uint32 bs = computeBlockSize(blocksz, wpp);
52  Record_info ri;
53  ri.m_size = 4 * bs;
54  {
55  ArenaBlock tmp;
56  const char * off_base = (char*)&tmp;
57  const char * off_next = (char*)&tmp.nextPool;
58  const char * off_magic = (char*)&tmp.m_magic;
59 
60  ri.m_offset_next_pool = Uint32(off_next - off_base);
61  ri.m_offset_magic = Uint32(off_magic - off_base);
62  }
63  ri.m_type_id = type_id;
64  m_pool.init(ri, pc);
65  m_block_size = bs - ArenaBlock::HeaderSize;
66 }
67 
68 bool
69 ArenaAllocator::seize(ArenaHead& ah)
70 {
71  Ptr<void> tmp;
72  if (m_pool.seize(tmp))
73  {
74  ah.m_first_block = tmp.i;
75  ah.m_current_block = tmp.i;
76  ah.m_block_size = m_block_size;
77  ah.m_current_block_ptr = static_cast<ArenaBlock*>(tmp.p);
78  ah.m_current_block_ptr->m_next_block = RNIL;
79  return true;
80  }
81  return false;
82 }
83 
84 void
85 ArenaAllocator::release(ArenaHead& ah)
86 {
87  Ptr<void> curr;
88  curr.i = ah.m_first_block;
89  while (curr.i != RNIL)
90  {
91  curr.p = m_pool.getPtr(curr.i);
92  Uint32 next = static_cast<ArenaBlock*>(curr.p)->m_next_block;
93  m_pool.release(curr);
94  curr.i = next;
95  }
96 
97  new (&ah) ArenaHead();
98 }
99 
100 void
101 ArenaPool::init(ArenaAllocator * alloc,
102  const Record_info& ri, const Pool_context&)
103 {
104  m_record_info = ri;
105 #if SIZEOF_CHARP == 4
106  m_record_info.m_size = ((ri.m_size + 3) >> 2); // Align to word boundary
107 #else
108  m_record_info.m_size = ((ri.m_size + 7) >> 3) << 1; // align 8-byte
109 #endif
110  m_record_info.m_offset_magic = ((ri.m_offset_magic + 3) >> 2);
111  m_record_info.m_offset_next_pool = ((ri.m_offset_next_pool + 3) >> 2);
112  m_allocator = alloc;
113 }
114 
115 bool
116 ArenaPool::seize(ArenaHead & ah, Ptr<void>& ptr)
117 {
118  Uint32 pos = ah.m_first_free;
119  Uint32 bs = ah.m_block_size;
120  Uint32 ptrI = ah.m_current_block;
121  ArenaBlock * block = ah.m_current_block_ptr;
122 
123  Uint32 sz = m_record_info.m_size;
124  Uint32 off = m_record_info.m_offset_magic;
125 
126  if (0)
127  ndbout_c("pos: %u sz: %u (sum: %u) bs: %u",
128  pos, sz, (pos + sz), bs);
129 
130  if (pos + sz <= bs)
131  {
135  ptr.i =
136  ((ptrI >> POOL_RECORD_BITS) << POOL_RECORD_BITS) +
137  (ptrI & POOL_RECORD_MASK) + pos + ArenaBlock::HeaderSize;
138  ptr.p = block->m_data + pos;
139  block->m_data[pos+off] = ~(Uint32)m_record_info.m_type_id;
140 
141  ah.m_first_free = pos + sz;
142  return true;
143  }
144  else
145  {
146  Ptr<void> tmp;
147  if (m_allocator->m_pool.seize(tmp))
148  {
149  ah.m_first_free = 0;
150  ah.m_current_block = tmp.i;
151  ah.m_current_block_ptr->m_next_block = tmp.i;
152  ah.m_current_block_ptr = static_cast<ArenaBlock*>(tmp.p);
153  ah.m_current_block_ptr->m_next_block = RNIL;
154  bool ret = seize(ah, ptr);
155  (void)ret;
156  assert(ret == true);
157  return true;
158  }
159  }
160  return false;
161 }
162 
163 void
164 ArenaPool::handle_invalid_release(Ptr<void> ptr)
165 {
166  char buf[255];
167 
168  //Uint32 pos = ptr.i & POOL_RECORD_MASK;
169  //Uint32 pageI = ptr.i >> POOL_RECORD_BITS;
170  Uint32 * record_ptr_p = (Uint32*)ptr.p;
171 
172  Uint32 magic = * (record_ptr_p + m_record_info.m_offset_magic);
173  BaseString::snprintf(buf, sizeof(buf),
174  "Invalid memory release: ptr (%x %p) magic: (%.8x %.8x)",
175  ptr.i, ptr.p, magic, m_record_info.m_type_id);
176 
177  m_allocator->m_pool.m_ctx.handleAbort(NDBD_EXIT_PRGERR, buf);
178 }