MySQL 8.0.39
Source Code Documentation
storage.h
Go to the documentation of this file.
1/* Copyright (c) 2016, 2024, Oracle and/or its affiliates.
2
3This program is free software; you can redistribute it and/or modify it under
4the terms of the GNU General Public License, version 2.0, as published by the
5Free Software Foundation.
6
7This program is designed to work with certain software (including
8but not limited to OpenSSL) that is licensed under separate terms,
9as designated in a particular file or component or in included license
10documentation. The authors of MySQL hereby grant you an additional
11permission to link the program and your derivative works with the
12separately licensed software that they have either included with
13the program or referenced in the documentation.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
18for more details.
19
20You should have received a copy of the GNU General Public License along with
21this program; if not, write to the Free Software Foundation, Inc.,
2251 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
23
24/** @file storage/temptable/include/temptable/storage.h
25TempTable Storage. */
26
27#ifndef TEMPTABLE_STORAGE_H
28#define TEMPTABLE_STORAGE_H
29
30#include <assert.h>
31#include <cstddef>
32#include <utility>
33
36
37namespace temptable {
38
39/** Storage container. This mimics std::vector and std::deque with the
40 * difference that the size of the objects that are being stored in it can be
41 * determined at runtime. Elements are stored next to each other in a
42 * pre-allocated pages of fixed size `STORAGE_PAGE_SIZE`. */
43class Storage {
44 public:
45 /** Type used for elements. We treat elements as black boxes. */
46 typedef void Element;
47 /** Type used for pages. */
48 typedef void Page;
49
50 /** Iterator over a Storage object. */
51 class Iterator {
52 public:
53 /** Default constructor. This creates a hollow iterator object, that must be
54 * assigned afterwards. */
55 Iterator();
56
57 /** Constructor where the Storage object to iterate over and the starting
58 * position are provided. The iterator is fully initialized after this and
59 * ready for iteration. */
61 /** [in] Storage object to iterate over. */
62 const Storage *storage,
63 /** [in] Initial position of the iterator, must point to an element
64 * inside `storage`. */
65 const Element *element);
66
67 /** Copy-construct from another iterator. */
68 Iterator(const Iterator &) = default;
69
70 /** Dereference the iterator to the element it points to.
71 * @return the element where the iterator is positioned */
72 Element *operator*() const;
73
74 /** Assign a new position within the same Storage object.
75 * @return *this */
77 /** [in] New position for the iterator. */
78 const Element *element);
79
80 /** Copy-assign from another iterator. */
81 Iterator &operator=(const Iterator &) = default;
82
83 /** Compare with another iterator. For two iterators to be equal, they must
84 * be positioned on the same element in the same storage.
85 * @return true if equal */
86 bool operator==(
87 /** [in] Iterator to compare with. */
88 const Iterator &rhs) const;
89
90 /** Compare with another iterator. For two iterators to be equal, they must
91 * be positioned on the same element in the same storage.
92 * @return true if not equal */
93 bool operator!=(
94 /** [in] Iterator to compare with. */
95 const Iterator &rhs) const;
96
97 /** Advance the iterator one element forward. If the iterator points to
98 * end() before this call, then the behavior is undefined.
99 * @return *this */
101
102 /** Recede the iterator one element backwards. If the iterator points to
103 * begin() before this call, then the behavior is undefined.
104 * @return *this */
106
107 private:
108 /** Storage over which the iterator operates. */
110
111 /** Current element. */
113 };
114
115 /** Constructor. */
116 explicit Storage(
117 /** [in,out] Allocator to use for allocating pages. */
118 Allocator<uint8_t> *allocator);
119
120 /** Copy constructing is disabled, too expensive and not necessary. */
121 Storage(const Storage &) = delete;
122
123 /** Copy assignment is disabled, too expensive and not necessary. */
124 Storage &operator=(const Storage &) = delete;
125
126 /** Move constructor. */
127 Storage(
128 /** [in,out] Object whose state to grasp, after this call the state of
129 * `other` is undefined. */
130 Storage &&other);
131
132 /** Move assignment. */
134 /** [in,out] Object whose state to grasp, after this call the state of
135 * `rhs` is undefined. */
136 Storage &&rhs);
137
138 /** Destructor. */
139 ~Storage();
140
141 /** Get an iterator, positioned on the first element.
142 * @return iterator */
143 Iterator begin() const;
144
145 /** Get an iterator, positioned after the last element.
146 * @return iterator */
147 Iterator end() const;
148
149 /** Set the element size. Only allowed if the storage is empty. */
150 void element_size(
151 /** [in] New element size to set, in bytes. */
152 size_t element_size);
153
154 /** Get the element size.
155 * @return element size in bytes. */
156 size_t element_size() const;
157
158 /** Get the number of elements in the storage.
159 * @return number of elements. */
160 size_t size() const;
161
162 /** Get the last element.
163 * @return a pointer to the last element */
164 Element *back();
165
166 /** Allocate space for one more element at the end and return a pointer to it.
167 * This will increase `size()` by one.
168 * @return pointer to the newly created (uninitialized) element */
170
171 /** Destroy the last element. This will decrease `size()` by one. */
172 void deallocate_back();
173
174 /** Delete the element pointed to by `position`. Subsequent or previous
175 * iterators are not invalidated. The memory occupied by the deleted element
176 * is not returned to the underlying allocator.
177 * @return an iterator to the next element (or end() if `position` points to
178 * the last element before this call) */
180 /** [in] Delete element at this position. */
181 const Iterator &position);
182
183 /** Delete all elements in the storage. After this `size()` will be zero. */
184 void clear();
185
186 /** A simple getter. */
187 size_t number_of_elements_per_page() const;
188
189 private:
190 /** Align elements to this number of bytes. */
191 static constexpr size_t ALIGN_TO = alignof(void *);
192
193 /** Flag that denotes an element is the first element on a page. */
194 static constexpr uint8_t ELEMENT_FIRST_ON_PAGE = 0x1;
195
196 /** Flag that denotes an element is the last element on a page. */
197 static constexpr uint8_t ELEMENT_LAST_ON_PAGE = 0x2;
198
199 /** Flag that denotes an element is deleted. Deleted elements are skipped
200 * during iteration. */
201 static constexpr uint8_t ELEMENT_DELETED = 0x4;
202
203 /** Extra bytes per element for element metadata. It must store all ELEMENT_*
204 * bits. */
205 static constexpr size_t META_BYTES_PER_ELEMENT = 1;
206
207 /** Extra bytes per page for page metadata. This stores the previous and next
208 * page pointers. */
209 static constexpr size_t META_BYTES_PER_PAGE = 2 * sizeof(Page *);
210
211 /** Calculate the size of a page. This is usually a little bit less than
212 * `STORAGE_PAGE_SIZE`. For example if `STORAGE_PAGE_SIZE == 100` and our
213 * element size is 10 and we need 4 extra bytes per page, then the calculated
214 * page size will be 94: 9 elements (10 bytes each) and the extra 4 bytes.
215 * @return page size in bytes */
216 size_t page_size() const;
217
218 /** Get a pointer to element's meta byte(s).
219 * @return pointer to meta byte(s) */
220 uint8_t *element_meta(
221 /** [in] Element whose meta byte(s) to get a pointer to. */
222 Element *element) const;
223
224 /** Check if element is the first on its page. If the element is the first,
225 * then the previous page pointer is stored right before that element (and its
226 * meta bytes).
227 * @return true if first */
229 /** [in] Element to check. */
230 Element *element) const;
231
232 /** Set element's first-on-page flag. */
234 /** [in] Flag to set, true if first on page. */
235 bool first_on_page,
236 /** [in,out] Element to modify. */
237 Element *element);
238
239 /** Check if element is the last on its page. If the element is the last,
240 * then the next page pointer is stored right after that element.
241 * @return true if last */
243 /** [in] Element to check. */
244 Element *element) const;
245
246 /** Set element's last-on-page flag. */
248 /** [in] Flag to set, true if last on page. */
249 bool last_on_page,
250 /** [in,out] Element to modify. */
251 Element *element);
252
253 /** Check if element is deleted.
254 * @return true if deleted */
255 bool element_deleted(
256 /** [in] Element to check. */
257 Element *element) const;
258
259 /** Set element's deleted flag. */
260 void element_deleted(
261 /** [in] Flag to set, true if deleted. */
262 bool deleted,
263 /** [in,out] Element to modify. */
264 Element *element);
265
266 /** Get the previous page. Undefined if !element_first_on_page().
267 * @return previous page or nullptr if this is the first page */
269 /** [in] The first element on a page. */
270 Element *first) const;
271
272 /** Get the next page. Undefined if !element_last_on_page().
273 * @return next page or nullptr if this is the last page */
275 /** [in] The last element on a page. */
276 Element *last) const;
277
278 /** Get the previous element of a given element on the same page. Undefined if
279 * this is the first element on the page.
280 * @return pointer to previous element, may be delete-marked */
282 /** [in] Element whose sibling in the page to fetch. */
283 Element *element) const;
284
285 /** Get the next element of a given element on the same page. Undefined if
286 * this is the last element on the page.
287 * @return pointer to next element, may be delete-marked */
289 /** [in] Element whose sibling in the page to fetch. */
290 Element *element) const;
291
292 /** Get the first element of a page.
293 * @return pointer to first element, may be delete-marked */
295 /** [in] Page whose first element to fetch. */
296 Page *page) const;
297
298 /** Get the last possible element of a page (not the last occupied).
299 * @return pointer where the last element would reside if the page is full,
300 * may be delete-marked. */
302 /** [in] Page whose last element to fetch. */
303 Page *page) const;
304
305 /** Get a pointer inside a page to the place denoting the previous page.
306 * @return pointer to the pointer to the previous page */
308 /** [in] Page whose previous to fetch. */
309 Page *page) const;
310
311 /** Get a pointer inside a page to the place denoting the next page.
312 * @return pointer to the pointer to the next page */
314 /** [in] Page whose next to fetch. */
315 Page *page) const;
316
317 /** Allocator to use for allocating new pages. */
319
320 /** Element size in bytes. */
322
323 /** Number of bytes used per element. This accounts for element size,
324 * alignment and our element meta bytes. */
326
327 /** Maximum number of elements a page can store. */
329
330 /** Number of elements in the container. Not counting deleted ones. */
332
333 /** First page of the storage. */
335
336 /** Last page of the storage. */
338
339 /** Last used element in the last page of the storage. The last page may not
340 * be fully occupied, so this may point somewhere in the middle of it. */
342};
343
344/* Implementation of inlined methods. */
345
346inline Storage::Iterator::Iterator() : m_storage(nullptr), m_element(nullptr) {}
347
349 const Element *element)
350 : m_storage(const_cast<Storage *>(storage)),
351 m_element(const_cast<Element *>(element)) {}
352
354 return m_element;
355}
356
358 assert(m_storage != nullptr || element == nullptr);
359 m_element = const_cast<Element *>(element);
360 return *this;
361}
362
363inline bool Storage::Iterator::operator==(const Iterator &rhs) const {
364 return m_element == rhs.m_element;
365}
366
367inline bool Storage::Iterator::operator!=(const Iterator &rhs) const {
368 return !(*this == rhs);
369}
370
372 assert(m_storage != nullptr);
373 assert(*this != m_storage->end());
374
375 do {
376 if (m_storage->element_last_on_page(m_element)) {
377 Page *next_page = *m_storage->element_next_page_ptr(m_element);
378 if (next_page == nullptr) {
379 /* Last element on last page, can't go further. */
380 *this = m_storage->end();
381 return *this;
382 }
383 m_element = m_storage->first_possible_element_on_page(next_page);
384 } else {
385 m_element = m_storage->next_element(m_element);
386 }
387 } while (m_storage->element_deleted(m_element));
388
389 return *this;
390}
391
393 assert(m_storage != nullptr);
394 assert(*this != m_storage->begin());
395
396 /* Since *this != m_storage->begin() there is at least one non-deleted element
397 * preceding our position (ie the one pointed to by begin()). */
398
399 do {
400 if (m_element == nullptr) {
401 m_element = m_storage->back();
402 } else if (m_storage->element_first_on_page(m_element)) {
403 /* Go to the last element on the previous page. */
404 Page *prev_page = *m_storage->element_prev_page_ptr(m_element);
405 assert(prev_page != nullptr);
406 m_element = m_storage->last_possible_element_on_page(prev_page);
407 assert(m_storage->element_last_on_page(m_element));
408 } else {
409 m_element = m_storage->prev_element(m_element);
410 }
411 } while (m_storage->element_deleted(m_element));
412
413 return *this;
414}
415
417 : m_allocator(allocator),
425
427 : m_first_page(nullptr), m_last_page(nullptr), m_last_element(nullptr) {
428 *this = std::move(other);
429}
430
432 assert(m_first_page == nullptr);
433 assert(m_last_page == nullptr);
434 assert(m_last_element == nullptr);
435
436 m_allocator = rhs.m_allocator;
437 rhs.m_allocator = nullptr;
438
439 m_element_size = rhs.m_element_size;
440 rhs.m_element_size = 0;
441
442 m_bytes_used_per_element = rhs.m_bytes_used_per_element;
443 rhs.m_bytes_used_per_element = 0;
444
445 m_number_of_elements_per_page = rhs.m_number_of_elements_per_page;
446 rhs.m_number_of_elements_per_page = 0;
447
448 m_number_of_elements = rhs.m_number_of_elements;
449 rhs.m_number_of_elements = 0;
450
451 m_first_page = rhs.m_first_page;
452 rhs.m_first_page = nullptr;
453
454 m_last_page = rhs.m_last_page;
455 rhs.m_last_page = nullptr;
456
457 m_last_element = rhs.m_last_element;
458 rhs.m_last_element = nullptr;
459
460 return *this;
461}
462
464
466 if (m_number_of_elements == 0) {
467 return end();
468 }
469
470 assert(m_first_page != nullptr);
471
473
474 for (;;) {
475 assert(it != end());
476 if (!element_deleted(*it)) {
477 break;
478 }
479 ++it;
480 }
481
482 return it;
483}
484
486 return Storage::Iterator(this, nullptr);
487}
488
489inline void Storage::element_size(size_t element_size) {
490 assert(m_number_of_elements == 0);
491
493
494 const size_t element_size_plus_meta = element_size + META_BYTES_PER_ELEMENT;
495
496 /* Confirm that ALIGN_TO is a power of 2 (or zero). */
497 assert(ALIGN_TO == 0 || (ALIGN_TO & (ALIGN_TO - 1)) == 0);
498
499 /* The next multiple of ALIGN_TO from element_size_plus_meta. */
501 (element_size_plus_meta + ALIGN_TO - 1) & ~(ALIGN_TO - 1);
502
505}
506
507inline size_t Storage::element_size() const { return m_element_size; }
508
509inline size_t Storage::size() const { return m_number_of_elements; }
510
512
514 if (m_last_page == nullptr) {
515 /* The storage is empty, create the first page. */
516 assert(m_first_page == nullptr);
517
518 m_first_page = m_allocator->allocate(page_size());
519
522
524
526
527#ifndef NDEBUG
529#endif /* NDEBUG */
530
533 /* Last page is full, create a new one. */
534 Page *new_page = m_allocator->allocate(page_size());
535
536 *page_next_page_ptr(m_last_page) = new_page;
537 *page_prev_page_ptr(new_page) = m_last_page;
538 *page_next_page_ptr(new_page) = nullptr;
539
540 m_last_page = new_page;
542
543#ifndef NDEBUG
545#endif /* NDEBUG */
546
548 } else {
550
552
553#ifndef NDEBUG
555#endif /* NDEBUG */
556
558 }
559
561
565
566 return m_last_element;
567}
568
570 assert(m_number_of_elements > 0);
571
573
574 do {
577 } else if (m_first_page == m_last_page) {
578 assert(m_number_of_elements == 0);
579 m_allocator->deallocate(static_cast<uint8_t *>(m_first_page),
580 page_size());
581 m_first_page = nullptr;
582 m_last_page = nullptr;
583 m_last_element = nullptr;
584 return;
585 } else {
586 Page *page_to_free = m_last_page;
587
590
592
593 m_allocator->deallocate(static_cast<uint8_t *>(page_to_free),
594 page_size());
595 }
597
600}
601
603 Iterator next_element_position = position;
604 ++next_element_position;
605
606 if (*position == m_last_element) {
608 } else {
609 assert(m_number_of_elements > 0);
611
612 element_deleted(true, *position);
613 }
614
615 return next_element_position;
616}
617
618inline void Storage::clear() {
619 if (m_first_page == nullptr) {
620 assert(m_number_of_elements == 0);
621 return;
622 }
623
624 if (m_first_page == m_last_page) {
626 } else {
628 do {
630
631 m_allocator->deallocate(static_cast<uint8_t *>(*page_prev_page_ptr(p)),
632 page_size());
633 } while (p != m_last_page);
634 }
635
636 m_allocator->deallocate(static_cast<uint8_t *>(m_last_page), page_size());
637
638 m_first_page = nullptr;
639 m_last_page = nullptr;
641}
642
645}
646
647inline size_t Storage::page_size() const {
648 assert(m_bytes_used_per_element > 0);
650
653}
654
655inline uint8_t *Storage::element_meta(Element *element) const {
656 return static_cast<uint8_t *>(element) + m_element_size;
657}
658
659inline bool Storage::element_first_on_page(Element *element) const {
660 return *element_meta(element) & ELEMENT_FIRST_ON_PAGE;
661}
662
663inline void Storage::element_first_on_page(bool first_on_page,
664 Element *element) {
665 if (first_on_page) {
667 } else {
668 *element_meta(element) &= ~ELEMENT_FIRST_ON_PAGE;
669 }
670}
671
672inline bool Storage::element_last_on_page(Element *element) const {
673 return *element_meta(element) & ELEMENT_LAST_ON_PAGE;
674}
675
676inline void Storage::element_last_on_page(bool last_on_page, Element *element) {
677 if (last_on_page) {
679 } else {
680 *element_meta(element) &= ~ELEMENT_LAST_ON_PAGE;
681 }
682}
683
684inline bool Storage::element_deleted(Element *element) const {
685 return *element_meta(element) & ELEMENT_DELETED;
686}
687
688inline void Storage::element_deleted(bool deleted, Element *element) {
689 if (deleted) {
690 *element_meta(element) |= ELEMENT_DELETED;
691 } else {
692 *element_meta(element) &= ~ELEMENT_DELETED;
693 }
694}
695
697 assert(element_first_on_page(element));
698 return reinterpret_cast<Page **>(static_cast<uint8_t *>(element) -
699 sizeof(Page *));
700}
701
703 assert(element_last_on_page(element));
704 return reinterpret_cast<Page **>(static_cast<uint8_t *>(element) +
706}
707
709 assert(element != nullptr);
710 assert(!element_first_on_page(element));
711 return static_cast<uint8_t *>(element) - m_bytes_used_per_element;
712}
713
715 assert(element != nullptr);
716 assert(!element_last_on_page(element));
717 return static_cast<uint8_t *>(element) + m_bytes_used_per_element;
718}
719
721 Page *page) const {
722 assert(page != nullptr);
723 return static_cast<uint8_t *>(page) + sizeof(Page *);
724}
725
727 Page *page) const {
728 assert(page != nullptr);
729 return static_cast<uint8_t *>(page) + sizeof(Page *) +
731}
732
734 assert(page != nullptr);
735 return reinterpret_cast<Page **>(page);
736}
737
739 assert(page != nullptr);
740 /* The sizeof(Page*) bytes just after the last element (and its meta byte(s)
741 * and padding). */
742 return reinterpret_cast<Page **>(
743 static_cast<uint8_t *>(page) + sizeof(Page *) +
745}
746
747} /* namespace temptable */
748
749#endif /* TEMPTABLE_STORAGE_H */
Custom memory allocator.
Definition: allocator.h:477
Iterator over a Storage object.
Definition: storage.h:51
bool operator!=(const Iterator &rhs) const
Compare with another iterator.
Definition: storage.h:367
Element * m_element
Current element.
Definition: storage.h:112
Iterator(const Iterator &)=default
Copy-construct from another iterator.
Iterator & operator++()
Advance the iterator one element forward.
Definition: storage.h:371
Iterator()
Default constructor.
Definition: storage.h:346
Iterator & operator=(const Iterator &)=default
Copy-assign from another iterator.
Element * operator*() const
Dereference the iterator to the element it points to.
Definition: storage.h:353
bool operator==(const Iterator &rhs) const
Compare with another iterator.
Definition: storage.h:363
Storage * m_storage
Storage over which the iterator operates.
Definition: storage.h:109
Iterator & operator--()
Recede the iterator one element backwards.
Definition: storage.h:392
Iterator & operator=(const Element *element)
Assign a new position within the same Storage object.
Definition: storage.h:357
Storage container.
Definition: storage.h:43
Element * back()
Get the last element.
Definition: storage.h:511
Allocator< uint8_t > * m_allocator
Allocator to use for allocating new pages.
Definition: storage.h:318
void Page
Type used for pages.
Definition: storage.h:48
size_t element_size() const
Get the element size.
Definition: storage.h:507
size_t page_size() const
Calculate the size of a page.
Definition: storage.h:647
Storage(const Storage &)=delete
Copy constructing is disabled, too expensive and not necessary.
Page ** element_prev_page_ptr(Element *first) const
Get the previous page.
Definition: storage.h:696
static constexpr uint8_t ELEMENT_LAST_ON_PAGE
Flag that denotes an element is the last element on a page.
Definition: storage.h:197
Element * m_last_element
Last used element in the last page of the storage.
Definition: storage.h:341
Element * last_possible_element_on_page(Page *page) const
Get the last possible element of a page (not the last occupied).
Definition: storage.h:726
Iterator end() const
Get an iterator, positioned after the last element.
Definition: storage.h:485
size_t size() const
Get the number of elements in the storage.
Definition: storage.h:509
size_t m_number_of_elements_per_page
Maximum number of elements a page can store.
Definition: storage.h:328
Page * m_last_page
Last page of the storage.
Definition: storage.h:337
bool element_last_on_page(Element *element) const
Check if element is the last on its page.
Definition: storage.h:672
Iterator begin() const
Get an iterator, positioned on the first element.
Definition: storage.h:465
size_t number_of_elements_per_page() const
A simple getter.
Definition: storage.h:643
Page ** page_next_page_ptr(Page *page) const
Get a pointer inside a page to the place denoting the next page.
Definition: storage.h:738
Element * next_element(Element *element) const
Get the next element of a given element on the same page.
Definition: storage.h:714
Page * m_first_page
First page of the storage.
Definition: storage.h:334
Element * allocate_back()
Allocate space for one more element at the end and return a pointer to it.
Definition: storage.h:513
static constexpr size_t ALIGN_TO
Align elements to this number of bytes.
Definition: storage.h:191
size_t m_bytes_used_per_element
Number of bytes used per element.
Definition: storage.h:325
void clear()
Delete all elements in the storage.
Definition: storage.h:618
static constexpr uint8_t ELEMENT_DELETED
Flag that denotes an element is deleted.
Definition: storage.h:201
Element * first_possible_element_on_page(Page *page) const
Get the first element of a page.
Definition: storage.h:720
Storage(Allocator< uint8_t > *allocator)
Constructor.
Definition: storage.h:416
static constexpr size_t META_BYTES_PER_ELEMENT
Extra bytes per element for element metadata.
Definition: storage.h:205
Page ** page_prev_page_ptr(Page *page) const
Get a pointer inside a page to the place denoting the previous page.
Definition: storage.h:733
bool element_first_on_page(Element *element) const
Check if element is the first on its page.
Definition: storage.h:659
size_t m_element_size
Element size in bytes.
Definition: storage.h:321
Storage & operator=(const Storage &)=delete
Copy assignment is disabled, too expensive and not necessary.
static constexpr size_t META_BYTES_PER_PAGE
Extra bytes per page for page metadata.
Definition: storage.h:209
~Storage()
Destructor.
Definition: storage.h:463
Iterator erase(const Iterator &position)
Delete the element pointed to by position.
Definition: storage.h:602
static constexpr uint8_t ELEMENT_FIRST_ON_PAGE
Flag that denotes an element is the first element on a page.
Definition: storage.h:194
bool element_deleted(Element *element) const
Check if element is deleted.
Definition: storage.h:684
void Element
Type used for elements.
Definition: storage.h:46
uint8_t * element_meta(Element *element) const
Get a pointer to element's meta byte(s).
Definition: storage.h:655
Page ** element_next_page_ptr(Element *last) const
Get the next page.
Definition: storage.h:702
void deallocate_back()
Destroy the last element.
Definition: storage.h:569
size_t m_number_of_elements
Number of elements in the container.
Definition: storage.h:331
Element * prev_element(Element *element) const
Get the previous element of a given element on the same page.
Definition: storage.h:708
const char * p
Definition: ctype-mb.cc:1237
int page
Definition: ctype-mb.cc:1236
Fido Client Authentication nullptr
Definition: fido_client_plugin.cc:222
Definition: allocator.h:45
constexpr size_t STORAGE_PAGE_SIZE
Storage page size.
Definition: constants.h:69
TempTable custom allocator.
TempTable constants.