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