1
/* Copyright (c) 2005 PrimeBase Technologies GmbH
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
* 2005-09-30 Paul McCullagh
23
#ifndef __xt_index_h__
24
#define __xt_index_h__
27
#include <drizzled/definitions.h>
28
#include <drizzled/sql_bitmap.h>
29
#include <drizzled/field.h>
30
using drizzled::Field;
32
#include <mysql_version.h>
33
#include <my_bitmap.h>
37
#include "thread_xt.h"
38
#include "linklist_xt.h"
39
#include "datalog_xt.h"
40
#include "datadic_xt.h"
42
#ifndef MYSQL_VERSION_ID
43
#error MYSQL_VERSION_ID must be defined!
46
//#define PRINT_IND_FLUSH_STATS
48
/* Define this to gather data on what area
49
* of an index page is being written.
51
#define IND_OPT_DATA_WRITTEN
53
#ifdef IND_OPT_DATA_WRITTEN
54
/* This is a debug switch that compares
55
* the contents of a cached page
56
* to the data just written to disk
58
* It requires information on what parts
59
* of the cache page have been changed.
61
//#define CHECK_IF_WRITE_WAS_OK
64
#ifdef IND_OPT_DATA_WRITTEN
65
/* Write only those parts of an index
66
* page that have been modified.
68
#define IND_WRITE_MIN_DATA
72
* Define this in order to complete write the
73
* end of an index page (i.e. unused space),
74
* if the next page to be written is the
75
* one that follows this page.
76
* Note that this does not work optimilly
77
* with the option to write minimum data.
79
//#define IND_FILL_BLOCK_TO_NEXT
81
/* Define this all writes to the index
82
* file should be in block sizes and on
85
//#define IND_WRITE_IN_BLOCK_SIZES
87
/* This is the block size used to write the index: */
88
#define IND_WRITE_BLOCK_SIZE XT_BLOCK_SIZE_FOR_DIRECT_IO
89
//#define IND_WRITE_BLOCK_SIZE (1024*1)
92
* Define this to skew the split of nodes
93
* when adding to the end of an index.
95
#define IND_SKEW_SPLIT_ON_APPEND
98
* The maximum amount of data to write before
99
* flushing the index file.
101
#define IND_FLUSH_THRESHOLD (512 * 1024 * 1024)
115
* When a transaction is rolled back, the index entries are not
116
* garbage collected!! Instead, the index entries are deleted
117
* when the data record is garbage collected.
119
* When an index record is written, and this record replaces
120
* some other record (i.e. a node is updated). The new record
121
* references its predecessor.
123
* On cleanup (rollback or commit), the predecessor records
124
* are garbage collected.
126
* NOTE: It is possible to loose memory if a crash occurs during
127
* index modification. This can occur if a node is split and
128
* we crash between writing the 2 new records.
133
* These flags influence the way the compare and search
136
* The low-order 16 bits are reserved for the caller
137
* (i.e. MySQL specific stuff).
139
#define XT_SEARCH_WHOLE_KEY 0x10000000 /* This flag is used to search for an insertion point, or to find
140
* a particular slot that has already been inserted into the
141
* index. The compare includes the handle of the variation.
143
#define XT_SEARCH_AFTER_KEY 0x20000000 /* This flags searches for the position just after the given key.
144
* Even if the key is not found, success is possible if there
145
* is a value in the index that would be after the search key.
147
* If this flag is not set then we search for the first
148
* occurrence of the key in the index. If not found we
149
* take the position just after the search key.
151
#define XT_SEARCH_FIRST_FLAG 0x40000000 /* Use this flags to find the first position in the index.
152
* When set, the actual key value is ignored.
154
#define XT_SEARCH_AFTER_LAST_FLAG 0x80000000 /* Search out the position after the last in the index.
155
* When set, the actual key value is ignored.
158
#define XT_INDEX_MAX_KEY_SIZE_MAX 2048 /* These are allocated on the stack, so this is the maximum! */
160
#define XT_INDEX_MAX_KEY_SIZE ((XT_INDEX_PAGE_SIZE >> 1) > XT_INDEX_MAX_KEY_SIZE_MAX ? XT_INDEX_MAX_KEY_SIZE_MAX : (XT_INDEX_PAGE_SIZE >> 1))
162
#define XT_IS_NODE_BIT 0x8000
164
#define XT_IS_NODE(x) ((x) & XT_IS_NODE_BIT)
166
#define XT_NODE_REF_SIZE 4
167
#define XT_GET_NODE_REF(t, x) XT_RET_NODE_ID(XT_GET_DISK_4(x))
168
#define XT_SET_NODE_REF(t, x, y) XT_SET_DISK_4((x), XT_NODE_ID(y))
170
#define XT_MAX_RECORD_REF_SIZE 8
172
#define XT_INDEX_PAGE_HEAD_SIZE offsetof(XTIdxBranchDRec, tb_data)
173
#define XT_INDEX_PAGE_DATA_SIZE (XT_INDEX_PAGE_SIZE - 2) // XT_INDEX_PAGE_HEAD_SIZE == 2!
175
#define XT_MAKE_LEAF_SIZE(x) ((x) + XT_INDEX_PAGE_HEAD_SIZE)
177
#define XT_MAKE_NODE_SIZE(x) (((x) + XT_INDEX_PAGE_HEAD_SIZE) | XT_IS_NODE_BIT)
179
#define XT_MAKE_BRANCH_SIZE(x, y) (((x) + XT_INDEX_PAGE_HEAD_SIZE) | ((y) ? XT_IS_NODE_BIT : 0))
181
#define XT_GET_INDEX_BLOCK_LEN(x) ((x) & 0x7FFF)
183
#define XT_GET_BRANCH_DATA_SIZE(x) (XT_GET_INDEX_BLOCK_LEN(x) - XT_INDEX_PAGE_HEAD_SIZE)
185
#define XT_DIRTY_BLOCK_LIST_SIZE 4096
187
typedef struct XTIndexHead {
188
XTDiskValue4 tp_format_offset_4; /* The offset of the format part of the header. */
190
XTDiskValue4 tp_header_size_4; /* The size of the header. */
191
XTDiskValue6 tp_not_used_6;
193
XTDiskValue6 tp_ind_eof_6;
194
XTDiskValue6 tp_ind_free_6;
196
/* The index roots follow. Each is if_node_ref_size_1 size. */
197
xtWord1 tp_data[XT_VAR_LENGTH];
198
} XTIndexHeadDRec, *XTIndexHeadDPtr;
200
typedef struct XTIndexFormat {
201
XTDiskValue4 if_format_size_4; /* The size of this structure (index format). */
202
XTDiskValue2 if_tab_version_2; /* The table version number. */
203
XTDiskValue2 if_ind_version_2; /* The index version number. */
204
XTDiskValue1 if_node_ref_size_1; /* This size of index node reference in indexes (default 4 bytes). */
205
XTDiskValue1 if_rec_ref_size_1; /* The size of record references in the indexes (default 4 bytes). */
206
XTDiskValue4 if_page_size_4;
207
} XTIndexFormatDRec, *XTIndexFormatDPtr;
209
typedef struct XTIdxBranch {
210
XTDiskValue2 tb_size_2; /* No of bytes used below. */
212
/* We enough space for 2 buffers when splitting! */
213
xtWord1 tb_data[XT_INDEX_PAGE_DATA_SIZE];
214
} XTIdxBranchDRec, *XTIdxBranchDPtr;
216
typedef struct XTIdxItem {
217
u_int i_total_size; /* Size of the data in the searched branch (excludes 2 byte header). */
218
u_int i_item_size; /* Size of the item at this position. */
219
u_int i_node_ref_size;
220
u_int i_item_offset; /* Item offset. */
221
} XTIdxItemRec, *XTIdxItemPtr;
223
typedef struct XTIdxResult {
224
xtBool sr_found; /* TRUE if the key was found. */
225
xtBool sr_duplicate; /* TRUE if the duplicate was found. */
226
xtBool sr_last_item; /* TRUE if the last item was found. */
227
xtRecordID sr_rec_id; /* Reference to the record of the found key. */
229
xtIndexNodeID sr_branch; /* Branch to follow when searching a node. */
230
XTIdxItemRec sr_item;
231
} XTIdxResultRec, *XTIdxResultPtr;
233
typedef struct XTIdxKeyValue {
235
xtRecordID sv_rec_id;
239
} XTIdxKeyValueRec, *XTIdxKeyValuePtr;
241
typedef struct XTIdxSearchKey {
242
xtBool sk_on_key; /* TRUE if we are positioned on the search key. */
243
XTIdxKeyValueRec sk_key_value; /* The value of the search key. */
244
xtWord1 sk_key_buf[XT_INDEX_MAX_KEY_SIZE];
245
} XTIdxSearchKeyRec, *XTIdxSearchKeyPtr;
247
typedef void (*XTScanBranchFunc)(struct XTTable *tab, struct XTIndex *ind, XTIdxBranchDPtr branch, register XTIdxKeyValuePtr value, register XTIdxResultRec *result);
248
typedef void (*XTPrevItemFunc)(struct XTTable *tab, struct XTIndex *ind, XTIdxBranchDPtr branch, register XTIdxResultRec *result);
249
typedef void (*XTLastItemFunc)(struct XTTable *tab, struct XTIndex *ind, XTIdxBranchDPtr branch, register XTIdxResultRec *result);
251
typedef int (*XTSimpleCompFunc)(struct XTIndex *ind, u_int key_length, xtWord1 *key_value, xtWord1 *b_value);
256
struct charset_info_st;
258
using drizzled::charset_info_st;
260
struct charset_info_st;
263
typedef struct XTIndexSeg /* Key-portion */
265
u_int col_idx; /* The table column index of this component. */
266
u_int is_recs_in_range; /* Value returned by records_in_range(). */
267
u_int is_selectivity; /* The number of unique values per mi_select_total. */
268
xtWord1 type; /* Type of key (for sort) */
270
xtWord1 null_bit; /* bitmask to test for NULL */
271
xtWord1 bit_start,bit_end; /* if bit field */
272
xtWord1 bit_pos,bit_length; /* (not used in 4.1) */
274
xtWord2 length; /* Keylength */
275
xtWord4 start; /* Start of key in record */
276
xtWord4 null_pos; /* position to NULL indicator */
277
MX_CONST_CHARSET_INFO *charset;
278
} XTIndexSegRec, *XTIndexSegPtr;
280
typedef struct XTIndFreeList {
281
struct XTIndFreeList *fl_next_list; /* List of free pages for this index. */
282
u_int fl_start; /* Start for allocating from the front of the list. */
283
u_int fl_free_count; /* Total items in the free list. */
284
xtIndexNodeID fl_page_id[XT_VAR_LENGTH]; /* List of page ID's of the free pages. */
285
} XTIndFreeListRec, *XTIndFreeListPtr;
287
typedef struct XTIndDirtyBlocks {
288
struct XTIndDirtyBlocks *db_next;
289
struct XTIndBlock *db_blocks[XT_DIRTY_BLOCK_LIST_SIZE];
290
} XTIndDirtyBlocksRec, *XTIndDirtyBlocksPtr;
292
typedef struct XTIndDirtyListItor {
295
XTIndDirtyBlocksPtr dli_list;
302
} XTIndDirtyListItorRec, *XTIndDirtyListItorPtr;
304
typedef struct XTIndDirtyList {
305
u_int dl_total_blocks; /* Count of the dirty blocks. */
306
u_int dl_list_usage; /* The number of elements used in the first block list: */
307
XTIndDirtyBlocksPtr dl_block_lists; /* A chain of dirty blocks. */
309
xtBool dl_add_block(struct XTIndBlock *block);
310
void dl_sort_blocks();
313
inline struct XTIndBlock *dl_next_block(XTIndDirtyListItorPtr it) {
314
struct XTIndBlock *block;
316
if (it->dli_i == it->dli_count) {
318
it->dli_count = XT_DIRTY_BLOCK_LIST_SIZE;
319
it->dli_list = it->dli_list->db_next;
322
it->dli_count = dl_list_usage;
323
it->dli_list = dl_block_lists;
330
block = it->dli_list->db_blocks[it->dli_i];
334
} XTIndDirtyListRec, *XTIndDirtyListPtr;
337
* XT_INDEX_USE_PTHREAD_RW:
338
* The stardard pthread RW lock is currently the fastest for INSERTs
339
* in 32 threads on smalltab: runTest(SMALL_INSERT_TEST, 32, dbUrl)
342
* XT_INDEX_USE_RWMUTEX:
343
* But the RW mutex is a close second, if not just as fast.
344
* If it is at least as fast, then it is better because read lock
345
* overhead is then zero.
347
* If definitely does get in the way of the
349
/* XT_INDEX_USE_PTHREAD_RW:
350
* But this is clearly better on Linux. 216682 instead of 169259
351
* payment transactions (DBT2 in non-conflict transactions,
352
* using only the customer table).
355
* The story continues. I have now fixed a bug in RW MUTEX that
356
* may have been slowing things down (see {RACE-WR_MUTEX}).
358
* So we will need to test "customer payment" again.
361
* Latest test show that RW mutex is slightly faster:
362
* 127460 to 123574 payment transactions.
366
#define XT_INDEX_USE_PTHREAD_RW
368
//#define XT_INDEX_USE_PTHREAD_RW
369
#define XT_TAB_ROW_USE_XSMUTEX
370
//#define XT_INDEX_SPINXSLOCK
373
#if defined(XT_INDEX_USE_PTHREAD_RW)
374
#define XT_INDEX_LOCK_TYPE xt_rwlock_type
375
#define XT_INDEX_INIT_LOCK(s, i) xt_init_rwlock_with_autoname(s, &(i)->mi_rwlock)
376
#define XT_INDEX_FREE_LOCK(s, i) xt_free_rwlock(&(i)->mi_rwlock)
377
#define XT_INDEX_READ_LOCK(i, o) do { xt_slock_rwlock_ns(&(i)->mi_rwlock); (void) (o); } while(0)
378
#define XT_INDEX_WRITE_LOCK(i, o) do { xt_xlock_rwlock_ns(&(i)->mi_rwlock); (void) (o); } while(0)
379
#define XT_INDEX_UNLOCK(i, o) do { xt_unlock_rwlock_ns(&(i)->mi_rwlock); (void) (o); } while(0)
380
#define XT_INDEX_HAVE_XLOCK(i, o) TRUE
381
#elif defined(XT_TAB_ROW_USE_XSMUTEX)
382
#define XT_INDEX_LOCK_TYPE XTMutexXSLockRec
383
#define XT_INDEX_INIT_LOCK(s, i) xt_xsmutex_init_with_autoname(s, &(i)->mi_rwlock)
384
#define XT_INDEX_FREE_LOCK(s, i) xt_xsmutex_free(s, &(i)->mi_rwlock)
385
#define XT_INDEX_READ_LOCK(i, o) xt_xsmutex_slock(&(i)->mi_rwlock, (o)->ot_thread->t_id)
386
#define XT_INDEX_WRITE_LOCK(i, o) xt_xsmutex_xlock(&(i)->mi_rwlock, (o)->ot_thread->t_id)
387
#define XT_INDEX_UNLOCK(i, o) xt_xsmutex_unlock(&(i)->mi_rwlock, (o)->ot_thread->t_id)
388
#define XT_INDEX_HAVE_XLOCK(i, o) ((i)->sxs_xlocker == (o)->ot_thread->t_id)
389
#elif defined(XT_INDEX_SPINXSLOCK)
390
#define XT_INDEX_LOCK_TYPE XTSpinXSLockRec
391
#define XT_INDEX_INIT_LOCK(s, i) xt_spinxslock_init_with_autoname(s, &(i)->mi_rwlock)
392
#define XT_INDEX_FREE_LOCK(s, i) xt_spinxslock_free(s, &(i)->mi_rwlock)
393
#define XT_INDEX_READ_LOCK(i, o) xt_spinxslock_slock(&(i)->mi_rwlock, (o)->ot_thread->t_id)
394
#define XT_INDEX_WRITE_LOCK(i, o) xt_spinxslock_xlock(&(i)->mi_rwlock, FALSE, (o)->ot_thread->t_id)
395
#define XT_INDEX_UNLOCK(i, o) xt_spinxslock_unlock(&(i)->mi_rwlock, (o)->ot_thread->t_id)
396
#define XT_INDEX_HAVE_XLOCK(i, o) ((i)->mi_rwlock.nrw_xlocker == (o)->ot_thread->t_id)
398
#error Please define the lock type
401
/* The R/W lock on the index is used as follows:
402
* Read Lock - used for operations on the index that are not of a structural nature.
403
* This includes any read operation and update operations that change an index
405
* Write lock - used to change the structure of the index. This includes adding
406
* and deleting pages.
408
typedef struct XTIndex {
409
u_int mi_index_no; /* The index number (used by MySQL). */
411
/* Protected by the mi_rwlock lock: */
412
XT_INDEX_LOCK_TYPE mi_rwlock; /* This lock protects the structure of the index.
413
* Read lock - structure may not change, but pages may change.
414
* Write lock - structure of index may be changed.
416
xtIndexNodeID mi_root; /* The index root node. */
417
XTIndFreeListPtr mi_free_list; /* List of free pages for this index. */
419
/* Protected by the mi_dirty_lock: */
420
XTSpinLockRec mi_dirty_lock; /* Spin lock protecting the dirty & free lists. */
421
struct XTIndBlock *mi_dirty_list; /* List of dirty pages for this index. */
422
u_int mi_dirty_blocks; /* Count of the dirty blocks. */
424
/* Index contants: */
427
u_int mi_max_items; /* The maximum number of items that can fit in a leaf node. */
428
xtBool mi_key_corrupted; /* Set to TRUE if a currupted index key is detected. */
430
xtBool mi_lazy_delete; /* TRUE if index entries are "lazy deleted". */
431
u_int mi_single_type; /* Used when the index contains a single field. */
432
u_int mi_select_total;
433
XTScanBranchFunc mi_scan_branch;
434
XTPrevItemFunc mi_prev_item;
435
XTLastItemFunc mi_last_item;
436
XTSimpleCompFunc mi_simple_comp_key;
437
MX_BITMAP mi_col_map; /* Bit-map of columns in the index. */
438
u_int mi_subset_of; /* Indicates if this index is a complete subset of someother index. */
440
XTIndexSegRec mi_seg[200];
441
} XTIndexRec, *XTIndexPtr;
443
#define XT_INDEX_OK 0
444
#define XT_INDEX_TOO_OLD 1
445
#define XT_INDEX_TOO_NEW 2
446
#define XT_INDEX_BAD_BLOCK 3
447
#define XT_INDEX_CORRUPTED 4
448
#define XT_INDEX_MISSING 5
449
#define XT_INDEX_NOT_RECOVERED 6
451
typedef void (*XTFreeDicFunc)(struct XTThread *self, struct XTDictionary *dic);
453
typedef struct XTDictionary {
454
XTDDTable *dic_table; /* XT table information. */
456
/* Table binary information. */
457
u_int dic_mysql_buf_size; /* This is the size of the MySQL buffer (row size + null bytes). */
458
u_int dic_mysql_rec_size; /* This is the size of the fixed length MySQL row. */
459
u_int dic_rec_size; /* This is the size of the handle data file record. */
460
xtBool dic_rec_fixed; /* TRUE if the record has a fixed length size. */
461
u_int dic_tab_flags; /* Table flags: XT_TF_MEMORY_TABLE, XT_TF_MEMORY_TABLE. */
462
xtWord8 dic_min_auto_inc; /* The minimum auto-increment value. */
463
xtWord8 dic_min_row_size;
464
xtWord8 dic_max_row_size;
465
xtWord8 dic_ave_row_size;
466
xtWord8 dic_def_ave_row_size; /* Defined row size set by the user. */
467
u_int dic_no_of_cols; /* Number of columns. */
468
u_int dic_fix_col_count; /* The number of columns always in the fixed part of a extended record. */
469
u_int dic_ind_cols_req; /* The number of columns required to build all indexes. */
470
xtWord8 dic_ind_rec_len; /* Length of the record part that is needed for all index columns! */
473
u_int dic_blob_cols_req; /* The number of the columns required to load all LONGBLOB columns. */
474
u_int dic_blob_count;
475
Field **dic_blob_cols;
477
/* MySQL related information. NULL when no tables are open from MySQL side! */
478
xtBool dic_no_lazy_delete; /* FALSE if lazy delete is OK. */
479
u_int dic_disable_index; /* Non-zero if the index cannot be used. */
480
u_int dic_index_ver; /* The version of the index. */
482
XTIndexPtr *dic_keys; /* MySQL/PBXT key description */
483
xtWord1 dic_table_type; /* XT_TABLE_TYPE_VALUE, so far used only in Drizzled */
484
STRUCT_TABLE *dic_my_table; /* MySQL table */
485
} XTDictionaryRec, *XTDictionaryPtr;
487
#define XT_DT_LOG_HEAD 0
488
#define XT_DT_INDEX_PAGE 1
489
#define XT_DT_FREE_LIST 2
490
#define XT_DT_HEADER 3
491
#define XT_DT_SHORT_IND_PAGE 4
492
#define XT_DT_MOD_IND_PAGE 5
493
#define XT_DT_MOD_IND_PAGE_HEAD 6
494
#define XT_DT_SET_PAGE_HEAD 7
495
#define XT_DT_2_MOD_IND_PAGE 8
496
#define XT_DT_MOD_IND_PAGE_EOB 9
497
#define XT_DT_MOD_IND_PAGE_HEAD_EOB 10
498
#define XT_DT_2_MOD_IND_PAGE_EOB 11
500
typedef struct XTIndLogHead {
501
xtWord1 ilh_data_type; /* XT_DT_LOG_HEAD */
502
XTDiskValue4 ilh_tab_id_4;
503
XTDiskValue4 ilh_log_eof_4; /* The entire size of the log (0 if invalid!) */
504
} XTIndLogHeadDRec, *XTIndLogHeadDPtr;
506
typedef struct XTIndPageData {
507
xtWord1 ild_data_type;
508
XTDiskValue4 ild_page_id_4;
509
xtWord1 ild_data[XT_VAR_LENGTH];
510
} XTIndPageDataDRec, *XTIndPageDataDPtr;
512
typedef struct XTIndHeadData {
513
xtWord1 ilh_data_type;
514
XTDiskValue2 ilh_head_size_2;
515
xtWord1 ilh_data[XT_VAR_LENGTH];
516
} XTIndHeadDataDRec, *XTIndHeadDataDPtr;
518
typedef struct XTIndSetPageHeadData {
519
xtWord1 ild_data_type; /* XT_DT_SET_PAGE_HEAD */
520
XTDiskValue4 ild_page_id_4;
521
XTDiskValue2 ild_page_head_2; /* The page header (first 2 bytes) */
522
} XTIndSetPageHeadDataDRec, *XTIndSetPageHeadDataDPtr;
524
typedef struct XTIndShortPageData {
525
xtWord1 ild_data_type; /* XT_DT_SHORT_IND_PAGE */
526
XTDiskValue4 ild_page_id_4;
527
XTDiskValue2 ild_size_2; /* Size of the data. */
528
xtWord1 ild_data[XT_VAR_LENGTH];
529
} XTIndShortPageDataDRec, *XTIndShortPageDataDPtr;
531
typedef struct XTIndModPageData {
532
xtWord1 ild_data_type; /* XT_DT_MOD_IND_PAGE */
533
XTDiskValue4 ild_page_id_4;
534
XTDiskValue2 ild_size_2; /* Size of the data. */
535
XTDiskValue2 ild_offset_2; /* Offset into the page. */
536
xtWord1 ild_data[XT_VAR_LENGTH];
537
} XTIndModPageDataDRec, *XTIndModPageDataDPtr;
539
typedef struct XTIndModPageHeadData {
540
xtWord1 ild_data_type; /* XT_DT_MOD_IND_PAGE_HEAD/XT_DT_MOD_IND_PAGE_HEAD_EOB */
541
XTDiskValue4 ild_page_id_4;
542
XTDiskValue2 ild_size_2; /* Size of the data. */
543
XTDiskValue2 ild_offset_2; /* Offset into the page. */
544
XTDiskValue2 ild_page_head_2; /* The page header (first 2 bytes) */
545
xtWord1 ild_data[XT_VAR_LENGTH];
546
} XTIndModPageHeadDataDRec, *XTIndModPageHeadDataDPtr;
548
typedef struct XTIndDoubleModPageData {
549
xtWord1 dld_data_type; /* XT_DT_2_MOD_IND_PAGE/XT_DT_2_MOD_IND_PAGE_EOB */
550
XTDiskValue4 dld_page_id_4;
551
XTDiskValue2 dld_size1_2; /* Size of the first data block, offset 0. */
552
XTDiskValue2 dld_offset2_2; /* Offset of second data block. */
553
XTDiskValue2 dld_size2_2; /* Size of the second data block. */
554
xtWord1 dld_data[XT_VAR_LENGTH];
555
} XTIndDoubleModPageDataDRec, *XTIndDoubleModPageDataDPtr;
557
typedef struct XTIndexLog {
558
struct XTIndexLogPool *il_pool;
559
struct XTIndexLog *il_next_in_pool;
561
xtLogID il_log_id; /* The ID of the data log. */
563
size_t il_buffer_size;
568
size_t il_buffer_len;
569
off_t il_buffer_offset;
570
XTSpinLockRec il_write_lock;
571
size_t il_bytes_written;
573
xtBool il_reset(struct XTOpenTable *ot);
574
void il_close(xtBool delete_it);
576
xtBool il_data_written();
578
xtBool il_write_byte(struct XTOpenTable *ot, xtWord1 val);
579
xtBool il_write_word4(struct XTOpenTable *ot, xtWord4 value);
580
xtBool il_write_block(struct XTOpenTable *ot, struct XTIndBlock *block);
581
xtBool il_write_free_list(struct XTOpenTable *ot, u_int free_count, XTIndFreeListPtr free_list);
582
xtBool il_require_space(size_t bytes, XTThreadPtr thread);
583
xtBool il_write_header(struct XTOpenTable *ot, size_t head_size, xtWord1 *head_data);
584
xtBool il_flush(struct XTOpenTable *ot);
585
xtBool il_apply_log_write(struct XTOpenTable *ot);
586
xtBool il_apply_log_flush(struct XTOpenTable *ot);
587
inline xtBool il_pwrite_file(struct XTOpenTable *ot, off_t offs, size_t siz, void *dat);
588
inline xtBool il_flush_file(struct XTOpenTable *ot);
590
xtBool il_open_table(struct XTOpenTable **ot);
591
void il_close_table(struct XTOpenTable *ot);
592
} XTIndexLogRec, *XTIndexLogPtr;
594
typedef struct XTIndexLogPool {
595
struct XTDatabase *ilp_db;
596
size_t ilp_log_buffer_size;
598
XTIndexLogPtr ilp_log_pool;
599
xt_mutex_type ilp_lock; /* The public pool lock. */
600
xtLogID ilp_next_log_id;
602
void ilp_init(struct XTThread *self, struct XTDatabase *db, size_t log_buffer_size);
603
void ilp_close(struct XTThread *self, xtBool lock);
604
void ilp_exit(struct XTThread *self);
605
void ilp_name(size_t size, char *path, xtLogID log_id);
607
xtBool ilp_open_log(XTIndexLogPtr *il, xtLogID log_id, xtBool excl, XTThreadPtr thread);
609
xtBool ilp_get_log(XTIndexLogPtr *il, XTThreadPtr thread);
610
void ilp_release_log(XTIndexLogPtr il);
611
} XTIndexLogPoolRec, *XTIndexLogPoolPtr;
613
class XTFlushIndexTask : public XTLockTask {
615
XTFlushIndexTask() : XTLockTask(),
617
fit_checkpoint(FALSE),
619
fit_blocks_flushed(0)
622
virtual xtBool tk_task(XTThreadPtr thread);
623
virtual void tk_reference();
624
virtual void tk_release();
626
struct XTTable *fit_table;
627
xtBool fit_checkpoint;
628
u_int fit_dirty_blocks; /* The number of dirty blocks being flushed! */
629
u_int fit_blocks_flushed;
632
/* A record reference consists of a record ID and a row ID: */
633
inline void xt_get_record_ref(register xtWord1 *item, xtRecordID *rec_id, xtRowID *row_id) {
634
*rec_id = XT_GET_DISK_4(item);
636
*row_id = XT_GET_DISK_4(item);
639
inline void xt_get_res_record_ref(register xtWord1 *item, register XTIdxResultRec *result) {
640
result->sr_rec_id = XT_GET_DISK_4(item);
642
result->sr_row_id = XT_GET_DISK_4(item);
645
inline void xt_set_record_ref(register xtWord1 *item, xtRecordID rec_id, xtRowID row_id) {
646
XT_SET_DISK_4(item, rec_id);
648
XT_SET_DISK_4(item, row_id);
651
inline void xt_set_val_record_ref(register xtWord1 *item, register XTIdxKeyValuePtr value) {
652
XT_SET_DISK_4(item, value->sv_rec_id);
654
XT_SET_DISK_4(item, value->sv_row_id);
657
xtBool xt_idx_insert(struct XTOpenTable *ot, struct XTIndex *ind, xtRowID row_id, xtRecordID rec_id, xtWord1 *rec_buf, xtWord1 *bef_buf, xtBool allow_dups);
658
xtBool xt_idx_delete(struct XTOpenTable *ot, struct XTIndex *ind, xtRecordID rec_id, xtWord1 *rec_buf);
659
xtBool xt_idx_update_row_id(struct XTOpenTable *ot, struct XTIndex *ind, xtRecordID rec_id, xtRowID row_id, xtWord1 *rec_buf);
660
void xt_idx_prep_key(struct XTIndex *ind, register XTIdxSearchKeyPtr search_key, int flags, xtWord1 *in_key_buf, size_t in_key_length);
661
xtBool xt_idx_research(struct XTOpenTable *ot, struct XTIndex *ind);
662
xtBool xt_idx_search(struct XTOpenTable *ot, struct XTIndex *ind, register XTIdxSearchKeyPtr search_key);
663
xtBool xt_idx_search_prev(struct XTOpenTable *ot, struct XTIndex *ind, register XTIdxSearchKeyPtr search_key);
664
xtBool xt_idx_next(register struct XTOpenTable *ot, register struct XTIndex *ind, register XTIdxSearchKeyPtr search_key);
665
xtBool xt_idx_prev(register struct XTOpenTable *ot, register struct XTIndex *ind, register XTIdxSearchKeyPtr search_key);
666
xtBool xt_idx_read(struct XTOpenTable *ot, struct XTIndex *ind, xtWord1 *rec_buf);
667
void xt_ind_set_index_selectivity(struct XTOpenTable *ot, XTThreadPtr thread);
668
void xt_check_indices(struct XTOpenTable *ot);
669
void xt_load_indices(XTThreadPtr self, struct XTOpenTable *ot);
670
void xt_ind_count_deleted_items(struct XTTable *ot, struct XTIndex *ind, struct XTIndBlock *block);
671
xtBool xt_async_flush_indices(struct XTTable *tab, xtBool notify_complete, xtBool notify_before_write, struct XTThread *thread);
672
xtBool xt_flush_indices(struct XTOpenTable *ot, off_t *bytes_flushed, xtBool have_table_lock, XTFlushIndexTask *ft);
673
void xt_ind_track_dump_block(struct XTTable *tab, xtIndexNodeID address);
675
#define XT_S_MODE_MATCH 0
676
#define XT_S_MODE_NEXT 1
677
#define XT_S_MODE_PREV 2
678
xtBool xt_idx_match_search(struct XTOpenTable *ot, struct XTIndex *ind, register XTIdxSearchKeyPtr search_key, xtWord1 *buf, int mode);
680
int xt_compare_2_int4(XTIndexPtr ind, uint key_length, xtWord1 *key_value, xtWord1 *b_value);
681
int xt_compare_3_int4(XTIndexPtr ind, uint key_length, xtWord1 *key_value, xtWord1 *b_value);
682
void xt_scan_branch_single(struct XTTable *tab, XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxKeyValuePtr value, register XTIdxResultRec *result);
683
void xt_scan_branch_fix(struct XTTable *tab, XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxKeyValuePtr value, register XTIdxResultRec *result);
684
void xt_scan_branch_fix_simple(struct XTTable *tab, XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxKeyValuePtr value, register XTIdxResultRec *result);
685
void xt_scan_branch_var(struct XTTable *tab, XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxKeyValuePtr value, register XTIdxResultRec *result);
687
void xt_prev_branch_item_fix(struct XTTable *tab, XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxResultRec *result);
688
void xt_prev_branch_item_var(struct XTTable *tab, XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxResultRec *result);
690
void xt_last_branch_item_fix(struct XTTable *tab, XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxResultPtr result);
691
void xt_last_branch_item_var(struct XTTable *tab, XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxResultPtr result);
692
xtBool xt_idx_lazy_delete_on_leaf(XTIndexPtr ind, struct XTIndBlock *block, xtWord2 branch_size);
694
//#define TRACK_ACTIVITY
695
#ifdef TRACK_ACTIVITY
697
#define TRACK_BLOCK_ALLOC(x) track_work(xt_ind_offset_to_node(tab, x), "A")
698
#define TRACK_BLOCK_FREE(x) track_work(xt_ind_offset_to_node(ot->ot_table, x), "-")
699
#define TRACK_BLOCK_SPLIT(x) track_work(xt_ind_offset_to_node(ot->ot_table, x), "/")
700
#define TRACK_BLOCK_WRITE(x) track_work(xt_ind_offset_to_node(ot->ot_table, x), "w")
701
#define TRACK_BLOCK_FLUSH_N(x) track_work(x, "F")
702
#define TRACK_BLOCK_TO_FLUSH(x) track_work(x, "f")
704
xtPublic void track_work(u_int block, char *what);
707
#define TRACK_BLOCK_ALLOC(x)
708
#define TRACK_BLOCK_FREE(x)
709
#define TRACK_BLOCK_SPLIT(x)
710
#define TRACK_BLOCK_WRITE(x)
711
#define TRACK_BLOCK_FLUSH_N(x)
712
#define TRACK_BLOCK_TO_FLUSH(x)