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