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