1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 2014, 2015, Oracle and/or its affiliates. All Rights Reserved. |
4 | Copyright (c) 2017, MariaDB Corporation. |
5 | |
6 | This program is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free Software |
8 | Foundation; version 2 of the License. |
9 | |
10 | This program is distributed in the hope that it will be useful, but WITHOUT |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License along with |
15 | this program; if not, write to the Free Software Foundation, Inc., |
16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
17 | |
18 | *****************************************************************************/ |
19 | |
20 | /**************************************************//** |
21 | @file ut/ut0new.h |
22 | Instrumented memory allocator. |
23 | |
24 | Created May 26, 2014 Vasil Dimov |
25 | *******************************************************/ |
26 | |
27 | /** Dynamic memory allocation within InnoDB guidelines. |
28 | All dynamic (heap) memory allocations (malloc(3), strdup(3), etc, "new", |
29 | various std:: containers that allocate memory internally), that are done |
30 | within InnoDB are instrumented. This means that InnoDB uses a custom set |
31 | of functions for allocating memory, rather than calling e.g. "new" directly. |
32 | |
33 | Here follows a cheat sheet on what InnoDB functions to use whenever a |
34 | standard one would have been used. |
35 | |
36 | Creating new objects with "new": |
37 | -------------------------------- |
38 | Standard: |
39 | new expression |
40 | or |
41 | new(std::nothrow) expression |
42 | InnoDB, default instrumentation: |
43 | UT_NEW_NOKEY(expression) |
44 | InnoDB, custom instrumentation, preferred: |
45 | UT_NEW(expression, key) |
46 | |
47 | Destroying objects, created with "new": |
48 | --------------------------------------- |
49 | Standard: |
50 | delete ptr |
51 | InnoDB: |
52 | UT_DELETE(ptr) |
53 | |
54 | Creating new arrays with "new[]": |
55 | --------------------------------- |
56 | Standard: |
57 | new type[num] |
58 | or |
59 | new(std::nothrow) type[num] |
60 | InnoDB, default instrumentation: |
61 | UT_NEW_ARRAY_NOKEY(type, num) |
62 | InnoDB, custom instrumentation, preferred: |
63 | UT_NEW_ARRAY(type, num, key) |
64 | |
65 | Destroying arrays, created with "new[]": |
66 | ---------------------------------------- |
67 | Standard: |
68 | delete[] ptr |
69 | InnoDB: |
70 | UT_DELETE_ARRAY(ptr) |
71 | |
72 | Declaring a type with a std:: container, e.g. std::vector: |
73 | ---------------------------------------------------------- |
74 | Standard: |
75 | std::vector<t> |
76 | InnoDB: |
77 | std::vector<t, ut_allocator<t> > |
78 | |
79 | Declaring objects of some std:: type: |
80 | ------------------------------------- |
81 | Standard: |
82 | std::vector<t> v |
83 | InnoDB, default instrumentation: |
84 | std::vector<t, ut_allocator<t> > v |
85 | InnoDB, custom instrumentation, preferred: |
86 | std::vector<t, ut_allocator<t> > v(ut_allocator<t>(key)) |
87 | |
88 | Raw block allocation (as usual in C++, consider whether using "new" would |
89 | not be more appropriate): |
90 | ------------------------------------------------------------------------- |
91 | Standard: |
92 | malloc(num) |
93 | InnoDB, default instrumentation: |
94 | ut_malloc_nokey(num) |
95 | InnoDB, custom instrumentation, preferred: |
96 | ut_malloc(num, key) |
97 | |
98 | Raw block resize: |
99 | ----------------- |
100 | Standard: |
101 | realloc(ptr, new_size) |
102 | InnoDB: |
103 | ut_realloc(ptr, new_size) |
104 | |
105 | Raw block deallocation: |
106 | ----------------------- |
107 | Standard: |
108 | free(ptr) |
109 | InnoDB: |
110 | ut_free(ptr) |
111 | |
112 | Note: the expression passed to UT_NEW() or UT_NEW_NOKEY() must always end |
113 | with (), thus: |
114 | Standard: |
115 | new int |
116 | InnoDB: |
117 | UT_NEW_NOKEY(int()) |
118 | */ |
119 | |
120 | #ifndef ut0new_h |
121 | #define ut0new_h |
122 | |
123 | #include <algorithm> /* std::min() */ |
124 | #include <limits> /* std::numeric_limits */ |
125 | #include <map> /* std::map */ |
126 | |
127 | #include <stddef.h> |
128 | #include <stdlib.h> /* malloc() */ |
129 | #include <string.h> /* strlen(), strrchr(), strncmp() */ |
130 | |
131 | #include "my_global.h" /* needed for headers from mysql/psi/ */ |
132 | #if !defined(DBUG_OFF) && defined(HAVE_MADVISE) |
133 | #include <sys/mman.h> |
134 | #endif |
135 | |
136 | /* JAN: TODO: missing 5.7 header */ |
137 | #ifdef HAVE_MYSQL_MEMORY_H |
138 | #include "mysql/psi/mysql_memory.h" /* PSI_MEMORY_CALL() */ |
139 | #endif |
140 | |
141 | #include "mysql/psi/psi_memory.h" /* PSI_memory_key, PSI_memory_info */ |
142 | |
143 | #include "univ.i" |
144 | |
145 | #include "os0proc.h" /* os_mem_alloc_large() */ |
146 | #include "os0thread.h" /* os_thread_sleep() */ |
147 | #include "ut0ut.h" /* ut_strcmp_functor, ut_basename_noext() */ |
148 | |
149 | #define OUT_OF_MEMORY_MSG \ |
150 | "Check if you should increase the swap file or ulimits of your" \ |
151 | " operating system. Note that on most 32-bit computers the process" \ |
152 | " memory space is limited to 2 GB or 4 GB." |
153 | |
154 | /** Maximum number of retries to allocate memory. */ |
155 | extern const size_t alloc_max_retries; |
156 | |
157 | /** Keys for registering allocations with performance schema. |
158 | Pointers to these variables are supplied to PFS code via the pfs_info[] |
159 | array and the PFS code initializes them via PSI_MEMORY_CALL(register_memory)(). |
160 | mem_key_other and mem_key_std are special in the following way (see also |
161 | ut_allocator::get_mem_key()): |
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_buf_buf_pool; |
172 | extern PSI_memory_key mem_key_dict_stats_bg_recalc_pool_t; |
173 | extern PSI_memory_key mem_key_dict_stats_index_map_t; |
174 | extern PSI_memory_key mem_key_dict_stats_n_diff_on_level; |
175 | extern PSI_memory_key mem_key_other; |
176 | extern PSI_memory_key mem_key_row_log_buf; |
177 | extern PSI_memory_key mem_key_row_merge_sort; |
178 | extern PSI_memory_key mem_key_std; |
179 | extern PSI_memory_key mem_key_partitioning; |
180 | |
181 | /** Setup the internal objects needed for UT_NEW() to operate. |
182 | This must be called before the first call to UT_NEW(). */ |
183 | void |
184 | ut_new_boot(); |
185 | |
186 | #ifdef UNIV_PFS_MEMORY |
187 | |
188 | /** Retrieve a memory key (registered with PFS), given a portion of the file |
189 | name of the caller. |
190 | @param[in] file portion of the filename - basename without an extension |
191 | @return registered memory key or PSI_NOT_INSTRUMENTED if not found */ |
192 | PSI_memory_key |
193 | ut_new_get_key_by_file( |
194 | const char* file); |
195 | |
196 | #endif /* UNIV_PFS_MEMORY */ |
197 | |
198 | /** A structure that holds the necessary data for performance schema |
199 | accounting. An object of this type is put in front of each allocated block |
200 | of memory when allocation is done by ut_allocator::allocate(). This is |
201 | because the data is needed even when freeing the memory. Users of |
202 | ut_allocator::allocate_large() are responsible for maintaining this |
203 | themselves. */ |
204 | struct ut_new_pfx_t { |
205 | |
206 | #ifdef UNIV_PFS_MEMORY |
207 | |
208 | /** Performance schema key. Assigned to a name at startup via |
209 | PSI_MEMORY_CALL(register_memory)() and later used for accounting |
210 | allocations and deallocations with |
211 | PSI_MEMORY_CALL(memory_alloc)(key, size, owner) and |
212 | PSI_MEMORY_CALL(memory_free)(key, size, owner). */ |
213 | PSI_memory_key m_key; |
214 | |
215 | /** |
216 | Thread owner. |
217 | Instrumented thread that owns the allocated memory. |
218 | This state is used by the performance schema to maintain |
219 | per thread statistics, |
220 | when memory is given from thread A to thread B. |
221 | */ |
222 | struct PSI_thread *m_owner; |
223 | |
224 | #endif /* UNIV_PFS_MEMORY */ |
225 | |
226 | /** Size of the allocated block in bytes, including this prepended |
227 | aux structure (for ut_allocator::allocate()). For example if InnoDB |
228 | code requests to allocate 100 bytes, and sizeof(ut_new_pfx_t) is 16, |
229 | then 116 bytes are allocated in total and m_size will be 116. |
230 | ut_allocator::allocate_large() does not prepend this struct to the |
231 | allocated block and its users are responsible for maintaining it |
232 | and passing it later to ut_allocator::deallocate_large(). */ |
233 | size_t m_size; |
234 | #if SIZEOF_VOIDP == 4 |
235 | /** Pad the header size to a multiple of 64 bits on 32-bit systems, |
236 | so that the payload will be aligned to 64 bits. */ |
237 | size_t pad; |
238 | #endif |
239 | }; |
240 | |
241 | static inline void ut_allocate_trace_dontdump(void *ptr, size_t bytes, |
242 | bool |
243 | #if defined(DBUG_OFF) && defined(HAVE_MADVISE) && defined(MADV_DONTDUMP) |
244 | dontdump |
245 | #endif |
246 | , ut_new_pfx_t* pfx, |
247 | const char* |
248 | #ifdef UNIV_PFS_MEMORY |
249 | file |
250 | #endif |
251 | |
252 | ) |
253 | { |
254 | ut_a(ptr != NULL); |
255 | |
256 | #if defined(DBUG_OFF) && defined(HAVE_MADVISE) && defined(MADV_DONTDUMP) |
257 | if (dontdump && madvise(ptr, bytes, MADV_DONTDUMP)) { |
258 | ib::warn() << "Failed to set memory to DONTDUMP: " |
259 | << strerror(errno) |
260 | << " ptr " << ptr |
261 | << " size " << bytes; |
262 | } |
263 | #endif |
264 | if (pfx != NULL) { |
265 | #ifdef UNIV_PFS_MEMORY |
266 | allocate_trace(bytes, file, pfx); |
267 | #endif /* UNIV_PFS_MEMORY */ |
268 | pfx->m_size = bytes; |
269 | } |
270 | } |
271 | |
272 | #if defined(DBUG_OFF) && defined(HAVE_MADVISE) && defined(MADV_DODUMP) |
273 | static inline void ut_dodump(void* ptr, size_t m_size) |
274 | { |
275 | if (ptr && madvise(ptr, m_size, MADV_DODUMP)) { |
276 | ib::warn() << "Failed to set memory to DODUMP: " |
277 | << strerror(errno) |
278 | << " ptr " << ptr |
279 | << " size " << m_size; |
280 | } |
281 | } |
282 | #else |
283 | static inline void ut_dodump(void*, size_t) {} |
284 | #endif |
285 | |
286 | /** Allocator class for allocating memory from inside std::* containers. |
287 | @tparam T type of allocated object |
288 | @tparam oom_fatal whether to commit suicide when running out of memory */ |
289 | template <class T, bool oom_fatal = true> |
290 | class ut_allocator { |
291 | public: |
292 | typedef T* pointer; |
293 | typedef const T* const_pointer; |
294 | typedef T& reference; |
295 | typedef const T& const_reference; |
296 | typedef T value_type; |
297 | typedef size_t size_type; |
298 | typedef ptrdiff_t difference_type; |
299 | |
300 | #ifdef UNIV_PFS_MEMORY |
301 | /** Default constructor. */ |
302 | explicit |
303 | ut_allocator(PSI_memory_key key = PSI_NOT_INSTRUMENTED) |
304 | : m_key(key) |
305 | { |
306 | } |
307 | #else |
308 | ut_allocator() {} |
309 | ut_allocator(PSI_memory_key) {} |
310 | #endif /* UNIV_PFS_MEMORY */ |
311 | |
312 | /** Constructor from allocator of another type. */ |
313 | template <class U> |
314 | ut_allocator(const ut_allocator<U>& |
315 | #ifdef UNIV_PFS_MEMORY |
316 | other |
317 | #endif |
318 | ) |
319 | #ifdef UNIV_PFS_MEMORY |
320 | : m_key(other.m_key) |
321 | #endif /* UNIV_PFS_MEMORY */ |
322 | { |
323 | } |
324 | |
325 | /** Return the maximum number of objects that can be allocated by |
326 | this allocator. */ |
327 | size_type |
328 | max_size() const |
329 | { |
330 | const size_type s_max = std::numeric_limits<size_type>::max(); |
331 | |
332 | #ifdef UNIV_PFS_MEMORY |
333 | return((s_max - sizeof(ut_new_pfx_t)) / sizeof(T)); |
334 | #else |
335 | return(s_max / sizeof(T)); |
336 | #endif /* UNIV_PFS_MEMORY */ |
337 | } |
338 | |
339 | pointer allocate(size_type n) { return allocate(n, NULL, NULL); } |
340 | |
341 | /** Allocate a chunk of memory that can hold 'n_elements' objects of |
342 | type 'T' and trace the allocation. |
343 | If the allocation fails this method may throw an exception. This |
344 | is mandated by the standard and if it returns NULL instead, then |
345 | STL containers that use it (e.g. std::vector) may get confused. |
346 | After successfull allocation the returned pointer must be passed |
347 | to ut_allocator::deallocate() when no longer needed. |
348 | @param[in] n_elements number of elements |
349 | @param[in] set_to_zero if true, then the returned memory is |
350 | initialized with 0x0 bytes. |
351 | @param[in] throw_on_error if true, raize exception if too big |
352 | @return pointer to the allocated memory */ |
353 | pointer |
354 | allocate( |
355 | size_type n_elements, |
356 | const_pointer, |
357 | const char* |
358 | #ifdef UNIV_PFS_MEMORY |
359 | file /*!< file name of the caller */ |
360 | #endif |
361 | , |
362 | bool set_to_zero = false, |
363 | bool throw_on_error = true) |
364 | { |
365 | if (n_elements == 0) { |
366 | return(NULL); |
367 | } |
368 | |
369 | if (n_elements > max_size()) { |
370 | if (throw_on_error) { |
371 | throw(std::bad_alloc()); |
372 | } else { |
373 | return(NULL); |
374 | } |
375 | } |
376 | |
377 | void* ptr; |
378 | size_t total_bytes = n_elements * sizeof(T); |
379 | |
380 | #ifdef UNIV_PFS_MEMORY |
381 | /* The header size must not ruin the 64-bit alignment |
382 | on 32-bit systems. Some allocated structures use |
383 | 64-bit fields. */ |
384 | ut_ad((sizeof(ut_new_pfx_t) & 7) == 0); |
385 | total_bytes += sizeof(ut_new_pfx_t); |
386 | #endif /* UNIV_PFS_MEMORY */ |
387 | |
388 | for (size_t retries = 1; ; retries++) { |
389 | |
390 | if (set_to_zero) { |
391 | ptr = calloc(1, total_bytes); |
392 | } else { |
393 | ptr = malloc(total_bytes); |
394 | } |
395 | |
396 | if (ptr != NULL || retries >= alloc_max_retries) { |
397 | break; |
398 | } |
399 | |
400 | os_thread_sleep(1000000 /* 1 second */); |
401 | } |
402 | |
403 | if (ptr == NULL) { |
404 | ib::fatal_or_error(oom_fatal) |
405 | << "Cannot allocate " << total_bytes |
406 | << " bytes of memory after " |
407 | << alloc_max_retries << " retries over " |
408 | << alloc_max_retries << " seconds. OS error: " |
409 | << strerror(errno) << " (" << errno << "). " |
410 | << OUT_OF_MEMORY_MSG; |
411 | if (throw_on_error) { |
412 | throw(std::bad_alloc()); |
413 | } else { |
414 | return(NULL); |
415 | } |
416 | } |
417 | |
418 | #ifdef UNIV_PFS_MEMORY |
419 | ut_new_pfx_t* pfx = static_cast<ut_new_pfx_t*>(ptr); |
420 | |
421 | allocate_trace(total_bytes, file, pfx); |
422 | |
423 | return(reinterpret_cast<pointer>(pfx + 1)); |
424 | #else |
425 | return(reinterpret_cast<pointer>(ptr)); |
426 | #endif /* UNIV_PFS_MEMORY */ |
427 | } |
428 | |
429 | /** Free a memory allocated by allocate() and trace the deallocation. |
430 | @param[in,out] ptr pointer to memory to free */ |
431 | void deallocate(pointer ptr, size_type) |
432 | { |
433 | #ifdef UNIV_PFS_MEMORY |
434 | if (ptr == NULL) { |
435 | return; |
436 | } |
437 | |
438 | ut_new_pfx_t* pfx = reinterpret_cast<ut_new_pfx_t*>(ptr) - 1; |
439 | |
440 | deallocate_trace(pfx); |
441 | |
442 | free(pfx); |
443 | #else |
444 | free(ptr); |
445 | #endif /* UNIV_PFS_MEMORY */ |
446 | } |
447 | |
448 | /** Create an object of type 'T' using the value 'val' over the |
449 | memory pointed by 'p'. */ |
450 | void |
451 | construct( |
452 | pointer p, |
453 | const T& val) |
454 | { |
455 | new(p) T(val); |
456 | } |
457 | |
458 | /** Destroy an object pointed by 'p'. */ |
459 | void |
460 | destroy( |
461 | pointer p) |
462 | { |
463 | p->~T(); |
464 | } |
465 | |
466 | /** Return the address of an object. */ |
467 | pointer |
468 | address( |
469 | reference x) const |
470 | { |
471 | return(&x); |
472 | } |
473 | |
474 | /** Return the address of a const object. */ |
475 | const_pointer |
476 | address( |
477 | const_reference x) const |
478 | { |
479 | return(&x); |
480 | } |
481 | |
482 | template <class U> |
483 | struct rebind { |
484 | typedef ut_allocator<U> other; |
485 | }; |
486 | |
487 | /* The following are custom methods, not required by the standard. */ |
488 | |
489 | #ifdef UNIV_PFS_MEMORY |
490 | |
491 | /** realloc(3)-like method. |
492 | The passed in ptr must have been returned by allocate() and the |
493 | pointer returned by this method must be passed to deallocate() when |
494 | no longer needed. |
495 | @param[in,out] ptr old pointer to reallocate |
496 | @param[in] n_elements new number of elements to allocate |
497 | @param[in] file file name of the caller |
498 | @return newly allocated memory */ |
499 | pointer |
500 | reallocate( |
501 | void* ptr, |
502 | size_type n_elements, |
503 | const char* file) |
504 | { |
505 | if (n_elements == 0) { |
506 | deallocate(static_cast<pointer>(ptr)); |
507 | return(NULL); |
508 | } |
509 | |
510 | if (ptr == NULL) { |
511 | return(allocate(n_elements, NULL, file, false, false)); |
512 | } |
513 | |
514 | if (n_elements > max_size()) { |
515 | return(NULL); |
516 | } |
517 | |
518 | ut_new_pfx_t* pfx_old; |
519 | ut_new_pfx_t* pfx_new; |
520 | size_t total_bytes; |
521 | |
522 | pfx_old = reinterpret_cast<ut_new_pfx_t*>(ptr) - 1; |
523 | |
524 | total_bytes = n_elements * sizeof(T) + sizeof(ut_new_pfx_t); |
525 | |
526 | for (size_t retries = 1; ; retries++) { |
527 | |
528 | pfx_new = static_cast<ut_new_pfx_t*>( |
529 | realloc(pfx_old, total_bytes)); |
530 | |
531 | if (pfx_new != NULL || retries >= alloc_max_retries) { |
532 | break; |
533 | } |
534 | |
535 | os_thread_sleep(1000000 /* 1 second */); |
536 | } |
537 | |
538 | if (pfx_new == NULL) { |
539 | ib::fatal_or_error(oom_fatal) |
540 | << "Cannot reallocate " << total_bytes |
541 | << " bytes of memory after " |
542 | << alloc_max_retries << " retries over " |
543 | << alloc_max_retries << " seconds. OS error: " |
544 | << strerror(errno) << " (" << errno << "). " |
545 | << OUT_OF_MEMORY_MSG; |
546 | return(NULL); |
547 | } |
548 | |
549 | /* pfx_new still contains the description of the old block |
550 | that was presumably freed by realloc(). */ |
551 | deallocate_trace(pfx_new); |
552 | |
553 | /* pfx_new is set here to describe the new block. */ |
554 | allocate_trace(total_bytes, file, pfx_new); |
555 | |
556 | return(reinterpret_cast<pointer>(pfx_new + 1)); |
557 | } |
558 | |
559 | /** Allocate, trace the allocation and construct 'n_elements' objects |
560 | of type 'T'. If the allocation fails or if some of the constructors |
561 | throws an exception, then this method will return NULL. It does not |
562 | throw exceptions. After successfull completion the returned pointer |
563 | must be passed to delete_array() when no longer needed. |
564 | @param[in] n_elements number of elements to allocate |
565 | @param[in] file file name of the caller |
566 | @return pointer to the first allocated object or NULL */ |
567 | pointer |
568 | new_array( |
569 | size_type n_elements, |
570 | const char* file) |
571 | { |
572 | T* p = allocate(n_elements, NULL, file, false, false); |
573 | |
574 | if (p == NULL) { |
575 | return(NULL); |
576 | } |
577 | |
578 | T* first = p; |
579 | size_type i; |
580 | |
581 | try { |
582 | for (i = 0; i < n_elements; i++) { |
583 | new(p) T; |
584 | ++p; |
585 | } |
586 | } catch (...) { |
587 | for (size_type j = 0; j < i; j++) { |
588 | --p; |
589 | p->~T(); |
590 | } |
591 | |
592 | deallocate(first); |
593 | |
594 | throw; |
595 | } |
596 | |
597 | return(first); |
598 | } |
599 | |
600 | /** Destroy, deallocate and trace the deallocation of an array created |
601 | by new_array(). |
602 | @param[in,out] ptr pointer to the first object in the array */ |
603 | void |
604 | delete_array( |
605 | T* ptr) |
606 | { |
607 | if (ptr == NULL) { |
608 | return; |
609 | } |
610 | |
611 | const size_type n_elements = n_elements_allocated(ptr); |
612 | |
613 | T* p = ptr + n_elements - 1; |
614 | |
615 | for (size_type i = 0; i < n_elements; i++) { |
616 | p->~T(); |
617 | --p; |
618 | } |
619 | |
620 | deallocate(ptr); |
621 | } |
622 | |
623 | #endif /* UNIV_PFS_MEMORY */ |
624 | |
625 | /** Allocate a large chunk of memory that can hold 'n_elements' |
626 | objects of type 'T' and trace the allocation. |
627 | @param[in] n_elements number of elements |
628 | @param[in] dontdump if true, advise the OS is not to core |
629 | dump this memory. |
630 | @param[out] pfx storage for the description of the |
631 | allocated memory. The caller must provide space for this one and keep |
632 | it until the memory is no longer needed and then pass it to |
633 | deallocate_large(). |
634 | @return pointer to the allocated memory or NULL */ |
635 | pointer |
636 | allocate_large( |
637 | size_type n_elements, |
638 | ut_new_pfx_t* pfx, |
639 | bool dontdump = false) |
640 | { |
641 | if (n_elements == 0 || n_elements > max_size()) { |
642 | return(NULL); |
643 | } |
644 | |
645 | ulint n_bytes = n_elements * sizeof(T); |
646 | |
647 | pointer ptr = reinterpret_cast<pointer>( |
648 | os_mem_alloc_large(&n_bytes)); |
649 | |
650 | if (ptr == NULL) { |
651 | return NULL; |
652 | } |
653 | |
654 | ut_allocate_trace_dontdump(ptr, n_bytes, dontdump, pfx, NULL); |
655 | |
656 | return(ptr); |
657 | } |
658 | |
659 | /** Free a memory allocated by allocate_large() and trace the |
660 | deallocation. |
661 | @param[in,out] ptr pointer to memory to free |
662 | @param[in] pfx descriptor of the memory, as returned by |
663 | allocate_large(). |
664 | @param[in] dodump if true, advise the OS to include this |
665 | memory again if a core dump occurs. */ |
666 | void |
667 | deallocate_large( |
668 | pointer ptr, |
669 | const ut_new_pfx_t* |
670 | #ifdef UNIV_PFS_MEMORY |
671 | pfx |
672 | #endif |
673 | , |
674 | size_t size, |
675 | bool dodump = false) |
676 | { |
677 | if (dodump) { |
678 | ut_dodump(ptr, size); |
679 | } |
680 | #ifdef UNIV_PFS_MEMORY |
681 | if (pfx) { |
682 | deallocate_trace(pfx); |
683 | } |
684 | #endif /* UNIV_PFS_MEMORY */ |
685 | |
686 | os_mem_free_large(ptr, size); |
687 | } |
688 | |
689 | #ifdef UNIV_PFS_MEMORY |
690 | |
691 | /** Get the performance schema key to use for tracing allocations. |
692 | @param[in] file file name of the caller or NULL if unknown |
693 | @return performance schema key */ |
694 | PSI_memory_key |
695 | get_mem_key( |
696 | const char* file) const |
697 | { |
698 | if (m_key != PSI_NOT_INSTRUMENTED) { |
699 | return(m_key); |
700 | } |
701 | |
702 | if (file == NULL) { |
703 | return(mem_key_std); |
704 | } |
705 | |
706 | /* e.g. "btr0cur", derived from "/path/to/btr0cur.cc" */ |
707 | char keyname[FILENAME_MAX]; |
708 | const size_t len = ut_basename_noext(file, keyname, |
709 | sizeof(keyname)); |
710 | /* If sizeof(keyname) was not enough then the output would |
711 | be truncated, assert that this did not happen. */ |
712 | ut_a(len < sizeof(keyname)); |
713 | |
714 | const PSI_memory_key key = ut_new_get_key_by_file(keyname); |
715 | |
716 | if (key != PSI_NOT_INSTRUMENTED) { |
717 | return(key); |
718 | } |
719 | |
720 | return(mem_key_other); |
721 | } |
722 | |
723 | private: |
724 | |
725 | /** Retrieve the size of a memory block allocated by new_array(). |
726 | @param[in] ptr pointer returned by new_array(). |
727 | @return size of memory block */ |
728 | size_type |
729 | n_elements_allocated( |
730 | const_pointer ptr) |
731 | { |
732 | const ut_new_pfx_t* pfx |
733 | = reinterpret_cast<const ut_new_pfx_t*>(ptr) - 1; |
734 | |
735 | const size_type user_bytes |
736 | = pfx->m_size - sizeof(ut_new_pfx_t); |
737 | |
738 | ut_ad(user_bytes % sizeof(T) == 0); |
739 | |
740 | return(user_bytes / sizeof(T)); |
741 | } |
742 | |
743 | /** Trace a memory allocation. |
744 | After the accounting, the data needed for tracing the deallocation |
745 | later is written into 'pfx'. |
746 | The PFS event name is picked on the following criteria: |
747 | 1. If key (!= PSI_NOT_INSTRUMENTED) has been specified when constructing |
748 | this ut_allocator object, then the name associated with that key will |
749 | be used (this is the recommended approach for new code) |
750 | 2. Otherwise, if "file" is NULL, then the name associated with |
751 | mem_key_std will be used |
752 | 3. Otherwise, if an entry is found by ut_new_get_key_by_file(), that |
753 | corresponds to "file", that will be used (see ut_new_boot()) |
754 | 4. Otherwise, the name associated with mem_key_other will be used. |
755 | @param[in] size number of bytes that were allocated |
756 | @param[in] file file name of the caller or NULL if unknown |
757 | @param[out] pfx placeholder to store the info which will be |
758 | needed when freeing the memory */ |
759 | void |
760 | allocate_trace( |
761 | size_t size, |
762 | const char* file, |
763 | ut_new_pfx_t* pfx) |
764 | { |
765 | const PSI_memory_key key = get_mem_key(file); |
766 | |
767 | pfx->m_key = PSI_MEMORY_CALL(memory_alloc)(key, size, & pfx->m_owner); |
768 | pfx->m_size = size; |
769 | } |
770 | |
771 | /** Trace a memory deallocation. |
772 | @param[in] pfx info for the deallocation */ |
773 | void |
774 | deallocate_trace( |
775 | const ut_new_pfx_t* pfx) |
776 | { |
777 | PSI_MEMORY_CALL(memory_free)(pfx->m_key, pfx->m_size, pfx->m_owner); |
778 | } |
779 | |
780 | /** Performance schema key. */ |
781 | PSI_memory_key m_key; |
782 | |
783 | #endif /* UNIV_PFS_MEMORY */ |
784 | |
785 | private: |
786 | |
787 | /** Assignment operator, not used, thus disabled (private). */ |
788 | template <class U> |
789 | void |
790 | operator=( |
791 | const ut_allocator<U>&); |
792 | }; |
793 | |
794 | /** Compare two allocators of the same type. |
795 | As long as the type of A1 and A2 is the same, a memory allocated by A1 |
796 | could be freed by A2 even if the pfs mem key is different. */ |
797 | template <typename T> |
798 | inline |
799 | bool |
800 | operator==(const ut_allocator<T>&, const ut_allocator<T>&) { return(true); } |
801 | |
802 | /** Compare two allocators of the same type. */ |
803 | template <typename T> |
804 | inline |
805 | bool |
806 | operator!=( |
807 | const ut_allocator<T>& lhs, |
808 | const ut_allocator<T>& rhs) |
809 | { |
810 | return(!(lhs == rhs)); |
811 | } |
812 | |
813 | #ifdef UNIV_PFS_MEMORY |
814 | |
815 | /** Allocate, trace the allocation and construct an object. |
816 | Use this macro instead of 'new' within InnoDB. |
817 | For example: instead of |
818 | Foo* f = new Foo(args); |
819 | use: |
820 | Foo* f = UT_NEW(Foo(args), mem_key_some); |
821 | Upon failure to allocate the memory, this macro may return NULL. It |
822 | will not throw exceptions. After successfull allocation the returned |
823 | pointer must be passed to UT_DELETE() when no longer needed. |
824 | @param[in] expr any expression that could follow "new" |
825 | @param[in] key performance schema memory tracing key |
826 | @return pointer to the created object or NULL */ |
827 | #define UT_NEW(expr, key) \ |
828 | /* Placement new will return NULL and not attempt to construct an |
829 | object if the passed in pointer is NULL, e.g. if allocate() has |
830 | failed to allocate memory and has returned NULL. */ \ |
831 | ::new(ut_allocator<byte>(key).allocate( \ |
832 | sizeof expr, NULL, __FILE__, false, false)) expr |
833 | |
834 | /** Allocate, trace the allocation and construct an object. |
835 | Use this macro instead of 'new' within InnoDB and instead of UT_NEW() |
836 | when creating a dedicated memory key is not feasible. |
837 | For example: instead of |
838 | Foo* f = new Foo(args); |
839 | use: |
840 | Foo* f = UT_NEW_NOKEY(Foo(args)); |
841 | Upon failure to allocate the memory, this macro may return NULL. It |
842 | will not throw exceptions. After successfull allocation the returned |
843 | pointer must be passed to UT_DELETE() when no longer needed. |
844 | @param[in] expr any expression that could follow "new" |
845 | @return pointer to the created object or NULL */ |
846 | #define UT_NEW_NOKEY(expr) UT_NEW(expr, PSI_NOT_INSTRUMENTED) |
847 | |
848 | /** Destroy, deallocate and trace the deallocation of an object created by |
849 | UT_NEW() or UT_NEW_NOKEY(). |
850 | We can't instantiate ut_allocator without having the type of the object, thus |
851 | we redirect this to a templated function. */ |
852 | #define UT_DELETE(ptr) ut_delete(ptr) |
853 | |
854 | /** Destroy and account object created by UT_NEW() or UT_NEW_NOKEY(). |
855 | @param[in,out] ptr pointer to the object */ |
856 | template <typename T> |
857 | inline |
858 | void |
859 | ut_delete( |
860 | T* ptr) |
861 | { |
862 | if (ptr == NULL) { |
863 | return; |
864 | } |
865 | |
866 | ut_allocator<T> allocator; |
867 | |
868 | allocator.destroy(ptr); |
869 | allocator.deallocate(ptr); |
870 | } |
871 | |
872 | /** Allocate and account 'n_elements' objects of type 'type'. |
873 | Use this macro to allocate memory within InnoDB instead of 'new[]'. |
874 | The returned pointer must be passed to UT_DELETE_ARRAY(). |
875 | @param[in] type type of objects being created |
876 | @param[in] n_elements number of objects to create |
877 | @param[in] key performance schema memory tracing key |
878 | @return pointer to the first allocated object or NULL */ |
879 | #define UT_NEW_ARRAY(type, n_elements, key) \ |
880 | ut_allocator<type>(key).new_array(n_elements, __FILE__) |
881 | |
882 | /** Allocate and account 'n_elements' objects of type 'type'. |
883 | Use this macro to allocate memory within InnoDB instead of 'new[]' and |
884 | instead of UT_NEW_ARRAY() when it is not feasible to create a dedicated key. |
885 | @param[in] type type of objects being created |
886 | @param[in] n_elements number of objects to create |
887 | @return pointer to the first allocated object or NULL */ |
888 | #define UT_NEW_ARRAY_NOKEY(type, n_elements) \ |
889 | UT_NEW_ARRAY(type, n_elements, PSI_NOT_INSTRUMENTED) |
890 | |
891 | /** Destroy, deallocate and trace the deallocation of an array created by |
892 | UT_NEW_ARRAY() or UT_NEW_ARRAY_NOKEY(). |
893 | We can't instantiate ut_allocator without having the type of the object, thus |
894 | we redirect this to a templated function. */ |
895 | #define UT_DELETE_ARRAY(ptr) ut_delete_array(ptr) |
896 | |
897 | /** Destroy and account objects created by UT_NEW_ARRAY() or |
898 | UT_NEW_ARRAY_NOKEY(). |
899 | @param[in,out] ptr pointer to the first object in the array */ |
900 | template <typename T> |
901 | inline |
902 | void |
903 | ut_delete_array( |
904 | T* ptr) |
905 | { |
906 | ut_allocator<T>().delete_array(ptr); |
907 | } |
908 | |
909 | #define ut_malloc(n_bytes, key) static_cast<void*>( \ |
910 | ut_allocator<byte>(key).allocate( \ |
911 | n_bytes, NULL, __FILE__, false, false)) |
912 | |
913 | #define ut_malloc_dontdump(n_bytes) static_cast<void*>( \ |
914 | ut_allocator<byte>(PSI_NOT_INSTRUMENTED).allocate_large( \ |
915 | n_bytes, true)) |
916 | |
917 | #define ut_zalloc(n_bytes, key) static_cast<void*>( \ |
918 | ut_allocator<byte>(key).allocate( \ |
919 | n_bytes, NULL, __FILE__, true, false)) |
920 | |
921 | #define ut_malloc_nokey(n_bytes) static_cast<void*>( \ |
922 | ut_allocator<byte>(PSI_NOT_INSTRUMENTED).allocate( \ |
923 | n_bytes, NULL, __FILE__, false, false)) |
924 | |
925 | #define ut_zalloc_nokey(n_bytes) static_cast<void*>( \ |
926 | ut_allocator<byte>(PSI_NOT_INSTRUMENTED).allocate( \ |
927 | n_bytes, NULL, __FILE__, true, false)) |
928 | |
929 | #define ut_zalloc_nokey_nofatal(n_bytes) static_cast<void*>( \ |
930 | ut_allocator<byte, false>(PSI_NOT_INSTRUMENTED).allocate( \ |
931 | n_bytes, NULL, __FILE__, true, false)) |
932 | |
933 | #define ut_realloc(ptr, n_bytes) static_cast<void*>( \ |
934 | ut_allocator<byte>(PSI_NOT_INSTRUMENTED).reallocate( \ |
935 | ptr, n_bytes, __FILE__)) |
936 | |
937 | #define ut_free(ptr) ut_allocator<byte>(PSI_NOT_INSTRUMENTED).deallocate( \ |
938 | reinterpret_cast<byte*>(ptr)) |
939 | |
940 | #define ut_free_dodump(ptr, size) static_cast<void*>( \ |
941 | ut_allocator<byte>(PSI_NOT_INSTRUMENTED).deallocate_large( \ |
942 | ptr, NULL, size, true)) |
943 | |
944 | #else /* UNIV_PFS_MEMORY */ |
945 | |
946 | /* Fallbacks when memory tracing is disabled at compile time. */ |
947 | |
948 | #define UT_NEW(expr, key) ::new(std::nothrow) expr |
949 | #define UT_NEW_NOKEY(expr) ::new(std::nothrow) expr |
950 | #define UT_DELETE(ptr) ::delete ptr |
951 | |
952 | #define UT_NEW_ARRAY(type, n_elements, key) \ |
953 | ::new(std::nothrow) type[n_elements] |
954 | |
955 | #define UT_NEW_ARRAY_NOKEY(type, n_elements) \ |
956 | ::new(std::nothrow) type[n_elements] |
957 | |
958 | #define UT_DELETE_ARRAY(ptr) ::delete[] ptr |
959 | |
960 | #define ut_malloc(n_bytes, key) ::malloc(n_bytes) |
961 | |
962 | #define ut_zalloc(n_bytes, key) ::calloc(1, n_bytes) |
963 | |
964 | #define ut_malloc_nokey(n_bytes) ::malloc(n_bytes) |
965 | |
966 | static inline void *ut_malloc_dontdump(size_t n_bytes) |
967 | { |
968 | void *ptr = os_mem_alloc_large(&n_bytes); |
969 | |
970 | ut_allocate_trace_dontdump(ptr, n_bytes, true, NULL, NULL); |
971 | return ptr; |
972 | } |
973 | |
974 | #define ut_zalloc_nokey(n_bytes) ::calloc(1, n_bytes) |
975 | |
976 | #define ut_zalloc_nokey_nofatal(n_bytes) ::calloc(1, n_bytes) |
977 | |
978 | #define ut_realloc(ptr, n_bytes) ::realloc(ptr, n_bytes) |
979 | |
980 | #define ut_free(ptr) ::free(ptr) |
981 | |
982 | static inline void ut_free_dodump(void *ptr, size_t size) |
983 | { |
984 | ut_dodump(ptr, size); |
985 | os_mem_free_large(ptr, size); |
986 | } |
987 | |
988 | #endif /* UNIV_PFS_MEMORY */ |
989 | |
990 | #endif /* ut0new_h */ |
991 | |