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