1
/* Copyright (c) 2005 PrimeBase Technologies GmbH
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
* 2005-01-03 Paul McCullagh
24
#include "xt_config.h"
33
#include <sys/resource.h>
43
#include "strutil_xt.h"
44
#include "pthread_xt.h"
45
#include "thread_xt.h"
46
#include "memory_xt.h"
47
#include "sortedlist_xt.h"
50
#include "database_xt.h"
53
#define DEBUG_NO_ACTIVITY
56
void xt_db_exit_thread(XTThreadPtr self);
58
static void thr_accumulate_statistics(XTThreadPtr self);
60
#define XT_NO_THREAD_ID 0
61
#define XT_SYS_THREAD_ID 1
62
#define XT_MIN_THREAD_ID 2
65
* -----------------------------------------------------------------------
69
xtPublic u_int xt_thr_maximum_threads;
70
xtPublic u_int xt_thr_current_thread_count;
71
xtPublic u_int xt_thr_current_max_threads;
73
/* This structure is a double linked list of thread, with a wait
76
static XTLinkedListPtr thr_list;
78
/* This structure maps thread ID's to thread pointers. */
79
THR_ARRAY_LOCK_TYPE xt_thr_array_resize_lock;
80
xtPublic XTThreadDataRec *xt_thr_array;
81
static xt_mutex_type thr_array_lock;
83
/* Global accumulated statistics: */
84
static XTStatisticsRec thr_statistics;
87
static void break_in_assertion(c_char *expr, c_char *func, c_char *file, u_int line)
89
printf("%s(%s:%d) %s\n", func, file, (int) line, expr);
94
* -----------------------------------------------------------------------
98
void XTLockTask::tk_init(struct XTThread *self)
100
xt_init_mutex_with_autoname(self, <_mutex);
103
void XTLockTask::tk_exit()
105
xt_free_mutex(<_mutex);
109
void XTLockTask::tk_lock()
111
xt_lock_mutex_ns(<_mutex);
114
void XTLockTask::tk_unlock()
116
xt_unlock_mutex_ns(<_mutex);
120
* -----------------------------------------------------------------------
124
static xt_mutex_type log_mutex;
125
static int log_level = 0;
126
static FILE *log_file = NULL;
127
static xtBool log_newline = TRUE;
129
xtPublic xtBool xt_init_logging(void)
134
log_level = XT_LOG_TRACE;
135
err = xt_p_mutex_init_with_autoname(&log_mutex, NULL);
137
xt_log_errno(XT_NS_CONTEXT, err);
142
if (!xt_init_trace()) {
149
xtPublic void xt_exit_logging(void)
152
xt_free_mutex(&log_mutex);
158
xtPublic void xt_get_now(char *buffer, size_t len)
164
if (ticks == (time_t) -1) {
166
printf(buffer, "** error %d getting time **", errno);
168
snprintf(buffer, len, "** error %d getting time **", errno);
172
localtime_r(&ticks, <ime);
173
strftime(buffer, len, "%y%m%d %H:%M:%S", <ime);
176
static void thr_log_newline(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level)
180
char thr_name[XT_THR_NAME_SIZE+3];
182
xt_get_now(time_str, 200);
183
if (self && *self->t_name) {
184
xt_strcpy(XT_THR_NAME_SIZE+3, thr_name, " ");
185
xt_strcat(XT_THR_NAME_SIZE+3, thr_name, self->t_name);
190
case XT_LOG_FATAL: level_str = " [Fatal]"; break;
191
case XT_LOG_ERROR: level_str = " [Error]"; break;
192
case XT_LOG_WARNING: level_str = " [Warning]"; break;
193
case XT_LOG_INFO: level_str = " [Note]"; break;
194
case XT_LOG_TRACE: level_str = " [Trace]"; break;
195
default: level_str = " "; break;
197
if (func && *func && *func != '-') {
198
char func_name[XT_MAX_FUNC_NAME_SIZE];
200
xt_strcpy_term(XT_MAX_FUNC_NAME_SIZE, func_name, func, '(');
202
fprintf(log_file, "%s%s%s %s(%s:%d) ", time_str, level_str, thr_name, func_name, xt_last_name_of_path(file), line);
204
fprintf(log_file, "%s%s%s %s() ", time_str, level_str, thr_name, func_name);
208
fprintf(log_file, "%s%s%s [%s:%d] ", time_str, level_str, thr_name, xt_last_name_of_path(file), line);
210
fprintf(log_file, "%s%s%s ", time_str, level_str, thr_name);
215
/* Windows uses printf()!! */
216
#define DEFAULT_LOG_BUFFER_SIZE 2000
219
#define DEFAULT_LOG_BUFFER_SIZE 10
221
#define DEFAULT_LOG_BUFFER_SIZE 2000
225
void xt_log_flush(XTThreadPtr XT_UNUSED(self))
231
* Log the given formated string information to the log file.
232
* Before each new line, this function writes the
233
* log header, which includes the time, log level,
234
* and source file and line number (optional).
236
static void thr_log_va(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, c_char *fmt, va_list ap)
238
char buffer[DEFAULT_LOG_BUFFER_SIZE];
239
char *log_string = NULL;
241
if (level > log_level)
244
xt_lock_mutex_ns(&log_mutex);
247
vsprintf(buffer, fmt, ap);
250
#if !defined(va_copy) || defined(XT_SOLARIS)
253
len = vsnprintf(buffer, DEFAULT_LOG_BUFFER_SIZE-1, fmt, ap);
254
if (len > DEFAULT_LOG_BUFFER_SIZE-1)
255
len = DEFAULT_LOG_BUFFER_SIZE-1;
259
/* Use the buffer, unless it is too small */
263
if (vsnprintf(buffer, DEFAULT_LOG_BUFFER_SIZE, fmt, ap) >= DEFAULT_LOG_BUFFER_SIZE) {
264
if (vasprintf(&log_string, fmt, ap2) == -1)
273
char *str, *str_end, tmp_ch;
278
thr_log_newline(self, func, file, line, level);
281
str_end = strchr(str, '\n');
289
str_end = str + strlen(str);
292
fprintf(log_file, "%s", str);
298
if (log_string != buffer)
302
xt_unlock_mutex_ns(&log_mutex);
305
xtPublic void xt_logf(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, c_char *fmt, ...)
310
thr_log_va(self, func, file, line, level, fmt, ap);
314
xtPublic void xt_log(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, c_char *string)
316
xt_logf(self, func, file, line, level, "%s", string);
319
static int thr_log_error_va(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, int xt_err, int sys_err, c_char *fmt, va_list ap)
322
char xt_err_string[50];
326
case XT_ASSERTION_FAILURE:
327
strcpy(xt_err_string, "Assertion");
328
default_level = XT_LOG_FATAL;
330
case XT_SYSTEM_ERROR:
331
strcpy(xt_err_string, "errno");
332
default_level = XT_LOG_ERROR;
334
case XT_SIGNAL_CAUGHT:
335
strcpy(xt_err_string, "Signal");
336
default_level = XT_LOG_ERROR;
339
sprintf(xt_err_string, "%d", xt_err);
340
default_level = XT_LOG_ERROR;
343
if (level == XT_LOG_DEFAULT)
344
level = default_level;
346
if (*xt_err_string) {
348
xt_logf(self, func, file, line, level, "%s (%d): ", xt_err_string, sys_err);
350
xt_logf(self, func, file, line, level, "%s: ", xt_err_string);
352
thr_log_va(self, func, file, line, level, fmt, ap);
353
xt_logf(self, func, file, line, level, "\n");
357
/* The function returns the actual log level used. */
358
xtPublic int xt_log_errorf(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, int xt_err, int sys_err, c_char *fmt, ...)
363
level = thr_log_error_va(self, func, file, line, level, xt_err, sys_err, fmt, ap);
368
/* The function returns the actual log level used. */
369
xtPublic int xt_log_error(XTThreadPtr self, c_char *func, c_char *file, u_int line, int level, int xt_err, int sys_err, c_char *string)
371
return xt_log_errorf(self, func, file, line, level, xt_err, sys_err, "%s", string);
374
xtPublic void xt_log_exception(XTThreadPtr self, XTExceptionPtr e, int level)
376
ASSERT_NS(e->e_xt_err);
377
level = xt_log_error(
386
/* Dump the catch trace: */
387
if (*e->e_catch_trace)
388
xt_logf(self, NULL, NULL, 0, level, "%s", e->e_catch_trace);
391
xtPublic void xt_log_and_clear_exception(XTThreadPtr self)
393
xt_log_exception(self, &self->t_exception, XT_LOG_DEFAULT);
394
xt_clear_exception(self);
397
xtPublic void xt_log_and_clear_exception_ns(void)
399
xt_log_and_clear_exception(xt_get_self());
402
xtPublic void xt_log_and_clear_warning(XTThreadPtr self)
404
xt_log_exception(self, &self->t_exception, XT_LOG_WARNING);
405
xt_clear_exception(self);
408
xtPublic void xt_log_and_clear_warning_ns(void)
410
xt_log_and_clear_warning(xt_get_self());
414
* -----------------------------------------------------------------------
418
static void thr_add_catch_trace(XTExceptionPtr e, c_char *func, c_char *file, u_int line)
420
if (func && *func && *func != '-') {
421
xt_strcat_term(XT_CATCH_TRACE_SIZE, e->e_catch_trace, func, '(');
422
xt_strcat(XT_CATCH_TRACE_SIZE, e->e_catch_trace, "(");
425
xt_strcat(XT_CATCH_TRACE_SIZE, e->e_catch_trace, xt_last_name_of_path(file));
429
sprintf(buffer, "%u", line);
430
xt_strcat(XT_CATCH_TRACE_SIZE, e->e_catch_trace, ":");
431
xt_strcat(XT_CATCH_TRACE_SIZE, e->e_catch_trace, buffer);
434
if (func && *func && *func != '-')
435
xt_strcat(XT_CATCH_TRACE_SIZE, e->e_catch_trace, ")");
436
xt_strcat(XT_CATCH_TRACE_SIZE, e->e_catch_trace, "\n");
439
static void thr_save_error_va(XTExceptionPtr e, XTThreadPtr self, xtBool throw_it, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *fmt, va_list ap)
446
e->e_xt_err = xt_err;
447
e->e_sys_err = sys_err;
448
vsnprintf(e->e_err_msg, XT_ERR_MSG_SIZE, fmt, ap);
450
/* Make the first character of the message upper case: */
451
/* This did not work for foreign languages! */
452
if (e->e_err_msg[0] >= 'a' && e->e_err_msg[0] <= 'z')
453
e->e_err_msg[0] = (char) toupper(e->e_err_msg[0]);
455
if (func && *func && *func != '-')
456
xt_strcpy_term(XT_MAX_FUNC_NAME_SIZE, e->e_func_name, func, '(');
460
xt_strcpy(XT_SOURCE_FILE_NAME_SIZE, e->e_source_file, xt_last_name_of_path(file));
461
e->e_source_line = line;
464
*e->e_source_file = 0;
465
e->e_source_line = 0;
467
*e->e_catch_trace = 0;
472
/* Create a stack trace for this exception: */
473
thr_add_catch_trace(e, func, file, line);
474
for (i=self->t_call_top-1; i>=0; i--)
475
thr_add_catch_trace(e, self->t_call_stack[i].cs_func, self->t_call_stack[i].cs_file, self->t_call_stack[i].cs_line);
482
* -----------------------------------------------------------------------
483
* THROWING EXCEPTIONS
486
/* If we have to allocate resources and the hold them temporarily during which
487
* time an exception could occur, then these functions provide a holding
488
* place for the data, which will be freed in the case of an exception.
490
* Note: the free functions could themselves allocated resources.
491
* to make sure all things work out we only remove the resource from
492
* then stack when it is freed.
494
static void thr_free_resources(XTThreadPtr self, XTResourcePtr top)
497
XTThreadFreeFunc free_func;
501
while (self->t_res_top > top) {
502
/* Pop the top resource: */
503
rp = (XTResourcePtr) (((char *) self->t_res_top) - self->t_res_top->r_prev_size);
505
/* Free the resource: */
506
if (rp->r_free_func) {
507
free_func = rp->r_free_func;
508
rp->r_free_func = NULL;
509
free_func(self, rp->r_data);
512
self->t_res_top = rp;
516
xtPublic void xt_bug(XTThreadPtr XT_UNUSED(self))
518
static int *bug_ptr = NULL;
524
* This function is called when an exception is caught.
525
* It restores the function call top and frees
526
* any resource allocated by lower levels.
528
xtPublic void xt_caught(XTThreadPtr self)
530
/* Restore the call top: */
531
self->t_call_top = self->t_jmp_env[self->t_jmp_depth].jb_call_top;
533
/* Free the temporary data that would otherwize be lost
534
* This should do nothing, because we actually free things on throw
537
thr_free_resources(self, self->t_jmp_env[self->t_jmp_depth].jb_res_top);
540
xtPublic void xt_enter_exception_handler(XTThreadPtr self, XTExceptionPtr e)
542
ASSERT_NS(self->t_exception.e_xt_err);
543
self->t_in_handler++;
544
*e = self->t_exception;
545
/* If freeing resources, generates an error, we will know: */
546
self->t_exception.e_xt_err = 0;
549
xtPublic void xt_exit_exception_handler(XTThreadPtr self, XTExceptionPtr e)
551
if (self->t_exception.e_xt_err)
552
xt_log_and_clear_exception(self);
553
/* Restore the exception: */
554
self->t_exception = *e;
555
self->t_in_handler--;
558
/* Throw an already registered error: */
559
xtPublic void xt_throw(XTThreadPtr self)
562
/* We should not throw an exception in an exception handler! */
563
ASSERT_NS(!self->t_in_handler);
565
/* We cannot actually handle the situation that an exception is
566
* thrown when freeing resources here!
568
if (self->t_jmp_depth > 0 && self->t_jmp_depth <= XT_MAX_JMP) {
569
/* Save the exception, in case it is overwritten during free
574
/* As recommended by Barry: free the resources before the stack is invalid! */
575
xt_enter_exception_handler(self, &e);
576
thr_free_resources(self, self->t_jmp_env[self->t_jmp_depth-1].jb_res_top);
577
xt_exit_exception_handler(self, &e);
579
/* Then do the longjmp: */
580
if (!self->t_in_handler)
581
longjmp(self->t_jmp_env[self->t_jmp_depth-1].jb_buffer, 1);
586
* We cannot throw an error, because it will not be caught.
587
* This means there is no try ... catch block above.
588
* In this case, we just return.
589
* The calling functions must handle errors...
591
xt_log(XT_CONTEXT, XT_LOG_FATAL, "Uncaught exception\n");
592
xt_exit_thread(self, NULL);
596
xtPublic void xt_throwf(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *fmt, ...)
599
XTThreadPtr thread = self ? self : xt_get_self();
602
thr_save_error_va(thread ? &thread->t_exception : NULL, thread, self ? TRUE : FALSE, func, file, line, xt_err, sys_err, fmt, ap);
606
xtPublic void xt_throw_error(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *msg)
608
xt_throwf(self, func, file, line, xt_err, sys_err, "%s", msg);
611
#define XT_SYS_ERR_SIZE 300
614
static c_char *thr_get_sys_error(int err, char *err_msg)
616
static c_char *thr_get_sys_error(int err, char *XT_UNUSED(err_msg))
622
if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL,
623
err, 0, err_msg, XT_SYS_ERR_SIZE, NULL)) {
624
return strerror(err);
627
ptr = &err_msg[strlen(err_msg)];
628
while (ptr-1 > err_msg) {
629
if (*(ptr-1) != '\n' && *(ptr-1) != '\r' && *(ptr-1) != '.')
636
return strerror(err);
640
static c_char *thr_get_err_string(int xt_err)
645
case XT_ERR_STACK_OVERFLOW: str = "Stack overflow"; break;
646
case XT_ERR_JUMP_OVERFLOW: str = "Jump overflow"; break;
647
case XT_ERR_TABLE_EXISTS: str = "Table `%s` already exists"; break;
648
case XT_ERR_NAME_TOO_LONG: str = "Name '%s' is too long"; break;
649
case XT_ERR_TABLE_NOT_FOUND: str = "Table `%s` not found"; break;
650
case XT_ERR_SESSION_NOT_FOUND: str = "Session %s not found"; break;
651
case XT_ERR_BAD_ADDRESS: str = "Incorrect address '%s'"; break;
652
case XT_ERR_UNKNOWN_SERVICE: str = "Unknown service '%s'"; break;
653
case XT_ERR_UNKNOWN_HOST: str = "Host '%s' not found"; break;
654
case XT_ERR_TOKEN_EXPECTED: str = "%s expected in place of %s"; break;
655
case XT_ERR_PROPERTY_REQUIRED: str = "Property '%s' required"; break;
656
case XT_ERR_DEADLOCK: str = "Deadlock, transaction aborted"; break;
657
case XT_ERR_CANNOT_CHANGE_DB: str = "Cannot change database while transaction is in progress"; break;
658
case XT_ERR_ILLEGAL_CHAR: str = "Illegal character: '%s'"; break;
659
case XT_ERR_UNTERMINATED_STRING:str = "Unterminated string: %s"; break;
660
case XT_ERR_SYNTAX: str = "Syntax error near %s"; break;
661
case XT_ERR_ILLEGAL_INSTRUCTION:str = "Illegal instruction"; break;
662
case XT_ERR_OUT_OF_BOUNDS: str = "Memory reference out of bounds"; break;
663
case XT_ERR_STACK_UNDERFLOW: str = "Stack underflow"; break;
664
case XT_ERR_TYPE_MISMATCH: str = "Type mismatch"; break;
665
case XT_ERR_ILLEGAL_TYPE: str = "Illegal type for operator"; break;
666
case XT_ERR_ID_TOO_LONG: str = "Identifier too long: %s"; break;
667
case XT_ERR_TYPE_OVERFLOW: str = "Type overflow: %s"; break;
668
case XT_ERR_TABLE_IN_USE: str = "Table `%s` in use"; break;
669
case XT_ERR_NO_DATABASE_IN_USE: str = "No database in use"; break;
670
case XT_ERR_CANNOT_RESOLVE_TYPE:str = "Cannot resolve type with ID: %s"; break;
671
case XT_ERR_BAD_INDEX_DESC: str = "Unsupported index description: %s"; break;
672
case XT_ERR_WRONG_NO_OF_VALUES: str = "Incorrect number of values"; break;
673
case XT_ERR_CANNOT_OUTPUT_VALUE:str = "Cannot output given type"; break;
674
case XT_ERR_COLUMN_NOT_FOUND: str = "Column `%s.%s` not found"; break;
675
case XT_ERR_NOT_IMPLEMENTED: str = "Not implemented"; break;
676
case XT_ERR_UNEXPECTED_EOS: str = "Connection unexpectedly lost"; break;
677
case XT_ERR_BAD_TOKEN: str = "Incorrect binary token"; break;
678
case XT_ERR_RES_STACK_OVERFLOW: str = "Internal error: resource stack overflow"; break;
679
case XT_ERR_BAD_INDEX_TYPE: str = "Unsupported index type: %s"; break;
680
case XT_ERR_INDEX_EXISTS: str = "Index '%s' already exists"; break;
681
case XT_ERR_INDEX_STRUC_EXISTS: str = "Index '%s' has an identical structure"; break;
682
case XT_ERR_INDEX_NOT_FOUND: str = "Index '%s' not found"; break;
683
case XT_ERR_INDEX_CORRUPT: str = "Cannot read index '%s'"; break;
684
case XT_ERR_TYPE_NOT_SUPPORTED: str = "Data type %s not supported"; break;
685
case XT_ERR_BAD_TABLE_VERSION: str = "Table `%s` version not supported, upgrade required"; break;
686
case XT_ERR_BAD_RECORD_FORMAT: str = "Record format unknown, either corrupted or upgrade required"; break;
687
case XT_ERR_BAD_EXT_RECORD: str = "Extended record part does not match reference"; break;
688
case XT_ERR_RECORD_CHANGED: str = "Record already updated, transaction aborted"; break;
689
case XT_ERR_XLOG_WAS_CORRUPTED: str = "Corrupted transaction log has been truncated"; break;
690
case XT_ERR_DUPLICATE_KEY: str = "Duplicate unique key"; break;
691
case XT_ERR_NO_DICTIONARY: str = "Table `%s` has not yet been opened by MySQL"; break;
692
case XT_ERR_TOO_MANY_TABLES: str = "Limit of %s tables per database exceeded"; break;
693
case XT_ERR_KEY_TOO_LARGE: str = "Index '%s' exceeds the key size limit of %s"; break;
694
case XT_ERR_MULTIPLE_DATABASES: str = "Multiple database in a single transaction is not permitted"; break;
695
case XT_ERR_NO_TRANSACTION: str = "Internal error: no transaction running"; break;
696
case XT_ERR_A_EXPECTED_NOT_B: str = "%s expected in place of %s"; break;
697
case XT_ERR_NO_MATCHING_INDEX: str = "Matching index required for '%s'"; break;
698
case XT_ERR_TABLE_LOCKED: str = "Table `%s` locked"; break;
699
case XT_ERR_NO_REFERENCED_ROW: str = "Constraint: `%s`"; break; // "Foreign key '%s', referenced row does not exist"
700
case XT_ERR_ROW_IS_REFERENCED: str = "Constraint: `%s`"; break; // "Foreign key '%s', has a referencing row"
701
case XT_ERR_BAD_DICTIONARY: str = "Internal dictionary does not match MySQL dictionary"; break;
702
case XT_ERR_LOADING_MYSQL_DIC: str = "Error loading %s.frm file, MySQL error: %s"; break;
703
case XT_ERR_COLUMN_IS_NOT_NULL: str = "Column `%s` is NOT NULL"; break;
704
case XT_ERR_INCORRECT_NO_OF_COLS: str = "Incorrect number of columns near %s"; break;
705
case XT_ERR_FK_ON_TEMP_TABLE: str = "Cannot create foreign key on temporary table"; break;
706
case XT_ERR_REF_TABLE_NOT_FOUND: str = "Referenced table `%s` not found"; break;
707
case XT_ERR_REF_TYPE_WRONG: str = "Incorrect data type on referenced column `%s`"; break;
708
case XT_ERR_DUPLICATE_FKEY: str = "Duplicate unique foreign key, contraint: %s"; break;
709
case XT_ERR_INDEX_FILE_TO_LARGE: str = "Index file has grown too large: %s"; break;
710
case XT_ERR_UPGRADE_TABLE: str = "Table `%s` must be upgraded from PBXT version %s"; break;
711
case XT_ERR_INDEX_NEW_VERSION: str = "Table `%s` index created by a newer version, upgrade required"; break;
712
case XT_ERR_LOCK_TIMEOUT: str = "Lock timeout on table `%s`"; break;
713
case XT_ERR_CONVERSION: str = "Error converting value for column `%s.%s`"; break;
714
case XT_ERR_NO_ROWS: str = "No matching row found in table `%s`"; break;
715
case XT_ERR_DATA_LOG_NOT_FOUND: str = "Data log not found: '%s'"; break;
716
case XT_ERR_LOG_MAX_EXCEEDED: str = "Maximum log count, %s, exceeded"; break;
717
case XT_ERR_MAX_ROW_COUNT: str = "Maximum row count reached"; break;
718
case XT_ERR_FILE_TOO_LONG: str = "File cannot be mapped, too large: '%s'"; break;
719
case XT_ERR_BAD_IND_BLOCK_SIZE: str = "Table `%s`, incorrect index block size: %s"; break;
720
case XT_ERR_INDEX_CORRUPTED: str = "Table `%s` index is corrupted, REPAIR TABLE required"; break;
721
case XT_ERR_NO_INDEX_CACHE: str = "Not enough index cache memory to handle concurrent updates"; break;
722
case XT_ERR_INDEX_LOG_CORRUPT: str = "Index log corrupt: '%s'"; break;
723
case XT_ERR_TOO_MANY_THREADS: str = "Too many threads: %s, increase pbxt_max_threads"; break;
724
case XT_ERR_TOO_MANY_WAITERS: str = "Too many waiting threads: %s"; break;
725
case XT_ERR_INDEX_OLD_VERSION: str = "Table `%s` index created by an older version, REPAIR TABLE required"; break;
726
case XT_ERR_PBXT_TABLE_EXISTS: str = "System table cannot be dropped because PBXT table still exists"; break;
727
case XT_ERR_SERVER_RUNNING: str = "A server is possibly already running"; break;
728
case XT_ERR_INDEX_MISSING: str = "Index file of table '%s' is missing"; break;
729
case XT_ERR_RECORD_DELETED: str = "Record was deleted"; break;
730
case XT_ERR_NEW_TYPE_OF_XLOG: str = "Transaction log %s, is using a newer format, upgrade required"; break;
731
case XT_ERR_NO_BEFORE_IMAGE: str = "Internal error: no before image"; break;
732
case XT_ERR_FK_REF_TEMP_TABLE: str = "Foreign key may not reference temporary table"; break;
733
case XT_ERR_FILE_OP_NOT_SUPP: str = "File operation not supported on this file: %s"; break;
734
case XT_ERR_INDEX_NOT_RECOVERED: str = "Index of table '%s' cannot be used because the table was not recovered"; break;
735
case XT_ERR_MYSQL_SHUTDOWN: str = "Cannot open table, MySQL has shutdown"; break;
736
case XT_ERR_MYSQL_NO_THREAD: str = "Cannot create thread, MySQL has shutdown"; break;
737
case XT_ERR_BUFFER_TOO_SMALL: str = "System backup buffer too small"; break;
738
case XT_ERR_BAD_BACKUP_FORMAT: str = "Unknown or corrupt backup format, restore aborted"; break;
739
case XT_ERR_PBXT_NOT_INSTALLED: str = "PBXT plugin is not installed"; break;
740
case XT_ERR_LOG_HEADER_CORRUPT: str = "Transaction log %s, file header corrupt"; break;
741
default: str = "Unknown XT error"; break;
746
xtPublic void xt_throw_i2xterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, c_char *item, c_char *item2)
748
xt_throwf(self, func, file, line, xt_err, 0, thr_get_err_string(xt_err), item, item2);
751
xtPublic void xt_throw_ixterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, c_char *item)
753
xt_throw_i2xterr(self, func, file, line, xt_err, item, NULL);
756
xtPublic void xt_throw_tabcolerr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, XTPathStrPtr tab_item, c_char *item2)
758
char buffer[XT_TABLE_NAME_BUF_SIZE];
760
xt_tab_make_table_name(tab_item, buffer, sizeof(buffer));
761
xt_throw_i2xterr(self, func, file, line, xt_err, buffer, item2);
764
xtPublic void xt_throw_taberr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, XTPathStrPtr tab_item)
766
char buffer[XT_TABLE_NAME_BUF_SIZE];
768
xt_tab_make_table_name(tab_item, buffer, sizeof(buffer));
769
xt_throw_ixterr(self, func, file, line, xt_err, buffer);
772
xtPublic void xt_throw_ulxterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, u_long value)
776
sprintf(buffer, "%lu", value);
777
xt_throw_ixterr(self, func, file, line, xt_err, buffer);
780
xtPublic void xt_throw_sulxterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, c_char *item, u_long value)
784
sprintf(buffer, "%lu", value);
785
xt_throw_i2xterr(self, func, file, line, xt_err, item, buffer);
788
xtPublic void xt_throw_xterr(XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err)
790
xt_throw_ixterr(self, func, file, line, xt_err, NULL);
793
xtPublic void xt_throw_errno(XTThreadPtr self, c_char *func, c_char *file, u_int line, int err)
795
char err_msg[XT_SYS_ERR_SIZE];
797
xt_throw_error(self, func, file, line, XT_SYSTEM_ERROR, err, thr_get_sys_error(err, err_msg));
800
xtPublic void xt_throw_ferrno(XTThreadPtr self, c_char *func, c_char *file, u_int line, int err, c_char *path)
802
char err_msg[XT_SYS_ERR_SIZE];
804
xt_throwf(self, func, file, line, XT_SYSTEM_ERROR, err, "%s: '%s'", thr_get_sys_error(err, err_msg), path);
807
xtPublic void xt_throw_assertion(XTThreadPtr self, c_char *func, c_char *file, u_int line, c_char *str)
809
xt_throw_error(self, func, file, line, XT_ASSERTION_FAILURE, 0, str);
812
static void xt_log_assertion(XTThreadPtr self, c_char *func, c_char *file, u_int line, c_char *str)
814
xt_log_error(self, func, file, line, XT_LOG_DEFAULT, XT_ASSERTION_FAILURE, 0, str);
817
xtPublic void xt_throw_signal(XTThreadPtr self, c_char *func, c_char *file, u_int line, int sig)
822
sprintf(buffer, "Signal #%d", sig);
823
xt_throw_error(self, func, file, line, XT_SIGNAL_CAUGHT, sig, buffer);
825
xt_throw_error(self, func, file, line, XT_SIGNAL_CAUGHT, sig, strsignal(sig));
830
* -----------------------------------------------------------------------
831
* REGISTERING EXCEPTIONS
834
xtPublic void xt_registerf(c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *fmt, ...)
837
XTThreadPtr thread = xt_get_self();
840
thr_save_error_va(thread ? &thread->t_exception : NULL, thread, FALSE, func, file, line, xt_err, sys_err, fmt, ap);
844
xtPublic void xt_register_i2xterr(c_char *func, c_char *file, u_int line, int xt_err, c_char *item, c_char *item2)
846
xt_registerf(func, file, line, xt_err, 0, thr_get_err_string(xt_err), item, item2);
849
xtPublic void xt_register_ixterr(c_char *func, c_char *file, u_int line, int xt_err, c_char *item)
851
xt_register_i2xterr(func, file, line, xt_err, item, NULL);
854
xtPublic void xt_register_tabcolerr(c_char *func, c_char *file, u_int line, int xt_err, XTPathStrPtr tab_item, c_char *item2)
856
char buffer[XT_TABLE_NAME_BUF_SIZE];
858
xt_tab_make_table_name(tab_item, buffer, sizeof(buffer));
859
xt_strcat(sizeof(buffer), buffer, ".");
860
xt_strcat(sizeof(buffer), buffer, item2);
861
xt_register_ixterr(func, file, line, xt_err, buffer);
864
xtPublic void xt_register_taberr(c_char *func, c_char *file, u_int line, int xt_err, XTPathStrPtr tab_item)
866
char buffer[XT_TABLE_NAME_BUF_SIZE];
868
xt_tab_make_table_name(tab_item, buffer, sizeof(buffer));
869
xt_register_ixterr(func, file, line, xt_err, buffer);
872
xtPublic void xt_register_ulxterr(c_char *func, c_char *file, u_int line, int xt_err, u_long value)
876
sprintf(buffer, "%lu", value);
877
xt_register_ixterr(func, file, line, xt_err, buffer);
880
xtPublic xtBool xt_register_ferrno(c_char *func, c_char *file, u_int line, int err, c_char *path)
882
char err_msg[XT_SYS_ERR_SIZE];
884
xt_registerf(func, file, line, XT_SYSTEM_ERROR, err, "%s: '%s'", thr_get_sys_error(err, err_msg), path);
888
xtPublic void xt_register_error(c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *msg)
890
xt_registerf(func, file, line, xt_err, sys_err, "%s", msg);
893
xtPublic xtBool xt_register_errno(c_char *func, c_char *file, u_int line, int err)
895
char err_msg[XT_SYS_ERR_SIZE];
897
xt_register_error(func, file, line, XT_SYSTEM_ERROR, err, thr_get_sys_error(err, err_msg));
901
xtPublic void xt_register_xterr(c_char *func, c_char *file, u_int line, int xt_err)
903
xt_register_error(func, file, line, xt_err, 0, thr_get_err_string(xt_err));
907
* -----------------------------------------------------------------------
908
* CREATING EXCEPTIONS
911
xtPublic void xt_exceptionf(XTExceptionPtr e, XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *fmt, ...)
916
thr_save_error_va(e, self, FALSE, func, file, line, xt_err, sys_err, fmt, ap);
920
xtPublic void xt_exception_error(XTExceptionPtr e, XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err, int sys_err, c_char *msg)
922
xt_exceptionf(e, self, func, file, line, xt_err, sys_err, "%s", msg);
925
xtPublic xtBool xt_exception_errno(XTExceptionPtr e, XTThreadPtr self, c_char *func, c_char *file, u_int line, int err)
927
char err_msg[XT_SYS_ERR_SIZE];
929
xt_exception_error(e, self, func, file, line, XT_SYSTEM_ERROR, err, thr_get_sys_error(err, err_msg));
933
xtPublic void xt_exception_xterr(XTExceptionPtr e, XTThreadPtr self, c_char *func, c_char *file, u_int line, int xt_err)
935
xt_exception_error(e, self, func, file, line, xt_err, 0, thr_get_err_string(xt_err));
939
* -----------------------------------------------------------------------
943
xtPublic void xt_log_errno(XTThreadPtr self, c_char *func, c_char *file, u_int line, int err)
947
xt_exception_errno(&e, self, func, file, line, err);
948
xt_log_exception(self, &e, XT_LOG_DEFAULT);
952
* -----------------------------------------------------------------------
953
* Assertions and failures (one breakpoints for all failures)
955
//#define CRASH_ON_ASSERT
957
xtPublic xtBool xt_assert(XTThreadPtr self, c_char *expr, c_char *func, c_char *file, u_int line)
961
//xt_set_fflush(TRUE);
963
break_in_assertion(expr, func, file, line);
964
#ifdef CRASH_ON_ASSERT
968
FatalAppExit(0, "Assertion Failed!");
971
xt_throw_assertion(self, func, file, line, expr);
976
xtPublic xtBool xt_assume(XTThreadPtr self, c_char *expr, c_char *func, c_char *file, u_int line)
978
xt_log_assertion(self, func, file, line, expr);
983
* -----------------------------------------------------------------------
984
* Create and destroy threads
987
typedef struct ThreadData {
990
void *(*td_start_routine)(XTThreadPtr self);
991
} ThreadDataRec, *ThreadDataPtr;
994
pthread_key(void *, thr_key);
996
static pthread_key_t thr_key;
999
#ifdef HANDLE_SIGNALS
1000
static void thr_ignore_signal(int sig)
1005
static void thr_throw_signal(int sig)
1009
self = xt_get_self();
1012
/* The main thread will pass on a signal to all threads: */
1013
xt_signal_all_threads(self, sig);
1014
if (sig != SIGTERM) {
1015
if (self->t_disable_interrupts) {
1016
self->t_delayed_signal = sig;
1017
self->t_disable_interrupts = FALSE; /* Prevent infinite loop */
1020
self->t_delayed_signal = 0;
1021
xt_throw_signal(self, "thr_throw_signal", NULL, 0, sig);
1026
if (self->t_disable_interrupts) {
1027
self->t_delayed_signal = sig;
1028
self->t_disable_interrupts = FALSE; /* Prevent infinite loop */
1031
self->t_delayed_signal = 0;
1032
xt_throw_signal(self, "thr_throw_signal", NULL, 0, sig);
1037
static xtBool thr_setup_signals(void)
1039
struct sigaction action;
1041
sigemptyset(&action.sa_mask);
1042
action.sa_flags = 0;
1043
action.sa_handler = thr_ignore_signal;
1045
if (sigaction(SIGPIPE, &action, NULL) == -1)
1046
goto error_occurred;
1047
if (sigaction(SIGHUP, &action, NULL) == -1)
1048
goto error_occurred;
1050
action.sa_handler = thr_throw_signal;
1052
if (sigaction(SIGQUIT, &action, NULL) == -1)
1053
goto error_occurred;
1054
if (sigaction(SIGTERM, &action, NULL) == -1)
1055
goto error_occurred;
1057
if (sigaction(SIGILL, &action, NULL) == -1)
1058
goto error_occurred;
1059
if (sigaction(SIGBUS, &action, NULL) == -1)
1060
goto error_occurred;
1061
if (sigaction(SIGSEGV, &action, NULL) == -1)
1062
goto error_occurred;
1067
xt_log_errno(XT_NS_CONTEXT, errno);
1072
typedef void *(*ThreadMainFunc)(XTThreadPtr self);
1074
extern "C" void *xt_thread_main(void *data)
1076
ThreadDataPtr td = (ThreadDataPtr) data;
1077
XTThreadPtr self = td->td_thr;
1078
ThreadMainFunc start_routine;
1082
self->t_pthread = pthread_self();
1083
start_routine = td->td_start_routine;
1086
#ifdef HANDLE_SIGNALS
1087
if (!thr_setup_signals())
1092
if (!xt_set_key((pthread_key_t)thr_key, self, &self->t_exception))
1094
td->td_started = TRUE;
1095
return_data = (*start_routine)(self);
1098
xt_log_and_clear_exception(self);
1103
xt_free_thread(self);
1105
/* {MYSQL-THREAD-KILL}
1106
* Clean up any remaining MySQL thread!
1108
myxt_delete_remaining_thread();
1112
static void thr_free_data(XTThreadPtr self)
1114
if (self->t_free_data) {
1115
(*self->t_free_data)(self, self->t_data);
1116
self->t_data = NULL;
1120
xtPublic void xt_set_thread_data(XTThreadPtr self, void *data, XTThreadFreeFunc free_func)
1122
thr_free_data(self);
1123
self->t_free_data = free_func;
1124
self->t_data = data;
1127
static void thr_exit(XTThreadPtr self)
1129
/* Free the thread temporary data. */
1130
thr_free_resources(self, (XTResourcePtr) self->x.t_res_stack);
1131
xt_db_exit_thread(self);
1132
thr_free_data(self); /* Free custom user data. */
1134
if (self->t_id > 0) {
1135
ASSERT(self->t_id < xt_thr_current_max_threads);
1136
xt_lock_mutex(self, &thr_array_lock);
1137
pushr_(xt_unlock_mutex, &thr_array_lock);
1138
thr_accumulate_statistics(self);
1139
// No read resize lock required if I have the array lock
1140
xt_thr_array[self->t_id].td_thread = NULL;
1141
xt_thr_current_thread_count--;
1142
if (self->t_id+1 == xt_thr_current_max_threads) {
1143
/* We can reduce the current maximum,
1144
* this makes operations that scan the array faster!
1150
if (xt_thr_array[i].td_thread)
1156
xt_thr_current_max_threads = i+1;
1158
freer_(); // xt_unlock_mutex(&thr_array_lock)
1161
xt_free_cond(&self->t_cond);
1162
xt_free_mutex(&self->t_lock);
1164
self->st_tasks_todo.pl_exit();
1165
self->st_tasks_done.pl_exit();
1167
self->st_thread_list_count = 0;
1168
self->st_thread_list_size = 0;
1169
if (self->st_thread_list) {
1170
xt_free_ns(self->st_thread_list);
1171
self->st_thread_list = NULL;
1176
#define XT_THREAD_ARRAY_INC_SIZE 5
1178
#define XT_THREAD_ARRAY_INC_SIZE 100
1181
static xtBool thr_init_ns(XTThreadPtr new_thread)
1183
new_thread->t_res_top = (XTResourcePtr) new_thread->x.t_res_stack;
1185
new_thread->st_thread_list_count = 0;
1186
new_thread->st_thread_list_size = 0;
1187
new_thread->st_thread_list = NULL;
1189
if (!new_thread->st_tasks_todo.pl_init_ns())
1192
if (!new_thread->st_tasks_done.pl_init_ns())
1195
xt_init_cond(NULL, &new_thread->t_cond);
1196
xt_init_mutex_with_autoname(NULL, &new_thread->t_lock);
1198
xt_lock_mutex_ns(&thr_array_lock);
1200
ASSERT_NS(xt_thr_current_thread_count <= xt_thr_current_max_threads);
1201
ASSERT_NS(xt_thr_current_max_threads <= xt_thr_maximum_threads);
1202
if (xt_thr_current_thread_count == xt_thr_maximum_threads) {
1203
XTThreadDataRec *tmp;
1205
/* We can use a fixed thread ID because only one thread can do
1206
* this at any given time.
1208
* We use XT_SYS_THREAD_ID to avoid the problem that we this function
1209
* allocates thread IDs, but needs a thread ID to aquire the
1212
THR_ARRAY_WRITE_LOCK(&xt_thr_array_resize_lock, XT_SYS_THREAD_ID);
1213
if (!(tmp = (XTThreadDataRec *) realloc(xt_thr_array, (xt_thr_maximum_threads + XT_THREAD_ARRAY_INC_SIZE) * sizeof(XTThreadDataRec)))) {
1214
THR_ARRAY_UNLOCK(&xt_thr_array_resize_lock, XT_SYS_THREAD_ID);
1219
xt_thr_maximum_threads += XT_THREAD_ARRAY_INC_SIZE;
1221
for (u_int i=xt_thr_maximum_threads - XT_THREAD_ARRAY_INC_SIZE; i<xt_thr_maximum_threads; i++)
1222
xt_thr_array[i].td_thread = NULL;
1224
for (u_int i=xt_thr_maximum_threads - XT_THREAD_ARRAY_INC_SIZE; i<xt_thr_maximum_threads; i++) {
1225
if (!(xt_thr_array[i].td_waiting = (XTWaitThreadPtr) xt_calloc_ns(sizeof(XTWaitThreadRec)))) {
1226
xt_thr_maximum_threads = i;
1227
THR_ARRAY_UNLOCK(&xt_thr_array_resize_lock, XT_SYS_THREAD_ID);
1230
xt_init_mutex_with_autoname(NULL, &xt_thr_array[i].td_waiting->wt_lock);
1231
xt_init_cond(NULL, &xt_thr_array[i].td_waiting->wt_cond);
1232
xt_spinlock_init_with_autoname(NULL, &xt_thr_array[i].td_waiting->wt_wait_list_lock);
1235
THR_ARRAY_UNLOCK(&xt_thr_array_resize_lock, XT_SYS_THREAD_ID);
1238
if (xt_thr_current_thread_count == xt_thr_current_max_threads) {
1239
new_thread->t_id = xt_thr_current_thread_count;
1240
xt_thr_array[new_thread->t_id].td_thread = new_thread;
1241
xt_thr_current_max_threads++;
1244
/* There must be a free slot: */
1245
for (u_int i=0; i<xt_thr_current_max_threads; i++) {
1246
if (!xt_thr_array[i].td_thread) {
1247
new_thread->t_id = i;
1248
xt_thr_array[i].td_thread = new_thread;
1253
xt_thr_current_thread_count++;
1255
xt_unlock_mutex_ns(&thr_array_lock);
1257
xt_db_init_thread_ns(new_thread);
1261
xt_unlock_mutex_ns(&thr_array_lock);
1264
thr_exit(new_thread);
1269
* The caller of this function automatically becomes the main thread.
1271
xtPublic XTThreadPtr xt_init_threading()
1273
volatile XTThreadPtr self = NULL;
1277
#ifdef HANDLE_SIGNALS
1278
if (!thr_setup_signals())
1282
xt_p_init_threading();
1284
err = pthread_key_create(&thr_key, NULL);
1286
xt_log_errno(XT_NS_CONTEXT, err);
1290
if ((err = xt_p_mutex_init_with_autoname(&thr_array_lock, NULL))) {
1291
xt_log_errno(XT_NS_CONTEXT, err);
1295
xt_thr_maximum_threads = 2;
1296
if (!(xt_thr_array = (XTThreadDataRec *) malloc(xt_thr_maximum_threads * sizeof(XTThreadDataRec)))) {
1297
xt_log_errno(XT_NS_CONTEXT, XT_ENOMEM);
1301
xt_thr_array[XT_NO_THREAD_ID].td_thread = (XTThreadPtr) 1; // Dummy, not used
1302
xt_thr_array[XT_NO_THREAD_ID].td_waiting = NULL;
1303
xt_thr_array[XT_SYS_THREAD_ID].td_thread = (XTThreadPtr) 1; // System ID, used for resizing the thread array
1304
xt_thr_array[XT_SYS_THREAD_ID].td_waiting = NULL;
1305
xt_thr_current_thread_count = XT_MIN_THREAD_ID;
1306
xt_thr_current_max_threads = XT_MIN_THREAD_ID;
1308
THR_ARRAY_INIT_LOCK(NULL, &xt_thr_array_resize_lock);
1310
/* Create the main thread: */
1311
self = xt_create_thread("MainThread", TRUE, FALSE, &e);
1313
xt_log_exception(NULL, &e, XT_LOG_DEFAULT);
1318
XTThreadPtr thread = self;
1319
thr_list = xt_new_linkedlist(thread, NULL, NULL, TRUE);
1323
XTThreadPtr thread = self;
1324
xt_log_and_clear_exception(thread);
1325
xt_exit_threading(thread);
1332
xt_exit_threading(NULL);
1336
xtPublic void xt_exit_threading(XTThreadPtr self)
1339
xt_free_linkedlist(self, thr_list);
1343
/* This should be the main thread! */
1345
ASSERT(self->t_main);
1346
xt_free_thread(self);
1350
for (u_int i=XT_MIN_THREAD_ID; i<xt_thr_maximum_threads; i++) {
1351
xt_free_mutex(&xt_thr_array[i].td_waiting->wt_lock);
1352
xt_free_cond(&xt_thr_array[i].td_waiting->wt_cond);
1353
xt_spinlock_free(self, &xt_thr_array[i].td_waiting->wt_wait_list_lock);
1354
if (xt_thr_array[i].td_waiting->wt_wait_list)
1355
xt_free_ns(xt_thr_array[i].td_waiting->wt_wait_list);
1356
xt_free_ns(xt_thr_array[i].td_waiting);
1360
xt_thr_array = NULL;
1361
THR_ARRAY_FREE_LOCK(self, &xt_thr_array_resize_lock);
1362
xt_free_mutex(&thr_array_lock);
1365
xt_thr_current_thread_count = 0;
1366
xt_thr_current_max_threads = 0;
1368
/* I no longer delete 'thr_key' because
1369
* functions that call xt_get_self() after this
1370
* point will get junk back if we delete
1371
* thr_key. In particular the XT_THREAD_LOCK_INFO
1374
pthread_key_delete(thr_key);
1375
thr_key = (pthread_key_t) 0;
1380
xtPublic void xt_wait_for_all_threads(XTThreadPtr self)
1383
xt_ll_wait_till_empty(self, thr_list);
1387
* Call this function in a busy wait loop!
1388
* Use if for wait loops that are not
1391
xtPublic void xt_busy_wait(void)
1400
xtPublic void xt_critical_wait(void)
1402
/* NOTE: On Mac xt_busy_wait() works better than xt_yield()
1404
#if defined(XT_MAC) || defined(XT_WIN)
1413
* Use this for loops that time critical.
1414
* Time critical means we need to get going
1415
* as soon as possible!
1417
xtPublic void xt_yield(void)
1421
#elif defined(XT_MAC) || defined(XT_SOLARIS)
1423
#elif defined(XT_NETBSD)
1430
xtPublic void xt_sleep_milli_second(u_int t)
1439
xtPublic void xt_signal_all_threads(XTThreadPtr self, int sig)
1442
XTThreadPtr sig_thr;
1444
xt_ll_lock(self, thr_list);
1446
li = thr_list->ll_items;
1448
sig_thr = (XTThreadPtr) li;
1449
if (sig_thr != self)
1450
pthread_kill(sig_thr->t_pthread, sig);
1455
xt_ll_unlock(self, thr_list);
1459
xt_ll_unlock(self, thr_list);
1463
* Apply the given function to all threads except self!
1465
xtPublic void xt_do_to_all_threads(XTThreadPtr self, void (*do_func_ptr)(XTThreadPtr self, XTThreadPtr to_thr, void *thunk), void *thunk)
1470
xt_ll_lock(self, thr_list);
1471
pushr_(xt_ll_unlock, thr_list);
1473
li = thr_list->ll_items;
1475
to_thr = (XTThreadPtr) li;
1477
(*do_func_ptr)(self, to_thr, thunk);
1481
freer_(); // xt_ll_unlock(thr_list)
1484
xtPublic XTThreadPtr xt_get_self(void)
1488
/* First check if the handler has the data: */
1489
if ((self = myxt_get_self()))
1491
/* Then it must be a background process, and the
1492
* thread info is stored in the local key: */
1493
return (XTThreadPtr) xt_get_key((pthread_key_t)thr_key);
1496
xtPublic void xt_set_self(XTThreadPtr self)
1498
xt_set_key((pthread_key_t)thr_key, self, NULL);
1501
xtPublic void xt_clear_exception(XTThreadPtr thread)
1503
thread->t_exception.e_xt_err = 0;
1504
thread->t_exception.e_sys_err = 0;
1505
*thread->t_exception.e_err_msg = 0;
1506
*thread->t_exception.e_func_name = 0;
1507
*thread->t_exception.e_source_file = 0;
1508
thread->t_exception.e_source_line = 0;
1509
*thread->t_exception.e_catch_trace = 0;
1513
* Create a thread without requiring thread to do it (as in xt_create_daemon()).
1515
* This function returns NULL on error.
1517
xtPublic XTThreadPtr xt_create_thread(c_char *name, xtBool main_thread, xtBool user_thread, XTExceptionPtr e)
1519
volatile XTThreadPtr self;
1521
self = (XTThreadPtr) xt_calloc_ns(sizeof(XTThreadRec));
1523
xt_exception_errno(e, XT_CONTEXT, ENOMEM);
1527
if (!xt_set_key((pthread_key_t)thr_key, self, e)) {
1532
xt_strcpy(XT_THR_NAME_SIZE, self->t_name, name);
1533
self->t_main = main_thread;
1534
self->t_daemon = FALSE;
1536
if (!thr_init_ns(self)) {
1537
*e = self->t_exception;
1538
xt_set_key((pthread_key_t)thr_key, NULL, NULL);
1543
if (self && user_thread) {
1544
/* Add non-temporary threads to the thread list. */
1546
xt_ll_add(self, thr_list, &self->t_links, TRUE);
1549
*e = self->t_exception;
1550
xt_free_thread(self);
1560
* Create a daemon thread.
1562
xtPublic XTThreadPtr xt_create_daemon_ns(c_char *name)
1564
XTThreadPtr new_thread;
1566
/* NOTE: thr_key will be set when this thread start running. */
1567
if (!(new_thread = (XTThreadPtr) xt_calloc_ns(sizeof(XTThreadRec))))
1570
xt_strcpy(XT_THR_NAME_SIZE, new_thread->t_name, name);
1571
new_thread->t_main = FALSE;
1572
new_thread->t_daemon = TRUE;
1574
if (!thr_init_ns(new_thread)) {
1575
xt_free_ns(new_thread);
1582
xtPublic XTThreadPtr xt_create_daemon(XTThreadPtr self, c_char *name)
1584
XTThreadPtr new_thread;
1586
if (!(new_thread = xt_create_daemon_ns(name)))
1591
void xt_free_thread(XTThreadPtr self)
1594
if (!self->t_daemon && thr_list)
1595
xt_ll_remove(self, thr_list, &self->t_links, TRUE);
1596
/* Note, if I move this before thr_exit() then self = xt_get_self(); will fail in
1597
* xt_close_file_ns() which is called by xt_unuse_database()!
1601
* Do not clear the pthread's key value unless it is the same as the thread just released.
1602
* This can happen during shutdown when the engine is deregistered with the PBMS engine.
1604
* What happens is that during deregistration the PBMS engine calls close to close all
1605
* PBXT resources on all MySQL THDs created by PBMS for it's own pthreads. So the 'self'
1606
* being freed is not the same 'self' associated with the PBXT 'thr_key'.
1608
if (thr_key && (self == ((XTThreadPtr) xt_get_key((pthread_key_t)thr_key)))) {
1609
xt_set_key((pthread_key_t)thr_key, NULL, NULL);
1614
xtPublic xtBool xt_run_thread_ns(XTThreadPtr child, void *(*start_routine)(XTThreadPtr))
1618
pthread_t child_thread;
1620
// 'data' can be on the stack because we are waiting for the thread to start
1621
// before exiting the function.
1622
data.td_started = FALSE;
1623
data.td_thr = child;
1624
data.td_start_routine = start_routine;
1627
pthread_attr_t attr = { 0, 0, 0 };
1629
attr.priority = THREAD_PRIORITY_NORMAL;
1630
err = pthread_create(&child_thread, &attr, xt_thread_main, &data);
1633
err = pthread_create(&child_thread, NULL, xt_thread_main, &data);
1636
xt_free_thread(child);
1637
return xt_register_errno(XT_REG_CONTEXT, err);
1640
while (!data.td_started) {
1641
/* Check that the self is still alive: */
1642
if (pthread_kill(child_thread, 0))
1650
xtPublic void xt_run_thread(XTThreadPtr self, XTThreadPtr child, void *(*start_routine)(XTThreadPtr))
1652
if (!xt_run_thread_ns(child, start_routine))
1656
xtPublic void xt_exit_thread(XTThreadPtr self, void *result)
1658
xt_free_thread(self);
1659
pthread_exit(result);
1662
xtPublic void *xt_wait_for_thread_to_exit(xtThreadID tid, xtBool ignore_error)
1665
void *value_ptr = NULL;
1670
xt_lock_mutex_ns(&thr_array_lock);
1671
if (tid < xt_thr_maximum_threads) {
1672
// No resize lock required if I have the array lock.
1673
if ((thread = xt_thr_array[tid].td_thread)) {
1674
t1 = thread->t_pthread;
1678
xt_unlock_mutex_ns(&thr_array_lock);
1680
err = xt_p_join(t1, &value_ptr);
1681
if (err && !ignore_error)
1682
xt_log_errno(XT_NS_CONTEXT, err);
1688
* Kill the given thead, and wait for it to terminate.
1689
* This function just returns if the self is already dead.
1691
xtPublic void xt_kill_thread(pthread_t t1)
1694
void *value_ptr = NULL;
1696
err = pthread_kill(t1, SIGTERM);
1699
err = xt_p_join(t1, &value_ptr);
1701
xt_log_errno(XT_NS_CONTEXT, err);
1705
* -----------------------------------------------------------------------
1706
* Read/write locking
1709
#ifdef XT_THREAD_LOCK_INFO
1710
xtPublic xtBool xt_init_rwlock(XTThreadPtr self, xt_rwlock_type *rwlock, const char *name)
1712
xtPublic xtBool xt_init_rwlock(XTThreadPtr self, xt_rwlock_type *rwlock)
1717
#ifdef XT_THREAD_LOCK_INFO
1718
err = xt_p_rwlock_init_with_name(rwlock, NULL, name);
1720
err = xt_p_rwlock_init(rwlock, NULL);
1724
xt_throw_errno(XT_CONTEXT, err);
1730
xtPublic void xt_free_rwlock(xt_rwlock_type *rwlock)
1735
err = xt_p_rwlock_destroy(rwlock);
1736
if (err != XT_EBUSY)
1740
/* PMC - xt_xn_exit_db() is called even when xt_xn_init_db() is not fully completed!
1741
* This generates a lot of log entries. But I have no desire to only call
1742
* free for those articles that I have init'ed!
1744
xt_log_errno(XT_NS_CONTEXT, err);
1748
xtPublic xt_rwlock_type *xt_slock_rwlock(XTThreadPtr self, xt_rwlock_type *rwlock)
1753
err = xt_slock_rwlock_ns(rwlock);
1754
if (err != XT_EAGAIN)
1759
xt_throw_errno(XT_CONTEXT, err);
1765
xtPublic xt_rwlock_type *xt_xlock_rwlock(XTThreadPtr self, xt_rwlock_type *rwlock)
1770
err = xt_xlock_rwlock_ns(rwlock);
1771
if (err != XT_EAGAIN)
1777
xt_throw_errno(XT_CONTEXT, err);
1783
xtPublic void xt_unlock_rwlock(XTThreadPtr XT_UNUSED(self), xt_rwlock_type *rwlock)
1787
err = xt_unlock_rwlock_ns(rwlock);
1789
xt_log_errno(XT_NS_CONTEXT, err);
1793
* -----------------------------------------------------------------------
1797
xtPublic xt_mutex_type *xt_new_mutex(XTThreadPtr self)
1801
if (!(mx = (xt_mutex_type *) xt_calloc(self, sizeof(xt_mutex_type))))
1803
pushr_(xt_free, mx);
1804
if (!xt_init_mutex_with_autoname(self, mx)) {
1812
xtPublic void xt_delete_mutex(XTThreadPtr self, xt_mutex_type *mx)
1820
#ifdef XT_THREAD_LOCK_INFO
1821
xtPublic xtBool xt_init_mutex(XTThreadPtr self, xt_mutex_type *mx, const char *name)
1823
xtPublic xtBool xt_init_mutex(XTThreadPtr self, xt_mutex_type *mx)
1828
err = xt_p_mutex_init_with_name(mx, NULL, name);
1830
xt_throw_errno(XT_CONTEXT, err);
1836
void xt_free_mutex(xt_mutex_type *mx)
1841
err = xt_p_mutex_destroy(mx);
1842
if (err != XT_EBUSY)
1846
/* PMC - xt_xn_exit_db() is called even when xt_xn_init_db() is not fully completed!
1848
xt_log_errno(XT_NS_CONTEXT, err);
1852
xtPublic xtBool xt_lock_mutex(XTThreadPtr self, xt_mutex_type *mx)
1857
err = xt_lock_mutex_ns(mx);
1858
if (err != XT_EAGAIN)
1864
xt_throw_errno(XT_CONTEXT, err);
1870
xtPublic void xt_unlock_mutex(XTThreadPtr self, xt_mutex_type *mx)
1874
err = xt_unlock_mutex_ns(mx);
1876
xt_throw_errno(XT_CONTEXT, err);
1879
xtPublic xtBool xt_set_key(pthread_key_t key, const void *value, XTExceptionPtr e)
1882
my_pthread_setspecific_ptr(thr_key, (void *) value);
1886
err = pthread_setspecific(key, value);
1889
xt_exception_errno(e, XT_NS_CONTEXT, err);
1896
xtPublic void *xt_get_key(pthread_key_t key)
1899
return my_pthread_getspecific_ptr(void *, thr_key);
1901
return pthread_getspecific(key);
1905
xtPublic xt_cond_type *xt_new_cond(XTThreadPtr self)
1909
if (!(cond = (xt_cond_type *) xt_calloc(self, sizeof(xt_cond_type))))
1911
pushr_(xt_free, cond);
1912
if (!xt_init_cond(self, cond)) {
1920
xtPublic void xt_delete_cond(XTThreadPtr self, xt_cond_type *cond)
1924
xt_free(self, cond);
1928
xtPublic xtBool xt_init_cond(XTThreadPtr self, xt_cond_type *cond)
1932
err = pthread_cond_init(cond, NULL);
1934
xt_throw_errno(XT_CONTEXT, err);
1940
xtPublic void xt_free_cond(xt_cond_type *cond)
1945
err = pthread_cond_destroy(cond);
1946
if (err != XT_EBUSY)
1950
/* PMC - xt_xn_exit_db() is called even when xt_xn_init_db() is not fully completed!
1952
xt_log_errno(XT_NS_CONTEXT, err);
1956
xtPublic xtBool xt_throw_delayed_signal(XTThreadPtr self, c_char *func, c_char *file, u_int line)
1958
XTThreadPtr me = self ? self : xt_get_self();
1960
if (me->t_delayed_signal) {
1961
int sig = me->t_delayed_signal;
1963
me->t_delayed_signal = 0;
1964
xt_throw_signal(self, func, file, line, sig);
1970
xtPublic xtBool xt_wait_cond(XTThreadPtr self, xt_cond_type *cond, xt_mutex_type *mutex)
1973
XTThreadPtr me = self ? self : xt_get_self();
1975
/* PMC - In my tests, if I throw an exception from within the wait
1976
* the condition and the mutex remain locked.
1978
me->t_disable_interrupts = TRUE;
1979
err = xt_p_cond_wait(cond, mutex);
1980
me->t_disable_interrupts = FALSE;
1982
xt_throw_errno(XT_CONTEXT, err);
1985
if (me->t_delayed_signal) {
1986
xt_throw_delayed_signal(XT_CONTEXT);
1992
xtPublic xtBool xt_suspend(XTThreadPtr thread)
1996
// You can only suspend yourself.
1997
ASSERT_NS(pthread_equal(thread->t_pthread, pthread_self()));
1999
xt_lock_mutex_ns(&thread->t_lock);
2000
ok = xt_wait_cond(NULL, &thread->t_cond, &thread->t_lock);
2001
xt_unlock_mutex_ns(&thread->t_lock);
2005
xtPublic xtBool xt_unsuspend(XTThreadPtr target)
2007
return xt_broadcast_cond_ns(&target->t_cond);
2010
xtPublic void xt_lock_thread(XTThreadPtr thread)
2012
xt_lock_mutex_ns(&thread->t_lock);
2015
xtPublic void xt_unlock_thread(XTThreadPtr thread)
2017
xt_unlock_mutex_ns(&thread->t_lock);
2020
xtPublic xtBool xt_wait_thread(XTThreadPtr thread)
2022
return xt_wait_cond(NULL, &thread->t_cond, &thread->t_lock);
2025
xtPublic xtBool xt_timed_wait_thread(XTThreadPtr thread, u_long milli_sec)
2027
return xt_timed_wait_cond(NULL, &thread->t_cond, &thread->t_lock, milli_sec);
2030
xtPublic void xt_signal_thread(XTThreadPtr target)
2032
xt_broadcast_cond_ns(&target->t_cond);
2035
xtPublic void xt_terminate_thread(XTThreadPtr XT_UNUSED(self), XTThreadPtr target)
2037
target->t_quit = TRUE;
2038
target->t_delayed_signal = SIGTERM;
2041
xtPublic xtProcID xt_getpid()
2044
return GetCurrentProcessId();
2050
xtPublic xtBool xt_process_exists(xtProcID pid)
2059
h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
2061
if (GetExitCodeProcess(h, &code)) {
2062
if (code == STILL_ACTIVE)
2070
err = HRESULT_CODE(GetLastError());
2071
if (err != ERROR_INVALID_PARAMETER)
2076
if (kill(pid, 0) == -1) {
2084
xtPublic xtBool xt_timed_wait_cond(XTThreadPtr self, xt_cond_type *cond, xt_mutex_type *mutex, u_long milli_sec)
2087
struct timespec abstime;
2088
XTThreadPtr me = self ? self : xt_get_self();
2093
GetSystemTimeAsFileTime(&now.ft);
2095
/* System time is measured in 100ns units.
2096
* This calculation will be reversed by the Windows implementation
2097
* of pthread_cond_timedwait(), in order to extract the
2098
* milli-second timeout!
2100
abstime.tv.i64 = now.i64 + (milli_sec * 10000);
2102
abstime.max_timeout_msec = milli_sec;
2107
/* Get the current time in microseconds: */
2108
gettimeofday(&now, NULL);
2109
micro_sec = (u_llong) now.tv_sec * (u_llong) 1000000 + (u_llong) now.tv_usec;
2111
/* Add the timeout which is in milli seconds */
2112
micro_sec += (u_llong) milli_sec * (u_llong) 1000;
2114
/* Setup the end time, which is in nano-seconds. */
2115
abstime.tv_sec = (long) (micro_sec / 1000000); /* seconds */
2116
abstime.tv_nsec = (long) ((micro_sec % 1000000) * 1000); /* and nanoseconds */
2119
me->t_disable_interrupts = TRUE;
2120
err = xt_p_cond_timedwait(cond, mutex, &abstime);
2121
me->t_disable_interrupts = FALSE;
2122
if (err && err != ETIMEDOUT) {
2123
xt_throw_errno(XT_CONTEXT, err);
2126
if (me->t_delayed_signal) {
2127
xt_throw_delayed_signal(XT_CONTEXT);
2133
xtPublic xtBool xt_signal_cond(XTThreadPtr self, xt_cond_type *cond)
2137
err = pthread_cond_signal(cond);
2139
xt_throw_errno(XT_CONTEXT, err);
2145
xtPublic void xt_broadcast_cond(XTThreadPtr self, xt_cond_type *cond)
2149
err = pthread_cond_broadcast(cond);
2151
xt_throw_errno(XT_CONTEXT, err);
2154
xtPublic xtBool xt_broadcast_cond_ns(xt_cond_type *cond)
2158
err = pthread_cond_broadcast(cond);
2160
xt_register_errno(XT_REG_CONTEXT, err);
2166
static int prof_setjmp_count = 0;
2168
xtPublic int prof_setjmp(void)
2170
prof_setjmp_count++;
2174
xtPublic void xt_set_low_priority(XTThreadPtr self)
2176
int err = xt_p_set_low_priority(self->t_pthread);
2178
self = NULL; /* Will cause logging, instead of throwing exception */
2179
xt_throw_errno(XT_CONTEXT, err);
2183
xtPublic void xt_set_normal_priority(XTThreadPtr self)
2185
int err = xt_p_set_normal_priority(self->t_pthread);
2187
self = NULL; /* Will cause logging, instead of throwing exception */
2188
xt_throw_errno(XT_CONTEXT, err);
2192
xtPublic void xt_set_high_priority(XTThreadPtr self)
2194
int err = xt_p_set_high_priority(self->t_pthread);
2196
self = NULL; /* Will cause logging, instead of throwing exception */
2197
xt_throw_errno(XT_CONTEXT, err);
2201
xtPublic void xt_set_priority(XTThreadPtr self, int priority)
2203
if (priority < XT_PRIORITY_NORMAL)
2204
xt_set_low_priority(self);
2205
else if (priority > XT_PRIORITY_NORMAL)
2206
xt_set_high_priority(self);
2208
xt_set_normal_priority(self);
2211
/* ----------------------------------------------------------------------
2216
* Add a thread the wakeup list of a thread.
2218
xtPublic xtBool xt_add_to_wakeup_list(xtThreadID waiting_id, xtThreadID wait_for_id)
2222
THR_ARRAY_READ_LOCK(&xt_thr_array_resize_lock, waiting_id);
2223
wt = xt_thr_array[wait_for_id].td_waiting;
2224
THR_ARRAY_UNLOCK(&xt_thr_array_resize_lock, waiting_id);
2225
xt_spinlock_lock(&wt->wt_wait_list_lock);
2226
if (wt->wt_wait_list_count == wt->wt_wait_list_size) {
2227
if (!xt_realloc_ns((void **) &wt->wt_wait_list, (wt->wt_wait_list_size+1) * sizeof(xtThreadID)))
2229
wt->wt_wait_list_size++;
2231
for (u_int i=0; i<wt->wt_wait_list_count; i++) {
2232
if (wt->wt_wait_list[i] == waiting_id)
2235
wt->wt_wait_list[wt->wt_wait_list_count] = waiting_id;
2236
wt->wt_wait_list_count++;
2238
xt_spinlock_unlock(&wt->wt_wait_list_lock);
2243
* Wakeup a single thread.
2245
xtPublic void xt_wakeup_thread(xtThreadID thd_id, XTThreadPtr thread)
2247
XTWaitThreadPtr target_wt;
2249
THR_ARRAY_READ_LOCK(&xt_thr_array_resize_lock, thread->t_id);
2250
target_wt = xt_thr_array[thd_id].td_waiting;
2251
THR_ARRAY_UNLOCK(&xt_thr_array_resize_lock, thread->t_id);
2252
xt_lock_mutex_ns(&target_wt->wt_lock);
2253
xt_broadcast_cond_ns(&target_wt->wt_cond);
2254
xt_unlock_mutex_ns(&target_wt->wt_lock);
2258
* Wakeup a list of threads (the list is local to the calling thread).
2260
xtPublic void xt_wakeup_thread_list(XTThreadPtr thread)
2262
XTWaitThreadPtr target_wt;
2264
for (u_int i=0; i<thread->st_thread_list_count; i++) {
2265
THR_ARRAY_READ_LOCK(&xt_thr_array_resize_lock, thread->t_id);
2266
target_wt = xt_thr_array[thread->st_thread_list[i]].td_waiting;
2267
THR_ARRAY_UNLOCK(&xt_thr_array_resize_lock, thread->t_id);
2268
xt_lock_mutex_ns(&target_wt->wt_lock);
2269
xt_broadcast_cond_ns(&target_wt->wt_cond);
2270
xt_unlock_mutex_ns(&target_wt->wt_lock);
2272
thread->st_thread_list_count = 0;
2276
* Wakeup all threads waiting for this thread.
2278
xtPublic void xt_wakeup_waiting_threads(XTThreadPtr thread)
2281
XTWaitThreadPtr target_wt;
2283
THR_ARRAY_READ_LOCK(&xt_thr_array_resize_lock, thread->t_id);
2284
wt = xt_thr_array[thread->t_id].td_waiting;
2285
THR_ARRAY_UNLOCK(&xt_thr_array_resize_lock, thread->t_id);
2286
if (!wt->wt_wait_list_count)
2289
xt_spinlock_lock(&wt->wt_wait_list_lock);
2290
if (thread->st_thread_list_size < wt->wt_wait_list_count) {
2291
if (!xt_realloc_ns((void **) &thread->st_thread_list, wt->wt_wait_list_count * sizeof(xtThreadID)))
2293
thread->st_thread_list_size = wt->wt_wait_list_count;
2295
memcpy(thread->st_thread_list, wt->wt_wait_list, wt->wt_wait_list_count * sizeof(xtThreadID));
2296
thread->st_thread_list_count = wt->wt_wait_list_count;
2297
wt->wt_wait_list_count = 0;
2298
xt_spinlock_unlock(&wt->wt_wait_list_lock);
2300
xt_wakeup_thread_list(thread);
2304
for (u_int i=0; i<wt->wt_wait_list_count; i++) {
2305
THR_ARRAY_READ_LOCK(&xt_thr_array_resize_lock, thread->t_id);
2306
target_wt = xt_thr_array[wt->wt_wait_list[i]].td_waiting;
2307
THR_ARRAY_UNLOCK(&xt_thr_array_resize_lock, thread->t_id);
2308
xt_lock_mutex_ns(&target_wt->wt_lock);
2309
xt_broadcast_cond_ns(&target_wt->wt_cond);
2310
xt_unlock_mutex_ns(&target_wt->wt_lock);
2312
wt->wt_wait_list_count = 0;
2313
xt_spinlock_unlock(&wt->wt_wait_list_lock);
2317
* -----------------------------------------------------------------------
2321
#ifdef DEBUG_NO_ACTIVITY
2322
static void debug_no_activity()
2324
xt_logf(XT_NT_INFO, "No activity!\n");
2327
time_t last_call_time;
2328
u_llong last_commit_total;
2329
xtWord8 last_rec_flush_time = (xtWord8) -1;
2330
xtWord8 last_rec_write_time = (xtWord8) -1;
2331
xtWord8 last_ind_flush_time = (xtWord8) -1;
2332
xtWord8 last_ind_write_time = (xtWord8) -1;
2333
xtWord8 last_ilog_flush_time = (xtWord8) -1;
2334
xtWord8 last_ilog_write_time = (xtWord8) -1;
2335
xtWord8 last_xlog_flush_time = (xtWord8) -1;
2336
xtWord8 last_xlog_write_time = (xtWord8) -1;
2337
xtWord8 last_data_flush_time = (xtWord8) -1;
2338
xtWord8 last_data_write_time = (xtWord8) -1;
2341
xtPublic void xt_gather_statistics(XTStatisticsPtr stats)
2343
XTThreadDataRec *thr_data;
2347
xt_lock_mutex_ns(&thr_array_lock);
2348
*stats = thr_statistics;
2349
// Ignore index 0, it is not used!
2350
// No read resize lock required if I have the array lock
2351
thr_data = &xt_thr_array[XT_MIN_THREAD_ID];
2352
for (u_int i=XT_MIN_THREAD_ID; i<xt_thr_current_max_threads; i++) {
2353
if ((thr = thr_data->td_thread)) {
2354
stats->st_commits += thr->st_statistics.st_commits;
2355
stats->st_rollbacks += thr->st_statistics.st_rollbacks;
2356
stats->st_stat_read += thr->st_statistics.st_stat_read;
2357
stats->st_stat_write += thr->st_statistics.st_stat_write;
2359
XT_ADD_STATS(stats->st_rec, thr->st_statistics.st_rec);
2360
if ((s = thr->st_statistics.st_rec.ts_flush_start))
2361
stats->st_rec.ts_flush_time += xt_trace_clock() - s;
2362
#ifdef XT_TIME_DISK_WRITES
2363
if ((s = thr->st_statistics.st_rec.ts_write_start))
2364
stats->st_rec.ts_write_time += xt_trace_clock() - s;
2366
#ifdef XT_TIME_DISK_READS
2367
if ((s = thr->st_statistics.st_rec.ts_read_start))
2368
stats->st_rec.ts_read_time += xt_trace_clock() - s;
2370
stats->st_rec_cache_hit += thr->st_statistics.st_rec_cache_hit;
2371
stats->st_rec_cache_miss += thr->st_statistics.st_rec_cache_miss;
2372
stats->st_rec_cache_frees += thr->st_statistics.st_rec_cache_frees;
2374
XT_ADD_STATS(stats->st_ind, thr->st_statistics.st_ind);
2375
if ((s = thr->st_statistics.st_ind.ts_flush_start))
2376
stats->st_ind.ts_flush_time += xt_trace_clock() - s;
2377
#ifdef XT_TIME_DISK_WRITES
2378
if ((s = thr->st_statistics.st_ind.ts_write_start))
2379
stats->st_ind.ts_write_time += xt_trace_clock() - s;
2381
#ifdef XT_TIME_DISK_READS
2382
if ((s = thr->st_statistics.st_ind.ts_read_start))
2383
stats->st_ind.ts_read_time += xt_trace_clock() - s;
2385
stats->st_ind_cache_hit += thr->st_statistics.st_ind_cache_hit;
2386
stats->st_ind_cache_miss += thr->st_statistics.st_ind_cache_miss;
2387
XT_ADD_STATS(stats->st_ilog, thr->st_statistics.st_ilog);
2388
if ((s = thr->st_statistics.st_ilog.ts_flush_start))
2389
stats->st_ilog.ts_flush_time += xt_trace_clock() - s;
2390
#ifdef XT_TIME_DISK_WRITES
2391
if ((s = thr->st_statistics.st_ilog.ts_write_start))
2392
stats->st_ilog.ts_write_time += xt_trace_clock() - s;
2394
#ifdef XT_TIME_DISK_READS
2395
if ((s = thr->st_statistics.st_ilog.ts_read_start))
2396
stats->st_ilog.ts_read_time += xt_trace_clock() - s;
2399
XT_ADD_STATS(stats->st_xlog, thr->st_statistics.st_xlog);
2400
if ((s = thr->st_statistics.st_xlog.ts_flush_start))
2401
stats->st_xlog.ts_flush_time += xt_trace_clock() - s;
2402
#ifdef XT_TIME_DISK_WRITES
2403
if ((s = thr->st_statistics.st_xlog.ts_write_start))
2404
stats->st_xlog.ts_write_time += xt_trace_clock() - s;
2406
#ifdef XT_TIME_DISK_READS
2407
if ((s = thr->st_statistics.st_xlog.ts_read_start))
2408
stats->st_xlog.ts_read_time += xt_trace_clock() - s;
2410
stats->st_xlog_cache_hit += thr->st_statistics.st_xlog_cache_hit;
2411
stats->st_xlog_cache_miss += thr->st_statistics.st_xlog_cache_miss;
2413
XT_ADD_STATS(stats->st_data, thr->st_statistics.st_data);
2414
if ((s = thr->st_statistics.st_data.ts_flush_start))
2415
stats->st_data.ts_flush_time += xt_trace_clock() - s;
2416
#ifdef XT_TIME_DISK_WRITES
2417
if ((s = thr->st_statistics.st_data.ts_write_start))
2418
stats->st_data.ts_write_time += xt_trace_clock() - s;
2420
#ifdef XT_TIME_DISK_READS
2421
if ((s = thr->st_statistics.st_data.ts_read_start))
2422
stats->st_data.ts_read_time += xt_trace_clock() - s;
2425
stats->st_scan_index += thr->st_statistics.st_scan_index;
2426
stats->st_scan_table += thr->st_statistics.st_scan_table;
2427
stats->st_row_select += thr->st_statistics.st_row_select;
2428
stats->st_row_insert += thr->st_statistics.st_row_insert;
2429
stats->st_row_update += thr->st_statistics.st_row_update;
2430
stats->st_row_delete += thr->st_statistics.st_row_delete;
2432
stats->st_wait_for_xact += thr->st_statistics.st_wait_for_xact;
2433
stats->st_retry_index_scan += thr->st_statistics.st_retry_index_scan;
2434
stats->st_reread_record_list += thr->st_statistics.st_reread_record_list;
2436
stats->st_ind_cache_dirty += thr->st_statistics.st_ind_cache_dirty;
2440
xt_unlock_mutex_ns(&thr_array_lock);
2442
#ifdef DEBUG_NO_ACTIVITY
2443
time_t now = time(NULL);
2445
/* Make sure at least 1 second has gone by: */
2446
if (!last_call_time || now > last_call_time) {
2447
if (last_commit_total &&
2448
last_commit_total == stats->st_commits &&
2449
last_rec_flush_time == stats->st_rec.ts_flush_time &&
2450
last_ind_flush_time == stats->st_ind.ts_flush_time &&
2451
last_ilog_flush_time == stats->st_ilog.ts_flush_time &&
2452
last_xlog_flush_time == stats->st_xlog.ts_flush_time &&
2453
last_data_flush_time == stats->st_data.ts_flush_time &&
2454
last_rec_write_time == stats->st_rec.ts_write_time &&
2455
last_ind_write_time == stats->st_ind.ts_write_time &&
2456
last_ilog_write_time == stats->st_ilog.ts_write_time &&
2457
last_xlog_write_time == stats->st_xlog.ts_write_time &&
2458
last_data_write_time == stats->st_data.ts_write_time
2460
debug_no_activity();
2462
last_call_time = now;
2463
last_commit_total = stats->st_commits;
2465
last_rec_flush_time = stats->st_rec.ts_flush_time;
2466
last_ind_flush_time = stats->st_ind.ts_flush_time;
2467
last_ilog_flush_time = stats->st_ilog.ts_flush_time;
2468
last_xlog_flush_time = stats->st_xlog.ts_flush_time;
2469
last_data_flush_time = stats->st_data.ts_flush_time;
2471
last_rec_write_time = stats->st_rec.ts_write_time;
2472
last_ind_write_time = stats->st_ind.ts_write_time;
2473
last_ilog_write_time = stats->st_ilog.ts_write_time;
2474
last_xlog_write_time = stats->st_xlog.ts_write_time;
2475
last_data_write_time = stats->st_data.ts_write_time;
2480
xtPublic int xt_get_index_cache_dirty_perc()
2482
XTThreadDataRec *thr;
2483
XTStatisticsRec stats;
2486
xt_lock_mutex_ns(&thr_array_lock);
2487
stats = thr_statistics;
2488
// Ignore index 0 and 1, it is not used!
2489
// No read resize lock required if I have the array lock
2490
thr = &xt_thr_array[XT_MIN_THREAD_ID];
2491
for (u_int i=XT_MIN_THREAD_ID; i<xt_thr_current_max_threads; i++) {
2493
stats.st_ind_cache_dirty += thr->td_thread->st_statistics.st_ind_cache_dirty;
2496
xt_unlock_mutex_ns(&thr_array_lock);
2497
v = (double) stats.st_ind_cache_dirty * (double) XT_INDEX_PAGE_SIZE;
2498
return (int) (v / (double) xt_ind_get_size() * (double) 100);
2501
static void thr_accumulate_statistics(XTThreadPtr self)
2503
thr_statistics.st_commits += self->st_statistics.st_commits;
2504
thr_statistics.st_rollbacks += self->st_statistics.st_rollbacks;
2505
thr_statistics.st_stat_read += self->st_statistics.st_stat_read;
2506
thr_statistics.st_stat_write += self->st_statistics.st_stat_write;
2508
XT_ADD_STATS(thr_statistics.st_rec, self->st_statistics.st_rec);
2509
thr_statistics.st_rec_cache_hit += self->st_statistics.st_rec_cache_hit;
2510
thr_statistics.st_rec_cache_miss += self->st_statistics.st_rec_cache_miss;
2511
thr_statistics.st_rec_cache_frees += self->st_statistics.st_rec_cache_frees;
2513
XT_ADD_STATS(thr_statistics.st_ind, self->st_statistics.st_ind);
2514
thr_statistics.st_ind_cache_hit += self->st_statistics.st_ind_cache_hit;
2515
thr_statistics.st_ind_cache_miss += self->st_statistics.st_ind_cache_miss;
2516
XT_ADD_STATS(thr_statistics.st_ilog, self->st_statistics.st_ilog);
2518
XT_ADD_STATS(thr_statistics.st_xlog, self->st_statistics.st_xlog);
2519
thr_statistics.st_xlog_cache_hit += self->st_statistics.st_xlog_cache_hit;
2520
thr_statistics.st_xlog_cache_miss += self->st_statistics.st_xlog_cache_miss;
2522
XT_ADD_STATS(thr_statistics.st_data, self->st_statistics.st_data);
2524
thr_statistics.st_scan_index += self->st_statistics.st_scan_index;
2525
thr_statistics.st_scan_table += self->st_statistics.st_scan_table;
2526
thr_statistics.st_row_select += self->st_statistics.st_row_select;
2527
thr_statistics.st_row_insert += self->st_statistics.st_row_insert;
2528
thr_statistics.st_row_update += self->st_statistics.st_row_update;
2529
thr_statistics.st_row_delete += self->st_statistics.st_row_delete;
2531
thr_statistics.st_wait_for_xact += self->st_statistics.st_wait_for_xact;
2532
thr_statistics.st_retry_index_scan += self->st_statistics.st_retry_index_scan;
2533
thr_statistics.st_reread_record_list += self->st_statistics.st_reread_record_list;
2535
thr_statistics.st_ind_cache_dirty += self->st_statistics.st_ind_cache_dirty;
2538
xtPublic u_llong xt_get_statistic(XTStatisticsPtr stats, XTDatabaseHPtr db, u_int rec_id)
2543
case XT_STAT_TIME_CURRENT:
2544
stat_value = (u_llong) time(NULL);
2546
case XT_STAT_TIME_PASSED:
2547
stat_value = (u_llong) xt_trace_clock();
2549
case XT_STAT_COMMITS:
2550
stat_value = stats->st_commits;
2552
case XT_STAT_ROLLBACKS:
2553
stat_value = stats->st_rollbacks;
2555
case XT_STAT_STAT_READS:
2556
stat_value = stats->st_stat_read;
2558
case XT_STAT_STAT_WRITES:
2559
stat_value = stats->st_stat_write;
2562
case XT_STAT_REC_BYTES_IN:
2563
stat_value = stats->st_rec.ts_read;
2565
case XT_STAT_REC_BYTES_OUT:
2566
stat_value = stats->st_rec.ts_write;
2568
case XT_STAT_REC_SYNC_COUNT:
2569
stat_value = stats->st_rec.ts_flush;
2571
case XT_STAT_REC_SYNC_TIME:
2572
stat_value = stats->st_rec.ts_flush_time;
2574
case XT_STAT_REC_CACHE_HIT:
2575
stat_value = stats->st_rec_cache_hit;
2577
case XT_STAT_REC_CACHE_MISS:
2578
stat_value = stats->st_rec_cache_miss;
2580
case XT_STAT_REC_CACHE_FREES:
2581
stat_value = stats->st_rec_cache_frees;
2583
case XT_STAT_REC_CACHE_USAGE:
2584
stat_value = (u_llong) xt_tc_get_usage();
2587
case XT_STAT_IND_BYTES_IN:
2588
stat_value = stats->st_ind.ts_read;
2590
case XT_STAT_IND_BYTES_OUT:
2591
stat_value = stats->st_ind.ts_write;
2593
case XT_STAT_IND_SYNC_COUNT:
2594
stat_value = stats->st_ind.ts_flush;
2596
case XT_STAT_IND_SYNC_TIME:
2597
stat_value = stats->st_ind.ts_flush_time;
2599
case XT_STAT_IND_CACHE_HIT:
2600
stat_value = stats->st_ind_cache_hit;
2602
case XT_STAT_IND_CACHE_MISS:
2603
stat_value = stats->st_ind_cache_miss;
2605
case XT_STAT_IND_CACHE_USAGE:
2606
stat_value = (u_llong) xt_ind_get_usage();
2608
case XT_STAT_ILOG_BYTES_IN:
2609
stat_value = stats->st_ilog.ts_read;
2611
case XT_STAT_ILOG_BYTES_OUT:
2612
stat_value = stats->st_ilog.ts_write;
2614
case XT_STAT_ILOG_SYNC_COUNT:
2615
stat_value = stats->st_ilog.ts_flush;
2617
case XT_STAT_ILOG_SYNC_TIME:
2618
stat_value = stats->st_ilog.ts_flush_time;
2621
case XT_STAT_XLOG_BYTES_IN:
2622
stat_value = stats->st_xlog.ts_read;
2624
case XT_STAT_XLOG_BYTES_OUT:
2625
stat_value = stats->st_xlog.ts_write;
2627
case XT_STAT_XLOG_SYNC_COUNT:
2628
stat_value = stats->st_xlog.ts_flush;
2630
case XT_STAT_XLOG_SYNC_TIME:
2631
stat_value = stats->st_xlog.ts_flush_time;
2633
case XT_STAT_XLOG_CACHE_HIT:
2634
stat_value = stats->st_xlog_cache_hit;
2636
case XT_STAT_XLOG_CACHE_MISS:
2637
stat_value = stats->st_xlog_cache_miss;
2639
case XT_STAT_XLOG_CACHE_USAGE:
2640
stat_value = (u_llong) xt_xlog_get_usage();
2643
case XT_STAT_DATA_BYTES_IN:
2644
stat_value = stats->st_data.ts_read;
2646
case XT_STAT_DATA_BYTES_OUT:
2647
stat_value = stats->st_data.ts_write;
2649
case XT_STAT_DATA_SYNC_COUNT:
2650
stat_value = stats->st_data.ts_flush;
2652
case XT_STAT_DATA_SYNC_TIME:
2653
stat_value = stats->st_data.ts_flush_time;
2656
case XT_STAT_BYTES_TO_CHKPNT:
2657
stat_value = db ? xt_bytes_since_last_checkpoint(db, db->db_xlog.xl_write_log_id, db->db_xlog.xl_write_log_offset) : 0;
2659
case XT_STAT_LOG_BYTES_TO_WRITE:
2660
stat_value = db ? db->db_xlog.xl_log_bytes_written - db->db_xlog.xl_log_bytes_read : 0;//db->db_xlog.xlog_bytes_to_write();
2662
case XT_STAT_BYTES_TO_SWEEP:
2663
/* This stat is potentially very expensive: */
2664
stat_value = db ? xt_xn_bytes_to_sweep(db, xt_get_self()) : 0;
2666
case XT_STAT_WAIT_FOR_XACT:
2667
stat_value = stats->st_wait_for_xact;
2669
case XT_STAT_XACT_TO_CLEAN:
2670
#ifdef XT_SWEEPER_SORT_XACTS
2671
stat_value = db ? db->db_xn_curr_id + 1 - db->db_sw_to_add + db->db_sw_list_size : 0;
2673
stat_value = db ? db->db_xn_curr_id + 1 - db->db_xn_to_clean_id : 0;
2676
case XT_STAT_SWEEPER_WAITS:
2677
stat_value = db ? db->db_stat_sweep_waits : 0;
2680
case XT_STAT_SCAN_INDEX:
2681
stat_value = stats->st_scan_index;
2683
case XT_STAT_SCAN_TABLE:
2684
stat_value = stats->st_scan_table;
2686
case XT_STAT_ROW_SELECT:
2687
stat_value = stats->st_row_select;
2689
case XT_STAT_ROW_INSERT:
2690
stat_value = stats->st_row_insert;
2692
case XT_STAT_ROW_UPDATE:
2693
stat_value = stats->st_row_update;
2695
case XT_STAT_ROW_DELETE:
2696
stat_value = stats->st_row_delete;
2699
case XT_STAT_RETRY_INDEX_SCAN:
2700
stat_value = stats->st_retry_index_scan;
2702
case XT_STAT_REREAD_REC_LIST:
2703
stat_value = stats->st_reread_record_list;
2706
case XT_STAT_IND_CACHE_DIRTY:
2707
ASSERT_NS(stats->st_ind_cache_dirty >= 0);
2708
if (stats->st_ind_cache_dirty < 0)
2711
stat_value = stats->st_ind_cache_dirty;
2712
stat_value *= (u_llong) XT_INDEX_PAGE_SIZE;
2715
#ifdef XT_TIME_DISK_WRITES
2716
case XT_STAT_REC_WRITE_TIME:
2717
stat_value = stats->st_rec.ts_write_time;
2719
case XT_STAT_IND_WRITE_TIME:
2720
stat_value = stats->st_ind.ts_write_time;
2722
case XT_STAT_ILOG_WRITE_TIME:
2723
stat_value = stats->st_ilog.ts_write_time;
2725
case XT_STAT_XLOG_WRITE_TIME:
2726
stat_value = stats->st_xlog.ts_write_time;
2728
case XT_STAT_DATA_WRITE_TIME:
2729
stat_value = stats->st_data.ts_write_time;
2733
#ifdef XT_TIME_DISK_READS
2734
case XT_STAT_REC_READ_TIME:
2735
stat_value = stats->st_rec.ts_read_time;
2737
case XT_STAT_IND_READ_TIME:
2738
stat_value = stats->st_ind.ts_read_time;
2740
case XT_STAT_LOG_READ_TIME:
2741
stat_value = stats->st_ilog.ts_read_time + stats->st_xlog.ts_read_time + stats->st_data.ts_read_time;