1 /*
2 Copyright (c) 2003, 2021, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25
26 #define DBTUP_C
27 #define DBTUP_TAB_DES_MAN_CPP
28 #include "Dbtup.hpp"
29 #include <RefConvert.hpp>
30 #include <ndb_limits.h>
31 #include <pc.hpp>
32
33 #define JAM_FILE_ID 412
34
35
36 /*
37 * TABLE DESCRIPTOR MEMORY MANAGER
38 *
39 * Each table has a descriptor which is a contiguous array of words.
40 * Newer NDB versions also have additional "dynamic descriptors"
41 * which are allocated separately using the same method.
42 *
43 * The descriptor is allocated from a global array using a buddy
44 * algorithm. Free lists exist for each power of 2 words. Freeing
45 * a piece first merges with free right and left neighbours and then
46 * divides itself up into free list chunks.
47 */
48
49 Uint32
getTabDescrOffsets(Uint32 noOfAttrs,Uint32 noOfCharsets,Uint32 noOfKeyAttr,Uint32 extraColumns,Uint32 * offset)50 Dbtup::getTabDescrOffsets(Uint32 noOfAttrs,
51 Uint32 noOfCharsets,
52 Uint32 noOfKeyAttr,
53 Uint32 extraColumns,
54 Uint32* offset)
55 {
56 // belongs to configure.in
57 unsigned sizeOfPointer = sizeof(CHARSET_INFO*);
58 ndbrequire((sizeOfPointer & 0x3) == 0);
59 sizeOfPointer = (sizeOfPointer >> 2);
60 // do in layout order and return offsets (see DbtupMeta.cpp)
61 Uint32 allocSize = 0;
62 // magically aligned to 8 bytes
63 offset[0] = allocSize += ZTD_SIZE;
64 offset[1] = allocSize += noOfAttrs * sizeOfReadFunction();
65 offset[2] = allocSize += noOfAttrs * sizeOfReadFunction();
66 offset[3] = allocSize += noOfCharsets * sizeOfPointer;
67 offset[4] = allocSize += noOfKeyAttr;
68 offset[5] = allocSize += (noOfAttrs + extraColumns) * ZAD_SIZE;
69 offset[6] = allocSize += (noOfAttrs+1) >> 1; // real order
70 allocSize += ZTD_TRAILER_SIZE;
71 // return number of words
72 return allocSize;
73 }
74
75 Uint32
getDynTabDescrOffsets(Uint32 MaskSize,Uint32 * offset)76 Dbtup::getDynTabDescrOffsets(Uint32 MaskSize, Uint32* offset)
77 {
78 // do in layout order and return offsets (see DbtupMeta.cpp)
79 Uint32 allocSize= 0;
80 offset[0]= allocSize += ZTD_SIZE;
81 offset[1]= allocSize += MaskSize;
82 offset[2]= allocSize += MaskSize;
83 allocSize+= ZTD_TRAILER_SIZE;
84 // return number of words
85 return allocSize;
86 }
87
88 void
releaseTabDescr(Uint32 descriptor)89 Dbtup::releaseTabDescr(Uint32 descriptor)
90 {
91 if (descriptor != RNIL)
92 {
93 Uint32 retNo= getTabDescrWord(descriptor + ZTD_DATASIZE);
94 ndbrequire(getTabDescrWord(descriptor + ZTD_HEADER) == ZTD_TYPE_NORMAL);
95 ndbrequire(retNo == getTabDescrWord((descriptor + retNo) - ZTD_TR_SIZE));
96 ndbrequire(ZTD_TYPE_NORMAL ==
97 getTabDescrWord((descriptor + retNo) - ZTD_TR_TYPE));
98 freeTabDescr(descriptor, retNo);
99 }
100 }
101
allocTabDescr(Uint32 allocSize)102 Uint32 Dbtup::allocTabDescr(Uint32 allocSize)
103 {
104 Uint32 reference = RNIL;
105 /* ---------------------------------------------------------------- */
106 /* ALWAYS ALLOCATE A MULTIPLE OF 16 WORDS */
107 /* ---------------------------------------------------------------- */
108 allocSize = (((allocSize - 1) >> 4) + 1) << 4;
109 Uint32 list = nextHigherTwoLog(allocSize - 1); /* CALCULATE WHICH LIST IT BELONGS TO */
110 for (Uint32 i = list; i < 16; i++) {
111 jam();
112 if (cfreeTdList[i] != RNIL) {
113 jam();
114 reference = cfreeTdList[i];
115 removeTdArea(reference, i); /* REMOVE THE AREA FROM THE FREELIST */
116 Uint32 retNo = (1 << i) - allocSize; /* CALCULATE THE DIFFERENCE */
117 if (retNo >= ZTD_FREE_SIZE) {
118 jam();
119 // return unused words, of course without attempting left merge
120 Uint32 retRef = reference + allocSize;
121 freeTabDescr(retRef, retNo, false);
122 } else {
123 jam();
124 allocSize = 1 << i;
125 }//if
126 break;
127 }//if
128 }//for
129 if (reference == RNIL) {
130 jam();
131 terrorCode = ZMEM_NOTABDESCR_ERROR;
132 return RNIL;
133 } else {
134 jam();
135 setTabDescrWord((reference + allocSize) - ZTD_TR_TYPE, ZTD_TYPE_NORMAL);
136 setTabDescrWord(reference + ZTD_DATASIZE, allocSize);
137
138 /* INITIALIZE THE TRAILER RECORD WITH TYPE AND SIZE */
139 /* THE TRAILER IS USED TO SIMPLIFY MERGE OF FREE AREAS */
140
141 setTabDescrWord(reference + ZTD_HEADER, ZTD_TYPE_NORMAL);
142 setTabDescrWord((reference + allocSize) - ZTD_TR_SIZE, allocSize);
143 return reference;
144 }//if
145 }//Dbtup::allocTabDescr()
146
freeTabDescr(Uint32 retRef,Uint32 retNo,bool normal)147 void Dbtup::freeTabDescr(Uint32 retRef, Uint32 retNo, bool normal)
148 {
149 itdaMergeTabDescr(retRef, retNo, normal); /* MERGE WITH POSSIBLE NEIGHBOURS */
150 while (retNo >= ZTD_FREE_SIZE) {
151 jam();
152 Uint32 list = nextHigherTwoLog(retNo);
153 list--; /* RETURN TO NEXT LOWER LIST */
154 Uint32 sizeOfChunk = 1 << list;
155 insertTdArea(retRef, list);
156 retRef += sizeOfChunk;
157 retNo -= sizeOfChunk;
158 }//while
159 ndbassert(retNo == 0);
160 }//Dbtup::freeTabDescr()
161
162 Uint32
getTabDescrWord(Uint32 index)163 Dbtup::getTabDescrWord(Uint32 index)
164 {
165 ndbrequire(index < cnoOfTabDescrRec);
166 return tableDescriptor[index].tabDescr;
167 }//Dbtup::getTabDescrWord()
168
169 void
setTabDescrWord(Uint32 index,Uint32 word)170 Dbtup::setTabDescrWord(Uint32 index, Uint32 word)
171 {
172 ndbrequire(index < cnoOfTabDescrRec);
173 tableDescriptor[index].tabDescr = word;
174 }//Dbtup::setTabDescrWord()
175
insertTdArea(Uint32 tabDesRef,Uint32 list)176 void Dbtup::insertTdArea(Uint32 tabDesRef, Uint32 list)
177 {
178 ndbrequire(list < 16);
179 RSS_OP_FREE_X(cnoOfFreeTabDescrRec, 1 << list);
180 setTabDescrWord(tabDesRef + ZTD_FL_HEADER, ZTD_TYPE_FREE);
181 setTabDescrWord(tabDesRef + ZTD_FL_NEXT, cfreeTdList[list]);
182 if (cfreeTdList[list] != RNIL) {
183 jam(); /* PREVIOUSLY EMPTY SLOT */
184 setTabDescrWord(cfreeTdList[list] + ZTD_FL_PREV, tabDesRef);
185 }//if
186 cfreeTdList[list] = tabDesRef; /* RELINK THE LIST */
187
188 setTabDescrWord(tabDesRef + ZTD_FL_PREV, RNIL);
189 setTabDescrWord(tabDesRef + ZTD_FL_SIZE, 1 << list);
190 setTabDescrWord((tabDesRef + (1 << list)) - ZTD_TR_TYPE, ZTD_TYPE_FREE);
191 setTabDescrWord((tabDesRef + (1 << list)) - ZTD_TR_SIZE, 1 << list);
192 }//Dbtup::insertTdArea()
193
194 /*
195 * Merge to-be-removed chunk (which need not be initialized with header
196 * and trailer) with left and right buddies. The start point retRef
197 * moves to left and the size retNo increases to match the new chunk.
198 */
itdaMergeTabDescr(Uint32 & retRef,Uint32 & retNo,bool normal)199 void Dbtup::itdaMergeTabDescr(Uint32& retRef, Uint32& retNo, bool normal)
200 {
201 // merge right
202 while ((retRef + retNo) < cnoOfTabDescrRec) {
203 jam();
204 Uint32 tabDesRef = retRef + retNo;
205 Uint32 headerWord = getTabDescrWord(tabDesRef + ZTD_FL_HEADER);
206 if (headerWord == ZTD_TYPE_FREE) {
207 jam();
208 Uint32 sizeOfMergedPart = getTabDescrWord(tabDesRef + ZTD_FL_SIZE);
209
210 retNo += sizeOfMergedPart;
211 Uint32 list = nextHigherTwoLog(sizeOfMergedPart - 1);
212 removeTdArea(tabDesRef, list);
213 } else {
214 jam();
215 break;
216 }
217 }
218 // merge left
219 const bool mergeLeft = normal;
220 while (mergeLeft && retRef > 0) {
221 jam();
222 Uint32 trailerWord = getTabDescrWord(retRef - ZTD_TR_TYPE);
223 if (trailerWord == ZTD_TYPE_FREE) {
224 jam();
225 Uint32 sizeOfMergedPart = getTabDescrWord(retRef - ZTD_TR_SIZE);
226 ndbrequire(retRef >= sizeOfMergedPart);
227 retRef -= sizeOfMergedPart;
228 retNo += sizeOfMergedPart;
229 Uint32 list = nextHigherTwoLog(sizeOfMergedPart - 1);
230 removeTdArea(retRef, list);
231 } else {
232 jam();
233 break;
234 }
235 }
236 ndbrequire((retRef + retNo) <= cnoOfTabDescrRec);
237 }//Dbtup::itdaMergeTabDescr()
238
239 /* ---------------------------------------------------------------- */
240 /* ------------------------ REMOVE_TD_AREA ------------------------ */
241 /* ---------------------------------------------------------------- */
242 /* */
243 /* THIS ROUTINE REMOVES A TD CHUNK FROM THE POOL OF TD RECORDS */
244 /* */
245 /* INPUT: TLIST LIST TO USE */
246 /* TAB_DESCR_PTR POINTS TO THE CHUNK TO BE REMOVED */
247 /* */
248 /* SHORTNAME: RMTA */
249 /* -----------------------------------------------------------------*/
removeTdArea(Uint32 tabDesRef,Uint32 list)250 void Dbtup::removeTdArea(Uint32 tabDesRef, Uint32 list)
251 {
252 ndbrequire(list < 16);
253 RSS_OP_ALLOC_X(cnoOfFreeTabDescrRec, 1 << list);
254
255 Uint32 tabDescrNextPtr = getTabDescrWord(tabDesRef + ZTD_FL_NEXT);
256 Uint32 tabDescrPrevPtr = getTabDescrWord(tabDesRef + ZTD_FL_PREV);
257
258 setTabDescrWord(tabDesRef + ZTD_HEADER, ZTD_TYPE_NORMAL);
259 setTabDescrWord((tabDesRef + (1 << list)) - ZTD_TR_TYPE, ZTD_TYPE_NORMAL);
260
261 if (tabDesRef == cfreeTdList[list]) {
262 jam();
263 cfreeTdList[list] = tabDescrNextPtr; /* RELINK THE LIST */
264 }//if
265 if (tabDescrNextPtr != RNIL) {
266 jam();
267 setTabDescrWord(tabDescrNextPtr + ZTD_FL_PREV, tabDescrPrevPtr);
268 }//if
269 if (tabDescrPrevPtr != RNIL) {
270 jam();
271 setTabDescrWord(tabDescrPrevPtr + ZTD_FL_NEXT, tabDescrNextPtr);
272 }//if
273 }//Dbtup::removeTdArea()
274
275 #if defined VM_TRACE || defined ERROR_INSERT
276 void
verifytabdes()277 Dbtup::verifytabdes()
278 {
279 struct WordType {
280 short fl; // free list 0-15
281 short ti; // table id
282 short td; // table descriptor area 0 or >0 for dynamic
283 WordType() : fl(-1), ti(-1), td(-1) {}
284 };
285 WordType* wt = new WordType [cnoOfTabDescrRec];
286 uint free_words = 0;
287 uint free_frags = 0;
288 uint used_words = 0;
289 // free lists
290 {
291 for (uint i = 0; i < 16; i++) {
292 Uint32 desc2 = RNIL;
293 Uint32 desc = cfreeTdList[i];
294 while (desc != RNIL) {
295 const Uint32 size = (1 << i);
296 ndbrequire(size >= ZTD_FREE_SIZE);
297 ndbrequire(desc + size <= cnoOfTabDescrRec);
298 { Uint32 index = desc + ZTD_FL_HEADER;
299 ndbrequire(tableDescriptor[index].tabDescr == ZTD_TYPE_FREE);
300 }
301 { Uint32 index = desc + ZTD_FL_SIZE;
302 ndbrequire(tableDescriptor[index].tabDescr == size);
303 }
304 { Uint32 index = desc + size - ZTD_TR_TYPE;
305 ndbrequire(tableDescriptor[index].tabDescr == ZTD_TYPE_FREE);
306 }
307 { Uint32 index = desc + size - ZTD_TR_SIZE;
308 ndbrequire(tableDescriptor[index].tabDescr == size);
309 }
310 { Uint32 index = desc + ZTD_FL_PREV;
311 ndbrequire(tableDescriptor[index].tabDescr == desc2);
312 }
313 for (uint j = 0; j < size; j++) {
314 ndbrequire(wt[desc + j].fl == -1);
315 wt[desc + j].fl = i;
316 }
317 desc2 = desc;
318 desc = tableDescriptor[desc + ZTD_FL_NEXT].tabDescr;
319 free_words += (1 << i);
320 free_frags++;
321 }
322 }
323 }
324 // tables
325 {
326 for (uint i = 0; i < cnoOfTablerec; i++) {
327 TablerecPtr ptr;
328 ptr.i = i;
329 ptrAss(ptr, tablerec);
330 if (ptr.p->tableStatus != DEFINED)
331 continue;
332 {
333 Uint32 offset[10];
334 const Uint32 alloc = getTabDescrOffsets(ptr.p->m_no_of_attributes,
335 ptr.p->noOfCharsets,
336 ptr.p->noOfKeyAttr,
337 ptr.p->m_no_of_extra_columns,
338 offset);
339 const Uint32 desc = ptr.p->readKeyArray - offset[3];
340 Uint32 size = alloc;
341 if (size % ZTD_FREE_SIZE != 0)
342 size += ZTD_FREE_SIZE - size % ZTD_FREE_SIZE;
343 ndbrequire(desc + size <= cnoOfTabDescrRec);
344 { Uint32 index = desc + ZTD_FL_HEADER;
345 ndbrequire(tableDescriptor[index].tabDescr == ZTD_TYPE_NORMAL);
346 }
347 { Uint32 index = desc + ZTD_FL_SIZE;
348 ndbrequire(tableDescriptor[index].tabDescr == size);
349 }
350 { Uint32 index = desc + size - ZTD_TR_TYPE;
351 ndbrequire(tableDescriptor[index].tabDescr == ZTD_TYPE_NORMAL);
352 }
353 { Uint32 index = desc + size - ZTD_TR_SIZE;
354 ndbrequire(tableDescriptor[index].tabDescr == size);
355 }
356 for (uint j = 0; j < size; j++) {
357 ndbrequire(wt[desc + j].ti == -1);
358 wt[desc + j].ti = i;
359 wt[desc + j].td = 0;
360 }
361 used_words += size;
362 }
363 for (uint k = 0; k < NO_DYNAMICS; k++)
364 {
365 Uint32 offset[3];
366 Uint32 MaskSize = (ptr.p->m_dyn_null_bits[k] + 31) >> 5;
367 const Uint32 alloc = getDynTabDescrOffsets(MaskSize, offset);
368 const Uint32 desc = ptr.p->dynTabDescriptor[k];
369 Uint32 size = alloc;
370 if (size % ZTD_FREE_SIZE != 0)
371 size += ZTD_FREE_SIZE - size % ZTD_FREE_SIZE;
372 ndbrequire(desc + size <= cnoOfTabDescrRec);
373 { Uint32 index = desc + ZTD_FL_HEADER;
374 ndbrequire(tableDescriptor[index].tabDescr == ZTD_TYPE_NORMAL);
375 }
376 { Uint32 index = desc + ZTD_FL_SIZE;
377 ndbrequire(tableDescriptor[index].tabDescr == size);
378 }
379 { Uint32 index = desc + size - ZTD_TR_TYPE;
380 ndbrequire(tableDescriptor[index].tabDescr == ZTD_TYPE_NORMAL);
381 }
382 { Uint32 index = desc + size - ZTD_TR_SIZE;
383 ndbrequire(tableDescriptor[index].tabDescr == size);
384 }
385 for (uint j = 0; j < size; j++) {
386 ndbrequire(wt[desc + j].ti == -1);
387 wt[desc + j].ti = i;
388 wt[desc + j].td = 1 + k;
389 }
390 used_words += size;
391 }
392 }
393 }
394 // all words
395 {
396 for (uint i = 0; i < cnoOfTabDescrRec; i++) {
397 bool is_fl = wt[i].fl != -1;
398 bool is_ti = wt[i].ti != -1;
399 ndbrequire(is_fl != is_ti);
400 }
401 }
402 delete [] wt;
403 ndbrequire(used_words + free_words == cnoOfTabDescrRec);
404 ndbout << "verifytabdes:"
405 << " total: " << cnoOfTabDescrRec
406 << " used: " << used_words
407 << " free: " << free_words
408 << " frags: " << free_frags
409 << endl;
410 }
411 #endif
412