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