MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SuperPool.cpp
1 /*
2  Copyright (C) 2005, 2006 MySQL AB
3  All rights reserved. Use is subject to license terms.
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; version 2 of the License.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #include <ndb_global.h>
20 #include "SuperPool.hpp"
21 
22 #define SP_ALIGN(sz, al) (((sz) + (al) - 1) & ~((al) - 1))
23 
24 // This is used for m_freeRecI when there is no record pool page.
25 #define NNIL 0xffffffff
26 
27 // SuperPool
28 
29 SuperPool::SuperPool(Uint32 pageSize, Uint32 pageBits) :
30  m_pageSize(pageSize),
31  m_pageBits(pageBits),
32  m_recBits(32 - m_pageBits),
33  m_recMask((1 << m_recBits) - 1),
34  m_memRoot(0),
35  m_pageEnt(0),
36  m_pageType(0),
37  m_freeList(),
38  m_initPages(0),
39  m_incrPages(0),
40  m_maxPages(0),
41  m_totPages(0),
42  m_typeCount(0),
43  m_groupMinPct(0),
44  m_groupMinPages(0),
45  m_groupTotPages(0)
46 {
47  assert(m_pageSize != 0 && (m_pageSize & (m_pageSize - 1)) == 0);
48  assert(m_pageBits <= 30);
49 }
50 
51 SuperPool::~SuperPool()
52 {
53 }
54 
55 SuperPool::PageEnt::PageEnt() :
56  m_pageType(0),
57  m_useCount(0),
58  m_freeRecI(NNIL),
59  m_nextPageI(RNIL),
60  m_prevPageI(RNIL)
61 {
62 }
63 
64 // page list routines
65 
66 SuperPool::PageList::PageList() :
67  m_headPageI(RNIL),
68  m_tailPageI(RNIL),
69  m_pageCount(0)
70 {
71 }
72 
73 SuperPool::PageList::PageList(PtrI pageI) :
74  m_headPageI(pageI),
75  m_tailPageI(pageI),
76  m_pageCount(1)
77 {
78  assert(pageI != RNIL);
79 }
80 
81 void
82 SuperPool::movePages(PageList& pl1, PageList& pl2)
83 {
84  PtrI pageI1 = pl1.m_tailPageI;
85  PtrI pageI2 = pl2.m_headPageI;
86  if (pl1.m_pageCount != 0) {
87  assert(pageI1 != RNIL);
88  if (pl2.m_pageCount != 0) {
89  assert(pageI2 != RNIL);
90  PageEnt& pe1 = getPageEnt(pageI1);
91  PageEnt& pe2 = getPageEnt(pageI2);
92  pe1.m_nextPageI = pageI2;
93  pe2.m_prevPageI = pageI1;
94  pl1.m_tailPageI = pl2.m_tailPageI;
95  pl1.m_pageCount += pl2.m_pageCount;
96  } else {
97  assert(pageI2 == RNIL);
98  }
99  } else {
100  assert(pageI1 == RNIL);
101  pl1 = pl2;
102  }
103  pl2.m_headPageI = pl2.m_tailPageI = RNIL;
104  pl2.m_pageCount = 0;
105 }
106 
107 void
108 SuperPool::addHeadPage(PageList& pl, PtrI pageI)
109 {
110  assert(pageI != RNIL);
111  PageEnt& pe = getPageEnt(pageI);
112  assert(pe.m_nextPageI == RNIL & pe.m_prevPageI == RNIL);
113  PageList pl2(pageI);
114  movePages(pl2, pl);
115  pl = pl2;
116 }
117 
118 void
119 SuperPool::addTailPage(PageList& pl, PtrI pageI)
120 {
121  assert(pageI != RNIL);
122  PageEnt& pe = getPageEnt(pageI);
123  assert(pe.m_nextPageI == RNIL & pe.m_prevPageI == RNIL);
124  PageList pl2(pageI);
125  movePages(pl, pl2);
126 }
127 
128 void
129 SuperPool::removePage(PageList& pl, PtrI pageI)
130 {
131  assert(pageI != RNIL);
132  PageEnt& pe = getPageEnt(pageI);
133  if (pe.m_nextPageI != RNIL) {
134  assert(pl.m_tailPageI != pageI);
135  PageEnt& nextPe = getPageEnt(pe.m_nextPageI);
136  nextPe.m_prevPageI = pe.m_prevPageI;
137  } else {
138  assert(pl.m_tailPageI == pageI);
139  pl.m_tailPageI = pe.m_prevPageI;
140  }
141  if (pe.m_prevPageI != RNIL) {
142  assert(pl.m_headPageI != pageI);
143  PageEnt& prevPe = getPageEnt(pe.m_prevPageI);
144  prevPe.m_nextPageI = pe.m_nextPageI;
145  } else {
146  assert(pl.m_headPageI == pageI);
147  pl.m_headPageI = pe.m_nextPageI;
148  }
149  pe.m_nextPageI = RNIL;
150  pe.m_prevPageI = RNIL;
151  assert(pl.m_pageCount != 0);
152  pl.m_pageCount--;
153 }
154 
155 // reverse mapping
156 
157 SuperPool::PtrI
158 SuperPool::getPageI(void* pageP)
159 {
160  Uint32 pageSize = m_pageSize;
161  Uint32 pageBits = m_pageBits;
162  Uint32 recBits = m_recBits;
163  void* memRoot = m_memRoot;
164  my_ptrdiff_t ipL = (Uint8*)pageP - (Uint8*)memRoot;
165  assert(ipL % pageSize == 0);
166  ipL /= (Int32)pageSize;
167  Int32 ip = (Int32)ipL;
168  Int32 lim = 1 << (pageBits - 1);
169  if (! (ip == ipL && -lim <= ip && ip < lim && ip != -1)) {
170  // page was too distant from memory root
171  return RNIL;
172  }
173  PtrI pageI = ip << recBits;
174  assert(pageP == getPageP(pageI));
175  return pageI;
176 }
177 
178 // record pool
179 
180 SuperPool::RecInfo::RecInfo(GroupPool& gp, Uint32 recSize) :
181  m_groupPool(gp),
182  m_recSize(recSize),
183  m_recType(0),
184  m_maxPerPage(0),
185  m_freeRecI(NNIL),
186  m_useCount(0),
187  m_pageList(),
188  m_hyX(1),
189  m_hyY(2)
190 {
191  SuperPool& sp = gp.m_superPool;
192  m_recType = (sp.m_typeCount++ << 1) | 1;
193  assert(m_recSize == SP_ALIGN(m_recSize, sizeof(Uint32)));
194  { // compute max records per page
195  Uint32 n1 = sp.m_pageSize / m_recSize;
196  Uint32 b2 = (sp.m_recBits < 16 ? sp.m_recBits : 16);
197  Uint32 n2 = (1 << b2) - 1; // last is reserved
198  m_maxPerPage = (n1 < n2 ? n1 : n2);
199  assert(m_maxPerPage != 0);
200  }
201 }
202 
203 Uint32
204 SuperPool::getFreeCount(RecInfo& ri, PtrI recI)
205 {
206  Uint32 n = 0;
207  Uint32 recMask = m_recMask;
208  Uint32 loopRecI = recI;
209  while ((loopRecI & recMask) != recMask) {
210  n++;
211  void* loopRecP = getRecP(loopRecI, ri);
212  loopRecI = *(Uint32*)loopRecP;
213  }
214  assert(n == (Uint16)n);
215  return n;
216 }
217 
218 Uint32
219 SuperPool::getRecPageCount(RecInfo& ri)
220 {
221  Uint32 n = 0;
222  for (Uint32 k = 0; k <= 2; k++)
223  n += ri.m_pageList[k].m_pageCount;
224  if (ri.m_freeRecI != NNIL)
225  n += 1;
226  return n;
227 }
228 
229 Uint32
230 SuperPool::getRecTotCount(RecInfo& ri)
231 {
232  return ri.m_maxPerPage * getRecPageCount(ri);
233 }
234 
235 Uint32
236 SuperPool::getRecUseCount(RecInfo& ri)
237 {
238  Uint32 n = ri.m_useCount;
239  // current page does not keep count
240  if (ri.m_freeRecI != NNIL) {
241  Uint32 maxPerPage = ri.m_maxPerPage;
242  Uint32 freeCount = getFreeCount(ri, ri.m_freeRecI);
243  assert(maxPerPage >= freeCount);
244  n += maxPerPage - freeCount;
245  }
246  return n;
247 }
248 
249 // current page
250 
251 Uint32
252 SuperPool::getRecPageList(RecInfo& ri, PageEnt& pe)
253 {
254  if (pe.m_useCount == 0)
255  return 0;
256  if (pe.m_useCount < ri.m_maxPerPage)
257  return 1;
258  if (pe.m_useCount == ri.m_maxPerPage)
259  return 2;
260  assert(false);
261  return ~(Uint32)0;
262 }
263 
264 void
265 SuperPool::addCurrPage(RecInfo& ri, PtrI pageI)
266 {
267  PageEnt& pe = getPageEnt(pageI);
268  ri.m_freeRecI = pe.m_freeRecI;
269  // remove from right list
270  Uint32 k = getRecPageList(ri, pe);
271  assert(k != 2);
272  removePage(ri.m_pageList[k], pageI);
273  assert(ri.m_useCount >= pe.m_useCount);
274  ri.m_useCount -= pe.m_useCount;
275 }
276 
277 void
278 SuperPool::removeCurrPage(RecInfo& ri)
279 {
280  Uint32 recMask = m_recMask;
281  PtrI pageI = ri.m_freeRecI & ~ m_recMask;
282  // update page entry
283  PageEnt& pe = getPageEnt(pageI);
284  pe.m_freeRecI = ri.m_freeRecI;
285  Uint32 maxPerPage = ri.m_maxPerPage;
286  Uint32 freeCount = getFreeCount(ri, pe.m_freeRecI);
287  assert(maxPerPage >= freeCount);
288  pe.m_useCount = maxPerPage - freeCount;
289  // add to right list
290  Uint32 k = getRecPageList(ri, pe);
291  addHeadPage(ri.m_pageList[k], pageI);
292  ri.m_useCount += pe.m_useCount;
293  ri.m_freeRecI = NNIL;
294  if (k == 0) {
295  freeRecPages(ri);
296  }
297 }
298 
299 // page allocation
300 
301 bool
302 SuperPool::getAvailPage(RecInfo& ri)
303 {
304  PtrI pageI;
305  if ((pageI = ri.m_pageList[1].m_headPageI) != RNIL ||
306  (pageI = ri.m_pageList[0].m_headPageI) != RNIL ||
307  (pageI = getFreePage(ri)) != RNIL) {
308  // the page is in record pool now
309  if (ri.m_freeRecI != NNIL)
310  removeCurrPage(ri);
311  addCurrPage(ri, pageI);
312  return true;
313  }
314  return false;
315 }
316 
317 SuperPool::PtrI
318 SuperPool::getFreePage(RecInfo& ri)
319 {
320  GroupPool& gp = ri.m_groupPool;
321  PtrI pageI;
322  if ((pageI = getFreePage(gp)) != RNIL) {
323  initFreePage(ri, pageI);
324  addHeadPage(ri.m_pageList[0], pageI);
325  return pageI;
326  }
327  return RNIL;
328 }
329 
330 SuperPool::PtrI
331 SuperPool::getFreePage(GroupPool& gp)
332 {
333  PtrI pageI;
334  if ((pageI = gp.m_freeList.m_headPageI) != RNIL) {
335  removePage(gp.m_freeList, pageI);
336  return pageI;
337  }
338  if (gp.m_totPages < getMaxPages(gp) &&
339  (pageI = getFreePage()) != RNIL) {
340  gp.m_totPages++;
341  return pageI;
342  }
343  return RNIL;
344 }
345 
346 SuperPool::PtrI
347 SuperPool::getFreePage()
348 {
349  PtrI pageI;
350  if ((pageI = m_freeList.m_headPageI) != RNIL) {
351  removePage(m_freeList, pageI);
352  return pageI;
353  }
354  if ((pageI = getNewPage()) != RNIL) {
355  return pageI;
356  }
357  return RNIL;
358 }
359 
360 void
361 SuperPool::initFreePage(RecInfo& ri, PtrI pageI)
362 {
363  void* pageP = getPageP(pageI);
364  // set up free record list
365  Uint32 num = ri.m_maxPerPage;
366  Uint32 recSize = ri.m_recSize;
367  void* recP = (Uint8*)pageP;
368  Uint32 irNext = 1;
369  while (irNext < num) {
370  *(Uint32*)recP = pageI | irNext;
371  recP = (Uint8*)recP + recSize;
372  irNext++;
373  }
374  // terminator has all recBits set
375  *(Uint32*)recP = pageI | m_recMask;
376  // set up new page entry
377  PageEnt& pe = getPageEnt(pageI);
378  new (&pe) PageEnt();
379  pe.m_pageType = ri.m_recType;
380  pe.m_freeRecI = pageI | 0;
381  pe.m_useCount = 0;
382  // set type check byte
383  Uint32 ip = pageI >> m_recBits;
384  m_pageType[ip] = (ri.m_recType & 0xFF);
385 }
386 
387 // release
388 
389 void
390 SuperPool::releaseNotCurrent(RecInfo& ri, PtrI recI)
391 {
392  PageEnt& pe = getPageEnt(recI);
393  void* recP = getRecP(recI, ri);
394  *(Uint32*)recP = pe.m_freeRecI;
395  pe.m_freeRecI = recI;
396  PtrI pageI = recI & ~ m_recMask;
397  Uint32 maxPerPage = ri.m_maxPerPage;
398  // move to right list
399  Uint32 k1 = getRecPageList(ri, pe);
400  assert(pe.m_useCount != 0);
401  pe.m_useCount--;
402  Uint32 k2 = getRecPageList(ri, pe);
403  if (k1 != k2) {
404  removePage(ri.m_pageList[k1], pageI);
405  addHeadPage(ri.m_pageList[k2], pageI);
406  if (k2 == 0) {
407  freeRecPages(ri);
408  }
409  }
410  assert(ri.m_useCount != 0);
411  ri.m_useCount--;
412 }
413 
414 void
415 SuperPool::freeRecPages(RecInfo& ri)
416 {
417  // ignore current page
418  Uint32 useCount = ri.m_useCount;
419  Uint32 totCount = 0;
420  for (uint32 k = 0; k <= 2; k++)
421  totCount += ri.m_pageList[k].m_pageCount;
422  totCount *= ri.m_maxPerPage;
423  assert(totCount >= useCount);
424  if ((totCount - useCount) * ri.m_hyY < useCount * ri.m_hyX)
425  return;
426  // free all free pages
427  GroupPool& gp = ri.m_groupPool;
428  Uint32 minPages = getMinPages(gp);
429  PageList& pl = ri.m_pageList[0];
430  while (pl.m_pageCount != 0) {
431  PtrI pageI = pl.m_headPageI;
432  removePage(pl, pageI);
433  PageEnt& pe = getPageEnt(pageI);
434  pe.m_pageType = 0;
435  pe.m_freeRecI = NNIL;
436  Uint32 ip = pageI >> m_recBits;
437  m_pageType[ip] = 0;
438  if (gp.m_totPages <= minPages) {
439  addHeadPage(gp.m_freeList, pageI);
440  } else {
441  // return excess to super pool
442  addHeadPage(m_freeList, pageI);
443  assert(gp.m_totPages != 0);
444  gp.m_totPages--;
445  }
446  }
447 }
448 
449 void
450 SuperPool::freeAllRecPages(RecInfo& ri, bool force)
451 {
452  GroupPool& gp = ri.m_groupPool;
453  if (ri.m_freeRecI != NNIL)
454  removeCurrPage(ri);
455  assert(force || ri.m_useCount == 0);
456  for (Uint32 k = 0; k <= 2; k++)
457  movePages(gp.m_freeList, ri.m_pageList[k]);
458 }
459 
460 // size parameters
461 
462 void
463 SuperPool::setInitPages(Uint32 initPages)
464 {
465  m_initPages = initPages;
466 }
467 
468 void
469 SuperPool::setIncrPages(Uint32 incrPages)
470 {
471  m_incrPages = incrPages;
472 }
473 
474 void
475 SuperPool::setMaxPages(Uint32 maxPages)
476 {
477  m_maxPages = maxPages;
478 }
479 
480 Uint32
481 SuperPool::getGpMinPages()
482 {
483  Uint32 minPages = (m_groupMinPct * m_totPages) / 100;
484  if (minPages < m_groupMinPages)
485  minPages = m_groupMinPages;
486  return minPages;
487 }
488 
489 Uint32
490 SuperPool::getMinPages(GroupPool& gp)
491 {
492  Uint32 minPages = (gp.m_minPct * m_totPages) / 100;
493  if (minPages < gp.m_minPages)
494  minPages = gp.m_minPages;
495  return minPages;
496 }
497 
498 Uint32
499 SuperPool::getMaxPages(GroupPool& gp)
500 {
501  Uint32 n1 = getGpMinPages();
502  Uint32 n2 = getMinPages(gp);
503  assert(n1 >= n2);
504  // pages reserved by other groups
505  Uint32 n3 = n1 - n2;
506  // rest can be claimed
507  Uint32 n4 = (m_totPages >= n3 ? m_totPages - n3 : 0);
508  return n4;
509 }
510 
511 // debug
512 
513 void
514 SuperPool::verify(RecInfo& ri)
515 {
516  GroupPool& gp = ri.m_groupPool;
517  verifyPageList(m_freeList);
518  verifyPageList(gp.m_freeList);
519  for (Uint32 k = 0; k <= 2; k++) {
520  PageList& pl = ri.m_pageList[k];
521  verifyPageList(pl);
522  PtrI pageI = pl.m_headPageI;
523  while (pageI != RNIL) {
524  PageEnt& pe = getPageEnt(pageI);
525  assert(pe.m_pageType == ri.m_recType);
526  Uint32 maxPerPage = ri.m_maxPerPage;
527  Uint32 freeCount = getFreeCount(ri, pe.m_freeRecI);
528  assert(maxPerPage >= freeCount);
529  Uint32 useCount = maxPerPage - freeCount;
530  assert(pe.m_useCount == useCount);
531  assert(k != 0 || useCount == 0);
532  assert(k != 1 || (useCount != 0 && freeCount != 0));
533  assert(k != 2 || freeCount == 0);
534  pageI = pe.m_nextPageI;
535  }
536  }
537 }
538 
539 void
540 SuperPool::verifyPageList(PageList& pl)
541 {
542  Uint32 count = 0;
543  PtrI pageI = pl.m_headPageI;
544  while (pageI != RNIL) {
545  PageEnt& pe = getPageEnt(pageI);
546  if (pe.m_prevPageI == RNIL) {
547  assert(count == 0);
548  } else {
549  PageEnt& prevPe = getPageEnt(pe.m_prevPageI);
550  assert(prevPe.m_nextPageI == pageI);
551  }
552  if (pe.m_nextPageI == RNIL) {
553  assert(pl.m_tailPageI == pageI);
554  } else {
555  PageEnt& nextPe = getPageEnt(pe.m_nextPageI);
556  assert(nextPe.m_prevPageI == pageI);
557  }
558  if (pe.m_pageType != 0) {
559  assert(pe.m_freeRecI != NNIL);
560  PageEnt& pe2 = getPageEnt(pe.m_freeRecI);
561  assert(&pe == &pe2);
562  } else {
563  assert(pe.m_freeRecI == NNIL);
564  }
565  pageI = pe.m_nextPageI;
566  count++;
567  }
568  assert(pl.m_pageCount == count);
569 }
570 
571 // GroupPool
572 
573 GroupPool::GroupPool(SuperPool& sp) :
574  m_superPool(sp),
575  m_minPct(0),
576  m_minPages(0),
577  m_totPages(0),
578  m_freeList()
579 {
580 }
581 
582 GroupPool::~GroupPool()
583 {
584 }
585 
586 void
587 GroupPool::setMinPct(Uint32 minPct)
588 {
589  SuperPool& sp = m_superPool;
590  // subtract any previous value
591  assert(sp.m_groupMinPct >= m_minPct);
592  sp.m_groupMinPct -= m_minPct;
593  // add new value
594  sp.m_groupMinPct += minPct;
595  m_minPct = minPct;
596 }
597 
598 void
599 GroupPool::setMinPages(Uint32 minPages)
600 {
601  SuperPool& sp = m_superPool;
602  // subtract any previous value
603  assert(sp.m_groupMinPages >= m_minPages);
604  sp.m_groupMinPages -= m_minPages;
605  // add new value
606  sp.m_groupMinPages += minPages;
607  m_minPages = minPages;
608 }
609 
610 // HeapPool
611 
612 HeapPool::HeapPool(Uint32 pageSize, Uint32 pageBits) :
613  SuperPool(pageSize, pageBits),
614  m_areaHead(),
615  m_currArea(&m_areaHead),
616  m_lastArea(&m_areaHead)
617 {
618 }
619 
620 HeapPool::~HeapPool()
621 {
622  free(m_pageEnt);
623  free(m_pageType);
624  Area* ap;
625  while ((ap = m_areaHead.m_nextArea) != 0) {
626  m_areaHead.m_nextArea = ap->m_nextArea;
627  free(ap->m_memory);
628  free(ap);
629  }
630 }
631 
632 HeapPool::Area::Area() :
633  m_nextArea(0),
634  m_firstPageI(RNIL),
635  m_currPage(0),
636  m_memory(0),
637  m_pages(0),
638  m_numPages(0)
639 {
640 }
641 
642 SuperPool::PtrI
643 HeapPool::getNewPage()
644 {
645  Area* ap = m_currArea;
646  if (ap->m_currPage == ap->m_numPages) {
647  // area is used up
648  if (ap->m_nextArea == 0) {
649  if (! allocMemoryImpl())
650  return RNIL;
651  }
652  ap = m_currArea = ap->m_nextArea;
653  assert(ap != 0);
654  }
655  assert(ap->m_currPage < ap->m_numPages);
656  PtrI pageI = ap->m_firstPageI;
657  Uint32 recBits = m_recBits;
658  Int32 ip = (Int32)pageI >> recBits;
659  ip += ap->m_currPage;
660  pageI = ip << recBits;
661  ap->m_currPage++;
662  return pageI;
663 }
664 
665 bool
666 HeapPool::allocInit()
667 {
668  Uint32 pageCount = (1 << m_pageBits);
669  if (m_pageEnt == 0) {
670  // allocate page entry array
671  Uint32 bytes = pageCount * sizeof(PageEnt);
672  m_pageEnt = static_cast<PageEnt*>(malloc(bytes));
673  if (m_pageEnt == 0)
674  return false;
675  for (Uint32 i = 0; i < pageCount; i++)
676  new (&m_pageEnt[i]) PageEnt();
677  }
678  if (m_pageType == 0) {
679  // allocate type check array
680  Uint32 bytes = pageCount;
681  m_pageType = static_cast<Uint8*>(malloc(bytes));
682  if (m_pageType == 0)
683  return false;
684  memset(m_pageType, 0, bytes);
685  }
686  return true;
687 }
688 
689 bool
690 HeapPool::allocArea(Area* ap, Uint32 tryPages)
691 {
692  Uint32 pageSize = m_pageSize;
693  // one page is usually lost due to alignment
694  Uint8* p1 = (Uint8*)malloc(pageSize * (tryPages + 1));
695  if (p1 == 0)
696  return false;
697  // align
698  UintPtr n1 = (UintPtr)p1;
699  UintPtr n2 = SP_ALIGN(n1, (UintPtr)pageSize);
700  Uint8* p2 = p1 + (n2 - n1);
701  assert(p2 >= p1 && p2 - p1 < pageSize && (UintPtr)p2 % pageSize == 0);
702  // set memory root to first allocated page
703  if (m_memRoot == 0)
704  m_memRoot = p2;
705  // convert to i-value
706  Uint32 pageI = getPageI(p2);
707  ap->m_firstPageI = pageI;
708  ap->m_currPage = 0;
709  ap->m_memory = p1;
710  ap->m_pages = p2;
711  ap->m_numPages = tryPages + (p1 == p2);
712  return true;
713 }
714 
715 bool
716 HeapPool::allocMemoryImpl()
717 {
718  if (! allocInit())
719  return false;
720  // compute number of additional pages needed
721  if (m_maxPages <= m_totPages)
722  return false;
723  Uint32 needPages = (m_totPages == 0 ? m_initPages : m_incrPages);
724  if (needPages > m_maxPages - m_totPages)
725  needPages = m_maxPages - m_totPages;
726  while (needPages != 0) {
727  // add new area
728  Area* ap = static_cast<Area*>(malloc(sizeof(Area)));
729  if (ap == 0)
730  return false;
731  new (ap) Area();
732  m_lastArea->m_nextArea = ap;
733  m_lastArea = ap;
734  // initial malloc is done in m_incrPages pieces
735  Uint32 wantPages = needPages;
736  if (m_incrPages != 0 && wantPages > m_incrPages)
737  wantPages = m_incrPages;
738  Uint32 tryPages = wantPages;
739  while (tryPages != 0) {
740  if (allocArea(ap, tryPages))
741  break;
742  tryPages /= 2;
743  }
744  if (tryPages == 0)
745  return false;
746  // update counts
747  Uint32 numPages = ap->m_numPages;
748  m_totPages += numPages;
749  needPages = (needPages > numPages ? needPages - numPages : 0);
750  }
751  return true;
752 }