~vkolesnikov/pbxt/pbxt-preload-test-bug

« back to all changes in this revision

Viewing changes to pbxt/src/ha_pbxt.cc

  • Committer: paul-mccullagh
  • Date: 2008-03-10 11:36:34 UTC
  • Revision ID: paul-mccullagh-417ebf175a9c8ee6e5b3777d9e2398e1fb197391
Implemented full durability

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2005 SNAP Innovation GmbH
 
1
/* Copyright (c) 2005 PrimeBase Technologies GmbH
2
2
 *
3
3
 * Derived from ha_example.h
4
4
 * Copyright (C) 2003 MySQL AB
44
44
#include "myxt_xt.h"
45
45
#include "datadic_xt.h"
46
46
#include "streaming_xt.h"
 
47
#include "tabcache_xt.h"
 
48
 
 
49
#ifdef DEBUG
 
50
//#define XT_USE_SYS_PAR_DEBUG_SIZES
 
51
//#define PBXT_PRINT_STAT
 
52
//#define PBXT_HANDLER_TRACE
 
53
//#define PBXT_TRACE_RETURN
 
54
//#define XT_PRINT_INDEX_OPT
 
55
#endif
47
56
 
48
57
static handler  *pbxt_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root);
49
58
static int              pbxt_init(void *p);
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);
60
 
 
61
 
//#define PBXT_PRINT_STAT
62
 
//#define PBXT_HANDLER_TRACE
 
68
 
 
69
#ifdef PBXT_TRACE_STAT
 
70
 
 
71
#define XT_PRINT_STAT0(y, x)
 
72
#define XT_TRACE_STAT1(y, x, a)         xt_trace_query(y, a)
 
73
#else
 
74
 
 
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)
 
78
#else
 
79
#define XT_PRINT_STAT0(y, x)
 
80
#define XT_TRACE_STAT1(y, x, a)
 
81
#endif
 
82
 
 
83
#endif
 
84
 
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
65
87
 
 
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
67
 
 
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)
70
 
#else
71
 
#define XT_RETURN(x)                    return (x)
72
 
#define XT_RETURN_VOID                  return
73
 
#endif
74
 
 
 
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)
 
92
#else
 
93
#define XT_RETURN(x)                            return (x)
 
94
#define XT_RETURN_VOID                          return
 
95
#endif
 
96
 
 
97
#else
 
98
 
 
99
#define XT_TRACE_CALL()
 
100
#define XT_RETURN(x)                            return (x)
 
101
#define XT_RETURN_VOID                          return
 
102
 
 
103
#endif
 
104
 
 
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)
79
 
 
80
110
#else
81
 
#define XT_ENTER()
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)
88
115
#endif
89
116
 
 
117
 
90
118
#define TS(x)                                   (x)->s
91
119
 
92
120
handlerton                      *pbxt_hton;
98
126
 
99
127
char                            *pbxt_index_cache_size;
100
128
char                            *pbxt_record_cache_size;
 
129
char                            *pbxt_log_cache_size;
 
130
char                            *pbxt_log_file_threshold;
 
131
char                            *pbxt_transaction_buffer_size;
 
132
char                            *pbxt_log_buffer_size;
 
133
char                            *pbxt_checkpoint_frequency;
 
134
char                            *pbxt_data_log_threshold;
 
135
 
101
136
xtBool                          pbxt_ignore_case = true;
102
137
const char                      *pbxt_extensions[]= { ".xtr", ".xtd", ".xtl", ".xti", ".xt", NULL };
103
138
 
150
185
        return xt_ht_casehash(share->sh_table_path);
151
186
}
152
187
 
153
 
static void ha_open_share(XTThreadPtr self, XTShareRec *share, char *table_name)
 
188
static void ha_open_share(XTThreadPtr self, XTShareRec *share, char *table_name, xtBool *tabled_opened)
154
189
{
155
190
        xt_lock_mutex(self, (xt_mutex_type *) share->sh_ex_mutex);
156
191
        pushr_(xt_unlock_mutex, share->sh_ex_mutex);
157
192
 
158
193
        if (!share->sh_table) {
159
 
                share->sh_table = xt_use_table(self, table_name, FALSE);
 
194
                share->sh_table = xt_use_table(self, table_name, FALSE, FALSE);
160
195
                share->sh_dic_key_count = share->sh_table->tab_dic.dic_key_count;
161
196
                share->sh_dic_keys = share->sh_table->tab_dic.dic_keys;
 
197
                if (tabled_opened)
 
198
                        *tabled_opened = TRUE;
162
199
        }
163
200
 
164
201
        freer_(); // xt_ht_unlock(pbxt_share_tables)
215
252
 * This structure contains information that is common to all handles.
216
253
 * (i.e. it is table specific).
217
254
 */
218
 
static XTSharePtr ha_get_share(XTThreadPtr self, const char *table_path, char *table_name, bool open_table)
 
255
static XTSharePtr ha_get_share(XTThreadPtr self, const char *table_path, char *table_name, bool open_table, xtBool *tabled_opened)
219
256
{
220
257
        XTShareRec      *share;
221
258
 
237
274
                share->sh_table_path = xt_dup_string(self, (char *) table_path);
238
275
 
239
276
                if (open_table)
240
 
                        ha_open_share(self, share, table_name);
 
277
                        ha_open_share(self, share, table_name, tabled_opened);
241
278
 
242
279
                popr_(); // Discard ha_cleanup_share(share);
243
280
 
264
301
        freer_(); // xt_ht_unlock(pbxt_share_tables)
265
302
}
266
303
 
 
304
static xtBool ha_unget_share_removed(XTThreadPtr self, XTSharePtr share)
 
305
{
 
306
        xtBool removed = FALSE;
 
307
 
 
308
        xt_ht_lock(self, pbxt_share_tables);
 
309
        pushr_(xt_ht_unlock, pbxt_share_tables);
 
310
 
 
311
        if (!--share->sh_use_count) {
 
312
                removed = TRUE;
 
313
                xt_ht_del(self, pbxt_share_tables, share->sh_table_path);
 
314
        }
 
315
 
 
316
        freer_(); // xt_ht_unlock(pbxt_share_tables)
 
317
        return removed;
 
318
}
 
319
 
267
320
/*
268
321
 * -----------------------------------------------------------------------
269
322
 * PUBLIC FUNCTIONS
278
331
        xt_strcpy(PATH_MAX, table_path, db_path);
279
332
        xt_add_dir_char(PATH_MAX, table_path);
280
333
        xt_strcat(PATH_MAX, table_path, table_name);
281
 
        share = ha_get_share(self, table_path, NULL, false);
 
334
        share = ha_get_share(self, table_path, NULL, false, NULL);
282
335
        ha_aquire_exclusive_use(self, share, NULL);
283
336
        ha_close_open_tables(self, share, NULL);
284
337
        return share;
417
470
        return self;
418
471
}
419
472
 
 
473
/* The first bit is 1. */
 
474
static u_int ha_get_max_bit(MY_BITMAP *map)
 
475
{
 
476
        my_bitmap_map   *data_ptr = map->bitmap;
 
477
        my_bitmap_map   *end_ptr = map->last_word_ptr;
 
478
        my_bitmap_map   b;
 
479
        u_int                   cnt = map->n_bits;
 
480
 
 
481
        for (; end_ptr >= data_ptr; end_ptr--) {
 
482
                if ((b = *end_ptr)) {
 
483
                        my_bitmap_map mask;
 
484
                        
 
485
                        if (end_ptr == map->last_word_ptr && map->last_word_mask)
 
486
                                mask = map->last_word_mask >> 1;
 
487
                        else
 
488
                                mask = 0x80000000;
 
489
                        while (!(b & mask)) {
 
490
                                b = b << 1;
 
491
                                cnt--;
 
492
                        }
 
493
                        return cnt;
 
494
                }
 
495
                if (end_ptr == map->last_word_ptr)
 
496
                        cnt = ((cnt-1) / 32) * 32;
 
497
                else
 
498
                        cnt -= 32;
 
499
        }
 
500
        return 0;
 
501
}
 
502
 
420
503
/*
421
504
 * -----------------------------------------------------------------------
422
505
 * SUPPORT FUNCTIONS
605
688
                                                ha_rollback(thd);
606
689
#endif
607
690
                                }
608
 
#ifdef PBXT_PRINT_STAT
609
 
                                XT_PRINT0(self, "ROLLBACK (error occurred)\n");
610
 
#endif
 
691
                                XT_PRINT_STAT0(self, "ROLLBACK (error occurred)\n");
611
692
                        }
612
693
                        break;
613
694
        }
614
695
        return ha_pbxt_to_mysql_error(xt_err);
615
696
}
616
697
 
617
 
static XTDatabaseHPtr ha_get_database_of_table(XTThreadPtr self, const char *table_path, char *table_name)
 
698
static void ha_get_db_name_and_table(const char *table_path, char *db_name, char *table_name)
618
699
{
619
 
        XTDatabaseHPtr  db;
620
 
        char                    db_path[PATH_MAX];
 
700
        char    db_path[PATH_MAX];
621
701
 
622
702
        xt_strcpy(PATH_MAX, db_path, (char *) table_path);
 
703
 
 
704
        xt_strcpy(XT_TAB_NAME_WITH_EXT_SIZE, table_name, xt_last_name_of_path(db_path));
 
705
        xt_remove_extension(table_name);
623
706
        xt_remove_last_name_of_path(db_path);
624
 
 
625
 
        if (table_name) {
626
 
                xt_strcpy(XT_TAB_NAME_WITH_EXT_SIZE, table_name, xt_last_name_of_path((char *) table_path));
627
 
                xt_remove_extension(table_name);
628
 
        }
629
 
 
630
 
        xt_lock_mutex(self, &pbxt_database_mutex);
631
 
        pushr_(xt_unlock_mutex, &pbxt_database_mutex);
632
 
        db = xt_get_database(self, db_path);
633
 
        freer_(); // xt_unlock_mutex(&pbxt_database_mutex);
634
 
 
635
 
        return db;
 
707
        xt_remove_dir_char(db_path);
 
708
        xt_strcpy(NAME_MAX, db_name, xt_last_name_of_path(db_path));
636
709
}
637
710
 
638
711
static void ha_conditional_close_database(XTThreadPtr self, XTThreadPtr other_thr, void *db)
664
737
        return ha_pbxt_thread_error_for_mysql(thd, self, ignore_dup_key);
665
738
}
666
739
 
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)
669
 
{
670
 
        if (key_only) {
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)
674
 
                                break;
675
 
 
676
 
                        switch (xt_tab_visible(ot)) {
677
 
                                case XT_DEL:
678
 
                                        /* The index is referencing a deleted record.
679
 
                                         * Remove the entry from the index!
680
 
                                         */
681
 
                                        *modified = TRUE;
682
 
                                        xt_idx_delete_current(ot, ind);
683
 
                                        /* Then move on to the next item! */
684
 
                                case FALSE:
685
 
                                        if (xt_idx_next(ot, ind, search_key))
686
 
                                                break;
687
 
                                case XT_ERR:
688
 
                                        return ha_log_pbxt_thread_error_for_mysql(FALSE);
689
 
                                default:
690
 
                                        if (!xt_idx_read(ot, ind, (xtWord1 *) buf))
691
 
                                                return ha_log_pbxt_thread_error_for_mysql(FALSE);
692
 
                                        return 0;
693
 
                        }
694
 
                }
695
 
        }
696
 
        else {
697
 
                while (ot->ot_curr_rec) {
698
 
                        if (search_key && !search_key->sk_on_key)
699
 
                                break;
700
 
 
701
 
                        switch (xt_tab_read_record(ot, (xtWord1 *) buf)) {
702
 
                                case XT_DEL:
703
 
                                        /* The index is referencing a deleted record.
704
 
                                         * Remove the entry from the index!
705
 
                                         */
706
 
                                        *modified = TRUE;
707
 
                                        xt_idx_delete_current(ot, ind);
708
 
                                        /* Then move on to the next item! */
709
 
                                case FALSE:
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))
712
 
                                                break;
713
 
                                case XT_ERR:
714
 
                                        return ha_log_pbxt_thread_error_for_mysql(FALSE);
715
 
                                default:
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));
717
 
                                        return 0;
718
 
                        }
719
 
                }
720
 
        }
721
 
        return HA_ERR_END_OF_FILE;
722
 
}
723
 
 
724
 
static int ha_idx_prev_read(XTOpenTablePtr ot, XTIndexPtr ind, xtBool key_only,
725
 
        register XTIdxSearchKeyPtr search_key, byte *buf, xtBool *modified)
726
 
{
727
 
        if (key_only) {
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)
731
 
                                break;
732
 
 
733
 
                        switch (xt_tab_visible(ot)) {
734
 
                                case XT_DEL:
735
 
                                        /* The index is referencing a deleted record.
736
 
                                         * Remove the entry from the index!
737
 
                                         */
738
 
                                        *modified = TRUE;
739
 
                                        xt_idx_delete_current(ot, ind);
740
 
                                        /* Then move on to the next item! */
741
 
                                case FALSE:
742
 
                                        if (xt_idx_prev(ot, ind, search_key))
743
 
                                                break;
744
 
                                case XT_ERR:
745
 
                                        return ha_log_pbxt_thread_error_for_mysql(FALSE);
746
 
                                default:
747
 
                                        if (!xt_idx_read(ot, ind, (xtWord1 *) buf))
748
 
                                                return ha_log_pbxt_thread_error_for_mysql(FALSE);
749
 
                                        return 0;
750
 
                        }
751
 
                }
752
 
        }
753
 
        else {
754
 
                /* We need to read the entire record: */
755
 
                while (ot->ot_curr_rec) {
756
 
                        if (search_key && !search_key->sk_on_key)
757
 
                                break;
758
 
 
759
 
                        switch (xt_tab_read_record(ot, (xtWord1 *) buf)) {
760
 
                                case XT_DEL:
761
 
                                        /* The index is referencing a deleted record.
762
 
                                         * Remove the entry from the index!
763
 
                                         */
764
 
                                        *modified = TRUE;
765
 
                                        xt_idx_delete_current(ot, ind);
766
 
                                        /* Then move on to the next item! */
767
 
                                case FALSE:
768
 
                                        if (xt_idx_prev(ot, ind, search_key))
769
 
                                                break;
770
 
                                case XT_ERR:
771
 
                                        return ha_log_pbxt_thread_error_for_mysql(FALSE);
772
 
                                default:
773
 
                                        return 0;
774
 
                        }
775
 
                }
776
 
        }
777
 
        return HA_ERR_END_OF_FILE;
778
 
}
779
 
 
780
740
/*
781
741
 * -----------------------------------------------------------------------
782
742
 * STATIC HOOKS
783
743
 *
784
744
 */
785
745
 
 
746
typedef struct HAVarParams {
 
747
        char            *vp_var;
 
748
        char            *vp_def;
 
749
        char            *vp_min;
 
750
        char            *vp_max4;
 
751
        char            *vp_max8;
 
752
} HAVarParamsRec, *HAVarParamsPtr;
 
753
 
 
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" };
 
763
#else
 
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" };
 
772
#endif
 
773
 
 
774
static xtWord8 ha_set_variable(char **value, HAVarParamsPtr vp)
 
775
{
 
776
        xtWord8 result;
 
777
        xtWord4 mi, ma;
 
778
        char    *mm;
 
779
 
 
780
        if (!*value)
 
781
                *value = getenv(vp->vp_var);
 
782
        if (!*value)
 
783
                *value = vp->vp_def;
 
784
        result = xt_byte_size_to_int8(*value);
 
785
        mi = xt_byte_size_to_int8(vp->vp_min);
 
786
        if (result < mi) {
 
787
                result = mi;
 
788
                *value = vp->vp_min;
 
789
        }
 
790
        if (sizeof(size_t) == 8)
 
791
                mm = vp->vp_max8;
 
792
        else
 
793
                mm = vp->vp_max4;
 
794
        ma = xt_byte_size_to_int8(mm);
 
795
        if (result > ma) {
 
796
                result = ma;
 
797
                *value = mm;
 
798
        }
 
799
        return result;
 
800
}
 
801
 
786
802
static void pbxt_call_init(XTThreadPtr self)
787
803
{
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;
790
812
 
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");
793
 
 
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";
802
 
        }
803
 
 
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";
812
 
        }
 
814
        xt_logf(XT_NT_INFO, "Paul McCullagh, PrimeBase Technologies GmbH, http://www.primebase.com/xt\n");
 
815
 
 
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);
813
824
 
814
825
        pbxt_ignore_case = lower_case_table_names != 0;
815
826
        if (pbxt_ignore_case)
818
829
                pbxt_share_tables = xt_new_hashtable(self, ha_hash_comp, ha_hash, ha_hash_free, TRUE, FALSE);
819
830
        xt_fs_init(self);
820
831
        xt_init_databases(self);
821
 
        xt_dc_init(self, (size_t) index_cache_size);
822
 
        xt_rc_init(self, (size_t) record_cache_size);
823
 
 
824
 
        //xt_int8_to_byte_size(pbxt_index_cache_size, value);
825
 
        xt_logf(XT_NT_INFO, "pbxt_index_cache_size = %s\n", pbxt_index_cache_size);
826
 
        //xt_int8_to_byte_size(pbxt_record_cache_size, value);
827
 
        xt_logf(XT_NT_INFO, "pbxt_record_cache_size = %s\n", pbxt_record_cache_size);
 
832
 
 
833
        xt_db_log_file_threshold = (size_t) log_file_threshold;
 
834
        xt_db_log_buffer_size = (size_t) transaction_buffer_size;
 
835
        xt_db_transaction_buffer_size =(size_t) log_buffer_size;
 
836
        xt_db_checkpoint_frequency = (size_t) checkpoint_frequency;
 
837
        xt_db_data_log_threshold = (size_t) data_log_threshold;
 
838
 
 
839
        xt_ind_init(self, (size_t) index_cache_size);
 
840
        xt_tc_init(self, (size_t) record_cache_size);
 
841
        xt_xlog_init(self, (size_t) log_cache_size);
828
842
}
829
843
 
830
844
static void pbxt_call_exit(XTThreadPtr self)
831
845
{
832
846
        xt_logf(XT_NT_INFO, "PrimeBase XT Engine shutdown...\n");
833
847
 
 
848
#ifdef PBXT_TRACE_STAT
 
849
        xt_dump_trace();
 
850
#endif
 
851
#ifdef DEBUG
 
852
        //xt_stop_database_threads(self, FALSE);
 
853
        xt_stop_database_threads(self, TRUE);
 
854
#else
 
855
        xt_stop_database_threads(self, TRUE);
 
856
#endif
 
857
        xt_stop_freeer(self);
834
858
        xt_exit_databases(self);
835
 
        xt_rc_exit(self);
836
 
        xt_dc_exit(self);
 
859
        xt_xlog_exit(self);
 
860
        xt_tc_exit(self);
 
861
        xt_ind_exit(self);
837
862
        xt_fs_exit(self);
838
863
        if (pbxt_share_tables) {
839
864
                xt_free_hashtable(self, pbxt_share_tables);
861
886
}
862
887
 
863
888
/*
 
889
 * Outout the PBXT status. Return FALSE on error.
 
890
 */
 
891
static bool pbxt_show_status(handlerton *hton, THD* thd, 
 
892
                          stat_print_fn* stat_print,
 
893
                          enum ha_stat_type stat_type)
 
894
{
 
895
        XTThreadPtr                     self;   
 
896
        int                                     err = 0;
 
897
        XTStringBufferRec       strbuf = { 0 };
 
898
        bool                            not_ok = FALSE;
 
899
 
 
900
/*DBG*
 
901
xt_trace("// %lu - dump\n", (u_long) time(NULL));
 
902
xt_dump_trace();
 
903
*DBG*/
 
904
        if (!(self = ha_set_current_thread(thd, &err)))
 
905
                return FALSE;
 
906
 
 
907
        try_(a) {
 
908
                myxt_get_status(self, &strbuf);
 
909
        }
 
910
        catch_(a) {
 
911
                not_ok = TRUE;
 
912
        }
 
913
        cont_(a);
 
914
 
 
915
        if (!not_ok) {
 
916
                if (stat_print(thd, "PBXT", 4, "", 0, strbuf.sb_cstring, strbuf.sb_len))
 
917
                        not_ok = TRUE;
 
918
        }
 
919
        xt_sb_set_size(self, &strbuf, 0);
 
920
 
 
921
        return not_ok;
 
922
}
 
923
 
 
924
/*
864
925
 * Initialize the PBXT sub-system.
865
926
 *
866
927
 * return 1 on error, else 0.
869
930
{
870
931
        int init_err = 0;
871
932
 
872
 
        XT_ENTER();
 
933
        XT_TRACE_CALL();
873
934
 
874
935
        if (sizeof(xtWordPS) != sizeof(void *)) {
875
936
                printf("PBXT: This won't work, I require that sizeof(xtWordPS) != sizeof(void *)!\n");
899
960
                pbxt_hton->create = pbxt_create_handler; /* Create a new handler */
900
961
                pbxt_hton->drop_database = pbxt_drop_database; /* Drop a database */
901
962
                pbxt_hton->panic = pbxt_panic; /* Panic call */
 
963
        pbxt_hton->show_status = pbxt_show_status;
902
964
                pbxt_hton->flags = HTON_NO_FLAGS; /* HTON_CAN_RECREATE - Without this flags TRUNCATE uses delete_all_rows() */
903
965
 
904
966
                if (!xt_init_logging())                                 /* Initialize logging */
950
1012
        XTThreadPtr             self;
951
1013
        int                             err = 0;
952
1014
 
953
 
        XT_ENTER();
 
1015
        XT_TRACE_CALL();
954
1016
 
955
1017
        if (pbxt_inited) {
956
1018
                XTExceptionRec  e;
1158
1220
 * threads to complete use of all handlers of the table.
1159
1221
 * At the same time we hold up all threads
1160
1222
 * that want to use handlers belonging to the table.
 
1223
 *
 
1224
 * But we do not hold up threads that close the handlers.
1161
1225
 */
1162
1226
static void ha_aquire_exclusive_use(XTThreadPtr self, XTSharePtr share, ha_pbxt *mine)
1163
1227
{
1214
1278
/*
1215
1279
 * If you have exclusively locked the table, you can close all handler
1216
1280
 * open tables.
 
1281
 *
 
1282
 * Call ha_close_open_tables() to get an exclusive lock.
1217
1283
 */
1218
1284
static void ha_close_open_tables(XTThreadPtr self, XTSharePtr share, ha_pbxt *mine)
1219
1285
{
1228
1294
        handler = share->sh_handlers;
1229
1295
        while (handler) {
1230
1296
                if (handler != mine && handler->pb_open_tab) {
1231
 
                        xt_close_table(handler->pb_open_tab);
 
1297
                        xt_db_return_table_to_pool_ns(handler->pb_open_tab);
1232
1298
                        handler->pb_open_tab = NULL;
1233
1299
                }
1234
1300
                handler = handler->pb_ex_next;
1240
1306
static void ha_release_exclusive_use(XTThreadPtr self, XTSharePtr share)
1241
1307
{
1242
1308
        XT_PRINT1(self, "ha_release_exclusive_use %s PBXT X UNLOCK\n", share->sh_table_path);
1243
 
        xt_mutex_lock((xt_mutex_type *) share->sh_ex_mutex);
 
1309
        xt_lock_mutex_ns((xt_mutex_type *) share->sh_ex_mutex);
1244
1310
        share->sh_table_lock = FALSE;
1245
1311
        xt_broadcast_cond(NULL, (xt_cond_type *) share->sh_ex_cond);
1246
 
        xt_mutex_unlock((xt_mutex_type *) share->sh_ex_mutex);
 
1312
        xt_unlock_mutex_ns((xt_mutex_type *) share->sh_ex_mutex);
1247
1313
}
1248
1314
 
1249
1315
static xtBool ha_wait_for_shared_use(ha_pbxt *mine, XTSharePtr share)
1252
1318
 
1253
1319
        XT_PRINT1(xt_get_self(), "ha_wait_for_shared_use %s share lock wait...\n", share->sh_table_path);
1254
1320
        mine->pb_ex_in_use = 0;
1255
 
        xt_mutex_lock((xt_mutex_type *) share->sh_ex_mutex);
 
1321
        xt_lock_mutex_ns((xt_mutex_type *) share->sh_ex_mutex);
1256
1322
        while (share->sh_table_lock) {
1257
1323
                /* Wake up the exclusive locker (may be waiting). He can try to continue: */
1258
1324
                xt_broadcast_cond(NULL, (xt_cond_type *) share->sh_ex_cond);
1259
1325
 
1260
1326
                if (!xt_timed_wait_cond(NULL, (xt_cond_type *) share->sh_ex_cond, (xt_mutex_type *) share->sh_ex_mutex, XT_SHARE_LOCK_WAIT)) {
1261
 
                        xt_mutex_unlock((xt_mutex_type *) share->sh_ex_mutex);
 
1327
                        xt_unlock_mutex_ns((xt_mutex_type *) share->sh_ex_mutex);
1262
1328
                        return FAILED;
1263
1329
                }
1264
1330
 
1265
1331
                if (time(NULL) > end_time) {
1266
 
                        xt_mutex_unlock((xt_mutex_type *) share->sh_ex_mutex);
 
1332
                        xt_unlock_mutex_ns((xt_mutex_type *) share->sh_ex_mutex);
1267
1333
                        xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_LOCK_TIMEOUT, share->sh_table_path);
1268
1334
                        return FAILED;
1269
1335
                }
1270
1336
        }
1271
1337
        mine->pb_ex_in_use = 1;
1272
 
        xt_mutex_unlock((xt_mutex_type *) share->sh_ex_mutex);
 
1338
        xt_unlock_mutex_ns((xt_mutex_type *) share->sh_ex_mutex);
1273
1339
        return OK;
1274
1340
}
1275
1341
 
1279
1345
        int                             err = 0;
1280
1346
        XTThreadPtr             self;   
1281
1347
        char                    table_name[XT_TAB_NAME_WITH_EXT_SIZE];
 
1348
        xtBool                  tabled_opened = FALSE;
1282
1349
 
1283
1350
        if (!(self = ha_set_current_thread(thd, &err)))
1284
1351
                return ha_pbxt_to_mysql_error(err);
1286
1353
        try_(a) {
1287
1354
                xt_ha_open_database_of_table(self, pb_share->sh_table_path, table_name);
1288
1355
 
1289
 
                ha_open_share(self, pb_share, table_name);
 
1356
                ha_open_share(self, pb_share, table_name, &tabled_opened);
1290
1357
 
1291
 
                if (!(pb_open_tab = xt_open_table(pb_share->sh_table)))
1292
 
                        throw_();
 
1358
                if (!(pb_open_tab = xt_db_open_table_using_tab(pb_share->sh_table, self)))
 
1359
                        xt_throw(self);
1293
1360
                pb_open_tab->ot_thread = self;
1294
1361
 
 
1362
                if (tabled_opened) {
 
1363
                        xt_tab_load_row_pointers(self, pb_open_tab);
 
1364
                        xt_ind_set_index_selectivity(self, pb_open_tab);
 
1365
                }
 
1366
 
1295
1367
                /* I am not doing this anymore because it was only required
1296
1368
                 * for DELETE FROM table;, which is now implemented
1297
1369
                 * by deleting each row.
1310
1382
 
1311
1383
/*
1312
1384
 * -----------------------------------------------------------------------
 
1385
 * INFORMATION SCHEMA FUNCTIONS
 
1386
 *
 
1387
 */
 
1388
 
 
1389
int pbxt_statistics_fill_table(THD *thd, TABLE_LIST *tables, COND *cond)
 
1390
{
 
1391
        XTThreadPtr             self;   
 
1392
        int                             err = 0;
 
1393
 
 
1394
        if (!(self = ha_set_current_thread(thd, &err)))
 
1395
                return ha_pbxt_to_mysql_error(err);
 
1396
        try_(a) {
 
1397
                err = myxt_statistics_fill_table(self, thd, tables, cond, system_charset_info);
 
1398
        }
 
1399
        catch_(a) {
 
1400
                err = ha_pbxt_thread_error_for_mysql(thd, self, FALSE);
 
1401
        }
 
1402
        cont_(a);
 
1403
        return err;
 
1404
}
 
1405
 
 
1406
ST_FIELD_INFO pbxt_statistics_fields_info[]=
 
1407
{
 
1408
        {"Database",                    120, MYSQL_TYPE_STRING,         0, 0, "The database name", SKIP_OPEN_TABLE},
 
1409
        {"Record_cache_usage",  8, MYSQL_TYPE_LONGLONG,         0, 0, "Bytes used by the table record cache", SKIP_OPEN_TABLE},
 
1410
        {"Index_cache_usage",   8, MYSQL_TYPE_LONGLONG,         0, 0, "Bytes used by the index cache", SKIP_OPEN_TABLE},
 
1411
        {"Log_cache_usage",             8, MYSQL_TYPE_LONGLONG,         0, 0, "Bytes used by the log cache", SKIP_OPEN_TABLE}
 
1412
};
 
1413
 
 
1414
int pbxt_init_statitics(void *p)
 
1415
{
 
1416
        DBUG_ENTER("pbxt_init_statitics");
 
1417
        ST_SCHEMA_TABLE *schema = (ST_SCHEMA_TABLE *) p;
 
1418
        schema->fields_info = pbxt_statistics_fields_info;
 
1419
        schema->fill_table = pbxt_statistics_fill_table;
 
1420
 
 
1421
        DBUG_RETURN(0);
 
1422
}
 
1423
 
 
1424
int pbxt_exit_statitics(void *p)
 
1425
{
 
1426
        DBUG_ENTER("pbxt_exit_statitics");
 
1427
        DBUG_RETURN(0);
 
1428
}
 
1429
 
 
1430
/*
 
1431
 * -----------------------------------------------------------------------
1313
1432
 * DYNAMIC HOOKS
1314
1433
 *
1315
1434
 */
1319
1438
        pb_share = NULL;
1320
1439
        pb_open_tab = NULL;
1321
1440
        pb_key_read = FALSE;
1322
 
        pb_modified = FALSE;
1323
1441
        pb_ignore_dup_key = 0;
1324
1442
        pb_lock_table = FALSE;
1325
1443
        pb_table_locked = FALSE;
1383
1501
                HA_FILE_BASED |
1384
1502
                /*
1385
1503
                 * Not sure what this does (but MyISAM and InnoDB have it)?!
 
1504
                 * Could it mean that we support the handler functions.
1386
1505
                 */
1387
1506
                HA_CAN_SQL_HANDLER |
1388
1507
                /*
1397
1516
                /* We can do row logging, but not statement, because
1398
1517
                 * MVCC is not serializable!
1399
1518
                 */
1400
 
                HA_BINLOG_ROW_CAPABLE | /* HA_BINLOG_STMT_CAPABLE | */
 
1519
                HA_BINLOG_ROW_CAPABLE |
 
1520
#ifdef DEBUG
 
1521
                HA_BINLOG_STMT_CAPABLE |
 
1522
#endif
1401
1523
#endif
1402
1524
                /*
1403
1525
                 * Auto-increment is allowed on a partial key.
1405
1527
                HA_AUTO_PART_KEY);
1406
1528
}
1407
1529
 
 
1530
/*
 
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
 
1534
 * sort.
 
1535
 *
 
1536
 * SELECT o_id, o_carrier_id, o_entry_d, o_ol_cnt
 
1537
 * FROM orders FORCE INDEX (o_w_id)
 
1538
 * WHERE o_w_id = 2
 
1539
   * AND o_d_id = 1
 
1540
   * AND o_c_id = 500
 
1541
 * ORDER BY o_id DESC limit 1;
 
1542
 *
 
1543
 */
 
1544
#define FLAGS_ARE_READ_DYNAMICALLY
 
1545
 
 
1546
ulong ha_pbxt::index_flags(uint inx, uint part, bool all_parts) const
 
1547
{
 
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.
 
1551
         *
 
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.
 
1555
         *
 
1556
         * A number of cases are demostrated here: [(11)]
 
1557
         *
 
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
 
1562
         *   scanned.
 
1563
         *
 
1564
         * In this "obscure" case, the index scan may return index
 
1565
         * entries in the wrong order.
 
1566
         */
 
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
 
1572
         * the scan!
 
1573
         */
 
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
 
1578
         * key.
 
1579
         */
 
1580
        return (HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER | HA_READ_RANGE | HA_KEYREAD_ONLY);
 
1581
#else
 
1582
        return (HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE | HA_KEYREAD_ONLY);
 
1583
#endif
 
1584
}
 
1585
 
1408
1586
void ha_pbxt::internal_close(void *t)
1409
1587
{
1410
1588
        XTThreadPtr self = (XTThreadPtr) t;
1411
1589
 
1412
1590
        if (pb_share) {
1413
 
                if (pb_open_tab) {
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.
 
1591
                xtBool                  removed;
 
1592
                XTOpenTablePtr  ot;
 
1593
 
 
1594
                try_(a) {
 
1595
                        /* This lock must be held when we remove the handler's
 
1596
                         * open table because ha_close_open_tables() can run
 
1597
                         * concurrently.
1417
1598
                         */
1418
 
                        if (pb_open_tab) {
 
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);
 
1604
                                pb_open_tab = NULL;
 
1605
                                pushr_(xt_db_return_table_to_pool, ot);
1423
1606
                        }
1424
 
                        pb_open_tab = NULL;
1425
 
                        xt_mutex_unlock(pb_share->sh_ex_mutex);
1426
 
                }
 
1607
                        xt_unlock_mutex_ns(pb_share->sh_ex_mutex);
1427
1608
 
1428
 
                try_(a) {
1429
1609
                        ha_remove_from_handler_list(self, pb_share, this);
1430
1610
 
1431
1611
                        /* Someone may be waiting for me to complete: */
1432
1612
                        xt_broadcast_cond(NULL, (xt_cond_type *) pb_share->sh_ex_cond);
1433
1613
 
1434
 
                        ha_unget_share(self, pb_share);
 
1614
                        removed = ha_unget_share_removed(self, pb_share);
 
1615
 
 
1616
                        if (ot) {
 
1617
                                /* Flush the table if this was the last handler: */
 
1618
                                if (removed)
 
1619
                                        xt_flush_table(self, ot);
 
1620
                                freer_(); // xt_db_return_table_to_pool(ot);
 
1621
                        }
1435
1622
                }
1436
1623
                catch_(a) {
1437
1624
                        xt_log_and_clear_exception(self);
1458
1645
        int                     err = 0;
1459
1646
        XTThreadPtr     self;
1460
1647
        char            table_name[XT_TAB_NAME_WITH_EXT_SIZE];
 
1648
        xtBool          tabled_opened = FALSE;
1461
1649
 
1462
 
        ref_length = XT_RECORD_REF_SIZE;
 
1650
        ref_length = XT_RECORD_OFFS_SIZE;
1463
1651
 
1464
1652
        if (!(self = ha_set_current_thread(thd, &err)))
1465
1653
                return ha_pbxt_to_mysql_error(err);
1470
1658
        try_(a) {
1471
1659
                xt_ha_open_database_of_table(self, table_path, table_name);
1472
1660
 
1473
 
                pb_share = ha_get_share(self, table_path, table_name, true);
 
1661
                pb_share = ha_get_share(self, table_path, table_name, true, &tabled_opened);
1474
1662
                ha_add_to_handler_list(self, pb_share, this);
1475
1663
                if (pb_share->sh_table_lock) {
1476
1664
                        if (!ha_wait_for_shared_use(this, pb_share))
1477
1665
                                xt_throw(self);
1478
1666
                }
1479
1667
 
1480
 
                ha_open_share(self, pb_share, table_name);
 
1668
                ha_open_share(self, pb_share, table_name, &tabled_opened);
1481
1669
 
1482
1670
                thr_lock_data_init(&pb_share->sh_lock, &pb_lock, NULL);
1483
 
                if (!(pb_open_tab = xt_open_table(pb_share->sh_table)))
1484
 
                        throw_();
 
1671
                if (!(pb_open_tab = xt_db_open_table_using_tab(pb_share->sh_table, self)))
 
1672
                        xt_throw(self);
1485
1673
                pb_open_tab->ot_thread = self;
1486
1674
 
 
1675
                if (tabled_opened) {
 
1676
                        xt_tab_load_row_pointers(self, pb_open_tab);
 
1677
                        xt_ind_set_index_selectivity(self, pb_open_tab);
 
1678
                }
 
1679
 
1487
1680
                init_auto_increment(0);
1488
1681
        }
1489
1682
        catch_(a) {
1501
1694
                if (pb_share->sh_table_lock)
1502
1695
                        xt_broadcast_cond(NULL, (xt_cond_type *) pb_share->sh_ex_cond);
1503
1696
        }
 
1697
/*DBG*
 
1698
xt_trace("// time=%lu, opened table %s\n", (u_long) time(NULL));
 
1699
*DBG*/
1504
1700
        return err;
1505
1701
}
1506
1702
 
1723
1919
        ASSERT_NS(pb_ex_in_use);
1724
1920
 
1725
1921
        XT_PRINT1(pb_open_tab->ot_thread, "ha_pbxt::write_row %s\n", pb_share->sh_table_path);
1726
 
        XT_DISABLED_TRACE(("INSERT tx=%d val=%d\n", (int) pb_open_tab->ot_thread->st_xact_data->xd_start_id, (int) XT_GET_DISK_4(&buf[1])));
 
1922
        XT_DISABLED_TRACE(("INSERT tx=%d val=%d\n", (int) pb_open_tab->ot_thread->st_xact_data->xd_start_xn_id, (int) XT_GET_DISK_4(&buf[1])));
1727
1923
        //statistic_increment(ha_write_count,&LOCK_status);
1728
1924
 
1729
1925
        /* GOTCHA: I have a huge problem with the transaction statement.
1777
1973
        ASSERT_NS(pb_ex_in_use);
1778
1974
 
1779
1975
        XT_PRINT1(self, "ha_pbxt::update_row %s\n", pb_share->sh_table_path);
1780
 
        XT_DISABLED_TRACE(("UPDATE tx=%d val=%d\n", (int) self->st_xact_data->xd_start_id, (int) XT_GET_DISK_4(&new_data[1])));
 
1976
        XT_DISABLED_TRACE(("UPDATE tx=%d val=%d\n", (int) self->st_xact_data->xd_start_xn_id, (int) XT_GET_DISK_4(&new_data[1])));
1781
1977
        //statistic_increment(ha_update_count,&LOCK_status);
1782
1978
 
1783
1979
        if (!self->st_stat_trans) {
1815
2011
        if (!xt_tab_update_record(pb_open_tab, (xtWord1 *) old_data, (xtWord1 *) new_data))
1816
2012
                err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key);
1817
2013
 
 
2014
        pb_open_tab->ot_table->tab_locks.xt_remove_temp_lock(pb_open_tab);
 
2015
 
1818
2016
        return err;
1819
2017
}
1820
2018
 
1834
2032
        ASSERT_NS(pb_ex_in_use);
1835
2033
 
1836
2034
        XT_PRINT1(pb_open_tab->ot_thread, "ha_pbxt::delete_row %s\n", pb_share->sh_table_path);
1837
 
        XT_DISABLED_TRACE(("DELETE tx=%d val=%d\n", (int) pb_open_tab->ot_thread->st_xact_data->xd_start_id, (int) XT_GET_DISK_4(&buf[1])));
 
2035
        XT_DISABLED_TRACE(("DELETE tx=%d val=%d\n", (int) pb_open_tab->ot_thread->st_xact_data->xd_start_xn_id, (int) XT_GET_DISK_4(&buf[1])));
1838
2036
        //statistic_increment(ha_delete_count,&LOCK_status);
1839
2037
 
1840
2038
        if (!pb_open_tab->ot_thread->st_stat_trans) {
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);
1848
2046
 
 
2047
        pb_open_tab->ot_table->tab_locks.xt_remove_temp_lock(pb_open_tab);
 
2048
 
1849
2049
        return err;
1850
2050
}
1851
2051
 
 
2052
/*
 
2053
 * -----------------------------------------------------------------------
 
2054
 * INDEX METHODS
 
2055
 */
 
2056
 
 
2057
/*
 
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
 
2061
 * an index scan.
 
2062
 *
 
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.
 
2066
 *
 
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).
 
2070
 *
 
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.
 
2073
 *
 
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
 
2076
 * such values.
 
2077
 *
 
2078
 * A number of test have been given below which demonstrate the use
 
2079
 * of the function.
 
2080
 *
 
2081
 * They also demonstrate the ORDER BY problem described here: [(11)].
 
2082
 *
 
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');
 
2092
 * 
 
2093
 * select * from test_tab where value = 1 order by value, name for update;
 
2094
 * 
 
2095
 * -- Test: 1
 
2096
 * -- C1
 
2097
 * begin;
 
2098
 * select * from test_tab where id = 5 for update;
 
2099
 * 
 
2100
 * -- C2
 
2101
 * begin;
 
2102
 * select * from test_tab where value = 2 order by value, name for update;
 
2103
 * 
 
2104
 * -- C1
 
2105
 * update test_tab set value = 3 where id = 6;
 
2106
 * commit;
 
2107
 * 
 
2108
 * -- Test: 2
 
2109
 * -- C1
 
2110
 * begin;
 
2111
 * select * from test_tab where id = 5 for update;
 
2112
 * 
 
2113
 * -- C2
 
2114
 * begin;
 
2115
 * select * from test_tab where value >= 2 order by value, name for update;
 
2116
 * 
 
2117
 * -- C1
 
2118
 * update test_tab set value = 3 where id = 6;
 
2119
 * commit;
 
2120
 * 
 
2121
 * -- Test: 3
 
2122
 * -- C1
 
2123
 * begin;
 
2124
 * select * from test_tab where id = 5 for update;
 
2125
 * 
 
2126
 * -- C2
 
2127
 * begin;
 
2128
 * select * from test_tab where value = 2 order by value, name for update;
 
2129
 * 
 
2130
 * -- C1
 
2131
 * update test_tab set value = 1 where id = 6;
 
2132
 * commit;
 
2133
 */
 
2134
 
 
2135
int ha_pbxt::xt_index_in_range(register XTOpenTablePtr ot, register XTIndexPtr ind,
 
2136
        register XTIdxSearchKeyPtr search_key, xtWord1 *buf)
 
2137
{
 
2138
        /* If search key is given, this means we want an exact match. */
 
2139
        if (search_key) {
 
2140
                xtWord1 key_buf[XT_INDEX_MAX_KEY_SIZE];
 
2141
 
 
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;
 
2146
        }
 
2147
 
 
2148
        /* Otherwise, check the end of the range. */
 
2149
        if (end_range)
 
2150
                return compare_key(end_range) <= 0;
 
2151
        return 1;
 
2152
}
 
2153
 
 
2154
int ha_pbxt::xt_index_next_read(register XTOpenTablePtr ot, register XTIndexPtr ind, xtBool key_only,
 
2155
        register XTIdxSearchKeyPtr search_key, byte *buf)
 
2156
{
 
2157
        if (key_only) {
 
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)
 
2161
                                break;
 
2162
 
 
2163
                        switch (xt_tab_visible(ot)) {
 
2164
                                case XT_DEL:
 
2165
                                        /* The index is referencing a deleted record.
 
2166
                                         * Remove the entry from the index!
 
2167
                                         */
 
2168
                                        xt_idx_delete_current(ot, ind);
 
2169
                                        /* Then move on to the next item! */
 
2170
                                case FALSE:
 
2171
                                        if (xt_idx_next(ot, ind, search_key))
 
2172
                                                break;
 
2173
                                case XT_ERR:
 
2174
                                        goto failed;
 
2175
                                case XT_NEW:
 
2176
                                        if (!xt_idx_read(ot, ind, (xtWord1 *) buf))
 
2177
                                                goto failed;
 
2178
                                        if (xt_index_in_range(ot, ind, search_key, buf))
 
2179
                                                return 0;
 
2180
                                        if (!xt_idx_next(ot, ind, search_key))
 
2181
                                                goto failed;
 
2182
                                        break;
 
2183
                                case XT_RETRY:
 
2184
                                        if (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);
 
2187
                                        }
 
2188
                                        else {
 
2189
                                                if (!xt_idx_research(pb_open_tab, ind))
 
2190
                                                        goto failed;
 
2191
                                        }
 
2192
                                        break;
 
2193
                                default:
 
2194
                                        if (!xt_idx_read(ot, ind, (xtWord1 *) buf))
 
2195
                                                goto failed;
 
2196
                                        return 0;
 
2197
                        }
 
2198
                }
 
2199
        }
 
2200
        else {
 
2201
                while (ot->ot_curr_rec_id) {
 
2202
                        if (search_key && !search_key->sk_on_key)
 
2203
                                break;
 
2204
 
 
2205
                        switch (xt_tab_read_record(ot, (xtWord1 *) buf)) {
 
2206
                                case XT_DEL:
 
2207
                                        /* The index is referencing a deleted record.
 
2208
                                         * Remove the entry from the index!
 
2209
                                         */
 
2210
                                        xt_idx_delete_current(ot, ind);
 
2211
                                        /* Then move on to the next item! */
 
2212
                                case FALSE:
 
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))
 
2215
                                                break;
 
2216
                                case XT_ERR:
 
2217
                                        goto failed;
 
2218
                                case XT_NEW:
 
2219
                                        if (xt_index_in_range(ot, ind, search_key, buf))
 
2220
                                                return 0;
 
2221
                                        if (!xt_idx_next(ot, ind, search_key))
 
2222
                                                goto failed;
 
2223
                                        break;
 
2224
                                case XT_RETRY:
 
2225
                                        if (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);
 
2228
                                        }
 
2229
                                        else {
 
2230
                                                if (!xt_idx_research(pb_open_tab, ind))
 
2231
                                                        goto failed;
 
2232
                                        }
 
2233
                                        break;
 
2234
                                default:
 
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));
 
2236
                                        return 0;
 
2237
                        }
 
2238
                }
 
2239
        }
 
2240
        return HA_ERR_END_OF_FILE;
 
2241
 
 
2242
        failed:
 
2243
        return ha_log_pbxt_thread_error_for_mysql(FALSE);
 
2244
}
 
2245
 
 
2246
int ha_pbxt::xt_index_prev_read(XTOpenTablePtr ot, XTIndexPtr ind, xtBool key_only,
 
2247
        register XTIdxSearchKeyPtr search_key, byte *buf)
 
2248
{
 
2249
        if (key_only) {
 
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)
 
2253
                                break;
 
2254
 
 
2255
                        switch (xt_tab_visible(ot)) {
 
2256
                                case XT_DEL:
 
2257
                                        /* The index is referencing a deleted record.
 
2258
                                         * Remove the entry from the index!
 
2259
                                         */
 
2260
                                        xt_idx_delete_current(ot, ind);
 
2261
                                        /* Then move on to the next item! */
 
2262
                                case FALSE:
 
2263
                                        if (xt_idx_prev(ot, ind, search_key))
 
2264
                                                break;
 
2265
                                case XT_ERR:
 
2266
                                        goto failed;
 
2267
                                case XT_NEW:
 
2268
                                        if (!xt_idx_read(ot, ind, (xtWord1 *) buf))
 
2269
                                                goto failed;
 
2270
                                        if (xt_index_in_range(ot, ind, search_key, buf))
 
2271
                                                return 0;
 
2272
                                        if (!xt_idx_next(ot, ind, search_key))
 
2273
                                                goto failed;
 
2274
                                        break;
 
2275
                                case XT_RETRY:
 
2276
                                        if (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);
 
2279
                                        }
 
2280
                                        else {
 
2281
                                                if (!xt_idx_research(pb_open_tab, ind))
 
2282
                                                        goto failed;
 
2283
                                        }
 
2284
                                        break;
 
2285
                                default:
 
2286
                                        if (!xt_idx_read(ot, ind, (xtWord1 *) buf))
 
2287
                                                goto failed;
 
2288
                                        return 0;
 
2289
                        }
 
2290
                }
 
2291
        }
 
2292
        else {
 
2293
                /* We need to read the entire record: */
 
2294
                while (ot->ot_curr_rec_id) {
 
2295
                        if (search_key && !search_key->sk_on_key)
 
2296
                                break;
 
2297
 
 
2298
                        switch (xt_tab_read_record(ot, (xtWord1 *) buf)) {
 
2299
                                case XT_DEL:
 
2300
                                        /* The index is referencing a deleted record.
 
2301
                                         * Remove the entry from the index!
 
2302
                                         */
 
2303
                                        xt_idx_delete_current(ot, ind);
 
2304
                                        /* Then move on to the next item! */
 
2305
                                case FALSE:
 
2306
                                        if (xt_idx_prev(ot, ind, search_key))
 
2307
                                                break;
 
2308
                                case XT_ERR:
 
2309
                                        goto failed;
 
2310
                                case XT_NEW:
 
2311
                                        if (xt_index_in_range(ot, ind, search_key, buf))
 
2312
                                                return 0;
 
2313
                                        if (!xt_idx_next(ot, ind, search_key))
 
2314
                                                goto failed;
 
2315
                                        break;
 
2316
                                case XT_RETRY:
 
2317
                                        if (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);
 
2320
                                        }
 
2321
                                        else {
 
2322
                                                if (!xt_idx_research(pb_open_tab, ind))
 
2323
                                                        goto failed;
 
2324
                                        }
 
2325
                                        break;
 
2326
                                default:
 
2327
                                        return 0;
 
2328
                        }
 
2329
                }
 
2330
        }
 
2331
        return HA_ERR_END_OF_FILE;
 
2332
 
 
2333
        failed:
 
2334
        return ha_log_pbxt_thread_error_for_mysql(FALSE);
 
2335
}
 
2336
 
 
2337
int ha_pbxt::index_init(uint idx, bool sorted)
 
2338
{
 
2339
        XTIndexPtr ind;
 
2340
 
 
2341
        active_index = idx;
 
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];
 
2347
 
 
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);
 
2349
#endif
 
2350
        }
 
2351
        else {
 
2352
                pb_open_tab->ot_cols_req = ha_get_max_bit(table->read_set);
 
2353
 
 
2354
                /* Check for index coverage!
 
2355
                 *
 
2356
                 * Given the following table:
 
2357
                 *
 
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,
 
2379
                 * `c_data` text,
 
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`)
 
2382
                 * ) ENGINE=PBXT;
 
2383
                 *
 
2384
                 * MySQL does not recognize index coverage on the followin select:
 
2385
                 *
 
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;
 
2388
                 *
 
2389
                 * TODO: Find out why this is necessary, MyISAM does not
 
2390
                 * seem to have this problem!
 
2391
                 */
 
2392
                ind = (XTIndexPtr) pb_share->sh_dic_keys[idx];
 
2393
                if (bitmap_is_subset(table->read_set, &ind->mi_col_map))
 
2394
                        pb_key_read = TRUE;
 
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));
 
2397
#endif
 
2398
        }
 
2399
        
 
2400
        return 0;
 
2401
}
 
2402
 
1852
2403
int ha_pbxt::index_end()
1853
2404
{
1854
2405
        int err = 0;
1855
2406
 
1856
 
        XT_ENTER();
 
2407
        XT_TRACE_CALL();
1857
2408
        ASSERT_NS(pb_ex_in_use);
1858
2409
        active_index = MAX_KEY;
1859
2410
        XT_RETURN(err);
1869
2420
        ASSERT_NS(pb_ex_in_use);
1870
2421
 
1871
2422
        XT_PRINT1(pb_open_tab->ot_thread, "ha_pbxt::index_read_xt %s\n", pb_share->sh_table_path);
1872
 
        XT_DISABLED_TRACE(("search tx=%d val=%d update=%d\n", (int) pb_open_tab->ot_thread->st_xact_data->xd_start_id, (int) XT_GET_DISK_4(key), pb_modified));
 
2423
        XT_DISABLED_TRACE(("search tx=%d val=%d update=%d\n", (int) pb_open_tab->ot_thread->st_xact_data->xd_start_xn_id, (int) XT_GET_DISK_4(key), pb_modified));
1873
2424
        ind = (XTIndexPtr) pb_share->sh_dic_keys[idx];
1874
2425
 
1875
2426
        switch (find_flag) {
1882
2433
                        if (!xt_idx_search_prev(pb_open_tab, ind, &search_key))
1883
2434
                                err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key);
1884
2435
                        else
1885
 
                                err = ha_idx_prev_read(pb_open_tab, ind, pb_key_read,
1886
 
                                        (find_flag == HA_READ_PREFIX_LAST) ? &search_key : NULL, buf, &pb_modified);
 
2436
                                err = xt_index_prev_read(pb_open_tab, ind, pb_key_read,
 
2437
                                        (find_flag == HA_READ_PREFIX_LAST) ? &search_key : NULL, buf);
1887
2438
                        break;
1888
2439
                case HA_READ_PREFIX:
1889
2440
                        prefix = SEARCH_PREFIX;
1895
2446
                        if (!xt_idx_search(pb_open_tab, ind, &search_key))
1896
2447
                                err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key);
1897
2448
                        else
1898
 
                                err = ha_idx_next_read(pb_open_tab, ind, pb_key_read,
1899
 
                                        (find_flag == HA_READ_KEY_EXACT || find_flag == HA_READ_PREFIX) ? &search_key : NULL, buf, &pb_modified);
 
2449
                                err = xt_index_next_read(pb_open_tab, ind, pb_key_read,
 
2450
                                        (find_flag == HA_READ_KEY_EXACT || find_flag == HA_READ_PREFIX) ? &search_key : NULL, buf);
1900
2451
                        break;
1901
2452
        }
1902
2453
 
1903
 
        XT_DISABLED_TRACE(("search tx=%d val=%d err=%d\n", (int) pb_open_tab->ot_thread->st_xact_data->xd_start_id, (int) XT_GET_DISK_4(key), err));
 
2454
        XT_DISABLED_TRACE(("search tx=%d val=%d err=%d\n", (int) pb_open_tab->ot_thread->st_xact_data->xd_start_xn_id, (int) XT_GET_DISK_4(key), err));
1904
2455
        table->status = err ? STATUS_NOT_FOUND : 0;
1905
2456
        return err;
1906
2457
}
1936
2487
        int                     err = 0;
1937
2488
        XTIndexPtr      ind;
1938
2489
 
1939
 
        XT_ENTER();
 
2490
        XT_TRACE_CALL();
1940
2491
        //statistic_increment(ha_read_next_count,&LOCK_status);
1941
2492
        ASSERT_NS(pb_ex_in_use);
1942
2493
 
1945
2496
        if (!xt_idx_next(pb_open_tab, ind, NULL))
1946
2497
                err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key);
1947
2498
        else
1948
 
                err = ha_idx_next_read(pb_open_tab, ind, pb_key_read, NULL, buf, &pb_modified);
 
2499
                err = xt_index_next_read(pb_open_tab, ind, pb_key_read, NULL, buf);
1949
2500
 
1950
2501
        table->status = err ? STATUS_NOT_FOUND : 0;
1951
2502
        XT_RETURN(err);
1968
2519
        XTIndexPtr                      ind;
1969
2520
        XTIdxSearchKeyRec       search_key;
1970
2521
 
1971
 
        XT_ENTER();
 
2522
        XT_TRACE_CALL();
1972
2523
        //statistic_increment(ha_read_next_count,&LOCK_status);
1973
2524
        ASSERT_NS(pb_ex_in_use);
1974
2525
 
1975
2526
        ind = (XTIndexPtr) pb_share->sh_dic_keys[active_index];
1976
2527
 
1977
2528
        search_key.sk_key_value.sv_flags = HA_READ_KEY_EXACT;
1978
 
        search_key.sk_key_value.sv_record = 0;
 
2529
        search_key.sk_key_value.sv_rec_id = 0;
 
2530
        search_key.sk_key_value.sv_row_id = 0;
1979
2531
        search_key.sk_key_value.sv_key = search_key.sk_key_buf;
1980
2532
        search_key.sk_key_value.sv_length = myxt_create_key_from_key(ind, search_key.sk_key_buf, (xtWord1 *) key, (u_int) length);
1981
2533
        search_key.sk_on_key = TRUE;
1983
2535
        if (!xt_idx_next(pb_open_tab, ind, &search_key))
1984
2536
                err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key);
1985
2537
        else
1986
 
                err = ha_idx_next_read(pb_open_tab, ind, pb_key_read, &search_key, buf, &pb_modified);
 
2538
                err = xt_index_next_read(pb_open_tab, ind, pb_key_read, &search_key, buf);
1987
2539
 
1988
2540
        table->status = err ? STATUS_NOT_FOUND : 0;
1989
2541
        XT_RETURN(err);
1997
2549
        int                     err = 0;
1998
2550
        XTIndexPtr      ind;
1999
2551
 
2000
 
        XT_ENTER();
 
2552
        XT_TRACE_CALL();
2001
2553
        //statistic_increment(ha_read_prev_count,&LOCK_status);
2002
2554
        ASSERT_NS(pb_ex_in_use);
2003
2555
 
2006
2558
        if (!xt_idx_prev(pb_open_tab, ind, NULL))
2007
2559
                err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key);
2008
2560
        else
2009
 
                err = ha_idx_prev_read(pb_open_tab, ind, pb_key_read, NULL, buf, &pb_modified);
 
2561
                err = xt_index_prev_read(pb_open_tab, ind, pb_key_read, NULL, buf);
2010
2562
 
2011
2563
        table->status = err ? STATUS_NOT_FOUND : 0;
2012
2564
        XT_RETURN(err);
2021
2573
        XTIndexPtr                      ind;
2022
2574
        XTIdxSearchKeyRec       search_key;
2023
2575
 
2024
 
        XT_ENTER();
 
2576
        XT_TRACE_CALL();
2025
2577
        //statistic_increment(ha_read_first_count,&LOCK_status);
2026
2578
        ASSERT_NS(pb_ex_in_use);
2027
2579
 
2031
2583
        if (!xt_idx_search(pb_open_tab, ind, &search_key))
2032
2584
                err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key);
2033
2585
        else
2034
 
                err = ha_idx_next_read(pb_open_tab, ind, pb_key_read, NULL, buf, &pb_modified);
 
2586
                err = xt_index_next_read(pb_open_tab, ind, pb_key_read, NULL, buf);
2035
2587
 
2036
2588
        table->status = err ? STATUS_NOT_FOUND : 0;
2037
2589
        XT_RETURN(err);
2038
2590
}
2039
2591
 
2040
2592
/*
 
2593
 * -----------------------------------------------------------------------
 
2594
 * RAMDOM/SEQUENTIAL READ METHODS
 
2595
 */
 
2596
 
 
2597
/*
2041
2598
 * index_last() asks for the last key in the index.
2042
2599
 */
2043
2600
int ha_pbxt::index_last(byte * buf)
2046
2603
        XTIndexPtr                      ind;
2047
2604
        XTIdxSearchKeyRec       search_key;
2048
2605
 
2049
 
        XT_ENTER();
 
2606
        XT_TRACE_CALL();
2050
2607
        //statistic_increment(ha_read_last_count,&LOCK_status);
2051
2608
        ASSERT_NS(pb_ex_in_use);
2052
2609
 
2056
2613
        if (!xt_idx_search_prev(pb_open_tab, ind, &search_key))
2057
2614
                err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key);
2058
2615
        else
2059
 
                err = ha_idx_prev_read(pb_open_tab, ind, pb_key_read, NULL, buf, &pb_modified);
 
2616
                err = xt_index_prev_read(pb_open_tab, ind, pb_key_read, NULL, buf);
2060
2617
 
2061
2618
        table->status = err ? STATUS_NOT_FOUND : 0;
2062
2619
        XT_RETURN(err);
2076
2633
        int err = 0;
2077
2634
 
2078
2635
        XT_PRINT1(pb_open_tab->ot_thread, "ha_pbxt::rnd_init %s\n", pb_share->sh_table_path);
2079
 
        XT_DISABLED_TRACE(("seq scan tx=%d\n", (int) pb_open_tab->ot_thread->st_xact_data->xd_start_id));
 
2636
        XT_DISABLED_TRACE(("seq scan tx=%d\n", (int) pb_open_tab->ot_thread->st_xact_data->xd_start_xn_id));
 
2637
 
 
2638
        /* The number of columns required: */
 
2639
        if (pb_open_tab->ot_is_modify)
 
2640
                pb_open_tab->ot_cols_req = table->read_set->n_bits;
 
2641
        else
 
2642
                pb_open_tab->ot_cols_req = ha_get_max_bit(table->read_set);
2080
2643
 
2081
2644
        ASSERT_NS(pb_ex_in_use);
2082
2645
        if (scan) {
2083
2646
                if (!xt_tab_seq_init(pb_open_tab))
2084
2647
                        err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key);
2085
2648
        }
 
2649
        else
 
2650
                xt_tab_seq_reset(pb_open_tab);
2086
2651
 
2087
2652
        return err;
2088
2653
}
2099
2664
        xt_dump_database(self, self->st_database);
2100
2665
        **/
2101
2666
#endif
2102
 
        XT_ENTER();
 
2667
        XT_TRACE_CALL();
 
2668
        xt_tab_seq_exit(pb_open_tab);
2103
2669
        XT_RETURN(0);
2104
2670
}
2105
2671
 
2117
2683
        int             err = 0;
2118
2684
        xtBool  eof;
2119
2685
 
2120
 
        XT_ENTER();
 
2686
        XT_TRACE_CALL();
2121
2687
        ASSERT_NS(pb_ex_in_use);
2122
2688
        //statistic_increment(ha_read_rnd_next_count, &LOCK_status);
2123
2689
 
2146
2712
 */
2147
2713
void ha_pbxt::position(const byte *record)
2148
2714
{
2149
 
        XT_ENTER();
 
2715
        XT_TRACE_CALL();
2150
2716
        ASSERT_NS(pb_ex_in_use);
2151
2717
        /*
2152
2718
         * I changed this from using little endian to big endian.
2168
2734
         * aa,cc,bb
2169
2735
         *
2170
2736
         */
2171
 
        (void) ASSERT_NS(XT_RECORD_REF_SIZE == 6);
2172
 
        mi_int6store((xtWord1 *) ref, pb_open_tab->ot_curr_rec);
 
2737
        (void) ASSERT_NS(XT_RECORD_OFFS_SIZE == 4);
 
2738
        mi_int4store((xtWord1 *) ref, pb_open_tab->ot_curr_rec_id);
2173
2739
        XT_RETURN_VOID;
2174
2740
}
2175
2741
 
2182
2748
{
2183
2749
        int err = 0;
2184
2750
 
2185
 
        XT_ENTER();
 
2751
        XT_TRACE_CALL();
2186
2752
        ASSERT_NS(pb_ex_in_use);
2187
2753
        //statistic_increment(ha_read_rnd_count, &LOCK_status);
2188
2754
        XT_PRINT1(pb_open_tab->ot_thread, "ha_pbxt::rnd_pos %s\n", pb_share->sh_table_path);
2189
2755
 
2190
 
        pb_open_tab->ot_curr_rec = mi_uint6korr((xtWord1 *) pos);
2191
 
        switch (xt_tab_read_record(pb_open_tab, (xtWord1 *) buf)) {
 
2756
        pb_open_tab->ot_curr_rec_id = mi_uint4korr((xtWord1 *) pos);
 
2757
        switch (xt_tab_dirty_read_record(pb_open_tab, (xtWord1 *) buf)) {
2192
2758
                case XT_DEL:
2193
 
                case FALSE:
2194
2759
                        /* Should not happen! */
2195
2760
                        err = HA_ERR_RECORD_DELETED;
2196
2761
                        break;
2197
 
                case XT_ERR:
 
2762
                case FALSE:
2198
2763
                        err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key);
2199
2764
                        break;
2200
2765
                default:
2206
2771
}
2207
2772
 
2208
2773
/*
 
2774
 * -----------------------------------------------------------------------
 
2775
 * INFO METHODS
 
2776
 */
 
2777
 
 
2778
/*
2209
2779
        ::info() is used to return information to the optimizer.
2210
2780
        Currently this table handler doesn't implement most of the fields
2211
2781
        really needed. SHOW also makes use of this data
2257
2827
        XTOpenTablePtr  ot;
2258
2828
        int                             in_use;
2259
2829
 
2260
 
        XT_ENTER();
 
2830
        XT_TRACE_CALL();
2261
2831
        
2262
2832
        if (!(in_use = pb_ex_in_use)) {
2263
2833
                pb_ex_in_use = 1;
2264
 
                if (pb_share->sh_table_lock) {
 
2834
                if (pb_share && pb_share->sh_table_lock) {
2265
2835
                        /* If some thread has an exclusive lock, then
2266
2836
                         * we wait for the lock to be removed:
2267
2837
                         */
2278
2848
        if ((ot = pb_open_tab)) {
2279
2849
                if (flag & HA_STATUS_VARIABLE) {
2280
2850
                        stats.deleted = ot->ot_table->tab_row_fnum;
2281
 
                        stats.records = (ha_rows) ((ot->ot_table->tab_row_eof >> XT_TAB_ROW_SHIFTS) - 1 - stats.deleted);
2282
 
                        stats.data_file_length = ot->ot_table->tab_data_eof;
 
2851
                        stats.records = (ha_rows) (ot->ot_table->tab_row_eof_id - 1 - stats.deleted);
 
2852
                        stats.data_file_length = ot->ot_table->tab_rec_eof_id;
2283
2853
                        stats.index_file_length = ot->ot_table->tab_ind_eof;
2284
 
                        stats.delete_length = ot->ot_table->tab_data_fnum * ot->ot_rec_size;
 
2854
                        stats.delete_length = ot->ot_table->tab_rec_fnum * ot->ot_rec_size;
2285
2855
                        //check_time = info.check_time;
2286
2856
                        stats.mean_rec_length = ot->ot_rec_size;
2287
2857
                }
2294
2864
                        stats.max_data_file_length = 0x00FFFFFF;
2295
2865
                        stats.max_index_file_length = 0x00FFFFFF;
2296
2866
                        //stats.create_time = info.create_time;
2297
 
                        ref_length = XT_RECORD_REF_SIZE;
 
2867
                        ref_length = XT_RECORD_OFFS_SIZE;
2298
2868
                        //share->db_options_in_use = info.options;
2299
 
                        stats.block_size = (1 << XT_PAGE_SIZE_SHIFTS);
 
2869
                        stats.block_size = XT_INDEX_PAGE_SIZE;
2300
2870
 
2301
2871
                        if (share->tmp_table == NO_TMP_TABLE)
2302
2872
#ifdef SAFE_MUTEX
2363
2933
                                xt_broadcast_cond(NULL, (xt_cond_type *) pb_share->sh_ex_cond);
2364
2934
                }
2365
2935
        }
2366
 
        complete:
2367
2936
#if MYSQL_VERSION_ID < 50114
2368
2937
        XT_RETURN_VOID;
2369
2938
#else
2400
2969
                         *
2401
2970
                         * GOTCHA: I cannot end the transaction here!
2402
2971
                         * I must end it in start_stmt().
2403
 
                         * The reason is because thre are situations
 
2972
                         * The reason is because there are situations
2404
2973
                         * where this would end a transaction that
2405
2974
                         * was begin by external_lock().
2406
2975
                         *
2423
2992
                                        if (self->st_stat_count == 0)
2424
2993
                                                self->st_stat_ended = TRUE;
2425
2994
                                }
 
2995
 
 
2996
                                /* This is the end of a statement, I can turn any locks into perminant locks now: */
 
2997
                                if (pb_open_tab)
 
2998
                                        pb_open_tab->ot_table->tab_locks.xt_make_lock_permanent(pb_open_tab, &self->st_lock_list);
2426
2999
                        }
2427
3000
                        break;
2428
3001
                case HA_EXTRA_KEYREAD:
2466
3039
 */
2467
3040
int ha_pbxt::reset(void)
2468
3041
{
2469
 
        XT_ENTER();
 
3042
        XT_TRACE_CALL();
2470
3043
        extra(HA_EXTRA_RESET_STATE);
2471
3044
        XT_RETURN(0);
2472
3045
}
2473
3046
 
 
3047
void ha_pbxt::unlock_row()
 
3048
{
 
3049
        XT_TRACE_CALL();
 
3050
        if (pb_open_tab)
 
3051
                pb_open_tab->ot_table->tab_locks.xt_remove_temp_lock(pb_open_tab);
 
3052
}
 
3053
 
2474
3054
/*
2475
3055
 * Used to delete all rows in a table. Both for cases of truncate and
2476
3056
 * for cases where the optimizer realizes that all rows will be
2490
3070
        char                    table_name[XT_TABLE_NAME_SIZE];
2491
3071
        XTDDTable               *tab_def = NULL;
2492
3072
 
2493
 
        XT_ENTER();
 
3073
        XT_TRACE_CALL();
2494
3074
 
2495
3075
        if (thd_sql_command(thd) != SQLCOM_TRUNCATE) {
2496
3076
                /* Just like InnoDB we only handle TRUNCATE TABLE
2569
3149
{
2570
3150
        int                             err = 0;
2571
3151
        XTDatabaseHPtr  db;
2572
 
        xtWord8                 my_id;
2573
 
        xtWord8                 clean_id = 0;
 
3152
        xtXactID                my_xn_id;
 
3153
        xtXactID                clean_xn_id = 0;
2574
3154
        uint                    cnt = 10;
2575
3155
 
2576
 
        XT_ENTER();
 
3156
        XT_TRACE_CALL();
2577
3157
 
2578
3158
        if (!pb_open_tab) {
2579
3159
                if ((err = reopen()))
2603
3183
         * 
2604
3184
         */
2605
3185
        if (pb_open_tab->ot_thread && pb_open_tab->ot_thread->st_xact_data) {
2606
 
                my_id = pb_open_tab->ot_thread->st_xact_data->xd_start_id;
 
3186
                my_xn_id = pb_open_tab->ot_thread->st_xact_data->xd_start_xn_id;
2607
3187
                XT_PRINT0(xt_get_self(), "xt_xn_commit\n");
2608
3188
                xt_xn_commit(pb_open_tab->ot_thread);
2609
3189
        }
2610
3190
        else
2611
 
                my_id = db->db_xn_to_clean_id;
 
3191
                my_xn_id = db->db_xn_to_clean_id;
2612
3192
 
2613
 
        while ((!db->db_sw_idle || db->db_xn_to_clean_id < my_id) && !thd_killed(thd)) {
 
3193
        while ((!db->db_sw_idle || xt_xn_is_before(db->db_xn_to_clean_id, my_xn_id)) && !thd_killed(thd)) {
2614
3194
                xt_busy_wait();
2615
3195
 
2616
3196
                /*
2631
3211
                 */
2632
3212
                if (db->db_sw_idle) {
2633
3213
                        /* This will make sure we don't wait forever: */
2634
 
                        if (clean_id != db->db_xn_to_clean_id) {
2635
 
                                clean_id = db->db_xn_to_clean_id;
 
3214
                        if (clean_xn_id != db->db_xn_to_clean_id) {
 
3215
                                clean_xn_id = db->db_xn_to_clean_id;
2636
3216
                                cnt = 10;
2637
3217
                        }
2638
3218
                        else {
2674
3254
                return ha_pbxt_to_mysql_error(err);
2675
3255
        if (self->st_lock_count)
2676
3256
                ASSERT(self->st_xact_data);
 
3257
 
 
3258
        if (!pb_table_locked) {
 
3259
                ha_aquire_exclusive_use(self, pb_share, this);
 
3260
                pushr_(ha_release_exclusive_use, pb_share);
 
3261
        }
 
3262
 
 
3263
        xt_check_table(self, pb_open_tab);
 
3264
 
 
3265
        if (!pb_table_locked)
 
3266
                freer_(); // ha_release_exclusive_use(pb_share)
 
3267
 
2677
3268
        //pbxt_mysql_trace_on = TRUE;
2678
3269
        return 0;
2679
3270
}
2711
3302
 
2712
3303
                XT_PRINT1(self, "ha_pbxt::EXTERNAL_LOCK %s lock_type=UNLOCK\n", pb_share->sh_table_path);
2713
3304
 
2714
 
                /* If the table was locked for update, then flush all table files: */
2715
 
                if (pb_modified) {
2716
 
                        if (pb_open_tab && !xt_flush_table(pb_open_tab))
2717
 
                                err = ha_log_pbxt_thread_error_for_mysql(pb_ignore_dup_key);
2718
 
                }
 
3305
                /* Make any temporary locks on this table permanent.
 
3306
                 *
 
3307
                 * This is required here because of the following example:
 
3308
                 * create table t1 (a int NOT NULL, b int, primary key (a));
 
3309
                 * create table t2 (a int NOT NULL, b int, primary key (a));
 
3310
                 * insert into t1 values (0, 10),(1, 11),(2, 12);
 
3311
                 * insert into t2 values (1, 21),(2, 22),(3, 23);
 
3312
                 * update t1 set b= (select b from t2 where t1.a = t2.a);
 
3313
                 * update t1 set b= (select b from t2 where t1.a = t2.a);
 
3314
                 * select * from t1;
 
3315
                 * drop table t1, t2;
 
3316
                 *
 
3317
                 */
 
3318
                if (pb_open_tab)
 
3319
                        pb_open_tab->ot_table->tab_locks.xt_make_lock_permanent(pb_open_tab, &self->st_lock_list);
2719
3320
 
2720
3321
                /* GOTCHA! It's weird, but, if this function returns an error
2721
3322
                 * on lock, then UNLOCK is called?!
2727
3328
                 * The result is, that my lock count can go wrong. So I could
2728
3329
                 * change the lock method, and increment the lock count, even
2729
3330
                 * if it fails. However, the consequences are more serious,
2730
 
                 * if some code descides not to call UNLOCK after lock fails.
2731
 
                 * The result is that I woiuld have a permanent too high lock,
 
3331
                 * if some code decides not to call UNLOCK after lock fails.
 
3332
                 * The result is that I would have a permanent too high lock,
2732
3333
                 * count and nothing will work.
2733
3334
                 * So instead, I handle the fact that I might too many unlocks
2734
3335
                 * here.
2779
3380
                                                err = ha_pbxt_thread_error_for_mysql(thd, self, pb_ignore_dup_key);
2780
3381
                                }
2781
3382
                        }
 
3383
 
 
3384
                        /* If the previous statement was "for update", then set the visibilty
 
3385
                         * so that non- for update SELECTs will see what the for update select
 
3386
                         * (or update statement) just saw.
 
3387
                         */
 
3388
                        if (pb_open_tab && pb_open_tab->ot_for_update)
 
3389
                                self->st_visible_time = self->st_database->db_xn_end_time;
2782
3390
                }
2783
3391
 
2784
3392
                if (pb_table_locked) {
2794
3402
                        xt_broadcast_cond(NULL, (xt_cond_type *) pb_share->sh_ex_cond);
2795
3403
        }
2796
3404
        else {
2797
 
#ifdef PBXT_PRINT_STAT
2798
 
                XT_PRINT1(self, "%s\n", thd->query);
2799
 
#endif
2800
3405
                XT_PRINT2(self, "ha_pbxt::EXTERNAL_LOCK %s lock_type=%d\n", pb_share->sh_table_path, lock_type);
2801
3406
                
2802
3407
                if (pb_lock_table) {
2813
3418
                                if (!pb_share->sh_table) {
2814
3419
                                        xt_ha_open_database_of_table(self, pb_share->sh_table_path, table_name);
2815
3420
 
2816
 
                                        ha_open_share(self, pb_share, table_name);
 
3421
                                        ha_open_share(self, pb_share, table_name, NULL);
2817
3422
                                }
2818
3423
                        }
2819
3424
                        catch_(a) {
2844
3449
 
2845
3450
                        /* Set the current thread for this open table: */
2846
3451
                        pb_open_tab->ot_thread = self;
 
3452
 
 
3453
                        /* If this is a set, then it is in UPDATE/DELETE TABLE ...
 
3454
                         * or SELECT ... FOR UPDATE
 
3455
                         */     
 
3456
                        pb_open_tab->ot_is_modify = FALSE;
 
3457
                        if ((pb_open_tab->ot_for_update = (lock_type == F_WRLCK))) {
 
3458
                                switch ((int) thd_sql_command(thd)) {
 
3459
                                        case SQLCOM_UPDATE:
 
3460
                                        case SQLCOM_UPDATE_MULTI:
 
3461
                                        case SQLCOM_DELETE:
 
3462
                                        case SQLCOM_DELETE_MULTI:
 
3463
                                        case SQLCOM_REPLACE:
 
3464
                                        case SQLCOM_REPLACE_SELECT:
 
3465
                                        case SQLCOM_INSERT:
 
3466
                                        case SQLCOM_INSERT_SELECT:
 
3467
                                                pb_open_tab->ot_is_modify = TRUE;
 
3468
                                                break;
 
3469
                                }
 
3470
                        }
2847
3471
                }
2848
3472
 
2849
3473
                /* Record the associated MySQL thread: */
2850
3474
                pb_mysql_thd = thd;
2851
3475
 
2852
 
                /* If this is a SELECT, then it is in UPDATE TABLE ...
2853
 
                 * or SELECT ... FOR UPDATE
2854
 
                 */     
2855
 
                pb_modified = (lock_type == F_WRLCK);
2856
 
 
2857
3476
                if (self->st_database != pb_share->sh_table->tab_db) {                          
2858
3477
                        try_(b) {
2859
3478
                                /* PBXT does not permit multiple databases us one statement,
2941
3560
                                XT_PRINT0(self, "ha_pbxt::external_lock trans_register_ha all=TRUE\n");
2942
3561
#ifdef PBXT_PRINT_STAT
2943
3562
                                switch (thd_tx_isolation(thd)) {
2944
 
                                        case ISO_READ_UNCOMMITTED: XT_PRINT0(self, "BEGIN (incommitted read)\n"); break;
2945
 
                                        case ISO_READ_COMMITTED: XT_PRINT0(self, "BEGIN (committed read)\n"); break;
2946
 
                                        case ISO_REPEATABLE_READ: XT_PRINT0(self, "BEGIN (repeatable read)\n"); break;
2947
 
                                        case ISO_SERIALIZABLE: XT_PRINT0(self, "BEGIN (serializable)\n"); break;
 
3563
                                        case ISO_READ_UNCOMMITTED: XT_PRINT_STAT0(self, "BEGIN (incommitted read)\n"); break;
 
3564
                                        case ISO_READ_COMMITTED: XT_PRINT_STAT0(self, "BEGIN (committed read)\n"); break;
 
3565
                                        case ISO_REPEATABLE_READ: XT_PRINT_STAT0(self, "BEGIN (repeatable read)\n"); break;
 
3566
                                        case ISO_SERIALIZABLE: XT_PRINT_STAT0(self, "BEGIN (serializable)\n"); break;
2948
3567
                                }
2949
3568
#endif
2950
3569
                        }
2951
3570
                }
2952
3571
 
 
3572
                if (lock_type == F_WRLCK || self->st_xact_mode < XT_XACT_REPEATABLE_READ)
 
3573
                        self->st_visible_time = self->st_database->db_xn_end_time;
 
3574
 
2953
3575
                self->st_lock_count++;
 
3576
/*DBG*
 
3577
xt_trace_query(self, thd_query(thd));
 
3578
*DBG*/
 
3579
                XT_TRACE_STAT1(self, "QUERY: %s\n", thd_query(thd));
2954
3580
        }
2955
3581
 
2956
3582
        complete:
2985
3611
        }
2986
3612
 
2987
3613
        ASSERT_NS(pb_open_tab->ot_thread == self);
2988
 
        
2989
3614
        ASSERT_NS(thd == pb_mysql_thd);
2990
 
 
2991
 
        pb_modified =
 
3615
        ASSERT_NS(self->st_database == pb_open_tab->ot_table->tab_db);
 
3616
 
 
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);
 
3626
                        }
 
3627
                        else {
 
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);
 
3631
                        }
 
3632
                }
 
3633
 
 
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.
 
3637
                 */
 
3638
                if (pb_open_tab->ot_for_update)
 
3639
                        self->st_visible_time = self->st_database->db_xn_end_time;
 
3640
        }
 
3641
 
 
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);
2996
 
 
2997
 
        ASSERT_NS(self->st_database == pb_open_tab->ot_table->tab_db);
2998
 
 
2999
 
        if (pb_modified) {
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)) {
 
3650
                        case SQLCOM_UPDATE:
 
3651
                        case SQLCOM_UPDATE_MULTI:
 
3652
                        case SQLCOM_DELETE:
 
3653
                        case SQLCOM_DELETE_MULTI:
 
3654
                        case SQLCOM_REPLACE:
 
3655
                        case SQLCOM_REPLACE_SELECT:
 
3656
                        case SQLCOM_INSERT:
 
3657
                        case SQLCOM_INSERT_SELECT:
 
3658
                                pb_open_tab->ot_is_modify = TRUE;
 
3659
                                break;
 
3660
                }
3002
3661
        }
3003
3662
 
 
3663
 
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.
3008
3668
         *
3016
3676
         */
3017
3677
        self->st_is_update = FALSE;
3018
3678
 
3019
 
        if (self->st_stat_ended) {
3020
 
                self->st_stat_ended = FALSE;
3021
 
                self->st_stat_trans = FALSE;
3022
 
                /* This section handles "auto-commit"... */
3023
 
                if (self->st_xact_data && self->st_auto_commit && self->st_table_trans) {
3024
 
                        if (self->st_abort_trans) {
3025
 
                                XT_PRINT0(self, "xt_xn_rollback\n");
3026
 
                                if (!xt_xn_rollback(self))
3027
 
                                        err = ha_pbxt_thread_error_for_mysql(pb_mysql_thd, self, pb_ignore_dup_key);
3028
 
                        }
3029
 
                        else {
3030
 
                                XT_PRINT0(self, "xt_xn_commit\n");
3031
 
                                if (!xt_xn_commit(self))
3032
 
                                        err = ha_pbxt_thread_error_for_mysql(pb_mysql_thd, self, pb_ignore_dup_key);
3033
 
                        }
3034
 
                }
3035
 
        }
3036
 
 
3037
3679
        /* See comment (**) */
3038
3680
        if (!self->st_xact_data) {
3039
3681
                self->st_xact_mode = thd_tx_isolation(thd) <= ISO_READ_COMMITTED ? XT_XACT_COMMITTED_READ : XT_XACT_REPEATABLE_READ;
3053
3695
                        XT_PRINT0(self, "ha_pbxt::start_stmt trans_register_ha all=TRUE\n");
3054
3696
#ifdef PBXT_PRINT_STAT
3055
3697
                        switch (thd_tx_isolation(thd)) {
3056
 
                                case ISO_READ_UNCOMMITTED: XT_PRINT0(self, "BEGIN (incommitted read)\n"); break;
3057
 
                                case ISO_READ_COMMITTED: XT_PRINT0(self, "BEGIN (committed read)\n"); break;
3058
 
                                case ISO_REPEATABLE_READ: XT_PRINT0(self, "BEGIN (repeatable read)\n"); break;
3059
 
                                case ISO_SERIALIZABLE: XT_PRINT0(self, "BEGIN (serializable)\n"); break;
 
3698
                                case ISO_READ_UNCOMMITTED: XT_PRINT_STAT0(self, "BEGIN (incommitted read)\n"); break;
 
3699
                                case ISO_READ_COMMITTED: XT_PRINT_STAT0(self, "BEGIN (committed read)\n"); break;
 
3700
                                case ISO_REPEATABLE_READ: XT_PRINT_STAT0(self, "BEGIN (repeatable read)\n"); break;
 
3701
                                case ISO_SERIALIZABLE: XT_PRINT_STAT0(self, "BEGIN (serializable)\n"); break;
3060
3702
                        }
3061
3703
#endif
3062
3704
                }
3063
3705
        }
3064
3706
 
 
3707
        if (pb_open_tab->ot_for_update || self->st_xact_mode < XT_XACT_REPEATABLE_READ)
 
3708
                self->st_visible_time = self->st_database->db_xn_end_time;
 
3709
 
3065
3710
        pb_in_stat = TRUE;
3066
3711
 
3067
3712
        self->st_stat_count++;
3260
3905
        if (!(self = ha_set_current_thread(thd, &err)))
3261
3906
                return ha_pbxt_to_mysql_error(err);
3262
3907
 
3263
 
#ifdef PBXT_PRINT_STAT
3264
 
        XT_PRINT1(self, "%s\n", thd->query);
3265
 
#endif
 
3908
        XT_TRACE_STAT1(self, "QUERY: %s\n", thd_query(thd));
3266
3909
        XT_PRINT1(self, "ha_pbxt::delete_table %s\n", table_path);
3267
3910
 
3268
3911
        try_(a) {
3274
3917
                         * We also cannot use pb_share because the handler used
3275
3918
                         * to delete a table is not openned correctly.
3276
3919
                         */
3277
 
                        share = ha_get_share(self, table_path, table_name, false);
 
3920
                        share = ha_get_share(self, table_path, table_name, false, NULL);
3278
3921
                        pushr_(ha_unget_share, share);
3279
3922
                        ha_aquire_exclusive_use(self, share, NULL);
3280
3923
                        pushr_(ha_release_exclusive_use, share);
3332
3975
        int                             err = 0;
3333
3976
        XTThreadPtr             self;
3334
3977
        char                    from_table_name[XT_TAB_NAME_WITH_EXT_SIZE];
 
3978
        char                    to_db_name[NAME_MAX];
3335
3979
        char                    to_table_name[XT_TAB_NAME_WITH_EXT_SIZE];
3336
 
        XTDatabaseHPtr  to_db;
3337
3980
        XTSharePtr              share;
3338
3981
 
3339
 
        XT_ENTER();
 
3982
        XT_TRACE_CALL();
3340
3983
 
3341
3984
        if (!(self = ha_set_current_thread(thd, &err)))
3342
3985
                return ha_pbxt_to_mysql_error(err);
3344
3987
        XT_PRINT2(self, "ha_pbxt::rename_table %s -> %s\n", from, to);
3345
3988
 
3346
3989
        try_(a) {
3347
 
                to_db = ha_get_database_of_table(self, to, to_table_name);
 
3990
                ha_get_db_name_and_table(to, to_db_name, to_table_name);
3348
3991
 
3349
3992
                xt_ha_open_database_of_table(self, from, from_table_name);
3350
3993
 
 
3994
                if (strcmp(self->st_database->db_name, to_db_name) != 0)
 
3995
                        xt_throw_xterr(XT_CONTEXT, XT_ERR_CANNOT_CHANGE_DB);
 
3996
 
3351
3997
                /*
3352
3998
                 * NOTE: MySQL does not lock before calling rename table!
3353
3999
                 *
3355
4001
                 * called without correctly initializing
3356
4002
                 * the handler!
3357
4003
                 */
3358
 
                share = ha_get_share(self, from, from_table_name, true);
 
4004
                share = ha_get_share(self, from, from_table_name, true, NULL);
3359
4005
                pushr_(ha_unget_share, share);
3360
4006
                ha_aquire_exclusive_use(self, share, NULL);
3361
4007
                pushr_(ha_release_exclusive_use, share);
3362
4008
                ha_close_open_tables(self, share, NULL);
3363
4009
 
3364
4010
                self->st_ignore_fkeys = (thd_test_options(thd, OPTION_NO_FOREIGN_KEY_CHECKS)) != 0;
3365
 
                if (self->st_database == to_db) {
3366
 
                        xt_heap_release(self, to_db);
3367
 
                        xt_rename_table(self, from_table_name, to_table_name);
3368
 
                }
3369
 
                else {
3370
 
                        /* Move the table to some other database: */
3371
 
                        pushr_(xt_heap_release, to_db);
3372
 
                        xt_move_table(self, from_table_name, to_db, to_table_name);
3373
 
                        freer_(); // xt_heap_release(to_db);
3374
 
 
3375
 
                }
 
4011
                xt_rename_table(self, from_table_name, to_table_name);
3376
4012
 
3377
4013
                freer_(); // ha_release_exclusive_use(share)
3378
4014
                freer_(); // ha_unget_share(share)
3403
4039
 
3404
4040
uint ha_pbxt::max_supported_key_length() const
3405
4041
{
3406
 
        return XT_IDX_MAX_KEY_SIZE;
 
4042
        return XT_INDEX_MAX_KEY_SIZE;
3407
4043
}
3408
4044
 
3409
4045
uint ha_pbxt::max_supported_key_part_length() const
3410
4046
{
3411
4047
        /* There is a little overhead in order to fit! */
3412
 
        return XT_IDX_MAX_KEY_SIZE-4;
 
4048
        return XT_INDEX_MAX_KEY_SIZE-4;
3413
4049
}
3414
4050
 
3415
4051
/*
3443
4079
 * if start_key matches any rows.
3444
4080
 * 
3445
4081
 * Called from opt_range.cc by check_quick_keys().
3446
 
*/
 
4082
 *
 
4083
 */
3447
4084
ha_rows ha_pbxt::records_in_range(uint inx, key_range *min_key, key_range *max_key)
3448
4085
{
3449
 
        ha_rows result = 1;
3450
 
        //if (min_key->length == max_key->length && memcmp(min_key->key, max_key->key, min_key->length) == 0)
3451
 
        //      return 1;
 
4086
        XTIndexPtr              ind;
 
4087
        key_part_map    keypart_map;
 
4088
        u_int                   segement = 0;
 
4089
        ha_rows                 result;
 
4090
 
 
4091
        if (min_key)
 
4092
                keypart_map = min_key->keypart_map;
 
4093
        else if (max_key)
 
4094
                keypart_map = max_key->keypart_map;
 
4095
        else
 
4096
                return 1;
 
4097
        ind = (XTIndexPtr) pb_share->sh_dic_keys[inx];
 
4098
        
 
4099
        while (keypart_map & 1) {
 
4100
                segement++;
 
4101
                keypart_map = keypart_map >> 1;
 
4102
        }
 
4103
 
 
4104
        if (segement < 1 || segement > ind->mi_seg_count)
 
4105
                result = 1;
 
4106
        else
 
4107
                result = ind->mi_seg[segement-1].is_recs_in_range;
 
4108
#ifdef XT_PRINT_INDEX_OPT
 
4109
        printf("records_in_range %s index %d cols req=%d/%d read_bits=%X write_bits=%X index_bits=%X --> %d\n", pb_open_tab->ot_table->tab_name, (int) inx, segement, ind->mi_seg_count, (int) *table->read_set->bitmap, (int) *table->write_set->bitmap, (int) *ind->mi_col_map.bitmap, (int) result);
 
4110
#endif
3452
4111
        return result;
3453
4112
}
3454
4113
 
3469
4128
        XTThreadPtr             self;
3470
4129
        char                    table_name[XT_TAB_NAME_WITH_EXT_SIZE];
3471
4130
        XTDDTable               *tab_def = NULL;
 
4131
        XTDictionaryRec dic = { 0, 0, 0, 0, 0, 0, 0, 0 };
3472
4132
 
3473
 
        XT_ENTER();
 
4133
        XT_TRACE_CALL();
3474
4134
 
3475
4135
        if (!(self = ha_set_current_thread(thd, &err)))
3476
4136
                return ha_pbxt_to_mysql_error(err);
3477
4137
 
3478
 
#ifdef PBXT_PRINT_STAT
3479
 
        XT_PRINT1(self, "%s\n", thd->query);
3480
 
#endif
 
4138
        XT_TRACE_STAT1(self, "QUERY: %s\n", thd_query(thd));
3481
4139
        XT_PRINT1(self, "ha_pbxt::create %s\n", table_path);
3482
4140
 
3483
4141
        try_(a) {
3484
 
                XTDictionaryRec dic = { 0, 0, 0, 0, 0, 0, 0, 0 };
3485
 
 
3486
4142
                xt_ha_open_database_of_table(self, table_path, table_name);
3487
4143
 
3488
4144
                for (uint i=0; i<TS(table_arg)->keys; i++) {
3489
 
                        if (table_arg->key_info[i].key_length > XT_IDX_MAX_KEY_SIZE)
3490
 
                                xt_throw_sulxterr(XT_CONTEXT, XT_ERR_KEY_TOO_LARGE, table_arg->key_info[i].name, (u_long) XT_IDX_MAX_KEY_SIZE);
 
4145
                        if (table_arg->key_info[i].key_length > XT_INDEX_MAX_KEY_SIZE)
 
4146
                                xt_throw_sulxterr(XT_CONTEXT, XT_ERR_KEY_TOO_LARGE, table_arg->key_info[i].name, (u_long) XT_INDEX_MAX_KEY_SIZE);
3491
4147
                }
3492
4148
 
3493
4149
                /* ($) auto_increment_value will be zero if 
3503
4159
                dic.dic_min_auto_inc = (xtWord8) create_info->auto_increment_value; /* ($) */
3504
4160
                myxt_setup_dictionary(self, &dic);
3505
4161
 
3506
 
 
3507
4162
                /* On CREATE TABLE we ignore "set foreign_key_checks=0;",
3508
4163
                 * and always generate an error.
3509
4164
                 *
3530
4185
        }
3531
4186
        cont_(a);
3532
4187
 
3533
 
        if (tab_def)
3534
 
                tab_def->release(self);
 
4188
        /* Free the dictionary, but not 'table_arg'! */
 
4189
        dic.dic_my_table = NULL;
 
4190
        myxt_free_dictionary(self, &dic);
3535
4191
 
3536
4192
        XT_RETURN(err);
3537
4193
}
3601
4257
        return TRUE;
3602
4258
}
3603
4259
 
 
4260
struct st_mysql_sys_var
 
4261
{
 
4262
  MYSQL_PLUGIN_VAR_HEADER;
 
4263
};
 
4264
 
 
4265
static void pbxt_record_cache_size_func(THD *thd, struct st_mysql_sys_var *var, void *tgt, void *save)
 
4266
{
 
4267
        xtInt8  record_cache_size;
 
4268
 
 
4269
        char *old= *(char **) tgt;
 
4270
        *(char **)tgt= *(char **) save;
 
4271
        if (var->flags & PLUGIN_VAR_MEMALLOC)
 
4272
        {
 
4273
                *(char **)tgt= my_strdup(*(char **) save, MYF(0));
 
4274
                my_free(old, MYF(0));
 
4275
        }
 
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);
 
4278
#ifdef DEBUG
 
4279
        char buffer[200];
 
4280
 
 
4281
        sprintf(buffer, "pbxt_record_cache_size=%llu\n", (u_llong) record_cache_size);
 
4282
        xt_logf(XT_NT_INFO, buffer);
 
4283
#endif
 
4284
}
 
4285
 
3604
4286
struct st_mysql_storage_engine pbxt_storage_engine = {
3605
4287
        MYSQL_HANDLERTON_INTERFACE_VERSION
3606
4288
};
 
4289
static st_mysql_information_schema pbxt_statitics = {
 
4290
        MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
 
4291
};
3607
4292
 
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);
3613
4298
 
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.",
3617
 
  NULL, NULL, NULL);
 
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);
 
4303
 
 
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.",
 
4307
  NULL, NULL, NULL);
 
4308
 
 
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.",
 
4312
  NULL, NULL, NULL);
 
4313
 
 
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).",
 
4317
  NULL, NULL, NULL);
 
4318
 
 
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.",
 
4322
  NULL, NULL, NULL);
 
4323
 
 
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.",
 
4327
  NULL, NULL, NULL);
 
4328
 
 
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.",
 
4332
  NULL, NULL, NULL);
 
4333
 
 
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);
3618
4338
 
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),
3622
4349
  NULL
3623
4350
};
3624
4351
#endif
3628
4355
        MYSQL_STORAGE_ENGINE_PLUGIN,
3629
4356
        &pbxt_storage_engine,
3630
4357
        "PBXT",
3631
 
        "Paul McCullagh, SNAP Innovation GmbH",
 
4358
        "Paul McCullagh, PrimeBase Technologies GmbH",
3632
4359
        "High performance, multi-versioning transactional engine",
3633
4360
        PLUGIN_LICENSE_GPL,
3634
4361
        pbxt_init, /* Plugin Init */
3641
4368
        NULL,
3642
4369
#endif
3643
4370
        NULL                                            /* config options                  */
 
4371
},
 
4372
{
 
4373
        MYSQL_INFORMATION_SCHEMA_PLUGIN,
 
4374
        &pbxt_statitics,
 
4375
        "PBXT_STATISTICS",
 
4376
        "Paul McCullagh, PrimeBase Technologies GmbH",
 
4377
        "PBXT internal system statitics",
 
4378
        PLUGIN_LICENSE_GPL,
 
4379
        pbxt_init_statitics,                                            /* plugin init */
 
4380
        pbxt_exit_statitics,                                            /* plugin deinit */
 
4381
        0x0005,
 
4382
        NULL,                                                                           /* status variables */
 
4383
        NULL,                                                                           /* system variables */
 
4384
        NULL                                                                            /* config options */
3644
4385
}
3645
4386
mysql_declare_plugin_end;
3646
4387