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