1 /*****************************************************************************
2
3 Copyright (c) 2014, 2020, Oracle and/or its affiliates. All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License, version 2.0, as published by the
7 Free Software Foundation.
8
9 This program is also distributed with certain software (including but not
10 limited to OpenSSL) that is licensed under separate terms, as designated in a
11 particular file or component or in included license documentation. The authors
12 of MySQL hereby grant you an additional permission to link the program and
13 your derivative works with the separately licensed software that they have
14 included with MySQL.
15
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
19 for more details.
20
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
25 *****************************************************************************/
26
27 /** @file include/ut0new.h
28 Instrumented memory allocator.
29
30 Created May 26, 2014 Vasil Dimov
31 *******************************************************/
32
33 /** Dynamic memory allocation within InnoDB guidelines.
34 All dynamic (heap) memory allocations (malloc(3), strdup(3), etc, "new",
35 various std:: containers that allocate memory internally), that are done
36 within InnoDB are instrumented. This means that InnoDB uses a custom set
37 of functions for allocating memory, rather than calling e.g. "new" directly.
38
39 Here follows a cheat sheet on what InnoDB functions to use whenever a
40 standard one would have been used.
41
42 Creating new objects with "new":
43 --------------------------------
44 Standard:
45 new expression
46 or
47 new(std::nothrow) expression
48 InnoDB, default instrumentation:
49 UT_NEW_NOKEY(expression)
50 InnoDB, custom instrumentation, preferred:
51 UT_NEW(expression, key)
52
53 Destroying objects, created with "new":
54 ---------------------------------------
55 Standard:
56 delete ptr
57 InnoDB:
58 UT_DELETE(ptr)
59
60 Creating new arrays with "new[]":
61 ---------------------------------
62 Standard:
63 new type[num]
64 or
65 new(std::nothrow) type[num]
66 InnoDB, default instrumentation:
67 UT_NEW_ARRAY_NOKEY(type, num)
68 InnoDB, custom instrumentation, preferred:
69 UT_NEW_ARRAY(type, num, key)
70
71 Destroying arrays, created with "new[]":
72 ----------------------------------------
73 Standard:
74 delete[] ptr
75 InnoDB:
76 UT_DELETE_ARRAY(ptr)
77
78 Declaring a type with a std:: container, e.g. std::vector:
79 ----------------------------------------------------------
80 Standard:
81 std::vector<t>
82 InnoDB:
83 std::vector<t, ut_allocator<t> >
84
85 Declaring objects of some std:: type:
86 -------------------------------------
87 Standard:
88 std::vector<t> v
89 InnoDB, default instrumentation:
90 std::vector<t, ut_allocator<t> > v
91 InnoDB, custom instrumentation, preferred:
92 std::vector<t, ut_allocator<t> > v(ut_allocator<t>(key))
93
94 Raw block allocation (as usual in C++, consider whether using "new" would
95 not be more appropriate):
96 -------------------------------------------------------------------------
97 Standard:
98 malloc(num)
99 InnoDB, default instrumentation:
100 ut_malloc_nokey(num)
101 InnoDB, custom instrumentation, preferred:
102 ut_malloc(num, key)
103
104 Raw block resize:
105 -----------------
106 Standard:
107 realloc(ptr, new_size)
108 InnoDB:
109 ut_realloc(ptr, new_size)
110
111 Raw block deallocation:
112 -----------------------
113 Standard:
114 free(ptr)
115 InnoDB:
116 ut_free(ptr)
117
118 Note: the expression passed to UT_NEW() or UT_NEW_NOKEY() must always end
119 with (), thus:
120 Standard:
121 new int
122 InnoDB:
123 UT_NEW_NOKEY(int())
124 */
125
126 #ifndef ut0new_h
127 #define ut0new_h
128
129 #include <algorithm>
130 #include <cerrno>
131 #include <cstddef>
132 #include <cstdlib>
133 #include <cstring>
134 #include <limits>
135 #include <map>
136 #include <type_traits> /* std::is_trivially_default_constructible */
137
138 #include "my_basename.h"
139 #include "mysql/psi/mysql_memory.h"
140 #include "mysql/psi/psi_base.h"
141 #include "mysql/psi/psi_memory.h"
142
143 #include "os0proc.h"
144 #include "os0thread.h"
145 #include "univ.i"
146 #include "ut0byte.h" /* ut_align */
147 #include "ut0cpu_cache.h"
148 #include "ut0ut.h"
149
150 #define OUT_OF_MEMORY_MSG \
151 "Check if you should increase the swap file or ulimits of your" \
152 " operating system. Note that on most 32-bit computers the process" \
153 " memory space is limited to 2 GB or 4 GB."
154
155 /** Maximum number of retries to allocate memory. */
156 extern const size_t alloc_max_retries;
157
158 /** Keys for registering allocations with performance schema.
159 Pointers to these variables are supplied to PFS code via the pfs_info[]
160 array and the PFS code initializes them via PSI_MEMORY_CALL(register_memory)().
161 mem_key_other and mem_key_std are special in the following way.
162 * If the caller has not provided a key and the file name of the caller is
163 unknown, then mem_key_std will be used. This happens only when called from
164 within std::* containers.
165 * If the caller has not provided a key and the file name of the caller is
166 known, but is not amongst the predefined names (see ut_new_boot()) then
167 mem_key_other will be used. Generally this should not happen and if it
168 happens then that means that the list of predefined names must be extended.
169 Keep this list alphabetically sorted. */
170 extern PSI_memory_key mem_key_ahi;
171 extern PSI_memory_key mem_key_archive;
172 extern PSI_memory_key mem_key_buf_buf_pool;
173 extern PSI_memory_key mem_key_buf_stat_per_index_t;
174 /** Memory key for clone */
175 extern PSI_memory_key mem_key_clone;
176 extern PSI_memory_key mem_key_dict_stats_bg_recalc_pool_t;
177 extern PSI_memory_key mem_key_dict_stats_index_map_t;
178 extern PSI_memory_key mem_key_dict_stats_n_diff_on_level;
179 extern PSI_memory_key mem_key_redo_log_archive_queue_element;
180 extern PSI_memory_key mem_key_other;
181 extern PSI_memory_key mem_key_partitioning;
182 extern PSI_memory_key mem_key_row_log_buf;
183 extern PSI_memory_key mem_key_row_merge_sort;
184 extern PSI_memory_key mem_key_std;
185 extern PSI_memory_key mem_key_trx_sys_t_rw_trx_ids;
186 extern PSI_memory_key mem_key_undo_spaces;
187 extern PSI_memory_key mem_key_ut_lock_free_hash_t;
188 /* Please obey alphabetical order in the definitions above. */
189
190 /** Setup the internal objects needed for UT_NEW() to operate.
191 This must be called before the first call to UT_NEW(). */
192 void ut_new_boot();
193
194 /** Setup the internal objects needed for UT_NEW() to operate.
195 This must be called before the first call to UT_NEW(). This
196 version of function might be called several times and it will
197 simply skip all calls except the first one, during which the
198 initialization will happen. */
199 void ut_new_boot_safe();
200
201 #ifdef UNIV_PFS_MEMORY
202
203 /** List of filenames that allocate memory and are instrumented via PFS. */
204 static constexpr const char *auto_event_names[] = {
205 /* Keep this list alphabetically sorted. */
206 "api0api",
207 "api0misc",
208 "btr0btr",
209 "btr0bulk",
210 "btr0cur",
211 "btr0pcur",
212 "btr0sea",
213 "btr0types",
214 "buf",
215 "buf0buddy",
216 "buf0buf",
217 "buf0checksum",
218 "buf0dblwr",
219 "buf0dump",
220 "buf0flu",
221 "buf0lru",
222 "buf0rea",
223 "buf0stats",
224 "buf0types",
225 "checksum",
226 "crc32",
227 "create",
228 "data0data",
229 "data0type",
230 "data0types",
231 "db0err",
232 "dict",
233 "dict0boot",
234 "dict0crea",
235 "dict0dd",
236 "dict0dict",
237 "dict0load",
238 "dict0mem",
239 "dict0priv",
240 "dict0sdi",
241 "dict0stats",
242 "dict0stats_bg",
243 "dict0types",
244 "dyn0buf",
245 "dyn0types",
246 "eval0eval",
247 "eval0proc",
248 "fil0fil",
249 "fil0types",
250 "file",
251 "fsp0file",
252 "fsp0fsp",
253 "fsp0space",
254 "fsp0sysspace",
255 "fsp0types",
256 "fts0ast",
257 "fts0blex",
258 "fts0config",
259 "fts0fts",
260 "fts0opt",
261 "fts0pars",
262 "fts0plugin",
263 "fts0priv",
264 "fts0que",
265 "fts0sql",
266 "fts0tlex",
267 "fts0tokenize",
268 "fts0types",
269 "fts0vlc",
270 "fut0fut",
271 "fut0lst",
272 "gis0geo",
273 "gis0rtree",
274 "gis0sea",
275 "gis0type",
276 "ha0ha",
277 "ha0storage",
278 "ha_innodb",
279 "ha_innopart",
280 "ha_prototypes",
281 "handler0alter",
282 "hash0hash",
283 "i_s",
284 "ib0mutex",
285 "ibuf0ibuf",
286 "ibuf0types",
287 "lexyy",
288 "lob0lob",
289 "lock0iter",
290 "lock0lock",
291 "lock0prdt",
292 "lock0priv",
293 "lock0types",
294 "lock0wait",
295 "log0log",
296 "log0recv",
297 "log0write",
298 "mach0data",
299 "mem",
300 "mem0mem",
301 "memory",
302 "mtr0log",
303 "mtr0mtr",
304 "mtr0types",
305 "os0atomic",
306 "os0event",
307 "os0file",
308 "os0numa",
309 "os0once",
310 "os0proc",
311 "os0thread",
312 "page",
313 "page0cur",
314 "page0page",
315 "page0size",
316 "page0types",
317 "page0zip",
318 "pars0grm",
319 "pars0lex",
320 "pars0opt",
321 "pars0pars",
322 "pars0sym",
323 "pars0types",
324 "que0que",
325 "que0types",
326 "read0read",
327 "read0types",
328 "rec",
329 "rem0cmp",
330 "rem0rec",
331 "rem0types",
332 "row0ext",
333 "row0ftsort",
334 "row0import",
335 "row0ins",
336 "row0log",
337 "row0merge",
338 "row0mysql",
339 "row0purge",
340 "row0quiesce",
341 "row0row",
342 "row0sel",
343 "row0types",
344 "row0uins",
345 "row0umod",
346 "row0undo",
347 "row0upd",
348 "row0vers",
349 "sess0sess",
350 "srv0conc",
351 "srv0mon",
352 "srv0srv",
353 "srv0start",
354 "srv0tmp",
355 "sync0arr",
356 "sync0debug",
357 "sync0policy",
358 "sync0sharded_rw",
359 "sync0rw",
360 "sync0sync",
361 "sync0types",
362 "trx0i_s",
363 "trx0purge",
364 "trx0rec",
365 "trx0roll",
366 "trx0rseg",
367 "trx0sys",
368 "trx0trx",
369 "trx0types",
370 "trx0undo",
371 "trx0xa",
372 "usr0sess",
373 "usr0types",
374 "ut",
375 "ut0byte",
376 "ut0counter",
377 "ut0crc32",
378 "ut0dbg",
379 "ut0link_buf",
380 "ut0list",
381 "ut0lock_free_hash",
382 "ut0lst",
383 "ut0mem",
384 "ut0mutex",
385 "ut0new",
386 "ut0pool",
387 "ut0rbt",
388 "ut0rnd",
389 "ut0sort",
390 "ut0stage",
391 "ut0ut",
392 "ut0vec",
393 "ut0wqueue",
394 "zipdecompress",
395 };
396
397 static constexpr size_t n_auto = UT_ARR_SIZE(auto_event_names);
398 extern PSI_memory_key auto_event_keys[n_auto];
399 extern PSI_memory_info pfs_info_auto[n_auto];
400
401 /** gcc 5 fails to evalutate costexprs at compile time. */
402 #if defined(__GNUG__) && (__GNUG__ == 5)
403
404 /** Compute whether a string begins with a given prefix, compile-time.
405 @param[in] a first string, taken to be zero-terminated
406 @param[in] b second string (prefix to search for)
407 @param[in] b_len length in bytes of second string
408 @param[in] index character index to start comparing at
409 @return whether b is a prefix of a */
410 constexpr bool ut_string_begins_with(const char *a, const char *b, size_t b_len,
411 size_t index = 0) {
412 return (index == b_len || (a[index] == b[index] &&
413 ut_string_begins_with(a, b, b_len, index + 1)));
414 }
415
416 /** Find the length of the filename without its file extension.
417 @param[in] file filename, with extension but without directory
418 @param[in] index character index to start scanning for extension
419 separator at
420 @return length, in bytes */
421 constexpr size_t ut_len_without_extension(const char *file, size_t index = 0) {
422 return ((file[index] == '\0' || file[index] == '.')
423 ? index
424 : ut_len_without_extension(file, index + 1));
425 }
426
427 /** Retrieve a memory key (registered with PFS), given the file name of the
428 caller.
429 @param[in] file portion of the filename - basename, with extension
430 @param[in] len length of the filename to check for
431 @param[in] index index of first PSI key to check
432 @return registered memory key or PSI_NOT_INSTRUMENTED if not found */
433 constexpr PSI_memory_key ut_new_get_key_by_base_file(const char *file,
434 size_t len,
435 size_t index = 0) {
436 return ((index == n_auto)
437 ? PSI_NOT_INSTRUMENTED
438 : (ut_string_begins_with(auto_event_names[index], file, len)
439 ? auto_event_keys[index]
440 : ut_new_get_key_by_base_file(file, len, index + 1)));
441 }
442
443 /** Retrieve a memory key (registered with PFS), given the file name of
444 the caller.
445 @param[in] file portion of the filename - basename, with extension
446 @return registered memory key or PSI_NOT_INSTRUMENTED if not found */
ut_new_get_key_by_file(const char * file)447 constexpr PSI_memory_key ut_new_get_key_by_file(const char *file) {
448 return (ut_new_get_key_by_base_file(file, ut_len_without_extension(file)));
449 }
450
451 #define UT_NEW_THIS_FILE_PSI_KEY ut_new_get_key_by_file(MY_BASENAME)
452
453 #else /* __GNUG__ == 5 */
454
455 /** Compute whether a string begins with a given prefix, compile-time.
456 @param[in] a first string, taken to be zero-terminated
457 @param[in] b second string (prefix to search for)
458 @param[in] b_len length in bytes of second string
459 @return whether b is a prefix of a */
ut_string_begins_with(const char * a,const char * b,size_t b_len)460 constexpr bool ut_string_begins_with(const char *a, const char *b,
461 size_t b_len) {
462 for (size_t i = 0; i < b_len; ++i) {
463 if (a[i] != b[i]) {
464 return false;
465 }
466 }
467 return true;
468 }
469
470 /** Find the length of the filename without its file extension.
471 @param[in] file filename, with extension but without directory
472 @return length, in bytes */
ut_len_without_extension(const char * file)473 constexpr size_t ut_len_without_extension(const char *file) {
474 for (size_t i = 0;; ++i) {
475 if (file[i] == '\0' || file[i] == '.') {
476 return i;
477 }
478 }
479 }
480
481 /** Retrieve a memory key (registered with PFS), given the file name of the
482 caller.
483 @param[in] file portion of the filename - basename, with extension
484 @param[in] len length of the filename to check for
485 @return index to registered memory key or -1 if not found */
ut_new_get_key_by_base_file(const char * file,size_t len)486 constexpr int ut_new_get_key_by_base_file(const char *file, size_t len) {
487 for (size_t i = 0; i < n_auto; ++i) {
488 if (ut_string_begins_with(auto_event_names[i], file, len)) {
489 return static_cast<int>(i);
490 }
491 }
492 return -1;
493 }
494
495 /** Retrieve a memory key (registered with PFS), given the file name of
496 the caller.
497 @param[in] file portion of the filename - basename, with extension
498 @return index to memory key or -1 if not found */
ut_new_get_key_by_file(const char * file)499 constexpr int ut_new_get_key_by_file(const char *file) {
500 return ut_new_get_key_by_base_file(file, ut_len_without_extension(file));
501 }
502
503 // Sending an expression through a template variable forces the compiler to
504 // evaluate the expression at compile time (constexpr in itself has no such
505 // guarantee, only that the compiler is allowed).
506 template <int Value>
507 struct force_constexpr {
508 static constexpr int value = Value;
509 };
510
511 #define UT_NEW_THIS_FILE_PSI_INDEX \
512 (force_constexpr<ut_new_get_key_by_file(MY_BASENAME)>::value)
513
514 #define UT_NEW_THIS_FILE_PSI_KEY \
515 (UT_NEW_THIS_FILE_PSI_INDEX == -1 \
516 ? PSI_NOT_INSTRUMENTED \
517 : auto_event_keys[UT_NEW_THIS_FILE_PSI_INDEX])
518
519 #endif /* __GNUG__ == 5 */
520
521 #endif /* UNIV_PFS_MEMORY */
522
523 /** A structure that holds the necessary data for performance schema
524 accounting. An object of this type is put in front of each allocated block
525 of memory when allocation is done by ut_allocator::allocate(). This is
526 because the data is needed even when freeing the memory. Users of
527 ut_allocator::allocate_large() are responsible for maintaining this
528 themselves.
529 To maintain proper alignment of the pointers ut_allocator returns to the
530 calling code, this struct is declared with alignas(std::max_align_t). This tells
531 the compiler to insert enough padding to the struct to satisfy the strictest
532 fundamental alignment requirement. The size of this object then becomes a
533 multiple of the alignment requirement, this is implied by the fact that arrays
534 are contiguous in memory. This means that when we increment a pointer to
535 ut_new_pfx_t the resulting pointer must be aligned to the alignment requirement
536 of std::max_align_t. Ref. C++ standard: 6.6.5 [basic.align], 11.3.4 [dcl.array]
537 */
alignas(std::max_align_t)538 struct alignas(std::max_align_t) ut_new_pfx_t {
539 #ifdef UNIV_PFS_MEMORY
540
541 /** Performance schema key. Assigned to a name at startup via
542 PSI_MEMORY_CALL(register_memory)() and later used for accounting
543 allocations and deallocations with
544 PSI_MEMORY_CALL(memory_alloc)(key, size, owner) and
545 PSI_MEMORY_CALL(memory_free)(key, size, owner). */
546 PSI_memory_key m_key;
547
548 /**
549 Thread owner.
550 Instrumented thread that owns the allocated memory.
551 This state is used by the performance schema to maintain
552 per thread statistics,
553 when memory is given from thread A to thread B.
554 */
555 struct PSI_thread *m_owner;
556
557 #endif /* UNIV_PFS_MEMORY */
558
559 /** Size of the allocated block in bytes, including this prepended
560 aux structure (for ut_allocator::allocate()). For example if InnoDB
561 code requests to allocate 100 bytes, and sizeof(ut_new_pfx_t) is 16,
562 then 116 bytes are allocated in total and m_size will be 116.
563 ut_allocator::allocate_large() does not prepend this struct to the
564 allocated block and its users are responsible for maintaining it
565 and passing it later to ut_allocator::deallocate_large(). */
566 size_t m_size;
567 };
568
569 /** Allocator class for allocating memory from inside std::* containers. */
570 template <class T>
571 class ut_allocator {
572 public:
573 typedef T *pointer;
574 typedef const T *const_pointer;
575 typedef T &reference;
576 typedef const T &const_reference;
577 typedef T value_type;
578 typedef size_t size_type;
579 typedef ptrdiff_t difference_type;
580
581 static_assert(alignof(T) <= alignof(std::max_align_t),
582 "ut_allocator does not support over-aligned types. Use "
583 "aligned_memory or another similar allocator for this type.");
584 /** Default constructor.
585 @param[in] key performance schema key. */
586 explicit ut_allocator(PSI_memory_key key = PSI_NOT_INSTRUMENTED)
587 :
588 #ifdef UNIV_PFS_MEMORY
m_key(key)589 m_key(key),
590 #endif /* UNIV_PFS_MEMORY */
591 m_oom_fatal(true) {
592 }
593
594 /** Constructor from allocator of another type.
595 @param[in] other the allocator to copy. */
596 template <class U>
ut_allocator(const ut_allocator<U> & other)597 ut_allocator(const ut_allocator<U> &other)
598 :
599 #ifdef UNIV_PFS_MEMORY
600 m_key(other.get_mem_key()),
601 #endif /* UNIV_PFS_MEMORY */
602 m_oom_fatal(other.is_oom_fatal()) {
603 }
604
605 /** When out of memory (OOM) happens, report error and do not
606 make it fatal.
607 @return a reference to the allocator. */
set_oom_not_fatal()608 ut_allocator &set_oom_not_fatal() {
609 m_oom_fatal = false;
610 return (*this);
611 }
612
613 /** Check if allocation failure is a fatal error.
614 @return true if allocation failure is fatal, false otherwise. */
is_oom_fatal()615 bool is_oom_fatal() const { return (m_oom_fatal); }
616
617 #ifdef UNIV_PFS_MEMORY
618 /** Get the performance schema key to use for tracing allocations.
619 @return performance schema key */
get_mem_key()620 PSI_memory_key get_mem_key() const {
621 /* note: keep this as simple getter as is used by copy constructor */
622 return (m_key);
623 }
624 #endif /* UNIV_PFS_MEMORY */
625
626 /** Return the maximum number of objects that can be allocated by
627 this allocator. */
max_size()628 size_type max_size() const {
629 const size_type s_max = std::numeric_limits<size_type>::max();
630
631 #ifdef UNIV_PFS_MEMORY
632 return ((s_max - sizeof(ut_new_pfx_t)) / sizeof(T));
633 #else
634 return (s_max / sizeof(T));
635 #endif /* UNIV_PFS_MEMORY */
636 }
637
638 /** Allocate a chunk of memory that can hold 'n_elements' objects of
639 type 'T' and trace the allocation.
640 If the allocation fails this method may throw an exception. This
641 is mandated by the standard and if it returns NULL instead, then
642 STL containers that use it (e.g. std::vector) may get confused.
643 After successful allocation the returned pointer must be passed
644 to ut_allocator::deallocate() when no longer needed.
645 @param[in] n_elements number of elements
646 @param[in] hint pointer to a nearby memory location,
647 unused by this implementation
648 @param[in] key performance schema key
649 @param[in] set_to_zero if true, then the returned memory is
650 initialized with 0x0 bytes.
651 @param[in] throw_on_error if true, then exception is throw on
652 allocation failure
653 @return pointer to the allocated memory */
654 pointer allocate(size_type n_elements, const_pointer hint = nullptr,
655 PSI_memory_key key = PSI_NOT_INSTRUMENTED,
656 bool set_to_zero = false, bool throw_on_error = true) {
657 if (n_elements == 0) {
658 return (nullptr);
659 }
660
661 if (n_elements > max_size()) {
662 if (throw_on_error) {
663 throw(std::bad_alloc());
664 } else {
665 return (nullptr);
666 }
667 }
668
669 void *ptr;
670 size_t total_bytes = n_elements * sizeof(T);
671
672 #ifdef UNIV_PFS_MEMORY
673 total_bytes += sizeof(ut_new_pfx_t);
674 #endif /* UNIV_PFS_MEMORY */
675
676 for (size_t retries = 1;; retries++) {
677 if (set_to_zero) {
678 ptr = calloc(1, total_bytes);
679 } else {
680 ptr = malloc(total_bytes);
681 }
682
683 if (ptr != nullptr || retries >= alloc_max_retries) {
684 break;
685 }
686
687 os_thread_sleep(1000000 /* 1 second */);
688 }
689
690 if (ptr == nullptr) {
691 ib::fatal_or_error(m_oom_fatal)
692 << "Cannot allocate " << total_bytes << " bytes of memory after "
693 << alloc_max_retries << " retries over " << alloc_max_retries
694 << " seconds. OS error: " << strerror(errno) << " (" << errno << "). "
695 << OUT_OF_MEMORY_MSG;
696 if (throw_on_error) {
697 throw(std::bad_alloc());
698 } else {
699 return (nullptr);
700 }
701 }
702
703 #ifdef UNIV_PFS_MEMORY
704 ut_new_pfx_t *pfx = static_cast<ut_new_pfx_t *>(ptr);
705
706 allocate_trace(total_bytes, key, pfx);
707
708 return (reinterpret_cast<pointer>(pfx + 1));
709 #else
710 return (reinterpret_cast<pointer>(ptr));
711 #endif /* UNIV_PFS_MEMORY */
712 }
713
714 /** Free a memory allocated by allocate() and trace the deallocation.
715 @param[in,out] ptr pointer to memory to free
716 @param[in] n_elements number of elements allocated (unused) */
717 void deallocate(pointer ptr, size_type n_elements = 0) {
718 if (ptr == nullptr) {
719 return;
720 }
721
722 #ifdef UNIV_PFS_MEMORY
723 ut_new_pfx_t *pfx = reinterpret_cast<ut_new_pfx_t *>(ptr) - 1;
724
725 deallocate_trace(pfx);
726
727 free(pfx);
728 #else
729 free(ptr);
730 #endif /* UNIV_PFS_MEMORY */
731 }
732
733 /** Create an object of type 'T' using the value 'val' over the
734 memory pointed by 'p'. */
construct(pointer p,const T & val)735 void construct(pointer p, const T &val) { new (p) T(val); }
736
737 /** Destroy an object pointed by 'p'. */
destroy(pointer p)738 void destroy(pointer p) { p->~T(); }
739
740 /** Return the address of an object. */
address(reference x)741 pointer address(reference x) const { return (&x); }
742
743 /** Return the address of a const object. */
address(const_reference x)744 const_pointer address(const_reference x) const { return (&x); }
745
746 template <class U>
747 struct rebind {
748 typedef ut_allocator<U> other;
749 };
750
751 /* The following are custom methods, not required by the standard. */
752
753 #ifdef UNIV_PFS_MEMORY
754
755 /** realloc(3)-like method.
756 The passed in ptr must have been returned by allocate() and the
757 pointer returned by this method must be passed to deallocate() when
758 no longer needed.
759 @param[in,out] ptr old pointer to reallocate
760 @param[in] n_elements new number of elements to allocate
761 @param[in] key Performance schema key to allocate under
762 @return newly allocated memory */
reallocate(void * ptr,size_type n_elements,PSI_memory_key key)763 pointer reallocate(void *ptr, size_type n_elements, PSI_memory_key key) {
764 if (n_elements == 0) {
765 deallocate(static_cast<pointer>(ptr));
766 return (nullptr);
767 }
768
769 if (ptr == nullptr) {
770 return (allocate(n_elements, nullptr, key, false, false));
771 }
772
773 if (n_elements > max_size()) {
774 return (nullptr);
775 }
776
777 ut_new_pfx_t *pfx_old;
778 ut_new_pfx_t *pfx_new;
779 size_t total_bytes;
780
781 pfx_old = reinterpret_cast<ut_new_pfx_t *>(ptr) - 1;
782
783 total_bytes = n_elements * sizeof(T) + sizeof(ut_new_pfx_t);
784
785 for (size_t retries = 1;; retries++) {
786 pfx_new = static_cast<ut_new_pfx_t *>(realloc(pfx_old, total_bytes));
787
788 if (pfx_new != nullptr || retries >= alloc_max_retries) {
789 break;
790 }
791
792 os_thread_sleep(1000000 /* 1 second */);
793 }
794
795 if (pfx_new == nullptr) {
796 ib::fatal_or_error(m_oom_fatal)
797 << "Cannot reallocate " << total_bytes << " bytes of memory after "
798 << alloc_max_retries << " retries over " << alloc_max_retries
799 << " seconds. OS error: " << strerror(errno) << " (" << errno << "). "
800 << OUT_OF_MEMORY_MSG;
801 /* not reached */
802 return (nullptr);
803 }
804
805 /* pfx_new still contains the description of the old block
806 that was presumably freed by realloc(). */
807 deallocate_trace(pfx_new);
808
809 /* pfx_new is set here to describe the new block. */
810 allocate_trace(total_bytes, key, pfx_new);
811
812 return (reinterpret_cast<pointer>(pfx_new + 1));
813 }
814
815 /** Allocate, trace the allocation and construct 'n_elements' objects
816 of type 'T'. If the allocation fails or if some of the constructors
817 throws an exception, then this method will return NULL. It does not
818 throw exceptions. After successful completion the returned pointer
819 must be passed to delete_array() when no longer needed.
820 @param[in] n_elements number of elements to allocate
821 @param[in] key Performance schema key to allocate under
822 @return pointer to the first allocated object or NULL */
new_array(size_type n_elements,PSI_memory_key key)823 pointer new_array(size_type n_elements, PSI_memory_key key) {
824 static_assert(std::is_default_constructible<T>::value,
825 "Array element type must be default-constructible");
826
827 T *p = allocate(n_elements, nullptr, key, false, false);
828
829 if (p == nullptr) {
830 return (nullptr);
831 }
832
833 T *first = p;
834 size_type i;
835
836 try {
837 for (i = 0; i < n_elements; i++) {
838 new (p) T;
839 ++p;
840 }
841 } catch (...) {
842 for (size_type j = 0; j < i; j++) {
843 --p;
844 p->~T();
845 }
846
847 deallocate(first);
848
849 throw;
850 }
851
852 return (first);
853 }
854
855 /** Destroy, deallocate and trace the deallocation of an array created
856 by new_array().
857 @param[in,out] ptr pointer to the first object in the array */
delete_array(T * ptr)858 void delete_array(T *ptr) {
859 if (ptr == nullptr) {
860 return;
861 }
862
863 const size_type n_elements = n_elements_allocated(ptr);
864
865 T *p = ptr + n_elements - 1;
866
867 for (size_type i = 0; i < n_elements; i++) {
868 p->~T();
869 --p;
870 }
871
872 deallocate(ptr);
873 }
874
875 #endif /* UNIV_PFS_MEMORY */
876
877 /** Allocate a large chunk of memory that can hold 'n_elements'
878 objects of type 'T' and trace the allocation.
879 @param[in] n_elements number of elements
880 @param[out] pfx storage for the description of the
881 allocated memory. The caller must provide space for this one and keep
882 it until the memory is no longer needed and then pass it to
883 deallocate_large().
884 @return pointer to the allocated memory or NULL */
allocate_large(size_type n_elements,ut_new_pfx_t * pfx)885 pointer allocate_large(size_type n_elements, ut_new_pfx_t *pfx) {
886 if (n_elements == 0 || n_elements > max_size()) {
887 return (nullptr);
888 }
889
890 ulint n_bytes = n_elements * sizeof(T);
891
892 pointer ptr = reinterpret_cast<pointer>(os_mem_alloc_large(&n_bytes));
893
894 #ifdef UNIV_PFS_MEMORY
895 if (ptr != nullptr) {
896 allocate_trace(n_bytes, PSI_NOT_INSTRUMENTED, pfx);
897 }
898 #else
899 pfx->m_size = n_bytes;
900 #endif /* UNIV_PFS_MEMORY */
901
902 return (ptr);
903 }
904
905 /** Free a memory allocated by allocate_large() and trace the
906 deallocation.
907 @param[in,out] ptr pointer to memory to free
908 @param[in] pfx descriptor of the memory, as returned by
909 allocate_large(). */
deallocate_large(pointer ptr,const ut_new_pfx_t * pfx)910 void deallocate_large(pointer ptr, const ut_new_pfx_t *pfx) {
911 #ifdef UNIV_PFS_MEMORY
912 deallocate_trace(pfx);
913 #endif /* UNIV_PFS_MEMORY */
914
915 os_mem_free_large(ptr, pfx->m_size);
916 }
917
918 private:
919 #ifdef UNIV_PFS_MEMORY
920
921 /** Retrieve the size of a memory block allocated by new_array().
922 @param[in] ptr pointer returned by new_array().
923 @return size of memory block */
n_elements_allocated(const_pointer ptr)924 size_type n_elements_allocated(const_pointer ptr) {
925 const ut_new_pfx_t *pfx = reinterpret_cast<const ut_new_pfx_t *>(ptr) - 1;
926
927 const size_type user_bytes = pfx->m_size - sizeof(ut_new_pfx_t);
928
929 ut_ad(user_bytes % sizeof(T) == 0);
930
931 return (user_bytes / sizeof(T));
932 }
933
934 /** Trace a memory allocation.
935 @param[in] size number of bytes that were allocated
936 @param[in] key Performance Schema key
937 @param[out] pfx placeholder to store the info which will be
938 needed when freeing the memory */
allocate_trace(size_t size,PSI_memory_key key,ut_new_pfx_t * pfx)939 void allocate_trace(size_t size, PSI_memory_key key, ut_new_pfx_t *pfx) {
940 if (m_key != PSI_NOT_INSTRUMENTED) {
941 key = m_key;
942 }
943
944 pfx->m_key = PSI_MEMORY_CALL(memory_alloc)(key, size, &pfx->m_owner);
945
946 pfx->m_size = size;
947 }
948
949 /** Trace a memory deallocation.
950 @param[in] pfx info for the deallocation */
deallocate_trace(const ut_new_pfx_t * pfx)951 void deallocate_trace(const ut_new_pfx_t *pfx) {
952 PSI_MEMORY_CALL(memory_free)(pfx->m_key, pfx->m_size, pfx->m_owner);
953 }
954 #endif /* UNIV_PFS_MEMORY */
955
956 /* Assignment operator, not used, thus disabled (private. */
957 template <class U>
958 void operator=(const ut_allocator<U> &);
959
960 #ifdef UNIV_PFS_MEMORY
961 /** Performance schema key. */
962 PSI_memory_key m_key;
963 #endif /* UNIV_PFS_MEMORY */
964
965 /** A flag to indicate whether out of memory (OOM) error is considered
966 fatal. If true, it is fatal. */
967 bool m_oom_fatal;
968 };
969
970 /** Compare two allocators of the same type.
971 As long as the type of A1 and A2 is the same, a memory allocated by A1
972 could be freed by A2 even if the pfs mem key is different. */
973 template <typename T>
974 inline bool operator==(const ut_allocator<T> &lhs, const ut_allocator<T> &rhs) {
975 return (true);
976 }
977
978 /** Compare two allocators of the same type. */
979 template <typename T>
980 inline bool operator!=(const ut_allocator<T> &lhs, const ut_allocator<T> &rhs) {
981 return (!(lhs == rhs));
982 }
983
984 #ifdef UNIV_PFS_MEMORY
985
986 /** Allocate, trace the allocation and construct an object.
987 Use this macro instead of 'new' within InnoDB.
988 For example: instead of
989 Foo* f = new Foo(args);
990 use:
991 Foo* f = UT_NEW(Foo(args), mem_key_some);
992 Upon failure to allocate the memory, this macro may return NULL. It
993 will not throw exceptions. After successful allocation the returned
994 pointer must be passed to UT_DELETE() when no longer needed.
995 @param[in] expr any expression that could follow "new"
996 @param[in] key performance schema memory tracing key
997 @return pointer to the created object or NULL */
998 #define UT_NEW(expr, key) \
999 /* Placement new will return NULL and not attempt to construct an \
1000 object if the passed in pointer is NULL, e.g. if allocate() has \
1001 failed to allocate memory and has returned NULL. */ \
1002 ::new (ut_allocator<decltype(expr)>(key).allocate(1, NULL, key, false, \
1003 false)) expr
1004
1005 /** Allocate, trace the allocation and construct an object.
1006 Use this macro instead of 'new' within InnoDB and instead of UT_NEW()
1007 when creating a dedicated memory key is not feasible.
1008 For example: instead of
1009 Foo* f = new Foo(args);
1010 use:
1011 Foo* f = UT_NEW_NOKEY(Foo(args));
1012 Upon failure to allocate the memory, this macro may return NULL. It
1013 will not throw exceptions. After successful allocation the returned
1014 pointer must be passed to UT_DELETE() when no longer needed.
1015 @param[in] expr any expression that could follow "new"
1016 @return pointer to the created object or NULL */
1017 #define UT_NEW_NOKEY(expr) UT_NEW(expr, PSI_NOT_INSTRUMENTED)
1018
1019 /** Destroy, deallocate and trace the deallocation of an object created by
1020 UT_NEW() or UT_NEW_NOKEY().
1021 We can't instantiate ut_allocator without having the type of the object, thus
1022 we redirect this to a template function. */
1023 #define UT_DELETE(ptr) ut_delete(ptr)
1024
1025 /** Destroy and account object created by UT_NEW() or UT_NEW_NOKEY().
1026 @param[in,out] ptr pointer to the object */
1027 template <typename T>
ut_delete(T * ptr)1028 inline void ut_delete(T *ptr) {
1029 if (ptr == nullptr) {
1030 return;
1031 }
1032
1033 ut_allocator<T> allocator;
1034
1035 allocator.destroy(ptr);
1036 allocator.deallocate(ptr);
1037 }
1038
1039 /** Allocate and account 'n_elements' objects of type 'type'.
1040 Use this macro to allocate memory within InnoDB instead of 'new[]'.
1041 The returned pointer must be passed to UT_DELETE_ARRAY().
1042 @param[in] type type of objects being created
1043 @param[in] n_elements number of objects to create
1044 @param[in] key performance schema memory tracing key
1045 @return pointer to the first allocated object or NULL */
1046 #define UT_NEW_ARRAY(type, n_elements, key) \
1047 ut_allocator<type>(key).new_array(n_elements, UT_NEW_THIS_FILE_PSI_KEY)
1048
1049 /** Allocate and account 'n_elements' objects of type 'type'.
1050 Use this macro to allocate memory within InnoDB instead of 'new[]' and
1051 instead of UT_NEW_ARRAY() when it is not feasible to create a dedicated key.
1052 @param[in] type type of objects being created
1053 @param[in] n_elements number of objects to create
1054 @return pointer to the first allocated object or NULL */
1055 #define UT_NEW_ARRAY_NOKEY(type, n_elements) \
1056 UT_NEW_ARRAY(type, n_elements, PSI_NOT_INSTRUMENTED)
1057
1058 /** Destroy, deallocate and trace the deallocation of an array created by
1059 UT_NEW_ARRAY() or UT_NEW_ARRAY_NOKEY().
1060 We can't instantiate ut_allocator without having the type of the object, thus
1061 we redirect this to a template function. */
1062 #define UT_DELETE_ARRAY(ptr) ut_delete_array(ptr)
1063
1064 /** Destroy and account objects created by UT_NEW_ARRAY() or
1065 UT_NEW_ARRAY_NOKEY().
1066 @param[in,out] ptr pointer to the first object in the array */
1067 template <typename T>
ut_delete_array(T * ptr)1068 inline void ut_delete_array(T *ptr) {
1069 ut_allocator<T>().delete_array(ptr);
1070 }
1071
1072 /**
1073 Do not use ut_malloc, ut_zalloc, ut_malloc_nokey, ut_zalloc_nokey,
1074 ut_zalloc_nokey_nofatal and ut_realloc when allocating memory for
1075 over-aligned types. We have to use aligned_pointer instead, analogously to how
1076 we have to use aligned_alloc when working with the standard library to handle
1077 dynamic allocation for over-aligned types. These macros use ut_allocator to
1078 allocate raw memory (no type information is passed). This is why ut_allocator
1079 needs to be instantiated with the byte type. This has implications on the max
1080 alignment of the objects that are allocated using this API. ut_allocator returns
1081 memory aligned to alignof(std::max_align_t), similarly to library allocation
1082 functions. This value is 16 bytes on most x64 machines. A static_assert enforces
1083 this when using UT_NEW, however, since the ut_allocator template is instantiated
1084 with byte here the assert will not be hit if using alignment >=
1085 alignof(std::max_align_t). Not meeting the alignment requirements for a type
1086 causes undefined behaviour.
1087 One should avoid using the macros below when writing new code in general,
1088 and try to remove them when refactoring existing code (in favor of using the
1089 UT_NEW). The reason behind this lies both in the undefined behaviour problem
1090 described above, and in the fact that standard C-like malloc use is discouraged
1091 in c++ (see CppCoreGuidelines - R.10: Avoid malloc() and free()). Using
1092 ut_malloc has the same problems as the standard library malloc.
1093 */
1094
1095 #define ut_malloc(n_bytes, key) \
1096 static_cast<void *>(ut_allocator<byte>(key).allocate( \
1097 n_bytes, NULL, UT_NEW_THIS_FILE_PSI_KEY, false, false))
1098
1099 #define ut_zalloc(n_bytes, key) \
1100 static_cast<void *>(ut_allocator<byte>(key).allocate( \
1101 n_bytes, NULL, UT_NEW_THIS_FILE_PSI_KEY, true, false))
1102
1103 #define ut_malloc_nokey(n_bytes) \
1104 static_cast<void *>( \
1105 ut_allocator<byte>(PSI_NOT_INSTRUMENTED) \
1106 .allocate(n_bytes, NULL, UT_NEW_THIS_FILE_PSI_KEY, false, false))
1107
1108 #define ut_zalloc_nokey(n_bytes) \
1109 static_cast<void *>( \
1110 ut_allocator<byte>(PSI_NOT_INSTRUMENTED) \
1111 .allocate(n_bytes, NULL, UT_NEW_THIS_FILE_PSI_KEY, true, false))
1112
1113 #define ut_zalloc_nokey_nofatal(n_bytes) \
1114 static_cast<void *>( \
1115 ut_allocator<byte>(PSI_NOT_INSTRUMENTED) \
1116 .set_oom_not_fatal() \
1117 .allocate(n_bytes, NULL, UT_NEW_THIS_FILE_PSI_KEY, true, false))
1118
1119 #define ut_realloc(ptr, n_bytes) \
1120 static_cast<void *>(ut_allocator<byte>(PSI_NOT_INSTRUMENTED) \
1121 .reallocate(ptr, n_bytes, UT_NEW_THIS_FILE_PSI_KEY))
1122
1123 #define ut_free(ptr) \
1124 ut_allocator<byte>(PSI_NOT_INSTRUMENTED) \
1125 .deallocate(reinterpret_cast<byte *>(ptr))
1126
1127 #else /* UNIV_PFS_MEMORY */
1128
1129 /* Fallbacks when memory tracing is disabled at compile time. */
1130
1131 #define UT_NEW(expr, key) ::new (std::nothrow) expr
1132 #define UT_NEW_NOKEY(expr) ::new (std::nothrow) expr
1133 #define UT_DELETE(ptr) ::delete ptr
1134
1135 #define UT_NEW_ARRAY(type, n_elements, key) \
1136 ::new (std::nothrow) type[n_elements]
1137
1138 #define UT_NEW_ARRAY_NOKEY(type, n_elements) \
1139 ::new (std::nothrow) type[n_elements]
1140
1141 #define UT_DELETE_ARRAY(ptr) ::delete[] ptr
1142
1143 #define ut_malloc(n_bytes, key) ::malloc(n_bytes)
1144
1145 #define ut_zalloc(n_bytes, key) ::calloc(1, n_bytes)
1146
1147 #define ut_malloc_nokey(n_bytes) ::malloc(n_bytes)
1148
1149 #define ut_zalloc_nokey(n_bytes) ::calloc(1, n_bytes)
1150
1151 #define ut_zalloc_nokey_nofatal(n_bytes) ::calloc(1, n_bytes)
1152
1153 #define ut_realloc(ptr, n_bytes) ::realloc(ptr, n_bytes)
1154
1155 #define ut_free(ptr) ::free(ptr)
1156
1157 #endif /* UNIV_PFS_MEMORY */
1158
1159 /** This is a forward declaration, which is because of the circular dependency
1160 between ut0new.h and ut0byte.h (going through univ.i and sync0types.h).
1161 I've managed to observe problem when building MEB and this helps then. */
1162 UNIV_INLINE
1163 void *ut_align(const void *ptr, ulint align_no);
1164
1165 /** Abstract class to manage an object that is aligned to specified number of
1166 bytes.
1167 @tparam T_Type type of the object that is going to be managed
1168 @tparam T_Align_to number of bytes to align to */
1169 template <typename T_Type, size_t T_Align_to>
1170 class aligned_memory {
1171 public:
~aligned_memory()1172 virtual ~aligned_memory() {
1173 if (!this->is_object_empty()) {
1174 this->free_memory();
1175 }
1176 }
1177
1178 virtual void destroy() = 0;
1179
1180 /** Allows casting to managed objects type to use it directly */
1181 operator T_Type *() const {
1182 ut_a(m_object != nullptr);
1183 return m_object;
1184 }
1185
1186 /** Allows referencing the managed object as this was a normal
1187 pointer. */
1188 T_Type *operator->() const {
1189 ut_a(m_object != nullptr);
1190 return m_object;
1191 }
1192
1193 protected:
1194 /** Checks if no object is currently being managed. */
is_object_empty()1195 bool is_object_empty() const { return m_object == nullptr; }
1196
1197 /** Allocates memory for a new object and prepares aligned address for
1198 the object.
1199 @param[in] size Number of bytes to be delivered for the aligned
1200 object. Number of bytes actually allocated will be higher. */
allocate(size_t size)1201 T_Type *allocate(size_t size) {
1202 static_assert(T_Align_to > 0, "Incorrect alignment parameter");
1203 ut_a(m_memory == nullptr);
1204 ut_a(m_object == nullptr);
1205
1206 m_memory = ut_zalloc_nokey(size + T_Align_to - 1);
1207 m_object = static_cast<T_Type *>(::ut_align(m_memory, T_Align_to));
1208 return m_object;
1209 }
1210
1211 /** Releases memory used to store the object. */
free_memory()1212 void free_memory() {
1213 ut_a(m_memory != nullptr);
1214 ut_a(m_object != nullptr);
1215
1216 ut_free(m_memory);
1217
1218 m_memory = nullptr;
1219 m_object = nullptr;
1220 }
1221
1222 private:
1223 /** Stores pointer to aligned object memory. */
1224 T_Type *m_object = nullptr;
1225
1226 /** Stores pointer to memory used to allocate the object. */
1227 void *m_memory = nullptr;
1228 };
1229
1230 /** Manages an object that is aligned to specified number of bytes.
1231 @tparam T_Type type of the object that is going to be managed
1232 @tparam T_Align_to number of bytes to align to */
1233 template <typename T_Type, size_t T_Align_to = ut::INNODB_CACHE_LINE_SIZE>
1234 class aligned_pointer : public aligned_memory<T_Type, T_Align_to> {
1235 public:
~aligned_pointer()1236 ~aligned_pointer() {
1237 if (!this->is_object_empty()) {
1238 this->destroy();
1239 }
1240 }
1241
1242 /** Allocates aligned memory for new object and constructs it there.
1243 @param[in] args arguments to be passed to object constructor */
1244 template <typename... T_Args>
create(T_Args...args)1245 void create(T_Args... args) {
1246 new (this->allocate(sizeof(T_Type))) T_Type(std::forward(args)...);
1247 }
1248
1249 /** Destroys the managed object and releases its memory. */
destroy()1250 void destroy() {
1251 (*this)->~T_Type();
1252 this->free_memory();
1253 }
1254 };
1255
1256 /** Manages an array of objects. The first element is aligned to specified
1257 number of bytes.
1258 @tparam T_Type type of the object that is going to be managed
1259 @tparam T_Align_to number of bytes to align to */
1260 template <typename T_Type, size_t T_Align_to = ut::INNODB_CACHE_LINE_SIZE>
1261 class aligned_array_pointer : public aligned_memory<T_Type, T_Align_to> {
1262 public:
1263 /** Allocates aligned memory for new objects. Objects must be trivially
1264 constructible and destructible.
1265 @param[in] size Number of elements to allocate. */
create(size_t size)1266 void create(size_t size) {
1267 #if !(defined __GNUC__ && __GNUC__ <= 4)
1268 static_assert(std::is_trivially_default_constructible<T_Type>::value,
1269 "Aligned array element type must be "
1270 "trivially default-constructible");
1271 #endif
1272 m_size = size;
1273 this->allocate(sizeof(T_Type) * m_size);
1274 }
1275
1276 /** Deallocates memory of array created earlier. */
destroy()1277 void destroy() {
1278 static_assert(std::is_trivially_destructible<T_Type>::value,
1279 "Aligned array element type must be "
1280 "trivially destructible");
1281 this->free_memory();
1282 }
1283
1284 /** Accesses specified index in the allocated array.
1285 @param[in] index index of element in array to get reference to */
1286 T_Type &operator[](size_t index) const {
1287 ut_a(index < m_size);
1288 return ((T_Type *)*this)[index];
1289 }
1290
1291 private:
1292 /** Size of the allocated array. */
1293 size_t m_size;
1294 };
1295
1296 namespace ut {
1297
1298 /** Specialization of basic_ostringstream which uses ut_allocator. Please note
1299 that it's .str() method returns std::basic_string which is not std::string, so
1300 it has similar API (in particular .c_str()), but you can't assign it to regular,
1301 std::string. */
1302 using ostringstream =
1303 std::basic_ostringstream<char, std::char_traits<char>, ut_allocator<char>>;
1304
1305 /** Specialization of vector which uses ut_allocator. */
1306 template <typename T>
1307 using vector = std::vector<T, ut_allocator<T>>;
1308
1309 } // namespace ut
1310 #endif /* ut0new_h */
1311