56
65
static void ha_aquire_exclusive_use(XTThreadPtr self, XTSharePtr share, ha_pbxt *mine);
57
66
static void ha_release_exclusive_use(XTThreadPtr self, XTSharePtr share);
58
67
static void ha_close_open_tables(XTThreadPtr self, XTSharePtr share, ha_pbxt *mine);
59
static void ha_wait_for_shared_use(XTThreadPtr self, XTSharePtr share);
61
//#define PBXT_PRINT_STAT
62
//#define PBXT_HANDLER_TRACE
69
#ifdef PBXT_TRACE_STAT
71
#define XT_PRINT_STAT0(y, x)
72
#define XT_TRACE_STAT1(y, x, a) xt_trace_query(y, a)
75
#ifdef PBXT_PRINT_STAT
76
#define XT_PRINT_STAT0(y, x) do { XTThreadPtr s = (y); printf("%s " x, s ? s->t_name : "-unknown-"); } while (0)
77
#define XT_TRACE_STAT1(y, x, a) do { XTThreadPtr s = (y); printf("%s " x, s ? s->t_name : "-unknown-", a); } while (0)
79
#define XT_PRINT_STAT0(y, x)
80
#define XT_TRACE_STAT1(y, x, a)
63
85
#ifdef PBXT_HANDLER_TRACE
64
#define XT_ENTER() do { XTThreadPtr s = xt_get_self(); printf("%s %s\n", s ? s->t_name : "-unknown-", __FUNC__); } while (0)
86
#define PBXT_ALLOW_PRINTING
88
#define XT_TRACE_CALL() do { XTThreadPtr s = xt_get_self(); printf("%s %s\n", s ? s->t_name : "-unknown-", __FUNC__); } while (0)
66
89
#ifdef PBXT_TRACE_RETURN
68
#define XT_RETURN(x) do { printf("%d\n", (int) (x)); return (x); } while (0)
69
#define XT_RETURN_VOID do { printf("out\n"); return; } while (0)
71
#define XT_RETURN(x) return (x)
72
#define XT_RETURN_VOID return
90
#define XT_RETURN(x) do { printf("%d\n", (int) (x)); return (x); } while (0)
91
#define XT_RETURN_VOID do { printf("out\n"); return; } while (0)
93
#define XT_RETURN(x) return (x)
94
#define XT_RETURN_VOID return
99
#define XT_TRACE_CALL()
100
#define XT_RETURN(x) return (x)
101
#define XT_RETURN_VOID return
105
#ifdef PBXT_ALLOW_PRINTING
75
106
#define XT_PRINT0(y, x) do { XTThreadPtr s = (y); printf("%s " x, s ? s->t_name : "-unknown-"); } while (0)
76
107
#define XT_PRINT1(y, x, a) do { XTThreadPtr s = (y); printf("%s " x, s ? s->t_name : "-unknown-", a); } while (0)
77
108
#define XT_PRINT2(y, x, a, b) do { XTThreadPtr s = (y); printf("%s " x, s ? s->t_name : "-unknown-", a, b); } while (0)
78
109
#define XT_PRINT3(y, x, a, b, c) do { XTThreadPtr s = (y); printf("%s " x, s ? s->t_name : "-unknown-", a, b, c); } while (0)
82
#define XT_RETURN(x) return (x)
83
#define XT_RETURN_VOID return
84
111
#define XT_PRINT0(y, x)
85
112
#define XT_PRINT1(y, x, a)
86
113
#define XT_PRINT2(y, x, a, b)
87
114
#define XT_PRINT3(y, x, a, b, c)
90
118
#define TS(x) (x)->s
92
120
handlerton *pbxt_hton;
664
737
return ha_pbxt_thread_error_for_mysql(thd, self, ignore_dup_key);
667
static int ha_idx_next_read(register XTOpenTablePtr ot, register XTIndexPtr ind, xtBool key_only,
668
register XTIdxSearchKeyPtr search_key, byte *buf, xtBool *modified)
671
/* We only need to read the data from the key: */
672
while (ot->ot_curr_rec) {
673
if (search_key && !search_key->sk_on_key)
676
switch (xt_tab_visible(ot)) {
678
/* The index is referencing a deleted record.
679
* Remove the entry from the index!
682
xt_idx_delete_current(ot, ind);
683
/* Then move on to the next item! */
685
if (xt_idx_next(ot, ind, search_key))
688
return ha_log_pbxt_thread_error_for_mysql(FALSE);
690
if (!xt_idx_read(ot, ind, (xtWord1 *) buf))
691
return ha_log_pbxt_thread_error_for_mysql(FALSE);
697
while (ot->ot_curr_rec) {
698
if (search_key && !search_key->sk_on_key)
701
switch (xt_tab_read_record(ot, (xtWord1 *) buf)) {
703
/* The index is referencing a deleted record.
704
* Remove the entry from the index!
707
xt_idx_delete_current(ot, ind);
708
/* Then move on to the next item! */
710
XT_DISABLED_TRACE(("not visi tx=%d rec=%d\n", (int) ot->ot_thread->st_xact_data->xd_start_id, (int) ot->ot_curr_rec));
711
if (xt_idx_next(ot, ind, search_key))
714
return ha_log_pbxt_thread_error_for_mysql(FALSE);
716
XT_DISABLED_TRACE(("visible tx=%d rec=%d\n", (int) ot->ot_thread->st_xact_data->xd_start_id, (int) ot->ot_curr_rec));
721
return HA_ERR_END_OF_FILE;
724
static int ha_idx_prev_read(XTOpenTablePtr ot, XTIndexPtr ind, xtBool key_only,
725
register XTIdxSearchKeyPtr search_key, byte *buf, xtBool *modified)
728
/* We only need to read the data from the key: */
729
while (ot->ot_curr_rec) {
730
if (search_key && !search_key->sk_on_key)
733
switch (xt_tab_visible(ot)) {
735
/* The index is referencing a deleted record.
736
* Remove the entry from the index!
739
xt_idx_delete_current(ot, ind);
740
/* Then move on to the next item! */
742
if (xt_idx_prev(ot, ind, search_key))
745
return ha_log_pbxt_thread_error_for_mysql(FALSE);
747
if (!xt_idx_read(ot, ind, (xtWord1 *) buf))
748
return ha_log_pbxt_thread_error_for_mysql(FALSE);
754
/* We need to read the entire record: */
755
while (ot->ot_curr_rec) {
756
if (search_key && !search_key->sk_on_key)
759
switch (xt_tab_read_record(ot, (xtWord1 *) buf)) {
761
/* The index is referencing a deleted record.
762
* Remove the entry from the index!
765
xt_idx_delete_current(ot, ind);
766
/* Then move on to the next item! */
768
if (xt_idx_prev(ot, ind, search_key))
771
return ha_log_pbxt_thread_error_for_mysql(FALSE);
777
return HA_ERR_END_OF_FILE;
781
741
* -----------------------------------------------------------------------
746
typedef struct HAVarParams {
752
} HAVarParamsRec, *HAVarParamsPtr;
754
#ifdef XT_USE_SYS_PAR_DEBUG_SIZES
755
static HAVarParamsRec vp_index_cache_size = { "pbxt_index_cache_size", "600000", "600000", "2GB", "2000GB" };
756
static HAVarParamsRec vp_record_cache_size = { "pbxt_record_cache_size", "6000000", "600000", "2GB", "2000GB" };
757
static HAVarParamsRec vp_log_cache_size = { "pbxt_log_cache_size", "4000000", "500000", "2GB", "2000GB" };
758
static HAVarParamsRec vp_log_file_threshold = { "pbxt_log_file_threshold", "300000", "300000", "2GB", "256TB" };
759
static HAVarParamsRec vp_transaction_buffer_size = { "pbxt_transaction_buffer_size", "100000", "100000", "1GB", "24GB" };
760
static HAVarParamsRec vp_log_buffer_size = { "pbxt_log_buffer_size", "10000", "201", "1GB", "24GB" };
761
static HAVarParamsRec vp_checkpoint_frequency = { "pbxt_checkpoint_frequency", "2000000", "120000", "1GB", "24GB" };
762
static HAVarParamsRec vp_data_log_threshold = { "pbxt_data_log_threshold", "50000", "50000", "2GB", "256TB" };
764
static HAVarParamsRec vp_index_cache_size = { "pbxt_index_cache_size", "32MB", "8MB", "2GB", "2000GB" };
765
static HAVarParamsRec vp_record_cache_size = { "pbxt_record_cache_size", "32MB", "8MB", "2GB", "2000GB" };
766
static HAVarParamsRec vp_log_cache_size = { "pbxt_log_cache_size", "16MB", "2MB", "2GB", "2000GB" };
767
static HAVarParamsRec vp_log_file_threshold = { "pbxt_log_file_threshold", "16MB", "1MB", "2GB", "256TB" };
768
static HAVarParamsRec vp_transaction_buffer_size = { "pbxt_transaction_buffer_size", "1MB", "128K", "1GB", "24GB" };
769
static HAVarParamsRec vp_log_buffer_size = { "pbxt_log_buffer_size", "256K", "64K", "1GB", "24GB" };
770
static HAVarParamsRec vp_checkpoint_frequency = { "pbxt_checkpoint_frequency", "24MB", "512K", "1GB", "24GB" };
771
static HAVarParamsRec vp_data_log_threshold = { "pbxt_data_log_threshold", "64MB", "1MB", "2GB", "256TB" };
774
static xtWord8 ha_set_variable(char **value, HAVarParamsPtr vp)
781
*value = getenv(vp->vp_var);
784
result = xt_byte_size_to_int8(*value);
785
mi = xt_byte_size_to_int8(vp->vp_min);
790
if (sizeof(size_t) == 8)
794
ma = xt_byte_size_to_int8(mm);
786
802
static void pbxt_call_init(XTThreadPtr self)
788
804
xtInt8 index_cache_size;
789
805
xtInt8 record_cache_size;
806
xtInt8 log_cache_size;
807
xtInt8 log_file_threshold;
808
xtInt8 transaction_buffer_size;
809
xtInt8 log_buffer_size;
810
xtInt8 checkpoint_frequency;
811
xtInt8 data_log_threshold;
791
813
xt_logf(XT_NT_INFO, "PrimeBase XT (PBXT) Engine %s loaded...\n", xt_get_version());
792
xt_logf(XT_NT_INFO, "Paul McCullagh, SNAP Innovation GmbH, http://www.primebase.com/xt\n");
794
if (!pbxt_index_cache_size)
795
pbxt_index_cache_size = getenv("pbxt_index_cache_size");
796
if (!pbxt_index_cache_size)
797
pbxt_index_cache_size = "32MB";
798
index_cache_size = xt_byte_size_to_int8(pbxt_index_cache_size);
799
if (index_cache_size < 8 * 1024 * 1024) {
800
index_cache_size = 8 * 1024 * 1024;
801
pbxt_index_cache_size = "8MB";
804
if (!pbxt_record_cache_size)
805
pbxt_record_cache_size = getenv("pbxt_record_cache_size");
806
if (!pbxt_record_cache_size)
807
pbxt_record_cache_size = "32MB";
808
record_cache_size = xt_byte_size_to_int8(pbxt_record_cache_size);
809
if (record_cache_size < 8 * 1024 * 1024) {
810
record_cache_size = 8 * 1024 * 1024;
811
pbxt_record_cache_size = "8MB";
814
xt_logf(XT_NT_INFO, "Paul McCullagh, PrimeBase Technologies GmbH, http://www.primebase.com/xt\n");
816
index_cache_size = ha_set_variable(&pbxt_index_cache_size, &vp_index_cache_size);
817
record_cache_size = ha_set_variable(&pbxt_record_cache_size, &vp_record_cache_size);
818
log_cache_size = ha_set_variable(&pbxt_log_cache_size, &vp_log_cache_size);
819
log_file_threshold = ha_set_variable(&pbxt_log_file_threshold, &vp_log_file_threshold);
820
transaction_buffer_size = ha_set_variable(&pbxt_transaction_buffer_size, &vp_transaction_buffer_size);
821
log_buffer_size = ha_set_variable(&pbxt_log_buffer_size, &vp_log_buffer_size);
822
checkpoint_frequency = ha_set_variable(&pbxt_checkpoint_frequency, &vp_checkpoint_frequency);
823
data_log_threshold = ha_set_variable(&pbxt_data_log_threshold, &vp_data_log_threshold);
814
825
pbxt_ignore_case = lower_case_table_names != 0;
815
826
if (pbxt_ignore_case)
1405
1527
HA_AUTO_PART_KEY);
1531
* The following query from the DBT1 test is VERY slow
1532
* if we do not set HA_READ_ORDER.
1533
* The reason is that it must scan all duplicates, then
1536
* SELECT o_id, o_carrier_id, o_entry_d, o_ol_cnt
1537
* FROM orders FORCE INDEX (o_w_id)
1541
* ORDER BY o_id DESC limit 1;
1544
#define FLAGS_ARE_READ_DYNAMICALLY
1546
ulong ha_pbxt::index_flags(uint inx, uint part, bool all_parts) const
1548
/* It would be nice if the dynamic version of this function works,
1549
* but it does not. MySQL loads this information when the table is openned,
1550
* and then it is fixed.
1552
* The problem is, I have had to remove the HA_READ_ORDER option although
1553
* it applies to PBXT. PBXT returns entries in index order during an index
1554
* scan in _almost_ all cases.
1556
* A number of cases are demostrated here: [(11)]
1558
* If involves the following conditions:
1559
* - a SELECT FOR UPDATE, UPDATE or DELETE statement
1560
* - an ORDER BY, or join that requires the sort order
1561
* - another transaction which updates the index while it is being
1564
* In this "obscure" case, the index scan may return index
1565
* entries in the wrong order.
1567
#ifdef FLAGS_ARE_READ_DYNAMICALLY
1568
/* If were are in an update (SELECT FOR UPDATE, UPDATE or DELETE), then
1569
* it may be that we return the rows from an index in the wrong
1570
* order! This is due to the fact that update reads wait for transactions
1571
* to commit and this means that index entries may change position during
1574
if (pb_open_tab && pb_open_tab->ot_for_update)
1575
return (HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE | HA_KEYREAD_ONLY);
1576
/* If I understand HA_KEYREAD_ONLY then this means I do not
1577
* need to fetch the record associated with an index
1580
return (HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER | HA_READ_RANGE | HA_KEYREAD_ONLY);
1582
return (HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE | HA_KEYREAD_ONLY);
1408
1586
void ha_pbxt::internal_close(void *t)
1410
1588
XTThreadPtr self = (XTThreadPtr) t;
1412
1590
if (pb_share) {
1414
xt_mutex_lock(pb_share->sh_ex_mutex);
1415
/* Before we close the table we must remove references
1416
* to the data we are about to delete.
1595
/* This lock must be held when we remove the handler's
1596
* open table because ha_close_open_tables() can run
1599
xt_lock_mutex_ns(pb_share->sh_ex_mutex);
1600
if ((ot = pb_open_tab)) {
1419
1601
pb_open_tab->ot_thread = self;
1420
if (!xt_flush_table(pb_open_tab))
1421
xt_log_and_clear_exception(self);
1422
xt_close_table(pb_open_tab);
1602
if (self->st_database != pb_open_tab->ot_table->tab_db)
1603
xt_ha_open_database_of_table(self, pb_share->sh_table_path, NULL);
1605
pushr_(xt_db_return_table_to_pool, ot);
1425
xt_mutex_unlock(pb_share->sh_ex_mutex);
1607
xt_unlock_mutex_ns(pb_share->sh_ex_mutex);
1429
1609
ha_remove_from_handler_list(self, pb_share, this);
1431
1611
/* Someone may be waiting for me to complete: */
1432
1612
xt_broadcast_cond(NULL, (xt_cond_type *) pb_share->sh_ex_cond);
1434
ha_unget_share(self, pb_share);
1614
removed = ha_unget_share_removed(self, pb_share);
1617
/* Flush the table if this was the last handler: */
1619
xt_flush_table(self, ot);
1620
freer_(); // xt_db_return_table_to_pool(ot);
1437
1624
xt_log_and_clear_exception(self);
1846
2044
if (!xt_tab_delete_record(pb_open_tab, (xtWord1 *) buf))
1847
2045
err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key);
2047
pb_open_tab->ot_table->tab_locks.xt_remove_temp_lock(pb_open_tab);
2053
* -----------------------------------------------------------------------
2058
* This looks like a hack, but actually, it is OK.
2059
* It depends on the setup done by the super-class. It involves an extra
2060
* range check that we need to do if a "new" record is returned during
2063
* A new record is returned if a row is updated (by another transaction)
2064
* during the index scan. If an update is detected, then the scan stops
2065
* and waits for the transaction to end.
2067
* If the transaction commits, then the updated row is returned instead
2068
* of the row it would have returned when doing a consistant read
2069
* (repeatable read).
2071
* These new records can appear out of index order, and may not even
2072
* belong to the index range that we are concerned with.
2074
* Notice that there is not check for the start of the range. It appears
2075
* that this is not necessary, MySQL seems to have no problem ignoring
2078
* A number of test have been given below which demonstrate the use
2081
* They also demonstrate the ORDER BY problem described here: [(11)].
2083
* DROP TABLE IF EXISTS test_tab, test_tab_1, test_tab_2;
2084
* CREATE TABLE test_tab (ID int primary key, Value int, Name varchar(20), index(Value, Name)) ENGINE=pbxt;
2085
* INSERT test_tab values(1, 1, 'A');
2086
* INSERT test_tab values(2, 1, 'B');
2087
* INSERT test_tab values(3, 1, 'C');
2088
* INSERT test_tab values(4, 2, 'D');
2089
* INSERT test_tab values(5, 2, 'E');
2090
* INSERT test_tab values(6, 2, 'F');
2091
* INSERT test_tab values(7, 2, 'G');
2093
* select * from test_tab where value = 1 order by value, name for update;
2098
* select * from test_tab where id = 5 for update;
2102
* select * from test_tab where value = 2 order by value, name for update;
2105
* update test_tab set value = 3 where id = 6;
2111
* select * from test_tab where id = 5 for update;
2115
* select * from test_tab where value >= 2 order by value, name for update;
2118
* update test_tab set value = 3 where id = 6;
2124
* select * from test_tab where id = 5 for update;
2128
* select * from test_tab where value = 2 order by value, name for update;
2131
* update test_tab set value = 1 where id = 6;
2135
int ha_pbxt::xt_index_in_range(register XTOpenTablePtr ot, register XTIndexPtr ind,
2136
register XTIdxSearchKeyPtr search_key, xtWord1 *buf)
2138
/* If search key is given, this means we want an exact match. */
2140
xtWord1 key_buf[XT_INDEX_MAX_KEY_SIZE];
2142
myxt_create_key_from_row(ind, key_buf, buf, NULL);
2143
search_key->sk_on_key = myxt_compare_key(ind, search_key->sk_key_value.sv_flags, search_key->sk_key_value.sv_length,
2144
search_key->sk_key_value.sv_key, key_buf) == 0;
2145
return search_key->sk_on_key;
2148
/* Otherwise, check the end of the range. */
2150
return compare_key(end_range) <= 0;
2154
int ha_pbxt::xt_index_next_read(register XTOpenTablePtr ot, register XTIndexPtr ind, xtBool key_only,
2155
register XTIdxSearchKeyPtr search_key, byte *buf)
2158
/* We only need to read the data from the key: */
2159
while (ot->ot_curr_rec_id) {
2160
if (search_key && !search_key->sk_on_key)
2163
switch (xt_tab_visible(ot)) {
2165
/* The index is referencing a deleted record.
2166
* Remove the entry from the index!
2168
xt_idx_delete_current(ot, ind);
2169
/* Then move on to the next item! */
2171
if (xt_idx_next(ot, ind, search_key))
2176
if (!xt_idx_read(ot, ind, (xtWord1 *) buf))
2178
if (xt_index_in_range(ot, ind, search_key, buf))
2180
if (!xt_idx_next(ot, ind, search_key))
2185
if (!xt_idx_search(pb_open_tab, ind, search_key))
2186
return ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key);
2189
if (!xt_idx_research(pb_open_tab, ind))
2194
if (!xt_idx_read(ot, ind, (xtWord1 *) buf))
2201
while (ot->ot_curr_rec_id) {
2202
if (search_key && !search_key->sk_on_key)
2205
switch (xt_tab_read_record(ot, (xtWord1 *) buf)) {
2207
/* The index is referencing a deleted record.
2208
* Remove the entry from the index!
2210
xt_idx_delete_current(ot, ind);
2211
/* Then move on to the next item! */
2213
XT_DISABLED_TRACE(("not visi tx=%d rec=%d\n", (int) ot->ot_thread->st_xact_data->xd_start_xn_id, (int) ot->ot_curr_rec_id));
2214
if (xt_idx_next(ot, ind, search_key))
2219
if (xt_index_in_range(ot, ind, search_key, buf))
2221
if (!xt_idx_next(ot, ind, search_key))
2226
if (!xt_idx_search(pb_open_tab, ind, search_key))
2227
return ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key);
2230
if (!xt_idx_research(pb_open_tab, ind))
2235
XT_DISABLED_TRACE(("visible tx=%d rec=%d\n", (int) ot->ot_thread->st_xact_data->xd_start_xn_id, (int) ot->ot_curr_rec_id));
2240
return HA_ERR_END_OF_FILE;
2243
return ha_log_pbxt_thread_error_for_mysql(FALSE);
2246
int ha_pbxt::xt_index_prev_read(XTOpenTablePtr ot, XTIndexPtr ind, xtBool key_only,
2247
register XTIdxSearchKeyPtr search_key, byte *buf)
2250
/* We only need to read the data from the key: */
2251
while (ot->ot_curr_rec_id) {
2252
if (search_key && !search_key->sk_on_key)
2255
switch (xt_tab_visible(ot)) {
2257
/* The index is referencing a deleted record.
2258
* Remove the entry from the index!
2260
xt_idx_delete_current(ot, ind);
2261
/* Then move on to the next item! */
2263
if (xt_idx_prev(ot, ind, search_key))
2268
if (!xt_idx_read(ot, ind, (xtWord1 *) buf))
2270
if (xt_index_in_range(ot, ind, search_key, buf))
2272
if (!xt_idx_next(ot, ind, search_key))
2277
if (!xt_idx_search_prev(pb_open_tab, ind, search_key))
2278
return ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key);
2281
if (!xt_idx_research(pb_open_tab, ind))
2286
if (!xt_idx_read(ot, ind, (xtWord1 *) buf))
2293
/* We need to read the entire record: */
2294
while (ot->ot_curr_rec_id) {
2295
if (search_key && !search_key->sk_on_key)
2298
switch (xt_tab_read_record(ot, (xtWord1 *) buf)) {
2300
/* The index is referencing a deleted record.
2301
* Remove the entry from the index!
2303
xt_idx_delete_current(ot, ind);
2304
/* Then move on to the next item! */
2306
if (xt_idx_prev(ot, ind, search_key))
2311
if (xt_index_in_range(ot, ind, search_key, buf))
2313
if (!xt_idx_next(ot, ind, search_key))
2318
if (!xt_idx_search_prev(pb_open_tab, ind, search_key))
2319
return ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key);
2322
if (!xt_idx_research(pb_open_tab, ind))
2331
return HA_ERR_END_OF_FILE;
2334
return ha_log_pbxt_thread_error_for_mysql(FALSE);
2337
int ha_pbxt::index_init(uint idx, bool sorted)
2342
/* The number of columns required: */
2343
if (pb_open_tab->ot_is_modify) {
2344
pb_open_tab->ot_cols_req = table->read_set->n_bits;
2345
#ifdef XT_PRINT_INDEX_OPT
2346
ind = (XTIndexPtr) pb_share->sh_dic_keys[idx];
2348
printf("index_init %s index %d cols req=%d/%d read_bits=%X write_bits=%X index_bits=%X\n", pb_open_tab->ot_table->tab_name, (int) idx, pb_open_tab->ot_cols_req, pb_open_tab->ot_cols_req, (int) *table->read_set->bitmap, (int) *table->write_set->bitmap, (int) *ind->mi_col_map.bitmap);
2352
pb_open_tab->ot_cols_req = ha_get_max_bit(table->read_set);
2354
/* Check for index coverage!
2356
* Given the following table:
2358
* CREATE TABLE `customer` (
2359
* `c_id` int(11) NOT NULL DEFAULT '0',
2360
* `c_d_id` int(11) NOT NULL DEFAULT '0',
2361
* `c_w_id` int(11) NOT NULL DEFAULT '0',
2362
* `c_first` varchar(16) DEFAULT NULL,
2363
* `c_middle` char(2) DEFAULT NULL,
2364
* `c_last` varchar(16) DEFAULT NULL,
2365
* `c_street_1` varchar(20) DEFAULT NULL,
2366
* `c_street_2` varchar(20) DEFAULT NULL,
2367
* `c_city` varchar(20) DEFAULT NULL,
2368
* `c_state` char(2) DEFAULT NULL,
2369
* `c_zip` varchar(9) DEFAULT NULL,
2370
* `c_phone` varchar(16) DEFAULT NULL,
2371
* `c_since` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
2372
* `c_credit` char(2) DEFAULT NULL,
2373
* `c_credit_lim` decimal(24,12) DEFAULT NULL,
2374
* `c_discount` double DEFAULT NULL,
2375
* `c_balance` decimal(24,12) DEFAULT NULL,
2376
* `c_ytd_payment` decimal(24,12) DEFAULT NULL,
2377
* `c_payment_cnt` double DEFAULT NULL,
2378
* `c_delivery_cnt` double DEFAULT NULL,
2380
* PRIMARY KEY (`c_w_id`,`c_d_id`,`c_id`),
2381
* KEY `c_w_id` (`c_w_id`,`c_d_id`,`c_last`,`c_first`,`c_id`)
2384
* MySQL does not recognize index coverage on the followin select:
2386
* SELECT c_id FROM customer WHERE c_w_id = 3 AND c_d_id = 8 AND
2387
* c_last = 'EINGATIONANTI' ORDER BY c_first ASC LIMIT 1;
2389
* TODO: Find out why this is necessary, MyISAM does not
2390
* seem to have this problem!
2392
ind = (XTIndexPtr) pb_share->sh_dic_keys[idx];
2393
if (bitmap_is_subset(table->read_set, &ind->mi_col_map))
2395
#ifdef XT_PRINT_INDEX_OPT
2396
printf("index_init %s index %d cols req=%d/%d read_bits=%X write_bits=%X index_bits=%X converage=%d\n", pb_open_tab->ot_table->tab_name, (int) idx, pb_open_tab->ot_cols_req, table->read_set->n_bits, (int) *table->read_set->bitmap, (int) *table->write_set->bitmap, (int) *ind->mi_col_map.bitmap, (int) (bitmap_is_subset(table->read_set, &ind->mi_col_map) != 0));
1852
2403
int ha_pbxt::index_end()
1857
2408
ASSERT_NS(pb_ex_in_use);
1858
2409
active_index = MAX_KEY;
1859
2410
XT_RETURN(err);
2987
3613
ASSERT_NS(pb_open_tab->ot_thread == self);
2989
3614
ASSERT_NS(thd == pb_mysql_thd);
3615
ASSERT_NS(self->st_database == pb_open_tab->ot_table->tab_db);
3617
if (self->st_stat_ended) {
3618
self->st_stat_ended = FALSE;
3619
self->st_stat_trans = FALSE;
3620
/* This section handles "auto-commit"... */
3621
if (self->st_xact_data && self->st_auto_commit && self->st_table_trans) {
3622
if (self->st_abort_trans) {
3623
XT_PRINT0(self, "xt_xn_rollback\n");
3624
if (!xt_xn_rollback(self))
3625
err = ha_pbxt_thread_error_for_mysql(pb_mysql_thd, self, pb_ignore_dup_key);
3628
XT_PRINT0(self, "xt_xn_commit\n");
3629
if (!xt_xn_commit(self))
3630
err = ha_pbxt_thread_error_for_mysql(pb_mysql_thd, self, pb_ignore_dup_key);
3634
/* If the previous statement was "for update", then set the visibilty
3635
* so that non- for update SELECTs will see what the for update select
3636
* (or update statement) just saw.
3638
if (pb_open_tab->ot_for_update)
3639
self->st_visible_time = self->st_database->db_xn_end_time;
3642
pb_open_tab->ot_for_update =
2992
3643
(lock_type != TL_READ &&
2993
3644
lock_type != TL_READ_WITH_SHARED_LOCKS &&
2994
3645
lock_type != TL_READ_HIGH_PRIORITY &&
2995
3646
lock_type != TL_READ_NO_INSERT);
2997
ASSERT_NS(self->st_database == pb_open_tab->ot_table->tab_db);
3000
if (pb_open_tab && !xt_flush_table(pb_open_tab))
3001
err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key);
3647
pb_open_tab->ot_is_modify = FALSE;
3648
if (pb_open_tab->ot_for_update) {
3649
switch ((int) thd_sql_command(thd)) {
3651
case SQLCOM_UPDATE_MULTI:
3653
case SQLCOM_DELETE_MULTI:
3654
case SQLCOM_REPLACE:
3655
case SQLCOM_REPLACE_SELECT:
3657
case SQLCOM_INSERT_SELECT:
3658
pb_open_tab->ot_is_modify = TRUE;
3004
3664
/* (***) This is required at this level!
3005
* No mater how often it is called, it is still the start of a
3665
* No matter how often it is called, it is still the start of a
3006
3666
* statement. We need to make sure statements that are NOT mistaken
3007
3667
* for different type of statement.
4260
struct st_mysql_sys_var
4262
MYSQL_PLUGIN_VAR_HEADER;
4265
static void pbxt_record_cache_size_func(THD *thd, struct st_mysql_sys_var *var, void *tgt, void *save)
4267
xtInt8 record_cache_size;
4269
char *old= *(char **) tgt;
4270
*(char **)tgt= *(char **) save;
4271
if (var->flags & PLUGIN_VAR_MEMALLOC)
4273
*(char **)tgt= my_strdup(*(char **) save, MYF(0));
4274
my_free(old, MYF(0));
4276
record_cache_size = ha_set_variable(&pbxt_record_cache_size, &vp_record_cache_size);
4277
xt_tc_set_cache_size((size_t) record_cache_size);
4281
sprintf(buffer, "pbxt_record_cache_size=%llu\n", (u_llong) record_cache_size);
4282
xt_logf(XT_NT_INFO, buffer);
3604
4286
struct st_mysql_storage_engine pbxt_storage_engine = {
3605
4287
MYSQL_HANDLERTON_INTERFACE_VERSION
4289
static st_mysql_information_schema pbxt_statitics = {
4290
MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
3608
4293
#if MYSQL_VERSION_ID >= 50118
3609
4294
static MYSQL_SYSVAR_STR(index_cache_size, pbxt_index_cache_size,
3610
4295
PLUGIN_VAR_READONLY,
3611
"The amount of memory allocated to the index (fixed-block) cache.",
4296
"The amount of memory allocated to the index cache, used only to cache index data.",
3612
4297
NULL, NULL, NULL);
3614
4299
static MYSQL_SYSVAR_STR(record_cache_size, pbxt_record_cache_size,
3615
PLUGIN_VAR_READONLY,
3616
"The amount of memory allocated to the record (variable length block) cache.",
4300
PLUGIN_VAR_READONLY, // PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC,
4301
"The amount of memory allocated to the record cache used to cache table data.",
4302
NULL, pbxt_record_cache_size_func, NULL);
4304
static MYSQL_SYSVAR_STR(log_cache_size, pbxt_log_cache_size,
4305
PLUGIN_VAR_READONLY,
4306
"The amount of memory allocated to the transaction log cache used to cache on transaction log data.",
4309
static MYSQL_SYSVAR_STR(log_file_threshold, pbxt_log_file_threshold,
4310
PLUGIN_VAR_READONLY,
4311
"The size of a transaction log before rollover, and a new log is created.",
4314
static MYSQL_SYSVAR_STR(transaction_buffer_size, pbxt_transaction_buffer_size,
4315
PLUGIN_VAR_READONLY,
4316
"The size of the global transaction log buffer (the engine allocates 2 buffers of this size).",
4319
static MYSQL_SYSVAR_STR(log_buffer_size, pbxt_log_buffer_size,
4320
PLUGIN_VAR_READONLY,
4321
"The size of the buffer used to cache data from transaction and data logs during sequential scans, or when writing a data log.",
4324
static MYSQL_SYSVAR_STR(checkpoint_frequency, pbxt_checkpoint_frequency,
4325
PLUGIN_VAR_READONLY,
4326
"The size of the transaction data buffer which is allocate by each thread.",
4329
static MYSQL_SYSVAR_STR(data_log_threshold, pbxt_data_log_threshold,
4330
PLUGIN_VAR_READONLY,
4331
"The maximum size of a data log file.",
4334
static MYSQL_SYSVAR_INT(garbage_threshold, xt_db_garbage_threshold,
4335
PLUGIN_VAR_OPCMDARG,
4336
"The percentage of garbage in a repository file before it is compacted.",
4337
NULL, NULL, XT_DL_DEFAULT_GARBAGE_LEVEL, 0, 100, 1);
3619
4339
static struct st_mysql_sys_var* pbxt_system_variables[] = {
3620
4340
MYSQL_SYSVAR(index_cache_size),
3621
4341
MYSQL_SYSVAR(record_cache_size),
4342
MYSQL_SYSVAR(log_cache_size),
4343
MYSQL_SYSVAR(log_file_threshold),
4344
MYSQL_SYSVAR(transaction_buffer_size),
4345
MYSQL_SYSVAR(log_buffer_size),
4346
MYSQL_SYSVAR(checkpoint_frequency),
4347
MYSQL_SYSVAR(data_log_threshold),
4348
MYSQL_SYSVAR(garbage_threshold),