1 /*
2    Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
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 #include <SectionReader.hpp>
27 #include <TransporterDefinitions.hpp>
28 #include "LongSignal.hpp"
29 
30 #if 0
31   Uint32 m_len;
32   class SectionSegmentPool & m_pool;
33   class SectionSegment * m_head;
34   class SectionSegment * m_currentPos;
35 #endif
36 
SectionReader(struct SegmentedSectionPtr & ptr,class SectionSegmentPool & pool)37 SectionReader::SectionReader
38 (struct SegmentedSectionPtr & ptr, class SectionSegmentPool & pool)
39   : m_pool(pool)
40 {
41   if(ptr.p == 0){
42     m_pos = 0;
43     m_len = 0;
44     m_headI= RNIL;
45     m_head = 0;
46     m_currI= RNIL;
47     m_currentSegment = 0;
48   } else {
49     m_pos = 0;
50     m_len = ptr.p->m_sz;
51     m_headI= ptr.i;
52     m_head = ptr.p;
53     m_currI= ptr.i;
54     m_currentSegment = ptr.p;
55   }
56 }
57 
SectionReader(Uint32 firstSectionIVal,class SectionSegmentPool & pool)58 SectionReader::SectionReader
59 (Uint32 firstSectionIVal, class SectionSegmentPool& pool)
60   : m_pool(pool)
61 {
62   SectionSegment* firstSeg= m_pool.getPtr(firstSectionIVal);
63 
64   m_pos = 0;
65   m_len = firstSeg->m_sz;
66   m_headI= m_currI= firstSectionIVal;
67   m_head = m_currentSegment = firstSeg;
68 }
69 
70 void
reset()71 SectionReader::reset(){
72   m_pos = 0;
73   m_currI= m_headI;
74   m_currentSegment = m_head;
75 }
76 
77 bool
step(Uint32 len)78 SectionReader::step(Uint32 len){
79   if(m_pos + len >= m_len) {
80     m_pos++;
81     return false;
82   }
83   while(len > SectionSegment::DataLength){
84     m_currI= m_currentSegment->m_nextSegment;
85     m_currentSegment = m_pool.getPtr(m_currI);
86 
87     len -= SectionSegment::DataLength;
88     m_pos += SectionSegment::DataLength;
89   }
90 
91   Uint32 ind = m_pos % SectionSegment::DataLength;
92   while(len > 0){
93     len--;
94     m_pos++;
95 
96     ind++;
97     if(ind == SectionSegment::DataLength){
98       ind = 0;
99       m_currI= m_currentSegment->m_nextSegment;
100       m_currentSegment = m_pool.getPtr(m_currI);
101     }
102   }
103   return true;
104 }
105 
106 bool
getWord(Uint32 * dst)107 SectionReader::getWord(Uint32 * dst){
108   if (peekWord(dst)) {
109     step(1);
110     return true;
111   }
112   return false;
113 }
114 
115 bool
peekWord(Uint32 * dst) const116 SectionReader::peekWord(Uint32 * dst) const {
117   if(m_pos < m_len){
118     Uint32 ind = m_pos % SectionSegment::DataLength;
119     * dst = m_currentSegment->theData[ind];
120     return true;
121   }
122   return false;
123 }
124 
125 bool
updateWord(Uint32 value) const126 SectionReader::updateWord(Uint32 value) const
127 {
128   if(m_pos < m_len){
129     Uint32 ind = m_pos % SectionSegment::DataLength;
130     m_currentSegment->theData[ind] = value;
131     return true;
132   }
133   return false;
134 }
135 
136 bool
peekWords(Uint32 * dst,Uint32 len) const137 SectionReader::peekWords(Uint32 * dst, Uint32 len) const {
138   if(m_pos + len > m_len)
139     return false;
140 
141   Uint32 ind = (m_pos % SectionSegment::DataLength);
142   Uint32 left = SectionSegment::DataLength - ind;
143   SectionSegment * p = m_currentSegment;
144 
145   while(len > left){
146     memcpy(dst, &p->theData[ind], 4 * left);
147     dst += left;
148     len -= left;
149     ind = 0;
150     left = SectionSegment::DataLength;
151     p = m_pool.getPtr(p->m_nextSegment);
152   }
153 
154   memcpy(dst, &p->theData[ind], 4 * len);
155   return true;
156 }
157 
158 bool
getWords(Uint32 * dst,Uint32 len)159 SectionReader::getWords(Uint32 * dst, Uint32 len){
160   if(m_pos + len > m_len)
161     return false;
162 
163   /* Use getWordsPtr to correctly traverse segments */
164 
165   while (len > 0)
166   {
167     const Uint32* readPtr;
168     Uint32 readLen;
169 
170     if (!getWordsPtr(len,
171                      readPtr,
172                      readLen))
173       return false;
174 
175     memcpy(dst, readPtr, readLen << 2);
176     len-= readLen;
177     dst+= readLen;
178   }
179 
180   return true;
181 }
182 
183 bool
getWordsPtr(Uint32 maxLen,const Uint32 * & readPtr,Uint32 & actualLen)184 SectionReader::getWordsPtr(Uint32 maxLen,
185                            const Uint32*& readPtr,
186                            Uint32& actualLen)
187 {
188   if(m_pos >= m_len)
189     return false;
190 
191   /* We return a pointer to the current position,
192    * with length the minimum of
193    *  - significant words remaining in the whole section
194    *  - space remaining in the current segment
195    *  - maxLen from caller
196    */
197   const Uint32 sectionRemain= m_len - m_pos;
198   const Uint32 startInd = (m_pos % SectionSegment::DataLength);
199   const Uint32 segmentSpace = SectionSegment::DataLength - startInd;
200   SectionSegment * p = m_currentSegment;
201 
202   const Uint32 remain= MIN(sectionRemain, segmentSpace);
203   actualLen= MIN(remain, maxLen);
204   readPtr= &p->theData[startInd];
205 
206   /* If we've read everything in this segment, and
207    * there's another one, move onto it ready for
208    * next time
209    */
210   m_pos += actualLen;
211 
212   if (((startInd + actualLen) == SectionSegment::DataLength) &&
213       (m_pos < m_len))
214   {
215     m_currI= p->m_nextSegment;
216     m_currentSegment= m_pool.getPtr(m_currI);
217   }
218 
219   return true;
220 }
221 
222 bool
getWordsPtr(const Uint32 * & readPtr,Uint32 & actualLen)223 SectionReader::getWordsPtr(const Uint32*& readPtr,
224                            Uint32& actualLen)
225 {
226   /* Cannot have more than SectionSegment::DataLength
227    * contiguous words
228    */
229   return getWordsPtr(SectionSegment::DataLength,
230                      readPtr,
231                      actualLen);
232 }
233 
234 
235 SectionReader::PosInfo
getPos()236 SectionReader::getPos()
237 {
238   PosInfo pi;
239   pi.currPos= m_pos;
240   pi.currIVal= m_currI;
241 
242   return pi;
243 }
244 
245 bool
setPos(PosInfo posInfo)246 SectionReader::setPos(PosInfo posInfo)
247 {
248   if (posInfo.currPos > m_len)
249     return false;
250 
251   if (posInfo.currIVal == RNIL)
252   {
253     if (posInfo.currPos > 0)
254       return false;
255     m_currentSegment= 0;
256   }
257   else
258   {
259     assert(segmentContainsPos(posInfo));
260 
261     m_currentSegment= m_pool.getPtr(posInfo.currIVal);
262   }
263 
264   m_pos= posInfo.currPos;
265   m_currI= posInfo.currIVal;
266 
267   return true;
268 }
269 
270 bool
segmentContainsPos(PosInfo posInfo)271 SectionReader::segmentContainsPos(PosInfo posInfo)
272 {
273   /* This is a check that the section referenced
274    * by this SectionReader contains the position
275    * given at the section given.
276    * It should not be run in-production
277    */
278   Uint32 IVal= m_headI;
279   Uint32 pos= posInfo.currPos;
280 
281   while (pos >= SectionSegment::DataLength)
282   {
283     /* Get next segment */
284     SectionSegment* seg= m_pool.getPtr(IVal);
285 
286     IVal= seg->m_nextSegment;
287     pos-= SectionSegment::DataLength;
288   }
289 
290   return (IVal == posInfo.currIVal);
291 }
292 
293 
294 #ifdef UNIT_TEST
295 
296 #define VERIFY(x) if ((x) == 0) { printf("VERIFY failed at Line %u : %s\n",__LINE__, #x);  return -1; }
297 
298 /* Redefine ArrayPool dependencies to enable standalone Unit-test compile */
handleAssert(const char * message,const char * file,int line,int ec)299 void ErrorReporter::handleAssert(const char* message, const char* file, int line, int ec)
300 {
301   printf("Error :\"%s\" at file : %s line %u ec %u\n",
302          message, file, line, ec);
303   abort();
304 }
305 
ndbd_malloc(size_t size)306 void* ndbd_malloc(size_t size)
307 {
308   return malloc(size);
309 }
310 
ndbd_free(void * p,size_t size)311 void ndbd_free(void* p, size_t size)
312 {
313   free(p);
314 }
315 
316 SectionSegmentPool g_sectionSegmentPool;
317 
318 /* Create a section of word length given from the
319  * Segment Pool supplied
320  */
createSection(SectionSegmentPool * pool,Uint32 length)321 Uint32 createSection(SectionSegmentPool* pool,
322                      Uint32 length)
323 {
324   Uint32 pos= 0;
325 
326   VERIFY(length > 0);
327 
328   Ptr<SectionSegment> first, current;
329 
330   VERIFY(pool->seize(first));
331 
332   first.p->m_sz= length;
333   current= first;
334 
335   while (length > SectionSegment::DataLength)
336   {
337     for (Uint32 i=0; i<SectionSegment::DataLength; i++)
338       current.p->theData[i]= pos+i;
339 
340     pos+= SectionSegment::DataLength;
341     length-= SectionSegment::DataLength;
342 
343     SectionSegment* prev= current.p;
344     VERIFY(pool->seize(current));
345     prev->m_nextSegment= current.i;
346   }
347 
348   if (length > 0)
349   {
350     for (Uint32 i=0; i< length; i++)
351       current.p->theData[i]= pos+i;
352   };
353 
354   first.p->m_lastSegment= current.i;
355 
356   return first.i;
357 };
358 
freeSection(SectionSegmentPool * pool,Uint32 firstIVal)359 bool freeSection(SectionSegmentPool* pool,
360                  Uint32 firstIVal)
361 {
362   Ptr<SectionSegment> p;
363 
364   p.i= firstIVal;
365   pool->getPtr(p);
366 
367   const Uint32 segs= (p.p->m_sz + SectionSegment::DataLength -1) /
368     SectionSegment::DataLength;
369 
370   pool->releaseList(segs, p.i, p.p->m_lastSegment);
371 
372   return true;
373 }
374 
checkBuffer(const Uint32 * buffer,Uint32 start,Uint32 len)375 int checkBuffer(const Uint32* buffer,
376                 Uint32 start,
377                 Uint32 len)
378 {
379   for (Uint32 i=0; i<len; i++)
380   {
381     if (buffer[i] != start + i)
382       printf("i=%u buffer[i]=%u, start=%u\n",
383              i, buffer[i], start);
384     VERIFY(buffer[i] == start + i);
385   }
386   return 0;
387 };
388 
389 #include <random.h>
390 
testSR(Uint32 iVal,SectionSegmentPool * ssp,Uint32 len)391 int testSR(Uint32 iVal, SectionSegmentPool* ssp, Uint32 len)
392 {
393   SectionReader srStepPeek(iVal, *ssp);
394   SectionReader srGetWord(iVal, *ssp);
395   SectionReader srPosSource(iVal, *ssp);
396   SectionReader srPosDest(iVal, *ssp);
397   SectionReader srPtrWord(iVal, *ssp);
398 
399   VERIFY(srStepPeek.getSize() == len);
400 
401   /* Reset the section readers at a random position */
402   const Uint32 noResetPos= 9999999;
403   Uint32 resetAt= len> 10 ? myRandom48(len) : noResetPos;
404 
405   /* Read from the section readers, 1 word at a time */
406   for (Uint32 i=0; i < len; i++)
407   {
408     Uint32 peekWord;
409     Uint32 getWord;
410     const Uint32* ptrWord;
411     Uint32 ptrReadSize;
412 
413     /* Check that peek, getWord and getWordsPtr return
414      * the same, correct value
415      */
416     VERIFY(srStepPeek.peekWord(&peekWord));
417     if (i < (len -1))
418         VERIFY(srStepPeek.step(1));
419     VERIFY(srGetWord.getWord(&getWord));
420     VERIFY(srPtrWord.getWordsPtr(1, ptrWord, ptrReadSize));
421     VERIFY(ptrReadSize == 1);
422     //printf("PeekWord=%u, i=%u\n",
423     //       peekWord, i);
424     VERIFY(peekWord == i);
425     VERIFY(peekWord == getWord);
426     VERIFY(peekWord == *ptrWord);
427 
428     /* Check that one sectionReader with it's position
429      * set from the first returns the same, correct word
430      */
431     SectionReader::PosInfo p= srPosSource.getPos();
432     srPosDest.setPos(p);
433 
434     Uint32 srcWord, destWord;
435 
436     VERIFY(srPosSource.getWord(&srcWord));
437     VERIFY(srPosDest.getWord(&destWord));
438 
439     VERIFY(srcWord == peekWord);
440     VERIFY(srcWord == destWord);
441 
442     /* Reset the readers */
443     if (i == resetAt)
444     {
445       //printf("Resetting\n");
446       resetAt= noResetPos;
447       i= (Uint32) -1;
448       srStepPeek.reset();
449       srGetWord.reset();
450       srPosSource.reset();
451       srPosDest.reset();
452       srPtrWord.reset();
453     }
454     else
455     {
456       if ((myRandom48(400) == 1) &&
457           (i < len -1))
458       {
459         /* Step all readers forward by some amount */
460         Uint32 stepSize= myRandom48((len - i) -1 );
461         //printf("Stepping %u words\n", stepSize);
462         VERIFY(srStepPeek.step(stepSize));
463         VERIFY(srGetWord.step(stepSize));
464         VERIFY(srPosSource.step(stepSize));
465         VERIFY(srPosDest.step(stepSize));
466         VERIFY(srPtrWord.step(stepSize));
467         i+= stepSize;
468       }
469     }
470   }
471 
472   /* Check that there's nothing left in any reader */
473   VERIFY(!srStepPeek.step(1));
474   VERIFY(!srGetWord.step(1));
475   VERIFY(!srPosSource.step(1));
476   VERIFY(!srPosDest.step(1));
477   VERIFY(!srPtrWord.step(1));
478 
479   srStepPeek.reset();
480   srGetWord.reset();
481   srPosSource.reset();
482   srPosDest.reset();
483   srPtrWord.reset();
484 
485   /* Now read larger chunks of words */
486   Uint32 pos= 0;
487   Uint32* buffer= (Uint32*) malloc(len * 4);
488 
489   VERIFY(buffer != NULL);
490 
491   while (pos < len)
492   {
493     const Uint32 remain= len-pos;
494     const Uint32 readSize= remain == 1 ? 1 : myRandom48(remain);
495     //printf("Pos=%u Len=%u readSize=%u \n", pos, len, readSize);
496     /* Check that peek + step get the correct words */
497     VERIFY(srStepPeek.peekWords(buffer, readSize));
498     if (len > pos + readSize)
499     {
500       VERIFY(srStepPeek.step(readSize));
501     }
502     else
503       VERIFY(srStepPeek.step((len - pos) - 1));
504 
505     VERIFY(checkBuffer(buffer, pos, readSize) == 0);
506 
507     /* Check that getWords gets the correct words */
508     VERIFY(srGetWord.getWords(buffer, readSize));
509     VERIFY(checkBuffer(buffer, pos, readSize) == 0);
510 
511     /* Check that using getPos + setPos gets the correct words */
512     VERIFY(srPosDest.setPos(srPosSource.getPos()));
513     VERIFY(srPosSource.getWords(buffer, readSize));
514     VERIFY(checkBuffer(buffer, pos, readSize) == 0);
515 
516     VERIFY(srPosDest.getWords(buffer, readSize));
517     VERIFY(checkBuffer(buffer, pos, readSize) == 0);
518 
519     /* Check that getWordsPtr gets the correct words */
520     Uint32 ptrWordsRead= 0;
521 
522     //printf("Reading from ptr\n");
523     while (ptrWordsRead < readSize)
524     {
525       const Uint32* ptr= NULL;
526       Uint32 readLen;
527       VERIFY(srPtrWord.getWordsPtr((readSize - ptrWordsRead),
528                                    ptr,
529                                    readLen));
530       VERIFY(readLen <= readSize);
531       //printf("Read %u words, from pos %u, offset %u\n",
532       //       readLen, pos, ptrWordsRead);
533       VERIFY(checkBuffer(ptr, pos+ ptrWordsRead, readLen) == 0);
534       ptrWordsRead+= readLen;
535     }
536 
537     pos += readSize;
538   }
539 
540   /* Check that there's no more words in any reader */
541   VERIFY(!srStepPeek.step(1));
542   VERIFY(!srGetWord.step(1));
543   VERIFY(!srPosSource.step(1));
544   VERIFY(!srPosDest.step(1));
545   VERIFY(!srPtrWord.step(1));
546 
547   /* Verify that ptr-fetch variants do not fetch beyond
548    * the length, even if we ask for more
549    */
550   srPtrWord.reset();
551   Uint32 readWords= 0;
552   while (readWords < len)
553   {
554     const Uint32* readPtr;
555     Uint32 wordsRead= 0;
556     VERIFY(srPtrWord.getWordsPtr(20, readPtr, wordsRead));
557     readWords+= wordsRead;
558     VERIFY(readWords <= len);
559   }
560 
561   free(buffer);
562   return 0;
563 }
564 
565 
main(int arg,char ** argv)566 int main(int arg, char** argv)
567 {
568   /* Test SectionReader
569    * -------------------
570    * To run this code :
571    *   cd storage/ndb/src/kernel/vm
572    *   make testSectionReader
573    *   ./testSectionReader
574    *
575    * Will print "OK" in success case and return 0
576    */
577 
578   g_sectionSegmentPool.setSize(1024);
579 
580   printf("g_sectionSegmentPool size is %u\n",
581          g_sectionSegmentPool.getSize());
582 
583   const Uint32 Iterations= 2000;
584   const Uint32 Sections= 5;
585   Uint32 sizes[ Sections ];
586   Uint32 iVals[ Sections ];
587 
588   for (Uint32 t=0; t < Iterations; t++)
589   {
590     for (Uint32 i=0; i<Sections; i++)
591     {
592       Uint32 available= g_sectionSegmentPool.getNoOfFree();
593       sizes[i] = available ?
594         myRandom48(SectionSegment::DataLength *
595                    available)
596         : 0;
597 
598       //if (0 == (sizes[i] % 60))
599       //  printf("Iteration %u, section %u, allocating %u words\n",
600       //         t, i, sizes[i]);
601       if (t % 100 == 0)
602         if (i==0)
603           printf("\nIteration %u", t);
604 
605       if (sizes[i] > 0)
606       {
607         iVals[i]= createSection(&g_sectionSegmentPool, sizes[i]);
608 
609         VERIFY(testSR(iVals[i], &g_sectionSegmentPool, sizes[i]) == 0);
610       }
611       else
612         iVals[i]= RNIL;
613     }
614 
615 
616     for (Uint32 i=0; i < Sections; i++)
617     {
618       if (sizes[i] > 0)
619         freeSection(&g_sectionSegmentPool, iVals[i]);
620     }
621   }
622 
623   printf("\nOK\n");
624   return 0;
625 }
626 
627 #endif
628