1 /* Copyright (c) 2008, 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 "LongSignal.hpp"
24 #include "LongSignalImpl.hpp"
25 #include <EventLogger.hpp>
26 
27 extern EventLogger * g_eventLogger;
28 
29 #define JAM_FILE_ID 262
30 
31 // Static function.
32 void
handleOutOfSegments(ArrayPool<SectionSegment> & pool)33 SectionSegmentPool::handleOutOfSegments(ArrayPool<SectionSegment>& pool)
34 {
35   g_eventLogger
36     ->warning("The long message buffer is out of free elements. This may "
37               "cause the data node to crash. Consider increasing the buffer "
38               "size via the LongMessageBuffer configuration parameter. The "
39               "current size of this pool is %lu bytes. You may also check "
40               "the state of this buffer via the ndbinfo.memoryusage table.",
41               static_cast<unsigned long>
42               (pool.getSize() * sizeof(SectionSegment)));
43 };
44 
45 /**
46  * verifySection
47  * Assertion method to check that a segmented section is constructed
48  * 'properly' where 'properly' is loosly defined.
49  */
50 bool
verifySection(Uint32 firstIVal,SectionSegmentPool & thePool)51 verifySection(Uint32 firstIVal, SectionSegmentPool& thePool)
52 {
53   if (firstIVal == RNIL)
54     return true;
55 
56   /* Get first section ptr (With assertions in getPtr) */
57   SectionSegment* first= thePool.getPtr(firstIVal);
58 
59   assert(first != NULL);
60   Uint32 totalSize= first->m_sz;
61 #ifdef VM_TRACE
62   Uint32 lastSegIVal= first->m_lastSegment;
63 #endif
64 
65   /* Hmm, need to be careful of length == 0
66    * Nature abhors a segmented section with length 0
67    */
68   //assert(totalSize != 0);
69   assert(lastSegIVal != RNIL); /* Should never be == RNIL */
70   /* We ignore m_ownerRef */
71 
72   if (totalSize <= SectionSegment::DataLength)
73   {
74     /* 1 segment */
75     assert(first->m_lastSegment == firstIVal);
76     // m_nextSegment not always set to RNIL on last segment
77     //assert(first->m_nextSegment == RNIL);
78   }
79   else
80   {
81     /* > 1 segment */
82     assert(first->m_nextSegment != RNIL);
83     assert(first->m_lastSegment != firstIVal);
84     Uint32 currIVal= firstIVal;
85     SectionSegment* curr= first;
86 
87     /* Traverse segments to where we think the end should be */
88     while (totalSize > SectionSegment::DataLength)
89     {
90       currIVal= curr->m_nextSegment;
91       curr= thePool.getPtr(currIVal);
92       totalSize-= SectionSegment::DataLength;
93       /* Ignore m_ownerRef, m_sz, m_lastSegment of intermediate
94        * Segments
95        */
96     }
97 
98     /* Once we are here, we are on the last Segment of this Section
99      * Check that last segment is as stated in the first segment
100      */
101     assert(currIVal == lastSegIVal);
102     // m_nextSegment not always set properly on last segment
103     //assert(curr->m_nextSegment == RNIL);
104     /* Ignore m_ownerRef, m_sz, m_lastSegment of last segment */
105   }
106 
107   return true;
108 }
109 
110 void
copy(Uint32 * & insertPtr,class SectionSegmentPool & thePool,const SegmentedSectionPtr & _ptr)111 copy(Uint32 * & insertPtr,
112      class SectionSegmentPool & thePool, const SegmentedSectionPtr & _ptr){
113 
114   Uint32 len = _ptr.sz;
115   SectionSegment * ptrP = _ptr.p;
116 
117   assert(verifySection(_ptr.i, thePool));
118 
119   while(len > 60){
120     memcpy(insertPtr, &ptrP->theData[0], 4 * 60);
121     len -= 60;
122     insertPtr += 60;
123     ptrP = thePool.getPtr(ptrP->m_nextSegment);
124   }
125   memcpy(insertPtr, &ptrP->theData[0], 4 * len);
126   insertPtr += len;
127 }
128 
129 void
copy(Uint32 * dst,SegmentedSectionPtr src)130 copy(Uint32 * dst, SegmentedSectionPtr src){
131   copy(dst, g_sectionSegmentPool, src);
132 }
133 
134 /* Copy variant which takes an IVal */
135 void
copy(Uint32 * dst,Uint32 srcFirstIVal)136 copy(Uint32* dst, Uint32 srcFirstIVal)
137 {
138   SegmentedSectionPtr p;
139   getSection(p, srcFirstIVal);
140 
141   copy(dst, p);
142 }
143 
144 void
print(SectionSegment * s,Uint32 len,FILE * out)145 print(SectionSegment * s, Uint32 len, FILE* out){
146   for(Uint32 i = 0; i<len; i++){
147     fprintf(out, "H\'0x%.8x ", s->theData[i]);
148     if(((i + 1) % 6) == 0)
149       fprintf(out, "\n");
150   }
151 }
152 
153 void
print(SegmentedSectionPtr ptr,FILE * out)154 print(SegmentedSectionPtr ptr, FILE* out){
155 
156   ptr.p = g_sectionSegmentPool.getPtr(ptr.i);
157   Uint32 len = ptr.p->m_sz;
158 
159   fprintf(out, "ptr.i = %d(%p) ptr.sz = %d(%d)\n", ptr.i, ptr.p, len, ptr.sz);
160   while(len > SectionSegment::DataLength){
161     print(ptr.p, SectionSegment::DataLength, out);
162 
163     len -= SectionSegment::DataLength;
164     fprintf(out, "ptr.i = %d\n", ptr.p->m_nextSegment);
165     ptr.p = g_sectionSegmentPool.getPtr(ptr.p->m_nextSegment);
166   }
167 
168   print(ptr.p, len, out);
169   fprintf(out, "\n");
170 }
171 
172 bool
dupSection(SPC_ARG Uint32 & copyFirstIVal,Uint32 srcFirstIVal)173 dupSection(SPC_ARG Uint32& copyFirstIVal, Uint32 srcFirstIVal)
174 {
175   assert(verifySection(srcFirstIVal));
176 
177   SectionSegment* p= g_sectionSegmentPool.getPtr(srcFirstIVal);
178   Uint32 sz= p->m_sz;
179   copyFirstIVal= RNIL;
180   bool ok= true;
181 
182   /* Duplicate bulk of section */
183   while (sz > SectionSegment::DataLength)
184   {
185     ok= appendToSection(SPC_CACHE_ARG copyFirstIVal, &p->theData[0],
186                         SectionSegment::DataLength);
187     if (!ok)
188       break;
189 
190     sz-= SectionSegment::DataLength;
191     srcFirstIVal= p->m_nextSegment;
192     p= g_sectionSegmentPool.getPtr(srcFirstIVal);
193   }
194 
195   /* Duplicate last segment */
196   if (ok && (sz > 0))
197     ok= appendToSection(SPC_CACHE_ARG copyFirstIVal, &p->theData[0], sz);
198 
199   if (unlikely(!ok))
200   {
201     releaseSection(SPC_CACHE_ARG copyFirstIVal);
202     copyFirstIVal= RNIL;
203     return false;
204   }
205 
206   assert(verifySection(copyFirstIVal));
207   return true;
208 }
209 
210 bool ErrorImportActive = false;
211 extern int ErrorSignalReceive;
212 extern int ErrorMaxSegmentsToSeize;
213 
214 /**
215  * appendToSection
216  * Append supplied words to the chain of section segments
217  * indicated by the first section passed.
218  * If the passed IVal == RNIL then a section will be seized
219  * and the IVal will be updated to indicate the first IVal
220  * section in the chain
221  * Sections are made up of linked SectionSegment objects
222  * where :
223  *   - The first SectionSegment's m_sz is the size of the
224  *     whole section
225  *   - The first SectionSegment's m_lastSegment refers to
226  *     the last segment in the section
227  *   - Each SectionSegment's m_nextSegment refers to the
228  *     next segment in the section, *except* for the last
229  *     SectionSegment's which is RNIL
230  *   - Each SectionSegment except the first does not use
231  *     its m_sz or m_nextSegment members.
232  */
233 bool
appendToSection(SPC_ARG Uint32 & firstSegmentIVal,const Uint32 * src,Uint32 len)234 appendToSection(SPC_ARG Uint32& firstSegmentIVal, const Uint32* src, Uint32 len)
235 {
236   Ptr<SectionSegment> firstPtr, currPtr;
237 
238   if (len == 0)
239     return true;
240 
241   Uint32 remain= SectionSegment::DataLength;
242   Uint32 segmentLen= 0;
243 
244   if (firstSegmentIVal == RNIL)
245   {
246 #ifdef ERROR_INSERT
247     /* Simulate running out of segments */
248     if (ErrorImportActive)
249     {
250       if ((ErrorSignalReceive == 1) &&
251           (ErrorMaxSegmentsToSeize == 0))
252       {
253         ndbout_c("append exhausted on first segment");
254         return false;
255       }
256     }
257 #endif
258     /* First data to be added to this section */
259     bool result= g_sectionSegmentPool.seize(SPC_SEIZE_ARG firstPtr);
260 
261     if (!result)
262       return false;
263 
264     firstPtr.p->m_sz= 0;
265     firstPtr.p->m_ownerRef= 0;
266     firstSegmentIVal= firstPtr.i;
267 
268     currPtr= firstPtr;
269   }
270   else
271   {
272     /* Section has at least one segment with data already */
273     g_sectionSegmentPool.getPtr(firstPtr, firstSegmentIVal);
274     g_sectionSegmentPool.getPtr(currPtr, firstPtr.p->m_lastSegment);
275 
276     Uint32 existingLen= firstPtr.p->m_sz;
277     assert(existingLen > 0);
278     segmentLen= existingLen % SectionSegment::DataLength;
279 
280     /* If existingLen %  SectionSegment::DataLength == 0
281      * we assume that the last segment is full
282      */
283     segmentLen= segmentLen == 0 ?
284       SectionSegment::DataLength :
285       segmentLen;
286 
287     remain= SectionSegment::DataLength - segmentLen;
288   }
289 
290   firstPtr.p->m_sz+= len;
291 
292 #ifdef ERROR_INSERT
293   Uint32 remainSegs= (Uint32) ErrorMaxSegmentsToSeize - 1;
294 #endif
295 
296   while(len > remain) {
297     /* Fill this segment, and link in another one
298      * Note that we can memcpy to a bad address with size 0
299      */
300     memcpy(&currPtr.p->theData[segmentLen], src, remain << 2);
301     src += remain;
302     len -= remain;
303     Ptr<SectionSegment> prevPtr= currPtr;
304 
305 #ifdef ERROR_INSERT
306     /* Simulate running out of segments */
307     if (ErrorImportActive)
308     {
309       if ((ErrorSignalReceive == 1) &&
310           (0 == remainSegs--))
311       {
312         ndbout_c("Append exhausted on segment %d", ErrorMaxSegmentsToSeize);
313         firstPtr.p->m_lastSegment= prevPtr.i;
314         firstPtr.p->m_sz-= len;
315         return false;
316       }
317     }
318 #endif
319     bool result = g_sectionSegmentPool.seize(SPC_SEIZE_ARG currPtr);
320     if (!result)
321     {
322       /* Failed, ensure segment list is consistent for
323        * freeing later
324        */
325       firstPtr.p->m_lastSegment= prevPtr.i;
326       firstPtr.p->m_sz-= len;
327       return false;
328     }
329     prevPtr.p->m_nextSegment = currPtr.i;
330     currPtr.p->m_sz= 0;
331     currPtr.p->m_ownerRef= 0;
332 
333     segmentLen= 0;
334     remain= SectionSegment::DataLength;
335   }
336 
337   /* Data fits in the current last segment */
338   firstPtr.p->m_lastSegment= currPtr.i;
339   currPtr.p->m_nextSegment= RNIL;
340   memcpy(&currPtr.p->theData[segmentLen], src, len << 2);
341 
342   return true;
343 }
344 bool
import(SPC_ARG Ptr<SectionSegment> & first,const Uint32 * src,Uint32 len)345 import(SPC_ARG Ptr<SectionSegment> & first, const Uint32 * src, Uint32 len){
346 
347 #ifdef ERROR_INSERT
348   /* Simulate running out of segments */
349   if (ErrorImportActive)
350   {
351     if ((ErrorSignalReceive == 1) &&
352         (ErrorMaxSegmentsToSeize == 0))
353     {
354       ndbout_c("Import exhausted on first segment");
355       return false;
356     }
357   }
358 #endif
359 
360   first.p = 0;
361   if(g_sectionSegmentPool.seize(SPC_SEIZE_ARG first)){
362     ;
363   } else {
364     ndbout_c("No Segmented Sections for import");
365     return false;
366   }
367 
368   first.p->m_sz = len;
369   first.p->m_ownerRef = 0;
370 
371   Ptr<SectionSegment> currPtr = first;
372 
373 #ifdef ERROR_INSERT
374   Uint32 remainSegs= (Uint32) ErrorMaxSegmentsToSeize - 1;
375 #endif
376 
377   while(len > SectionSegment::DataLength){
378     memcpy(&currPtr.p->theData[0], src, 4 * SectionSegment::DataLength);
379     src += SectionSegment::DataLength;
380     len -= SectionSegment::DataLength;
381     Ptr<SectionSegment> prevPtr = currPtr;
382 
383 #ifdef ERROR_INSERT
384     /* Simulate running out of segments */
385     if (ErrorImportActive)
386     {
387       if ((ErrorSignalReceive == 1) &&
388           (0 == remainSegs--))
389       {
390         ndbout_c("Import exhausted on segment %d",
391                  ErrorMaxSegmentsToSeize);
392         first.p->m_lastSegment= prevPtr.i;
393         first.p->m_sz-= len;
394         prevPtr.p->m_nextSegment = RNIL;
395         return false;
396       }
397     }
398 #endif
399 
400     if(g_sectionSegmentPool.seize(SPC_SEIZE_ARG currPtr)){
401       prevPtr.p->m_nextSegment = currPtr.i;
402       ;
403     } else {
404       /* Leave segment chain in ok condition for release */
405       first.p->m_lastSegment = prevPtr.i;
406       first.p->m_sz-= len;
407       prevPtr.p->m_nextSegment = RNIL;
408       ndbout_c("Not enough Segmented Sections during import");
409       return false;
410     }
411   }
412 
413   first.p->m_lastSegment = currPtr.i;
414   currPtr.p->m_nextSegment = RNIL;
415   memcpy(&currPtr.p->theData[0], src, 4 * len);
416 
417   assert(verifySection(first.i));
418   return true;
419 }
420 
421 void
release(SPC_ARG SegmentedSectionPtr & ptr)422 release(SPC_ARG SegmentedSectionPtr & ptr)
423 {
424   g_sectionSegmentPool.releaseList(SPC_SEIZE_ARG
425                                    relSz(ptr.sz),
426 				   ptr.i,
427 				   ptr.p->m_lastSegment);
428 }
429 
430 void
releaseSection(SPC_ARG Uint32 firstSegmentIVal)431 releaseSection(SPC_ARG Uint32 firstSegmentIVal)
432 {
433   if (firstSegmentIVal != RNIL)
434   {
435     SectionSegment* p = g_sectionSegmentPool.getPtr(firstSegmentIVal);
436 
437     g_sectionSegmentPool.releaseList(SPC_SEIZE_ARG
438                                      relSz(p->m_sz),
439                                      firstSegmentIVal,
440                                      p->m_lastSegment);
441   }
442 }
443 
444 bool
writeToSection(Uint32 firstSegmentIVal,Uint32 offset,const Uint32 * src,Uint32 len)445 writeToSection(Uint32 firstSegmentIVal, Uint32 offset,
446                const Uint32* src,
447                Uint32 len)
448 {
449   Ptr<SectionSegment> segPtr;
450 
451   if (len == 0)
452     return true;
453 
454   if (firstSegmentIVal == RNIL)
455   {
456     return false;
457   }
458   else
459   {
460     /* Section has at least one segment with data already */
461     g_sectionSegmentPool.getPtr(segPtr, firstSegmentIVal);
462 
463     Uint32 existingLen= segPtr.p->m_sz;
464 
465     assert(existingLen > 0);
466     if (offset >= existingLen)
467       return false;         /* No sparse sections or extension */
468     if (len > (existingLen - offset))
469       return false;         /* Would be extending beyond current length */
470 
471     /* Advance through segments to the one containing the start offset */
472     while (offset >= SectionSegment::DataLength)
473     {
474       g_sectionSegmentPool.getPtr(segPtr, segPtr.p->m_nextSegment);
475       offset-= SectionSegment::DataLength;
476     }
477 
478     /* Now overwrite the words */
479     while (true)
480     {
481       Uint32 wordsToCopy = MIN(len,
482                                SectionSegment::DataLength - offset);
483       memcpy(&segPtr.p->theData[offset], src, (wordsToCopy << 2));
484       src+= wordsToCopy;
485       len-= wordsToCopy;
486 
487       if (!len)
488       {
489         return true;
490       }
491 
492       offset = 0;
493       g_sectionSegmentPool.getPtr(segPtr, segPtr.p->m_nextSegment);
494     }
495   }
496 }
497 
498 /**
499  * #undef is needed since this file is included by LongSignal_nonmt.cpp
500  * and LongSignal_mt.cpp
501  */
502 #undef JAM_FILE_ID
503