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