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