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