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