1
/* Copyright (C) 2003 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
#ifndef LINEAR_POOL_HPP
17
#define LINEAR_POOL_HPP
19
#include <Bitmask.hpp>
20
#include "SuperPool.hpp"
23
* LinearPool - indexed record pool
25
* LinearPool implements a pool where each record has a 0-based index.
26
* Any index value (up to 2^32-1) is allowed. Normal efficient usage is
27
* to assign index values in sequence and to re-use any values which
28
* have become free. This is default seize/release behaviour.
30
* LinearPool has 2 internal RecordPool instances:
32
* (a) record pool of T (the template argument class)
33
* (b) record pool of "maps" (array of Uint32)
35
* The maps translate an index into an i-value in (a). Each map has
36
* a level. Level 0 maps point to i-values. Level N+1 maps point to
37
* level N maps. There is a unique "root map" at top.
39
* This works exactly like numbers in a given base. Each map has base
40
* size entries. For implementation convenience the base must be power
41
* of 2 between 2^1 and 2^15. It is given by its log2 value (1-15).
43
* A position in a map is also called a "digit".
45
* There is a doubly linked list of available maps (some free entries)
46
* on each level. There is a doubly linked freelist within each map.
47
* There is also a bitmask of used entries in each map.
49
* Level 0 free entry has space for one record. Level N free entry
50
* implies space for base^N records. The implied levels are created and
51
* removed on demand. Empty maps are usually removed.
53
* Default base is 256 (log2 = 8) which requires maximum 4 levels or
54
* digits (similar to ip address).
58
* - move most of the inline code to LinearPool.cpp
59
* - optimize for common case
60
* - add optimized 2-level implementation (?)
63
#include "SuperPool.hpp"
65
template <class T, Uint32 LogBase = 8>
67
typedef SuperPool::PtrI PtrI;
70
STATIC_CONST( Base = 1 << LogBase );
73
STATIC_CONST( DigitMask = Base - 1 );
75
// Max possible levels (0 to max root level).
76
STATIC_CONST( MaxLevels = (32 + LogBase - 1) / LogBase );
78
// Number of words in map used bit mask.
79
STATIC_CONST( BitmaskSize = (Base + 31) / 32 );
84
Uint32 m_occup; // number of used entries
85
Uint32 m_firstfree; // position of first free entry
86
PtrI m_parent; // parent map
87
Uint32 m_index; // from root to here
90
Uint32 m_bitmask[BitmaskSize];
97
LinearPool(GroupPool& gp);
102
// Update pointer ptr.p according to index value ptr.i.
103
void getPtr(Ptr<T>& ptr);
105
// Allocate record from the pool. Reuses free index if possible.
106
bool seize(Ptr<T>& ptr);
108
// Allocate given index. Like seize but returns -1 if in use.
109
int seize_index(Ptr<T>& ptr, Uint32 index);
111
// Return record to the pool.
112
void release(Ptr<T>& ptr);
114
// Return number of used records (may require 1 page scan).
117
// Verify (debugging).
122
// Given index find the bottom map.
123
void get_map(Ptr<Map>& map_ptr, Uint32 index);
125
// Add new root map and increase level
128
// Add new non-root map.
129
bool add_map(Ptr<Map>& map_ptr, Ptr<Map> parent_ptr, Uint32 digit);
131
// Subroutine to initialize map free lists.
132
void init_free(Ptr<Map> map_ptr);
134
// Add entry at given free position.
135
void add_entry(Ptr<Map> map_ptr, Uint32 digit, PtrI ptr_i);
137
// Remove entry and map if it becomes empty.
138
void remove_entry(Ptr<Map> map_ptr, Uint32 digit);
140
// Remove map and all parents which become empty.
141
void remove_map(Ptr<Map> map_ptr);
143
// Add map to available list.
144
void add_avail(Ptr<Map> map_ptr);
146
// Remove map from available list.
147
void remove_avail(Ptr<Map> map_ptr);
149
// Verify available lists
152
// Verify map (recursive).
153
void verify_map(Ptr<Map> map_ptr, Uint32 level, Uint32* count);
155
RecordPool<T> m_records;
156
RecordPool<Map> m_maps;
157
Uint32 m_levels; // 0 means empty pool
159
PtrI m_avail[MaxLevels];
162
template <class T, Uint32 LogBase>
164
LinearPool<T, LogBase>::LinearPool(GroupPool& gp) :
171
for (n = 0; n < MaxLevels; n++)
175
template <class T, Uint32 LogBase>
177
LinearPool<T, LogBase>::~LinearPool()
181
template <class T, Uint32 LogBase>
183
LinearPool<T, LogBase>::getPtr(Ptr<T>& ptr)
185
Uint32 index = ptr.i;
188
get_map(map_ptr, index);
191
Uint32 digit = index & DigitMask;
192
assert(BitmaskImpl::get(BitmaskSize, map_ptr.p->m_bitmask, digit));
193
rec_ptr.i = map_ptr.p->m_entry[digit];
194
m_records.getPtr(rec_ptr);
198
template <class T, Uint32 LogBase>
200
LinearPool<T, LogBase>::seize(Ptr<T>& ptr)
202
// look for free list on some level
206
while (n < m_levels) {
207
if ((map_ptr.i = m_avail[n]) != RNIL)
211
if (map_ptr.i == RNIL) {
212
// add new level with available maps
215
assert(n < m_levels);
216
map_ptr.i = m_avail[n];
218
m_maps.getPtr(map_ptr);
219
// walk down creating missing levels and using an entry on each
224
digit = map_ptr.p->m_firstfree;
228
if (! add_map(child_ptr, map_ptr, digit)) {
229
if (new_ptr.i != RNIL)
238
assert(map_ptr.p->m_level == 0);
240
if (! m_records.seize(rec_ptr)) {
241
if (new_ptr.i != RNIL)
245
add_entry(map_ptr, digit, rec_ptr.i);
246
ptr.i = digit + (map_ptr.p->m_index << LogBase);
251
template <class T, Uint32 LogBase>
253
LinearPool<T, LogBase>::seize_index(Ptr<T>& ptr, Uint32 index)
255
// extract all digits at least up to current root level
256
Uint32 digits[MaxLevels];
260
digits[n] = tmp & DigitMask;
262
} while (++n < m_levels || tmp != 0);
263
// add any new root levels
264
while (n > m_levels) {
271
m_maps.getPtr(map_ptr);
272
// walk down creating or re-using existing levels
279
used = BitmaskImpl::get(BitmaskSize, map_ptr.p->m_bitmask, digit);
283
map_ptr.i = map_ptr.p->m_entry[digit];
284
m_maps.getPtr(map_ptr);
287
if (! add_map(child_ptr, map_ptr, digit)) {
288
if (new_ptr.i != RNIL)
296
assert(map_ptr.p->m_level == 0);
298
if (used || ! m_records.seize(rec_ptr)) {
299
if (new_ptr.i != RNIL)
301
return used ? -1 : false;
303
add_entry(map_ptr, digit, rec_ptr.i);
304
assert(index == digit + (map_ptr.p->m_index << LogBase));
310
template <class T, Uint32 LogBase>
312
LinearPool<T, LogBase>::release(Ptr<T>& ptr)
314
Uint32 index = ptr.i;
317
get_map(map_ptr, index);
320
Uint32 digit = index & DigitMask;
321
rec_ptr.i = map_ptr.p->m_entry[digit];
322
m_records.release(rec_ptr);
324
remove_entry(map_ptr, digit);
330
template <class T, Uint32 LogBase>
332
LinearPool<T, LogBase>::count()
334
SuperPool& sp = m_records.m_superPool;
335
Uint32 count1 = sp.getRecUseCount(m_records.m_recInfo);
339
template <class T, Uint32 LogBase>
341
LinearPool<T, LogBase>::verify()
344
if (m_root == RNIL) {
345
assert(m_levels == 0);
348
assert(m_levels != 0);
351
m_maps.getPtr(map_ptr);
352
Uint32 count1 = count();
354
verify_map(map_ptr, m_levels - 1, &count2);
355
assert(count1 == count2);
360
template <class T, Uint32 LogBase>
362
LinearPool<T, LogBase>::get_map(Ptr<Map>& map_ptr, Uint32 index)
364
// root map must exist
367
m_maps.getPtr(tmp_ptr);
368
assert(tmp_ptr.p->m_level + 1 == m_levels);
369
// extract index digits up to current root level
370
Uint32 digits[MaxLevels];
373
digits[n] = index & DigitMask;
375
} while (++n < m_levels);
377
// walk down indirect levels
379
tmp_ptr.i = tmp_ptr.p->m_entry[digits[n]];
380
m_maps.getPtr(tmp_ptr);
383
assert(tmp_ptr.p->m_level == 0);
387
template <class T, Uint32 LogBase>
389
LinearPool<T, LogBase>::add_root()
393
if (! m_maps.seize(map_ptr))
395
Uint32 n = m_levels++;
396
assert(n < MaxLevels);
398
map_ptr.p->m_level = n;
399
map_ptr.p->m_parent = RNIL;
400
map_ptr.p->m_index = 0;
402
// on level > 0 digit 0 points to old root
406
m_maps.getPtr(old_ptr);
407
assert(old_ptr.p->m_parent == RNIL);
408
old_ptr.p->m_parent = map_ptr.i;
409
add_entry(map_ptr, 0, old_ptr.i);
416
template <class T, Uint32 LogBase>
418
LinearPool<T, LogBase>::add_map(Ptr<Map>& map_ptr, Ptr<Map> parent_ptr, Uint32 digit)
420
if (! m_maps.seize(map_ptr))
422
assert(parent_ptr.p->m_level != 0);
424
map_ptr.p->m_level = parent_ptr.p->m_level - 1;
425
map_ptr.p->m_parent = parent_ptr.i;
426
map_ptr.p->m_index = digit + (parent_ptr.p->m_index << LogBase);
428
add_entry(parent_ptr, digit, map_ptr.i);
432
template <class T, Uint32 LogBase>
434
LinearPool<T, LogBase>::init_free(Ptr<Map> map_ptr)
436
map_ptr.p->m_occup = 0;
437
map_ptr.p->m_firstfree = 0;
441
for (j = 0; j < Base - 1; j++) {
442
map_ptr.p->m_entry[j] = back | ((j + 1) << 16);
445
map_ptr.p->m_entry[j] = back | (ZNIL << 16);
447
BitmaskImpl::clear(BitmaskSize, map_ptr.p->m_bitmask);
452
template <class T, Uint32 LogBase>
454
LinearPool<T, LogBase>::add_entry(Ptr<Map> map_ptr, Uint32 digit, PtrI ptr_i)
456
assert(map_ptr.p->m_occup < Base && digit < Base);
457
assert(! BitmaskImpl::get(BitmaskSize, map_ptr.p->m_bitmask, digit));
458
// unlink from freelist
459
Uint32 val = map_ptr.p->m_entry[digit];
460
Uint16 back = val & ZNIL;
461
Uint16 forw = val >> 16;
464
map_ptr.p->m_entry[back] &= ZNIL;
465
map_ptr.p->m_entry[back] |= (forw << 16);
469
map_ptr.p->m_entry[forw] &= (ZNIL << 16);
470
map_ptr.p->m_entry[forw] |= back;
473
map_ptr.p->m_firstfree = forw;
476
map_ptr.p->m_entry[digit] = ptr_i;
477
map_ptr.p->m_occup++;
478
BitmaskImpl::set(BitmaskSize, map_ptr.p->m_bitmask, digit);
479
if (map_ptr.p->m_occup == Base)
480
remove_avail(map_ptr);
483
template <class T, Uint32 LogBase>
485
LinearPool<T, LogBase>::remove_entry(Ptr<Map> map_ptr, Uint32 digit)
487
assert(map_ptr.p->m_occup != 0 && digit < Base);
488
assert(BitmaskImpl::get(BitmaskSize, map_ptr.p->m_bitmask, digit));
490
Uint32 firstfree = map_ptr.p->m_firstfree;
491
map_ptr.p->m_entry[digit] = ZNIL | (firstfree << 16);
492
if (firstfree != ZNIL) {
493
assert(firstfree < Base);
494
map_ptr.p->m_entry[firstfree] &= (ZNIL << 16);
495
map_ptr.p->m_entry[firstfree] |= digit;
497
map_ptr.p->m_firstfree = digit;
498
map_ptr.p->m_occup--;
499
BitmaskImpl::clear(BitmaskSize, map_ptr.p->m_bitmask, digit);
500
if (map_ptr.p->m_occup + 1 == Base)
502
else if (map_ptr.p->m_occup == 0)
506
template <class T, Uint32 LogBase>
508
LinearPool<T, LogBase>::remove_map(Ptr<Map> map_ptr)
510
assert(map_ptr.p->m_occup == 0);
511
remove_avail(map_ptr);
513
parent_ptr.i = map_ptr.p->m_parent;
514
Uint32 digit = map_ptr.p->m_index & DigitMask;
515
PtrI map_ptr_i = map_ptr.i;
516
m_maps.release(map_ptr);
517
if (m_root == map_ptr_i) {
518
assert(parent_ptr.i == RNIL);
519
Uint32 used = count();
524
if (parent_ptr.i != RNIL) {
525
m_maps.getPtr(parent_ptr);
526
// remove child entry (recursive)
527
remove_entry(parent_ptr, digit);
531
template <class T, Uint32 LogBase>
533
LinearPool<T, LogBase>::add_avail(Ptr<Map> map_ptr)
535
Uint32 n = map_ptr.p->m_level;
536
assert(n < m_levels);
537
map_ptr.p->m_nextavail = m_avail[n];
538
if (map_ptr.p->m_nextavail != RNIL) {
540
next_ptr.i = map_ptr.p->m_nextavail;
541
m_maps.getPtr(next_ptr);
542
next_ptr.p->m_prevavail = map_ptr.i;
544
map_ptr.p->m_prevavail = RNIL;
545
m_avail[n] = map_ptr.i;
548
template <class T, Uint32 LogBase>
550
LinearPool<T, LogBase>::remove_avail(Ptr<Map> map_ptr)
552
Uint32 n = map_ptr.p->m_level;
553
assert(n < m_levels);
554
if (map_ptr.p->m_nextavail != RNIL) {
556
next_ptr.i = map_ptr.p->m_nextavail;
557
m_maps.getPtr(next_ptr);
558
next_ptr.p->m_prevavail = map_ptr.p->m_prevavail;
560
if (map_ptr.p->m_prevavail != RNIL) {
562
prev_ptr.i = map_ptr.p->m_prevavail;
563
m_maps.getPtr(prev_ptr);
564
prev_ptr.p->m_nextavail = map_ptr.p->m_nextavail;
566
if (map_ptr.p->m_prevavail == RNIL) {
567
m_avail[n] = map_ptr.p->m_nextavail;
569
map_ptr.p->m_nextavail = RNIL;
570
map_ptr.p->m_prevavail = RNIL;
573
template <class T, Uint32 LogBase>
575
LinearPool<T, LogBase>::verify_avail()
577
// check available lists
578
for (Uint32 n = 0; n < MaxLevels; n++) {
580
map_ptr.i = m_avail[n];
582
while (map_ptr.i != RNIL) {
583
m_maps.getPtr(map_ptr);
584
assert(map_ptr.p->m_occup < Base);
585
assert(back == map_ptr.p->m_prevavail);
587
map_ptr.i = map_ptr.p->m_nextavail;
592
template <class T, Uint32 LogBase>
594
LinearPool<T, LogBase>::verify_map(Ptr<Map> map_ptr, Uint32 level, Uint32* count)
596
assert(level < MaxLevels);
597
assert(map_ptr.p->m_level == level);
600
Uint32 nused = BitmaskImpl::count(BitmaskSize, map_ptr.p->m_bitmask);
601
assert(nused <= Base);
602
assert(map_ptr.p->m_occup == nused);
604
Uint32 j = map_ptr.p->m_firstfree;
608
assert(! BitmaskImpl::get(BitmaskSize, map_ptr.p->m_bitmask, j));
609
Uint32 val = map_ptr.p->m_entry[j];
610
assert(back == (val & ZNIL));
615
assert(nused + nfree == Base);
619
for (Uint32 j = 0; j < Base; j++) {
620
bool free = ! BitmaskImpl::get(BitmaskSize, map_ptr.p->m_bitmask, j);
625
child_ptr.i = map_ptr.p->m_entry[j];
626
m_maps.getPtr(child_ptr);
627
assert(child_ptr.p->m_parent == map_ptr.i);
628
assert(child_ptr.p->m_index == j + (map_ptr.p->m_index << LogBase));
629
verify_map(child_ptr, level - 1, count);
632
rec_ptr.i = map_ptr.p->m_entry[j];
633
m_records.getPtr(rec_ptr);
638
// check membership on available list
641
avail_ptr.i = m_avail[map_ptr.p->m_level];
643
while (avail_ptr.i != RNIL) {
644
if (avail_ptr.i == map_ptr.i) {
648
m_maps.getPtr(avail_ptr);
649
avail_ptr.i = avail_ptr.p->m_nextavail;
651
assert(found == (map_ptr.p->m_occup < Base));