1 /*****************************************************************************
2
3 Copyright (c) 1994, 2019, 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 ut/ut0ut.cc
28 Various utilities for Innobase.
29
30 Created 5/11/1994 Heikki Tuuri
31 ********************************************************************/
32
33 #include "my_config.h"
34
35 #include <errno.h>
36 #include <time.h>
37 #include <string>
38
39 #include "ha_prototypes.h"
40
41 #ifdef HAVE_SYS_TIME_H
42 #include <sys/time.h>
43 #endif
44
45 #ifndef UNIV_HOTBACKUP
46 #include <mysql_com.h>
47 #endif /* !UNIV_HOTBACKUP */
48
49 #include "mysql_com.h"
50 #include "os0thread.h"
51 #include "ut0ut.h"
52
53 #ifndef UNIV_HOTBACKUP
54 #include "sql/log.h"
55 #include "trx0trx.h"
56 #endif /* !UNIV_HOTBACKUP */
57
58 #include "clone0api.h"
59 #include "mysql/components/services/log_builtins.h"
60 #include "sql/derror.h"
61
62 namespace ut {
63 ulong spin_wait_pause_multiplier = 50;
64 }
65
66 /** Returns system time. We do not specify the format of the time returned:
67 the only way to manipulate it is to use the function ut_difftime.
68 @return system time */
ut_time(void)69 ib_time_t ut_time(void) { return (time(nullptr)); }
70
71 /** Returns the number of microseconds since epoch. Uses the monotonic clock.
72 @return us since epoch or 0 if failed to retrieve */
ut_time_monotonic_us(void)73 ib_time_monotonic_us_t ut_time_monotonic_us(void) {
74 const auto now = std::chrono::steady_clock::now();
75 return (std::chrono::duration_cast<std::chrono::microseconds>(
76 now.time_since_epoch())
77 .count());
78 }
79
80 /** Returns the number of milliseconds since epoch. Uses the monotonic clock.
81 @return ms since epoch */
ut_time_monotonic_ms(void)82 ib_time_monotonic_ms_t ut_time_monotonic_ms(void) {
83 const auto now = std::chrono::steady_clock::now();
84 return (std::chrono::duration_cast<std::chrono::milliseconds>(
85 now.time_since_epoch())
86 .count());
87 }
88
89 /** Returns the number of seconds since epoch. Uses the monotonic clock.
90 @return us since epoch or 0 if failed to retrieve */
ut_time_monotonic(void)91 ib_time_monotonic_t ut_time_monotonic(void) {
92 const auto now = std::chrono::steady_clock::now();
93
94 const auto ret =
95 std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch())
96 .count();
97
98 return (ret);
99 }
100
101 /** Returns the difference of two times in seconds.
102 @return time2 - time1 expressed in seconds */
ut_difftime(ib_time_t time2,ib_time_t time1)103 double ut_difftime(ib_time_t time2, /*!< in: time */
104 ib_time_t time1) /*!< in: time */
105 {
106 return (difftime(time2, time1));
107 }
108
109 #ifdef UNIV_HOTBACKUP
110 /** Sprintfs a timestamp to a buffer with no spaces and with ':' characters
111 replaced by '_'.
112 @param[in] buf buffer where to sprintf */
meb_sprintf_timestamp_without_extra_chars(char * buf)113 void meb_sprintf_timestamp_without_extra_chars(
114 char *buf) /*!< in: buffer where to sprintf */
115 {
116 #ifdef _WIN32
117 SYSTEMTIME cal_tm;
118
119 GetLocalTime(&cal_tm);
120
121 sprintf(buf, "%02d%02d%02d_%2d_%02d_%02d", (int)cal_tm.wYear % 100,
122 (int)cal_tm.wMonth, (int)cal_tm.wDay, (int)cal_tm.wHour,
123 (int)cal_tm.wMinute, (int)cal_tm.wSecond);
124 #else
125 struct tm *cal_tm_ptr;
126 time_t tm;
127
128 struct tm cal_tm;
129 time(&tm);
130 localtime_r(&tm, &cal_tm);
131 cal_tm_ptr = &cal_tm;
132 sprintf(buf, "%02d%02d%02d_%2d_%02d_%02d", cal_tm_ptr->tm_year % 100,
133 cal_tm_ptr->tm_mon + 1, cal_tm_ptr->tm_mday, cal_tm_ptr->tm_hour,
134 cal_tm_ptr->tm_min, cal_tm_ptr->tm_sec);
135 #endif
136 }
137
138 #else /* UNIV_HOTBACKUP */
139
ut_delay(ulint delay)140 ulint ut_delay(ulint delay) {
141 ulint i, j;
142 /* We don't expect overflow here, as ut::spin_wait_pause_multiplier is limited
143 to 100, and values of delay are not larger than @@innodb_spin_wait_delay
144 which is limited by 1 000. Anyway, in case an overflow happened, the program
145 would still work (as iterations is unsigned). */
146 const ulint iterations = delay * ut::spin_wait_pause_multiplier;
147 UT_LOW_PRIORITY_CPU();
148
149 j = 0;
150
151 for (i = 0; i < iterations; i++) {
152 j += i;
153 UT_RELAX_CPU();
154 }
155
156 UT_RESUME_PRIORITY_CPU();
157
158 return (j);
159 }
160 #endif /* UNIV_HOTBACKUP */
161
162 /** Calculates fast the number rounded up to the nearest power of 2.
163 @return first power of 2 which is >= n */
ut_2_power_up(ulint n)164 ulint ut_2_power_up(ulint n) /*!< in: number != 0 */
165 {
166 ulint res;
167
168 res = 1;
169
170 ut_ad(n > 0);
171
172 while (res < n) {
173 res = res * 2;
174 }
175
176 return (res);
177 }
178
179 #ifndef UNIV_HOTBACKUP
180 /** Get a fixed-length string, quoted as an SQL identifier.
181 If the string contains a slash '/', the string will be
182 output as two identifiers separated by a period (.),
183 as in SQL database_name.identifier.
184 @param [in] trx transaction (NULL=no quotes).
185 @param [in] name table name.
186 @retval String quoted as an SQL identifier.
187 */
ut_get_name(const trx_t * trx,const char * name)188 std::string ut_get_name(const trx_t *trx, const char *name) {
189 /* 2 * NAME_LEN for database and table name,
190 and some slack for the #mysql50# prefix and quotes */
191 char buf[3 * NAME_LEN];
192 const char *bufend;
193
194 bufend = innobase_convert_name(buf, sizeof buf, name, strlen(name),
195 trx ? trx->mysql_thd : nullptr);
196 buf[bufend - buf] = '\0';
197 return (std::string(buf, 0, bufend - buf));
198 }
199
200 /** Outputs a fixed-length string, quoted as an SQL identifier.
201 If the string contains a slash '/', the string will be
202 output as two identifiers separated by a period (.),
203 as in SQL database_name.identifier. */
ut_print_name(FILE * f,const trx_t * trx,const char * name)204 void ut_print_name(FILE *f, /*!< in: output stream */
205 const trx_t *trx, /*!< in: transaction */
206 const char *name) /*!< in: name to print */
207 {
208 /* 2 * NAME_LEN for database and table name,
209 and some slack for the #mysql50# prefix and quotes */
210 char buf[3 * NAME_LEN];
211 const char *bufend;
212
213 bufend = innobase_convert_name(buf, sizeof buf, name, strlen(name),
214 trx ? trx->mysql_thd : nullptr);
215
216 if (fwrite(buf, 1, bufend - buf, f) != (size_t)(bufend - buf)) {
217 perror("fwrite");
218 }
219 }
220
221 /** Format a table name, quoted as an SQL identifier.
222 If the name contains a slash '/', the result will contain two
223 identifiers separated by a period (.), as in SQL
224 database_name.table_name.
225 @see table_name_t
226 @param[in] name table or index name
227 @param[out] formatted formatted result, will be NUL-terminated
228 @param[in] formatted_size size of the buffer in bytes
229 @return pointer to 'formatted' */
ut_format_name(const char * name,char * formatted,ulint formatted_size)230 char *ut_format_name(const char *name, char *formatted, ulint formatted_size) {
231 switch (formatted_size) {
232 case 1:
233 formatted[0] = '\0';
234 /* FALL-THROUGH */
235 case 0:
236 return (formatted);
237 }
238
239 char *end;
240
241 end = innobase_convert_name(formatted, formatted_size, name, strlen(name),
242 nullptr);
243
244 /* If the space in 'formatted' was completely used, then sacrifice
245 the last character in order to write '\0' at the end. */
246 if ((ulint)(end - formatted) == formatted_size) {
247 end--;
248 }
249
250 ut_a((ulint)(end - formatted) < formatted_size);
251
252 *end = '\0';
253
254 return (formatted);
255 }
256
257 /** Catenate files. */
ut_copy_file(FILE * dest,FILE * src)258 void ut_copy_file(FILE *dest, /*!< in: output file */
259 FILE *src) /*!< in: input file to be appended to output */
260 {
261 long len = ftell(src);
262 char buf[4096];
263
264 rewind(src);
265 do {
266 size_t maxs = len < (long)sizeof buf ? (size_t)len : sizeof buf;
267 size_t size = fread(buf, 1, maxs, src);
268 if (fwrite(buf, 1, size, dest) != size) {
269 perror("fwrite");
270 }
271 len -= (long)size;
272 if (size < maxs) {
273 break;
274 }
275 } while (len > 0);
276 }
277
ut_format_byte_value(uint64_t data_bytes,std::string & data_str)278 void ut_format_byte_value(uint64_t data_bytes, std::string &data_str) {
279 int unit_sz = 1024;
280 auto exp = static_cast<int>(
281 (data_bytes == 0) ? 0 : std::log(data_bytes) / std::log(unit_sz));
282 auto data_value = data_bytes / std::pow(unit_sz, exp);
283
284 char unit[] = " KMGTPE";
285 auto index = static_cast<size_t>(exp > 0 ? exp : 0);
286
287 /* 64 BIT number should never go beyond Exabyte. */
288 auto max_index = sizeof(unit) - 2;
289 if (index > max_index) {
290 ut_ad(false);
291 index = max_index;
292 }
293
294 std::stringstream data_strm;
295 if (index == 0) {
296 data_strm << std::setprecision(2) << std::fixed << data_value << " "
297 << "Bytes";
298 } else {
299 data_strm << std::setprecision(2) << std::fixed << data_value << " "
300 << unit[index] << "iB";
301 }
302 data_str = data_strm.str();
303 }
304
305 #endif /* !UNIV_HOTBACKUP */
306
307 #ifdef _WIN32
308 #include <stdarg.h>
309
310 /** A substitute for vsnprintf(3), formatted output conversion into
311 a limited buffer. Note: this function DOES NOT return the number of
312 characters that would have been printed if the buffer was unlimited because
313 VC's _vsnprintf() returns -1 in this case and we would need to call
314 _vscprintf() in addition to estimate that but we would need another copy
315 of "ap" for that and VC does not provide va_copy(). */
ut_vsnprintf(char * str,size_t size,const char * fmt,va_list ap)316 void ut_vsnprintf(char *str, /*!< out: string */
317 size_t size, /*!< in: str size */
318 const char *fmt, /*!< in: format */
319 va_list ap) /*!< in: format values */
320 {
321 _vsnprintf(str, size, fmt, ap);
322 str[size - 1] = '\0';
323 }
324
325 #endif /* _WIN32 */
326
327 /** Convert an error number to a human readable text message.
328 The returned string is static and should not be freed or modified.
329 @param[in] num InnoDB internal error number
330 @return string, describing the error */
ut_strerr(dberr_t num)331 const char *ut_strerr(dberr_t num) {
332 switch (num) {
333 case DB_CACHE_RECORDS:
334 return ("Request caller to copy tuple");
335 case DB_SUCCESS:
336 return ("Success");
337 case DB_SUCCESS_LOCKED_REC:
338 return ("Success, record lock created");
339 case DB_SKIP_LOCKED:
340 return ("Skip locked records");
341 case DB_LOCK_NOWAIT:
342 return ("Don't wait for locks");
343 case DB_ERROR:
344 return ("Generic error");
345 case DB_READ_ONLY:
346 return ("Read only transaction");
347 case DB_INTERRUPTED:
348 return ("Operation interrupted");
349 case DB_OUT_OF_MEMORY:
350 return ("Cannot allocate memory");
351 case DB_OUT_OF_FILE_SPACE:
352 case DB_OUT_OF_DISK_SPACE:
353 return ("Out of disk space");
354 case DB_LOCK_WAIT:
355 return ("Lock wait");
356 case DB_DEADLOCK:
357 return ("Deadlock");
358 case DB_ROLLBACK:
359 return ("Rollback");
360 case DB_DUPLICATE_KEY:
361 return ("Duplicate key");
362 case DB_MISSING_HISTORY:
363 return ("Required history data has been deleted");
364 case DB_CLUSTER_NOT_FOUND:
365 return ("Cluster not found");
366 case DB_TABLE_NOT_FOUND:
367 return ("Table not found");
368 case DB_MUST_GET_MORE_FILE_SPACE:
369 return ("More file space needed");
370 case DB_TABLE_IS_BEING_USED:
371 return ("Table is being used");
372 case DB_TOO_BIG_RECORD:
373 return ("Record too big");
374 case DB_TOO_BIG_INDEX_COL:
375 return ("Index columns size too big");
376 case DB_LOCK_WAIT_TIMEOUT:
377 return ("Lock wait timeout");
378 case DB_NO_REFERENCED_ROW:
379 return ("Referenced key value not found");
380 case DB_ROW_IS_REFERENCED:
381 return ("Row is referenced");
382 case DB_CANNOT_ADD_CONSTRAINT:
383 return ("Cannot add constraint");
384 case DB_CORRUPTION:
385 return ("Data structure corruption");
386 case DB_CANNOT_DROP_CONSTRAINT:
387 return ("Cannot drop constraint");
388 case DB_NO_SAVEPOINT:
389 return ("No such savepoint");
390 case DB_TABLESPACE_EXISTS:
391 return ("Tablespace already exists");
392 case DB_TABLESPACE_DELETED:
393 return ("Tablespace deleted or being deleted");
394 case DB_TABLESPACE_NOT_FOUND:
395 return ("Tablespace not found");
396 case DB_LOCK_TABLE_FULL:
397 return ("Lock structs have exhausted the buffer pool");
398 case DB_FOREIGN_DUPLICATE_KEY:
399 return ("Foreign key activated with duplicate keys");
400 case DB_FOREIGN_EXCEED_MAX_CASCADE:
401 return ("Foreign key cascade delete/update exceeds max depth");
402 case DB_TOO_MANY_CONCURRENT_TRXS:
403 return ("Too many concurrent transactions");
404 case DB_UNSUPPORTED:
405 return ("Unsupported");
406 case DB_INVALID_NULL:
407 return ("NULL value encountered in NOT NULL column");
408 case DB_STATS_DO_NOT_EXIST:
409 return ("Persistent statistics do not exist");
410 case DB_FAIL:
411 return ("Failed, retry may succeed");
412 case DB_OVERFLOW:
413 return ("Overflow");
414 case DB_UNDERFLOW:
415 return ("Underflow");
416 case DB_STRONG_FAIL:
417 return ("Failed, retry will not succeed");
418 case DB_ZIP_OVERFLOW:
419 return ("Zip overflow");
420 case DB_RECORD_NOT_FOUND:
421 return ("Record not found");
422 case DB_CHILD_NO_INDEX:
423 return ("No index on referencing keys in referencing table");
424 case DB_PARENT_NO_INDEX:
425 return ("No index on referenced keys in referenced table");
426 case DB_FTS_INVALID_DOCID:
427 return ("FTS Doc ID cannot be zero");
428 case DB_INDEX_CORRUPT:
429 return ("Index corrupted");
430 case DB_UNDO_RECORD_TOO_BIG:
431 return ("Undo record too big");
432 case DB_END_OF_INDEX:
433 return ("End of index");
434 case DB_END_OF_BLOCK:
435 return ("End of block");
436 case DB_IO_ERROR:
437 return ("I/O error");
438 case DB_TABLE_IN_FK_CHECK:
439 return ("Table is being used in foreign key check");
440 case DB_DATA_MISMATCH:
441 return ("data mismatch");
442 case DB_SCHEMA_MISMATCH:
443 return ("schema mismatch");
444 case DB_NOT_FOUND:
445 return ("not found");
446 case DB_ONLINE_LOG_TOO_BIG:
447 return ("Log size exceeded during online index creation");
448 case DB_IDENTIFIER_TOO_LONG:
449 return ("Identifier name is too long");
450 case DB_FTS_EXCEED_RESULT_CACHE_LIMIT:
451 return ("FTS query exceeds result cache limit");
452 case DB_TEMP_FILE_WRITE_FAIL:
453 return ("Temp file write failure");
454 case DB_CANT_CREATE_GEOMETRY_OBJECT:
455 return ("Can't create specificed geometry data object");
456 case DB_CANNOT_OPEN_FILE:
457 return ("Cannot open a file");
458 case DB_TABLE_CORRUPT:
459 return ("Table is corrupted");
460 case DB_FTS_TOO_MANY_WORDS_IN_PHRASE:
461 return ("Too many words in a FTS phrase or proximity search");
462 case DB_IO_DECOMPRESS_FAIL:
463 return ("Page decompress failed after reading from disk");
464 case DB_IO_NO_PUNCH_HOLE:
465 return ("No punch hole support");
466 case DB_IO_NO_PUNCH_HOLE_FS:
467 return ("Punch hole not supported by the file system");
468 case DB_IO_NO_PUNCH_HOLE_TABLESPACE:
469 return ("Punch hole not supported by the tablespace");
470 case DB_IO_NO_ENCRYPT_TABLESPACE:
471 return ("Page encryption not supported by the tablespace");
472 case DB_IO_DECRYPT_FAIL:
473 return ("Page decryption failed after reading from disk");
474 case DB_IO_PARTIAL_FAILED:
475 return ("Partial IO failed");
476 case DB_FORCED_ABORT:
477 return (
478 "Transaction aborted by another higher priority "
479 "transaction");
480 case DB_WRONG_FILE_NAME:
481 return ("Invalid Filename");
482 case DB_NO_FK_ON_S_BASE_COL:
483 return (
484 "Cannot add foreign key on the base column "
485 "of stored column");
486 case DB_COMPUTE_VALUE_FAILED:
487 return ("Compute generated column failed");
488 case DB_V1_DBLWR_INIT_FAILED:
489 return (
490 "Failed to initialize the doublewrite extents "
491 "in the system tablespace");
492 case DB_V1_DBLWR_CREATE_FAILED:
493 return (
494 "Failed to create the doublewrite extents "
495 "in the system tablespace");
496 case DB_DBLWR_INIT_FAILED:
497 return ("Failed to create a doublewrite instance");
498 case DB_DBLWR_NOT_EXISTS:
499 return (
500 "Failed to find a doublewrite buffer "
501 "in the system tablespace");
502 case DB_INVALID_ENCRYPTION_META:
503 return ("Invalid encryption meta-data information");
504 case DB_ABORT_INCOMPLETE_CLONE:
505 return ("Incomplete cloned data directory");
506 case DB_SERVER_VERSION_LOW:
507 return (
508 "Cannot boot server with lower version than that built the "
509 "tablespace");
510 case DB_NO_SESSION_TEMP:
511 return ("No session temporary tablespace allocated");
512 case DB_TOO_LONG_PATH:
513 return (
514 "Cannot create tablespace since the filepath is too long for this "
515 "OS");
516 case DB_BTREE_LEVEL_LIMIT_EXCEEDED:
517 return ("Btree level limit exceeded");
518 case DB_END_SAMPLE_READ:
519 return ("Sample reader has been requested to stop sampling");
520 case DB_OUT_OF_RESOURCES:
521 return ("System has run out of resources");
522
523 case DB_PAGE_IS_BLANK:
524 return ("Page is blank");
525
526 case DB_ERROR_UNSET:;
527 /* Fall through. */
528
529 /* do not add default: in order to produce a warning if new code
530 is added to the enum but not added here */
531 }
532
533 /* we abort here because if unknown error code is given, this could
534 mean that memory corruption has happened and someone's error-code
535 variable has been overwritten with bogus data */
536 ut_error;
537 }
538
539 namespace ib {
540
541 #if !defined(UNIV_HOTBACKUP) && !defined(UNIV_NO_ERR_MSGS)
542
log_event(std::string msg)543 void logger::log_event(std::string msg) {
544 #if !(defined XTRABACKUP)
545 LogEvent()
546 .type(LOG_TYPE_ERROR)
547 .prio(m_level)
548 .errcode(m_err)
549 .subsys("InnoDB")
550 .verbatim(msg.c_str());
551 #else
552 fprintf(stderr, "%s\n", msg.c_str());
553 #endif
554 }
~logger()555 logger::~logger() { log_event(m_oss.str()); }
556
~fatal()557 fatal::~fatal() {
558 #if !(defined XTRABACKUP)
559 log_event("[FATAL] " + m_oss.str());
560 #else
561 fprintf(stderr, "%s\n", m_oss.str().c_str());
562 #endif
563 ut_error;
564 }
565
~fatal_or_error()566 fatal_or_error::~fatal_or_error() {
567 if (m_fatal) {
568 log_event("[FATAL] " + m_oss.str());
569 ut_error;
570 }
571 }
572
573 #endif /* !UNIV_NO_ERR_MSGS */
574
575 } // namespace ib
576