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