MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
LinearPool.hpp
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 #ifndef LINEAR_POOL_HPP
20 #define LINEAR_POOL_HPP
21 
22 #include <Bitmask.hpp>
23 #include "SuperPool.hpp"
24 
25 /*
26  * LinearPool - indexed record pool
27  *
28  * LinearPool implements a pool where each record has a 0-based index.
29  * Any index value (up to 2^32-1) is allowed. Normal efficient usage is
30  * to assign index values in sequence and to re-use any values which
31  * have become free. This is default seize/release behaviour.
32  *
33  * LinearPool has 2 internal RecordPool instances:
34  *
35  * (a) record pool of T (the template argument class)
36  * (b) record pool of "maps" (array of Uint32)
37  *
38  * The maps translate an index into an i-value in (a). Each map has
39  * a level. Level 0 maps point to i-values. Level N+1 maps point to
40  * level N maps. There is a unique "root map" at top.
41  *
42  * This works exactly like numbers in a given base. Each map has base
43  * size entries. For implementation convenience the base must be power
44  * of 2 between 2^1 and 2^15. It is given by its log2 value (1-15).
45  *
46  * A position in a map is also called a "digit".
47  *
48  * There is a doubly linked list of available maps (some free entries)
49  * on each level. There is a doubly linked freelist within each map.
50  * There is also a bitmask of used entries in each map.
51  *
52  * Level 0 free entry has space for one record. Level N free entry
53  * implies space for base^N records. The implied levels are created and
54  * removed on demand. Empty maps are usually removed.
55  *
56  * Default base is 256 (log2 = 8) which requires maximum 4 levels or
57  * digits (similar to ip address).
58  *
59  * TODO
60  *
61  * - move most of the inline code to LinearPool.cpp
62  * - optimize for common case
63  * - add optimized 2-level implementation (?)
64  */
65 
66 #include "SuperPool.hpp"
67 
68 template <class T, Uint32 LogBase = 8>
69 class LinearPool {
70  typedef SuperPool::PtrI PtrI;
71 
72  // Base.
73  STATIC_CONST( Base = 1 << LogBase );
74 
75  // Digit mask.
76  STATIC_CONST( DigitMask = Base - 1 );
77 
78  // Max possible levels (0 to max root level).
79  STATIC_CONST( MaxLevels = (32 + LogBase - 1) / LogBase );
80 
81  // Number of words in map used bit mask.
82  STATIC_CONST( BitmaskSize = (Base + 31) / 32 );
83 
84  // Map.
85  struct Map {
86  Uint32 m_level;
87  Uint32 m_occup; // number of used entries
88  Uint32 m_firstfree; // position of first free entry
89  PtrI m_parent; // parent map
90  Uint32 m_index; // from root to here
91  PtrI m_nextavail;
92  PtrI m_prevavail;
93  Uint32 m_bitmask[BitmaskSize];
94  PtrI m_entry[Base];
95  };
96 
97 public:
98 
99  // Constructor.
100  LinearPool(GroupPool& gp);
101 
102  // Destructor.
103  ~LinearPool();
104 
105  // Update pointer ptr.p according to index value ptr.i.
106  void getPtr(Ptr<T>& ptr);
107 
108  // Allocate record from the pool. Reuses free index if possible.
109  bool seize(Ptr<T>& ptr);
110 
111  // Allocate given index. Like seize but returns -1 if in use.
112  int seize_index(Ptr<T>& ptr, Uint32 index);
113 
114  // Return record to the pool.
115  void release(Ptr<T>& ptr);
116 
117  // Return number of used records (may require 1 page scan).
118  Uint32 count();
119 
120  // Verify (debugging).
121  void verify();
122 
123 private:
124 
125  // Given index find the bottom map.
126  void get_map(Ptr<Map>& map_ptr, Uint32 index);
127 
128  // Add new root map and increase level
129  bool add_root();
130 
131  // Add new non-root map.
132  bool add_map(Ptr<Map>& map_ptr, Ptr<Map> parent_ptr, Uint32 digit);
133 
134  // Subroutine to initialize map free lists.
135  void init_free(Ptr<Map> map_ptr);
136 
137  // Add entry at given free position.
138  void add_entry(Ptr<Map> map_ptr, Uint32 digit, PtrI ptr_i);
139 
140  // Remove entry and map if it becomes empty.
141  void remove_entry(Ptr<Map> map_ptr, Uint32 digit);
142 
143  // Remove map and all parents which become empty.
144  void remove_map(Ptr<Map> map_ptr);
145 
146  // Add map to available list.
147  void add_avail(Ptr<Map> map_ptr);
148 
149  // Remove map from available list.
150  void remove_avail(Ptr<Map> map_ptr);
151 
152  // Verify available lists
153  void verify_avail();
154 
155  // Verify map (recursive).
156  void verify_map(Ptr<Map> map_ptr, Uint32 level, Uint32* count);
157 
158  RecordPool<T> m_records;
159  RecordPool<Map> m_maps;
160  Uint32 m_levels; // 0 means empty pool
161  PtrI m_root;
162  PtrI m_avail[MaxLevels];
163 };
164 
165 template <class T, Uint32 LogBase>
166 inline
168  m_records(gp),
169  m_maps(gp),
170  m_levels(0),
171  m_root(RNIL)
172 {
173  Uint32 n;
174  for (n = 0; n < MaxLevels; n++)
175  m_avail[n] = RNIL;
176 }
177 
178 template <class T, Uint32 LogBase>
179 inline
181 {
182 }
183 
184 template <class T, Uint32 LogBase>
185 inline void
187 {
188  Uint32 index = ptr.i;
189  // get level 0 map
190  Ptr<Map> map_ptr;
191  get_map(map_ptr, index);
192  // get record
193  Ptr<T> rec_ptr;
194  Uint32 digit = index & DigitMask;
195  assert(BitmaskImpl::get(BitmaskSize, map_ptr.p->m_bitmask, digit));
196  rec_ptr.i = map_ptr.p->m_entry[digit];
197  m_records.getPtr(rec_ptr);
198  ptr.p = rec_ptr.p;
199 }
200 
201 template <class T, Uint32 LogBase>
202 inline bool
204 {
205  // look for free list on some level
206  Ptr<Map> map_ptr;
207  map_ptr.i = RNIL;
208  Uint32 n = 0;
209  while (n < m_levels) {
210  if ((map_ptr.i = m_avail[n]) != RNIL)
211  break;
212  n++;
213  }
214  if (map_ptr.i == RNIL) {
215  // add new level with available maps
216  if (! add_root())
217  return false;
218  assert(n < m_levels);
219  map_ptr.i = m_avail[n];
220  }
221  m_maps.getPtr(map_ptr);
222  // walk down creating missing levels and using an entry on each
223  Uint32 digit;
224  Ptr<Map> new_ptr;
225  new_ptr.i = RNIL;
226  while (true) {
227  digit = map_ptr.p->m_firstfree;
228  if (n == 0)
229  break;
230  Ptr<Map> child_ptr;
231  if (! add_map(child_ptr, map_ptr, digit)) {
232  if (new_ptr.i != RNIL)
233  remove_map(new_ptr);
234  return false;
235  }
236  new_ptr = child_ptr;
237  map_ptr = child_ptr;
238  n--;
239  }
240  // now on level 0
241  assert(map_ptr.p->m_level == 0);
242  Ptr<T> rec_ptr;
243  if (! m_records.seize(rec_ptr)) {
244  if (new_ptr.i != RNIL)
245  remove_map(new_ptr);
246  return false;
247  }
248  add_entry(map_ptr, digit, rec_ptr.i);
249  ptr.i = digit + (map_ptr.p->m_index << LogBase);
250  ptr.p = rec_ptr.p;
251  return true;
252 }
253 
254 template <class T, Uint32 LogBase>
255 inline int
257 {
258  // extract all digits at least up to current root level
259  Uint32 digits[MaxLevels];
260  Uint32 n = 0;
261  Uint32 tmp = index;
262  do {
263  digits[n] = tmp & DigitMask;
264  tmp >>= LogBase;
265  } while (++n < m_levels || tmp != 0);
266  // add any new root levels
267  while (n > m_levels) {
268  if (! add_root())
269  return false;
270  }
271  // start from root
272  Ptr<Map> map_ptr;
273  map_ptr.i = m_root;
274  m_maps.getPtr(map_ptr);
275  // walk down creating or re-using existing levels
276  Uint32 digit;
277  bool used;
278  Ptr<Map> new_ptr;
279  new_ptr.i = RNIL;
280  while (true) {
281  digit = digits[--n];
282  used = BitmaskImpl::get(BitmaskSize, map_ptr.p->m_bitmask, digit);
283  if (n == 0)
284  break;
285  if (used) {
286  map_ptr.i = map_ptr.p->m_entry[digit];
287  m_maps.getPtr(map_ptr);
288  } else {
289  Ptr<Map> child_ptr;
290  if (! add_map(child_ptr, map_ptr, digit)) {
291  if (new_ptr.i != RNIL)
292  remove_map(new_ptr);
293  }
294  new_ptr = child_ptr;
295  map_ptr = child_ptr;
296  }
297  }
298  // now at level 0
299  assert(map_ptr.p->m_level == 0);
300  Ptr<T> rec_ptr;
301  if (used || ! m_records.seize(rec_ptr)) {
302  if (new_ptr.i != RNIL)
303  remove_map(new_ptr);
304  return used ? -1 : false;
305  }
306  add_entry(map_ptr, digit, rec_ptr.i);
307  assert(index == digit + (map_ptr.p->m_index << LogBase));
308  ptr.i = index;
309  ptr.p = rec_ptr.p;
310  return true;
311 }
312 
313 template <class T, Uint32 LogBase>
314 inline void
316 {
317  Uint32 index = ptr.i;
318  // get level 0 map
319  Ptr<Map> map_ptr;
320  get_map(map_ptr, index);
321  // release record
322  Ptr<T> rec_ptr;
323  Uint32 digit = index & DigitMask;
324  rec_ptr.i = map_ptr.p->m_entry[digit];
325  m_records.release(rec_ptr);
326  // remove entry
327  remove_entry(map_ptr, digit);
328  // null pointer
329  ptr.i = RNIL;
330  ptr.p = 0;
331 }
332 
333 template <class T, Uint32 LogBase>
334 inline Uint32
336 {
337  SuperPool& sp = m_records.m_superPool;
338  Uint32 count1 = sp.getRecUseCount(m_records.m_recInfo);
339  return count1;
340 }
341 
342 template <class T, Uint32 LogBase>
343 inline void
345 {
346  verify_avail();
347  if (m_root == RNIL) {
348  assert(m_levels == 0);
349  return;
350  }
351  assert(m_levels != 0);
352  Ptr<Map> map_ptr;
353  map_ptr.i = m_root;
354  m_maps.getPtr(map_ptr);
355  Uint32 count1 = count();
356  Uint32 count2 = 0;
357  verify_map(map_ptr, m_levels - 1, &count2);
358  assert(count1 == count2);
359 }
360 
361 // private methods
362 
363 template <class T, Uint32 LogBase>
364 inline void
365 LinearPool<T, LogBase>::get_map(Ptr<Map>& map_ptr, Uint32 index)
366 {
367  // root map must exist
368  Ptr<Map> tmp_ptr;
369  tmp_ptr.i = m_root;
370  m_maps.getPtr(tmp_ptr);
371  assert(tmp_ptr.p->m_level + 1 == m_levels);
372  // extract index digits up to current root level
373  Uint32 digits[MaxLevels];
374  Uint32 n = 0;
375  do {
376  digits[n] = index & DigitMask;
377  index >>= LogBase;
378  } while (++n < m_levels);
379  assert(index == 0);
380  // walk down indirect levels
381  while (--n > 0) {
382  tmp_ptr.i = tmp_ptr.p->m_entry[digits[n]];
383  m_maps.getPtr(tmp_ptr);
384  }
385  // level 0 map
386  assert(tmp_ptr.p->m_level == 0);
387  map_ptr = tmp_ptr;
388 }
389 
390 template <class T, Uint32 LogBase>
391 inline bool
393 {
394  // new root
395  Ptr<Map> map_ptr;
396  if (! m_maps.seize(map_ptr))
397  return false;
398  Uint32 n = m_levels++;
399  assert(n < MaxLevels);
400  // set up
401  map_ptr.p->m_level = n;
402  map_ptr.p->m_parent = RNIL;
403  map_ptr.p->m_index = 0;
404  init_free(map_ptr);
405  // on level > 0 digit 0 points to old root
406  if (n > 0) {
407  Ptr<Map> old_ptr;
408  old_ptr.i = m_root;
409  m_maps.getPtr(old_ptr);
410  assert(old_ptr.p->m_parent == RNIL);
411  old_ptr.p->m_parent = map_ptr.i;
412  add_entry(map_ptr, 0, old_ptr.i);
413  }
414  // set new root
415  m_root = map_ptr.i;
416  return true;
417 }
418 
419 template <class T, Uint32 LogBase>
420 inline bool
421 LinearPool<T, LogBase>::add_map(Ptr<Map>& map_ptr, Ptr<Map> parent_ptr, Uint32 digit)
422 {
423  if (! m_maps.seize(map_ptr))
424  return false;
425  assert(parent_ptr.p->m_level != 0);
426  // set up
427  map_ptr.p->m_level = parent_ptr.p->m_level - 1;
428  map_ptr.p->m_parent = parent_ptr.i;
429  map_ptr.p->m_index = digit + (parent_ptr.p->m_index << LogBase);
430  init_free(map_ptr);
431  add_entry(parent_ptr, digit, map_ptr.i);
432  return true;
433 }
434 
435 template <class T, Uint32 LogBase>
436 inline void
438 {
439  map_ptr.p->m_occup = 0;
440  map_ptr.p->m_firstfree = 0;
441  // freelist
442  Uint32 j;
443  Uint16 back = ZNIL;
444  for (j = 0; j < Base - 1; j++) {
445  map_ptr.p->m_entry[j] = back | ((j + 1) << 16);
446  back = j;
447  }
448  map_ptr.p->m_entry[j] = back | (ZNIL << 16);
449  // bitmask
450  BitmaskImpl::clear(BitmaskSize, map_ptr.p->m_bitmask);
451  // add to available
452  add_avail(map_ptr);
453 }
454 
455 template <class T, Uint32 LogBase>
456 inline void
457 LinearPool<T, LogBase>::add_entry(Ptr<Map> map_ptr, Uint32 digit, PtrI ptr_i)
458 {
459  assert(map_ptr.p->m_occup < Base && digit < Base);
460  assert(! BitmaskImpl::get(BitmaskSize, map_ptr.p->m_bitmask, digit));
461  // unlink from freelist
462  Uint32 val = map_ptr.p->m_entry[digit];
463  Uint16 back = val & ZNIL;
464  Uint16 forw = val >> 16;
465  if (back != ZNIL) {
466  assert(back < Base);
467  map_ptr.p->m_entry[back] &= ZNIL;
468  map_ptr.p->m_entry[back] |= (forw << 16);
469  }
470  if (forw != ZNIL) {
471  assert(forw < Base);
472  map_ptr.p->m_entry[forw] &= (ZNIL << 16);
473  map_ptr.p->m_entry[forw] |= back;
474  }
475  if (back == ZNIL) {
476  map_ptr.p->m_firstfree = forw;
477  }
478  // set new value
479  map_ptr.p->m_entry[digit] = ptr_i;
480  map_ptr.p->m_occup++;
481  BitmaskImpl::set(BitmaskSize, map_ptr.p->m_bitmask, digit);
482  if (map_ptr.p->m_occup == Base)
483  remove_avail(map_ptr);
484 }
485 
486 template <class T, Uint32 LogBase>
487 inline void
488 LinearPool<T, LogBase>::remove_entry(Ptr<Map> map_ptr, Uint32 digit)
489 {
490  assert(map_ptr.p->m_occup != 0 && digit < Base);
491  assert(BitmaskImpl::get(BitmaskSize, map_ptr.p->m_bitmask, digit));
492  // add to freelist
493  Uint32 firstfree = map_ptr.p->m_firstfree;
494  map_ptr.p->m_entry[digit] = ZNIL | (firstfree << 16);
495  if (firstfree != ZNIL) {
496  assert(firstfree < Base);
497  map_ptr.p->m_entry[firstfree] &= (ZNIL << 16);
498  map_ptr.p->m_entry[firstfree] |= digit;
499  }
500  map_ptr.p->m_firstfree = digit;
501  map_ptr.p->m_occup--;
502  BitmaskImpl::clear(BitmaskSize, map_ptr.p->m_bitmask, digit);
503  if (map_ptr.p->m_occup + 1 == Base)
504  add_avail(map_ptr);
505  else if (map_ptr.p->m_occup == 0)
506  remove_map(map_ptr);
507 }
508 
509 template <class T, Uint32 LogBase>
510 inline void
512 {
513  assert(map_ptr.p->m_occup == 0);
514  remove_avail(map_ptr);
515  Ptr<Map> parent_ptr;
516  parent_ptr.i = map_ptr.p->m_parent;
517  Uint32 digit = map_ptr.p->m_index & DigitMask;
518  PtrI map_ptr_i = map_ptr.i;
519  m_maps.release(map_ptr);
520  if (m_root == map_ptr_i) {
521  assert(parent_ptr.i == RNIL);
522  Uint32 used = count();
523  assert(used == 0);
524  m_root = RNIL;
525  m_levels = 0;
526  }
527  if (parent_ptr.i != RNIL) {
528  m_maps.getPtr(parent_ptr);
529  // remove child entry (recursive)
530  remove_entry(parent_ptr, digit);
531  }
532 }
533 
534 template <class T, Uint32 LogBase>
535 inline void
537 {
538  Uint32 n = map_ptr.p->m_level;
539  assert(n < m_levels);
540  map_ptr.p->m_nextavail = m_avail[n];
541  if (map_ptr.p->m_nextavail != RNIL) {
542  Ptr<Map> next_ptr;
543  next_ptr.i = map_ptr.p->m_nextavail;
544  m_maps.getPtr(next_ptr);
545  next_ptr.p->m_prevavail = map_ptr.i;
546  }
547  map_ptr.p->m_prevavail = RNIL;
548  m_avail[n] = map_ptr.i;
549 }
550 
551 template <class T, Uint32 LogBase>
552 inline void
554 {
555  Uint32 n = map_ptr.p->m_level;
556  assert(n < m_levels);
557  if (map_ptr.p->m_nextavail != RNIL) {
558  Ptr<Map> next_ptr;
559  next_ptr.i = map_ptr.p->m_nextavail;
560  m_maps.getPtr(next_ptr);
561  next_ptr.p->m_prevavail = map_ptr.p->m_prevavail;
562  }
563  if (map_ptr.p->m_prevavail != RNIL) {
564  Ptr<Map> prev_ptr;
565  prev_ptr.i = map_ptr.p->m_prevavail;
566  m_maps.getPtr(prev_ptr);
567  prev_ptr.p->m_nextavail = map_ptr.p->m_nextavail;
568  }
569  if (map_ptr.p->m_prevavail == RNIL) {
570  m_avail[n] = map_ptr.p->m_nextavail;
571  }
572  map_ptr.p->m_nextavail = RNIL;
573  map_ptr.p->m_prevavail = RNIL;
574 }
575 
576 template <class T, Uint32 LogBase>
577 inline void
579 {
580  // check available lists
581  for (Uint32 n = 0; n < MaxLevels; n++) {
582  Ptr<Map> map_ptr;
583  map_ptr.i = m_avail[n];
584  Uint32 back = RNIL;
585  while (map_ptr.i != RNIL) {
586  m_maps.getPtr(map_ptr);
587  assert(map_ptr.p->m_occup < Base);
588  assert(back == map_ptr.p->m_prevavail);
589  back = map_ptr.i;
590  map_ptr.i = map_ptr.p->m_nextavail;
591  }
592  }
593 }
594 
595 template <class T, Uint32 LogBase>
596 inline void
597 LinearPool<T, LogBase>::verify_map(Ptr<Map> map_ptr, Uint32 level, Uint32* count)
598 {
599  assert(level < MaxLevels);
600  assert(map_ptr.p->m_level == level);
601  // check freelist
602  {
603  Uint32 nused = BitmaskImpl::count(BitmaskSize, map_ptr.p->m_bitmask);
604  assert(nused <= Base);
605  assert(map_ptr.p->m_occup == nused);
606  Uint32 nfree = 0;
607  Uint32 j = map_ptr.p->m_firstfree;
608  Uint16 back = ZNIL;
609  while (j != ZNIL) {
610  assert(j < Base);
611  assert(! BitmaskImpl::get(BitmaskSize, map_ptr.p->m_bitmask, j));
612  Uint32 val = map_ptr.p->m_entry[j];
613  assert(back == (val & ZNIL));
614  back = j;
615  j = (val >> 16);
616  nfree++;
617  }
618  assert(nused + nfree == Base);
619  }
620  // check entries
621  {
622  for (Uint32 j = 0; j < Base; j++) {
623  bool free = ! BitmaskImpl::get(BitmaskSize, map_ptr.p->m_bitmask, j);
624  if (free)
625  continue;
626  if (level != 0) {
627  Ptr<Map> child_ptr;
628  child_ptr.i = map_ptr.p->m_entry[j];
629  m_maps.getPtr(child_ptr);
630  assert(child_ptr.p->m_parent == map_ptr.i);
631  assert(child_ptr.p->m_index == j + (map_ptr.p->m_index << LogBase));
632  verify_map(child_ptr, level - 1, count);
633  } else {
634  Ptr<T> rec_ptr;
635  rec_ptr.i = map_ptr.p->m_entry[j];
636  m_records.getPtr(rec_ptr);
637  (*count)++;
638  }
639  }
640  }
641  // check membership on available list
642  {
643  Ptr<Map> avail_ptr;
644  avail_ptr.i = m_avail[map_ptr.p->m_level];
645  bool found = false;
646  while (avail_ptr.i != RNIL) {
647  if (avail_ptr.i == map_ptr.i) {
648  found = true;
649  break;
650  }
651  m_maps.getPtr(avail_ptr);
652  avail_ptr.i = avail_ptr.p->m_nextavail;
653  }
654  assert(found == (map_ptr.p->m_occup < Base));
655  }
656 }
657 
658 #endif