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