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