95
#define xt_dc_write(x, y, z, a) (!key_cache_write(&my_cache, (x)->of_filedes, y, 3, (byte *) (a), XT_IDX_PAGE_SIZE, 1024, 1))
96
#define xt_ind_write(x, y, z, a) (!key_cache_write(&my_cache, (x)->of_filedes, y, 3, (byte *) (a), XT_INDEX_PAGE_SIZE, 1024, 1))
97
#define xt_dc_read(x, y, z, a) (key_cache_read(&my_cache, (x)->of_filedes, y, 3, (byte *) (a), z, 1024, 0) ? 1 : my_set_mem((xtWord1 *) (a), z))
98
#define xt_ind_read(x, y, z, a) (key_cache_read(&my_cache, (x)->of_filedes, y, 3, (byte *) (a), z, 1024, 0) ? 1 : my_set_mem((xtWord1 *) (a), z))
153
154
register XTTableHPtr tab = ot->ot_table;
156
xt_mutex_lock(&tab->tab_ind_lock);
157
xt_lock_mutex_ns(&tab->tab_ind_lock);
157
158
if ((wrote_pos = tab->tab_ind_free)) {
158
159
/* Use the block on the free list: */
159
160
IdxFreeBlockRec free_block;
161
if (!xt_dc_read(ot->ot_ind_file, wrote_pos, sizeof(IdxFreeBlockRec), (xtWord1 *) &free_block))
162
if (!xt_ind_read(ot->ot_ind_file, wrote_pos, sizeof(IdxFreeBlockRec), (xtWord1 *) &free_block))
163
164
tab->tab_ind_free = XT_GET_DISK_8(free_block.if_next_block_8);
164
tab->tab_head_dirty = TRUE;
165
xt_mutex_unlock(&tab->tab_ind_lock);
165
tab->tab_ind_head_dirty = TRUE;
166
xt_unlock_mutex_ns(&tab->tab_ind_lock);
167
168
*address = wrote_pos;
171
172
/* PMC - Dont allow overflow! */
172
if (tab->tab_ind_eof >= ( ((xtWord8) 1) << (32 + XT_IDX_PAGE_SHIFTS) ) ) {
173
if (tab->tab_ind_eof >= ( ((xtWord8) 1) << (32 + XT_INDEX_PAGE_SHIFTS) ) ) {
173
174
xt_register_ixterr(XT_REG_CONTEXT, XT_ERR_INDEX_FILE_TO_LARGE, xt_file_path(ot->ot_ind_file));
176
177
*address = tab->tab_ind_eof;
177
tab->tab_ind_eof += XT_IDX_PAGE_SIZE;
178
tab->tab_head_dirty = TRUE;
178
tab->tab_ind_eof += XT_INDEX_PAGE_SIZE;
179
tab->tab_ind_head_dirty = TRUE;
180
xt_mutex_unlock(&tab->tab_ind_lock);
181
xt_unlock_mutex_ns(&tab->tab_ind_lock);
184
xt_mutex_unlock(&tab->tab_ind_lock);
185
xt_unlock_mutex_ns(&tab->tab_ind_lock);
190
191
register XTTableHPtr tab = ot->ot_table;
191
192
IdxFreeBlockRec free_block = { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } };
193
xt_mutex_lock(&tab->tab_ind_lock);
194
xt_lock_mutex_ns(&tab->tab_ind_lock);
195
196
/* Use the block on the free list: */
196
197
XT_SET_DISK_8(free_block.if_next_block_8, tab->tab_ind_free);
197
if (!xt_dc_write(ot->ot_ind_file, address, sizeof(IdxFreeBlockRec), (xtWord1 *) &free_block))
198
if (!xt_ind_write(ot->ot_ind_file, address, sizeof(IdxFreeBlockRec), (xtWord1 *) &free_block))
199
200
tab->tab_ind_free = address;
200
tab->tab_head_dirty = TRUE;
201
xt_mutex_unlock(&tab->tab_ind_lock);
201
tab->tab_ind_head_dirty = TRUE;
202
xt_unlock_mutex_ns(&tab->tab_ind_lock);
205
xt_mutex_unlock(&tab->tab_ind_lock);
206
xt_unlock_mutex_ns(&tab->tab_ind_lock);
210
211
* -----------------------------------------------------------------------
212
* Simple compare functions
215
xtPublic int xt_compare_2_int4(XTIndexPtr ind, uint key_length, xtWord1 *key_value, xtWord1 *b_value)
219
ASSERT_NS(key_length == 4 || key_length == 8);
220
r = (xtInt4) XT_GET_DISK_4(key_value) - (xtInt4) XT_GET_DISK_4(b_value);
221
if (r == 0 && key_length > 4) {
224
r = (xtInt4) XT_GET_DISK_4(key_value) - (xtInt4) XT_GET_DISK_4(b_value);
229
xtPublic int xt_compare_3_int4(XTIndexPtr ind, uint key_length, xtWord1 *key_value, xtWord1 *b_value)
233
ASSERT_NS(key_length == 4 || key_length == 8 || key_length == 12);
234
r = (xtInt4) XT_GET_DISK_4(key_value) - (xtInt4) XT_GET_DISK_4(b_value);
235
if (r == 0 && key_length > 4) {
238
r = (xtInt4) XT_GET_DISK_4(key_value) - (xtInt4) XT_GET_DISK_4(b_value);
239
if (r == 0 && key_length > 8) {
242
r = (xtInt4) XT_GET_DISK_4(key_value) - (xtInt4) XT_GET_DISK_4(b_value);
249
* -----------------------------------------------------------------------
211
250
* Tree branch sanning (searching nodes and leaves)
392
435
if (search_flags & XT_SEARCH_WHOLE_KEY) {
393
off_t item_record = XT_GET_RECORD_REF(bitem + ind->mi_key_size);
395
/* This should not happen because we should never
396
* try to insert the same record twice into the
399
result->sr_duplicate = TRUE;
400
if (key_record == item_record) {
401
result->sr_found = TRUE;
402
result->sr_record = item_record;
403
result->sr_branch = XT_GET_NODE_REF(bitem - node_ref_size);
404
result->sr_item.i_item_offset = node_ref_size + guess * full_item_size;
407
if (key_record < item_record)
413
result->sr_found = TRUE;
414
/* -1 causes a search to the beginning of the duplicate list of keys.
415
* 1 causes a search to just after the key.
417
if (search_flags & XT_SEARCH_AFTER_KEY)
431
bitem = base + i * full_item_size;
432
result->sr_record = XT_GET_RECORD_REF(bitem + ind->mi_key_size);
436
xtRecordID item_record;
439
xt_get_record_ref(bitem + ind->mi_key_size, &item_record, &row_id);
441
/* This should not happen because we should never
442
* try to insert the same record twice into the
445
result->sr_duplicate = TRUE;
446
if (key_record == item_record) {
447
result->sr_found = TRUE;
448
result->sr_rec_id = item_record;
449
result->sr_row_id = row_id;
450
result->sr_branch = XT_GET_NODE_REF(bitem - node_ref_size);
451
result->sr_item.i_item_offset = node_ref_size + guess * full_item_size;
454
if (key_record < item_record)
460
result->sr_found = TRUE;
461
/* -1 causes a search to the beginning of the duplicate list of keys.
462
* 1 causes a search to just after the key.
464
if (search_flags & XT_SEARCH_AFTER_KEY)
478
bitem = base + i * full_item_size;
479
xt_get_res_record_ref(bitem + ind->mi_key_size, result);
480
result->sr_branch = XT_GET_NODE_REF(bitem - node_ref_size); /* Only valid if this is a node. */
481
result->sr_item.i_item_offset = node_ref_size + i * full_item_size;
484
xtPublic void xt_scan_branch_fix_simple(XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxKeyValuePtr value, register XTIdxResultRec *result)
488
u_int full_item_size;
494
branch_size = XT_GET_DISK_2(branch->tb_size_2);
495
node_ref_size = XT_IS_NODE(branch_size) ? XT_NODE_REF_SIZE : 0;
497
result->sr_found = FALSE;
498
result->sr_duplicate = FALSE;
499
result->sr_item.i_total_size = XT_GET_BRANCH_DATA_SIZE(branch_size);
500
ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_INDEX_PAGE_SIZE-2);
502
result->sr_item.i_item_size = ind->mi_key_size + XT_RECORD_REF_SIZE;
503
full_item_size = result->sr_item.i_item_size + node_ref_size;
504
result->sr_item.i_node_ref_size = node_ref_size;
506
search_flags = value->sv_flags;
507
base = branch->tb_data + node_ref_size;
508
if (search_flags & XT_SEARCH_FIRST_FLAG)
510
else if (search_flags & XT_SEARCH_AFTER_LAST_FLAG)
511
i = (result->sr_item.i_total_size - node_ref_size) / full_item_size;
513
register u_int guess;
514
register u_int count;
515
xtRecordID key_record;
518
key_record = value->sv_rec_id;
519
count = (result->sr_item.i_total_size - node_ref_size) / full_item_size;
524
guess = (i + count - 1) >> 1;
526
bitem = base + guess * full_item_size;
528
r = ind->mi_simple_comp_key(ind, value->sv_length, value->sv_key, bitem);
531
if (search_flags & XT_SEARCH_WHOLE_KEY) {
532
xtRecordID item_record;
535
xt_get_record_ref(bitem + ind->mi_key_size, &item_record, &row_id);
537
/* This should not happen because we should never
538
* try to insert the same record twice into the
541
result->sr_duplicate = TRUE;
542
if (key_record == item_record) {
543
result->sr_found = TRUE;
544
result->sr_rec_id = item_record;
545
result->sr_row_id = row_id;
546
result->sr_branch = XT_GET_NODE_REF(bitem - node_ref_size);
547
result->sr_item.i_item_offset = node_ref_size + guess * full_item_size;
550
if (key_record < item_record)
556
result->sr_found = TRUE;
557
/* -1 causes a search to the beginning of the duplicate list of keys.
558
* 1 causes a search to just after the key.
560
if (search_flags & XT_SEARCH_AFTER_KEY)
574
bitem = base + i * full_item_size;
575
xt_get_res_record_ref(bitem + ind->mi_key_size, result);
433
576
result->sr_branch = XT_GET_NODE_REF(bitem - node_ref_size); /* Only valid if this is a node. */
434
577
result->sr_item.i_item_offset = node_ref_size + i * full_item_size;
699
846
static xtBool idx_remove_branch_item_right(XTOpenTablePtr ot, XTIndexPtr ind, off_t address, XTIdxBranchDPtr branch, register XTIdxItemPtr item)
848
u_int size = item->i_item_size + item->i_node_ref_size;
701
850
/* Remove the node reference to the left of the item: */
702
851
memmove(&branch->tb_data[item->i_item_offset],
703
&branch->tb_data[item->i_item_offset + item->i_item_size + item->i_node_ref_size],
704
item->i_total_size - item->i_item_offset - item->i_item_size - item->i_node_ref_size);
705
item->i_total_size -= (item->i_item_size + item->i_node_ref_size);
852
&branch->tb_data[item->i_item_offset + size],
853
item->i_total_size - item->i_item_offset - size);
854
item->i_total_size -= size;
706
855
XT_SET_DISK_2(branch->tb_size_2, XT_MAKE_BRANCH_SIZE(item->i_total_size, item->i_node_ref_size));
707
return xt_dc_write(ot->ot_ind_file, address, offsetof(XTIdxBranchDRec, tb_data) + item->i_total_size, (xtWord1 *) branch);
856
return xt_ind_write(ot->ot_ind_file, address, offsetof(XTIdxBranchDRec, tb_data) + item->i_total_size, (xtWord1 *) branch);
710
859
static xtBool idx_remove_branch_item_left(XTOpenTablePtr ot, XTIndexPtr ind, off_t address, XTIdxBranchDPtr branch, register XTIdxItemPtr item)
861
u_int size = item->i_item_size + item->i_node_ref_size;
712
863
/* Remove the node reference to the left of the item: */
713
864
memmove(&branch->tb_data[item->i_item_offset - item->i_node_ref_size],
714
865
&branch->tb_data[item->i_item_offset + item->i_item_size],
715
866
item->i_total_size - item->i_item_offset - item->i_item_size);
716
item->i_total_size -= (item->i_item_size + item->i_node_ref_size);
867
item->i_total_size -= size;
717
868
XT_SET_DISK_2(branch->tb_size_2, XT_MAKE_BRANCH_SIZE(item->i_total_size, item->i_node_ref_size));
718
return xt_dc_write(ot->ot_ind_file, address, offsetof(XTIdxBranchDRec, tb_data) + item->i_total_size, (xtWord1 *) branch);
869
return xt_ind_write(ot->ot_ind_file, address, offsetof(XTIdxBranchDRec, tb_data) + item->i_total_size, (xtWord1 *) branch);
721
872
static void idx_insert_leaf_item(XTIndexPtr ind, XTIdxBranchDPtr leaf, XTIdxKeyValuePtr value, XTIdxResultPtr result)
846
997
/* Split the node: */
847
998
new_size = result.sr_item.i_total_size - result.sr_item.i_item_offset - result.sr_item.i_item_size;
848
new_branch_ptr = (XTIdxBranchDPtr) &ot->ot_ind_wbuf.tb_data[XT_IDX_PAGE_DATA_SIZE];
999
new_branch_ptr = (XTIdxBranchDPtr) &ot->ot_ind_wbuf.tb_data[XT_INDEX_PAGE_DATA_SIZE];
849
1000
memmove(new_branch_ptr->tb_data, &ot->ot_ind_wbuf.tb_data[result.sr_item.i_item_offset + result.sr_item.i_item_size], new_size);
851
1002
XT_SET_DISK_2(new_branch_ptr->tb_size_2, XT_MAKE_NODE_SIZE(new_size));
852
if (!xt_dc_write(ot->ot_ind_file, new_branch, offsetof(XTIdxBranchDRec, tb_data) + new_size, (xtWord1 *) new_branch_ptr))
1003
if (!xt_ind_write(ot->ot_ind_file, new_branch, offsetof(XTIdxBranchDRec, tb_data) + new_size, (xtWord1 *) new_branch_ptr))
855
1006
/* Change the size of the old branch: */
856
1007
XT_SET_DISK_2(ot->ot_ind_wbuf.tb_size_2, XT_MAKE_NODE_SIZE(result.sr_item.i_item_offset));
857
if (!xt_dc_write(ot->ot_ind_file, current, offsetof(XTIdxBranchDRec, tb_data) + result.sr_item.i_item_offset, (xtWord1 *) &ot->ot_ind_wbuf))
1008
if (!xt_ind_write(ot->ot_ind_file, current, offsetof(XTIdxBranchDRec, tb_data) + result.sr_item.i_item_offset, (xtWord1 *) &ot->ot_ind_wbuf))
860
1011
/* Insert the new branch into the parent node, using the new middle key value: */
907
1058
ditem += XT_NODE_REF_SIZE;
908
1059
size = ditem - ot->ot_ind_wbuf.tb_data;
909
1060
XT_SET_DISK_2(ot->ot_ind_wbuf.tb_size_2, XT_MAKE_NODE_SIZE(size));
910
if (!xt_dc_write(ot->ot_ind_file, new_branch, offsetof(XTIdxBranchDRec, tb_data) + size, (xtWord1 *) &ot->ot_ind_wbuf))
1061
if (!xt_ind_write(ot->ot_ind_file, new_branch, offsetof(XTIdxBranchDRec, tb_data) + size, (xtWord1 *) &ot->ot_ind_wbuf))
912
1063
ind->mi_root = new_branch;
913
ot->ot_table->tab_head_dirty = TRUE;
1064
ot->ot_table->tab_ind_head_dirty = TRUE;
917
1068
current = stack_item->i_branch;
918
if (!xt_dc_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_wbuf))
1069
if (!xt_ind_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_wbuf))
920
1071
ASSERT_NS(XT_IS_NODE(XT_GET_DISK_2(ot->ot_ind_wbuf.tb_size_2)));
921
1072
ind->mi_scan_branch(ind, &ot->ot_ind_wbuf, key_value, &result);
923
1074
idx_insert_node_item(ind, &ot->ot_ind_wbuf, key_value, &result, branch);
924
if (result.sr_item.i_total_size <= XT_IDX_PAGE_DATA_SIZE) {
925
if (!xt_dc_write(ot->ot_ind_file, current, offsetof(XTIdxBranchDRec, tb_data) + result.sr_item.i_total_size, (xtWord1 *) &ot->ot_ind_wbuf))
1075
if (result.sr_item.i_total_size <= XT_INDEX_PAGE_DATA_SIZE) {
1076
if (!xt_ind_write(ot->ot_ind_file, current, offsetof(XTIdxBranchDRec, tb_data) + result.sr_item.i_total_size, (xtWord1 *) &ot->ot_ind_wbuf))
936
1087
/* Split the node: */
937
1088
new_size = result.sr_item.i_total_size - result.sr_item.i_item_offset - result.sr_item.i_item_size;
938
new_branch_ptr = (XTIdxBranchDPtr) &ot->ot_ind_wbuf.tb_data[XT_IDX_PAGE_DATA_SIZE];
1089
new_branch_ptr = (XTIdxBranchDPtr) &ot->ot_ind_wbuf.tb_data[XT_INDEX_PAGE_DATA_SIZE];
939
1090
memmove(new_branch_ptr->tb_data, &ot->ot_ind_wbuf.tb_data[result.sr_item.i_item_offset + result.sr_item.i_item_size], new_size);
941
1092
XT_SET_DISK_2(new_branch_ptr->tb_size_2, XT_MAKE_NODE_SIZE(new_size));
942
if (!xt_dc_write(ot->ot_ind_file, new_branch, offsetof(XTIdxBranchDRec, tb_data) + new_size, (xtWord1 *) new_branch_ptr))
1093
if (!xt_ind_write(ot->ot_ind_file, new_branch, offsetof(XTIdxBranchDRec, tb_data) + new_size, (xtWord1 *) new_branch_ptr))
945
1096
/* Change the size of the old branch: */
946
1097
XT_SET_DISK_2(ot->ot_ind_wbuf.tb_size_2, XT_MAKE_NODE_SIZE(result.sr_item.i_item_offset));
947
if (!xt_dc_write(ot->ot_ind_file, current, offsetof(XTIdxBranchDRec, tb_data) + result.sr_item.i_item_offset, (xtWord1 *) &ot->ot_ind_wbuf))
1098
if (!xt_ind_write(ot->ot_ind_file, current, offsetof(XTIdxBranchDRec, tb_data) + result.sr_item.i_item_offset, (xtWord1 *) &ot->ot_ind_wbuf))
950
1101
/* Insert the new branch into the parent node, using the new middle key value: */
1183
1333
idx_insert_leaf_item(ind, &ot->ot_ind_wbuf, &key_value, &result);
1184
if (result.sr_item.i_total_size <= XT_IDX_PAGE_DATA_SIZE) {
1185
if (!xt_dc_write(ot->ot_ind_file, current, offsetof(XTIdxBranchDRec, tb_data) + result.sr_item.i_total_size, (xtWord1 *) &ot->ot_ind_wbuf))
1334
if (result.sr_item.i_total_size <= XT_INDEX_PAGE_DATA_SIZE) {
1335
if (!xt_ind_write(ot->ot_ind_file, current, offsetof(XTIdxBranchDRec, tb_data) + result.sr_item.i_total_size, (xtWord1 *) &ot->ot_ind_wbuf))
1340
#ifdef XT_INDEX_LOG_CHANGES
1341
u_int insert_offset = result.sr_item.i_item_offset;
1342
u_int insert_len = key_value.sv_length + XT_RECORD_REF_SIZE;
1343
u_int org_size = result.sr_item.i_total_size - insert_len;
1190
1346
/* Key does not fit, must split... */
1191
1347
idx_get_middle_branch_item(ind, &ot->ot_ind_wbuf, &key_value, &result);
1193
1349
if (!idx_new_branch(ot, &new_branch))
1352
#ifdef XT_INDEX_LOG_CHANGES
1353
/* Note: the middle item is not copied into any of the
1354
* 2 resulting nodes.
1356
if (result.sr_item.i_item_offset <= insert_offset) {
1357
/* This is were the node split occored before the insertion point. */
1358
u_int toff = result.sr_item.i_item_offset + result.sr_item.i_item_size;
1360
/* Copy the end part of the current node to the new node. */
1361
XT_COPY_TO_NEW(current, toff, org_size - toff, new_branch);
1362
if (insert_offset > toff) {
1363
/* Insert the the data into the new branch: */
1364
toff = insert_offset - toff;
1365
XT_INSERT_INTO_BRANCH(new_branch, toff, insert_len, &ot->ot_ind_wbuf.tb_data[insert_offset]);
1367
/* Set the current node size. */
1368
XT_SET_NODE_SIZE(current, result.sr_item.i_item_offset);
1371
/* This is the case where the split is after the insert point. */
1372
/* This is the original offset into the node: */
1373
u_int toff = result.sr_item.i_item_offset - insert_len;
1375
/* Copy to the new node, and set the size of the old: */
1376
XT_COPY_TO_NEW(current, toff, org_size - toff - result.sr_item.i_item_size, new_branch);
1377
XT_SET_NODE_SIZE(current, toff);
1379
/* Insert into the correct position in old node: */
1380
XT_INSERT_INTO_BRANCH(current, inserted_offset, insert_len, &ot->ot_ind_wbuf.tb_data[insert_offset]);
1196
1384
/* Copy and write the rest of the data to the new node: */
1197
1385
new_size = result.sr_item.i_total_size - result.sr_item.i_item_offset - result.sr_item.i_item_size;
1198
new_branch_ptr = (XTIdxBranchDPtr) &ot->ot_ind_wbuf.tb_data[XT_IDX_PAGE_DATA_SIZE];
1386
new_branch_ptr = (XTIdxBranchDPtr) &ot->ot_ind_wbuf.tb_data[XT_INDEX_PAGE_DATA_SIZE];
1199
1387
memmove(new_branch_ptr->tb_data, &ot->ot_ind_wbuf.tb_data[result.sr_item.i_item_offset + result.sr_item.i_item_size], new_size);
1201
1389
XT_SET_DISK_2(new_branch_ptr->tb_size_2, XT_MAKE_LEAF_SIZE(new_size));
1202
if (!xt_dc_write(ot->ot_ind_file, new_branch, offsetof(XTIdxBranchDRec, tb_data) + new_size, (xtWord1 *) new_branch_ptr))
1390
if (!xt_ind_write(ot->ot_ind_file, new_branch, offsetof(XTIdxBranchDRec, tb_data) + new_size, (xtWord1 *) new_branch_ptr))
1205
1393
/* Modify the first node: */
1206
1394
XT_SET_DISK_2(ot->ot_ind_wbuf.tb_size_2, XT_MAKE_LEAF_SIZE(result.sr_item.i_item_offset));
1207
if (!xt_dc_write(ot->ot_ind_file, current, offsetof(XTIdxBranchDRec, tb_data) + result.sr_item.i_item_offset, (xtWord1 *) &ot->ot_ind_wbuf))
1395
if (!xt_ind_write(ot->ot_ind_file, current, offsetof(XTIdxBranchDRec, tb_data) + result.sr_item.i_item_offset, (xtWord1 *) &ot->ot_ind_wbuf))
1210
1398
/* Insert the new branch into the parent node, using the new middle key value: */
1351
1539
xtPublic void xt_idx_delete_current(XTOpenTablePtr ot, XTIndexPtr ind)
1353
1541
XTIdxKeyValueRec key_value;
1354
xtWord1 key_buf[XT_IDX_MAX_KEY_SIZE + XT_MAX_RECORD_REF_SIZE];
1542
xtWord1 key_buf[XT_INDEX_MAX_KEY_SIZE + XT_MAX_RECORD_REF_SIZE];
1543
XTIdxItemRec tmp_state;
1356
1545
key_value.sv_flags = XT_SEARCH_WHOLE_KEY;
1357
key_value.sv_record = XT_GET_RECORD_REF(&ot->ot_ind_rbuf.tb_data[ot->ot_ind_state.i_item_offset + ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE]);
1546
xt_get_record_ref(&ot->ot_ind_rbuf.tb_data[ot->ot_ind_state.i_item_offset + ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE], &key_value.sv_rec_id, &key_value.sv_row_id);
1358
1547
key_value.sv_length = ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE;
1359
1548
key_value.sv_key = key_buf;
1360
1549
memcpy(key_buf, &ot->ot_ind_rbuf.tb_data[ot->ot_ind_state.i_item_offset], key_value.sv_length);
1550
tmp_state = ot->ot_ind_state;
1362
1552
if (!idx_delete(ot, ind, &key_value))
1363
1553
xt_log_and_clear_exception_ns();
1365
// Setup things so that next or prev will work!
1555
/* Setup things so that next or prev will work!
1556
* This basically means that we must force a search
1557
* for the next key value.
1559
* I assume that what I am trying to do is restore
1560
* the search value, to that which we had before the
1563
* The problem is, key_buf can be changed by idx_delete().
1565
* However, I am assuming that ot_ind_rbuf does not
1566
* change so we can just restore the state?
1366
1567
ot->ot_ind_state.i_node_ref_size = XT_NODE_REF_SIZE;
1367
1568
ot->ot_ind_state.i_item_offset = 0;
1368
1569
ot->ot_ind_state.i_item_size = key_value.sv_length + XT_RECORD_REF_SIZE;
1369
XT_SET_RECORD_REF(&ot->ot_ind_rbuf.tb_data[key_value.sv_length], key_value.sv_record);
1570
xt_set_val_record_ref(&ot->ot_ind_rbuf.tb_data[key_value.sv_length], &key_value);
1370
1571
memcpy(ot->ot_ind_rbuf.tb_data, key_buf, key_value.sv_length);
1573
ot->ot_ind_state = tmp_state;
1574
/* This will force search, because it says that this is not a leaf
1575
* node. Only leaf nodes can be stepped!
1577
ot->ot_ind_state.i_node_ref_size = XT_NODE_REF_SIZE;
1373
xtPublic xtBool xt_idx_delete(XTOpenTablePtr ot, XTIndexPtr ind, off_t address, xtWord1 *rec_buf)
1580
xtPublic xtBool xt_idx_delete(XTOpenTablePtr ot, XTIndexPtr ind, xtRecordID rec_id, xtWord1 *rec_buf)
1375
1582
XTIdxKeyValueRec key_value;
1376
xtWord1 key_buf[XT_IDX_MAX_KEY_SIZE + XT_MAX_RECORD_REF_SIZE];
1583
xtWord1 key_buf[XT_INDEX_MAX_KEY_SIZE + XT_MAX_RECORD_REF_SIZE];
1378
1585
key_value.sv_flags = XT_SEARCH_WHOLE_KEY;
1379
key_value.sv_record = address;
1586
key_value.sv_rec_id = rec_id;
1587
key_value.sv_row_id = 0;
1380
1588
key_value.sv_key = key_buf;
1381
1589
key_value.sv_length = myxt_create_key_from_row(ind, key_buf, rec_buf, NULL);
1383
1591
return idx_delete(ot, ind, &key_value);
1594
xtPublic xtBool xt_idx_update_row_id(XTOpenTablePtr ot, XTIndexPtr ind, xtRecordID rec_id, xtRowID row_id, xtWord1 *rec_buf)
1597
XTIdxResultRec result;
1598
XTIdxKeyValueRec key_value;
1599
xtWord1 key_buf[XT_INDEX_MAX_KEY_SIZE + XT_MAX_RECORD_REF_SIZE];
1601
#ifdef CHECK_AND_PRINT
1602
idx_print_index(ot, ind, TRUE);
1604
key_value.sv_flags = XT_SEARCH_WHOLE_KEY;
1605
key_value.sv_rec_id = rec_id;
1606
key_value.sv_row_id = 0;
1607
key_value.sv_key = key_buf;
1608
key_value.sv_length = myxt_create_key_from_row(ind, key_buf, rec_buf, NULL);
1610
/* NOTE: Only a read lock is required for this!! */
1611
xt_rwlock_rdlock(&ind->mi_rwlock);
1613
if (!(current = ind->mi_root))
1617
if (!xt_ind_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_rbuf))
1619
ind->mi_scan_branch(ind, &ot->ot_ind_rbuf, &key_value, &result);
1620
if (result.sr_found || !result.sr_item.i_node_ref_size)
1622
current = result.sr_branch;
1625
if (result.sr_found) {
1626
xt_set_record_ref(&ot->ot_ind_rbuf.tb_data[result.sr_item.i_item_offset + result.sr_item.i_item_size - XT_RECORD_REF_SIZE], key_value.sv_rec_id, row_id);
1627
if (!xt_ind_write(ot->ot_ind_file, current, offsetof(XTIdxBranchDRec, tb_data) + result.sr_item.i_total_size, (xtWord1 *) &ot->ot_ind_rbuf))
1632
xt_rwlock_unlock(&ind->mi_rwlock);
1635
//idx_print_index(ot, ind, TRUE);
1636
//idx_check_index(ot, ind);
1637
//idx_check_on_key(ot);
1642
xt_rwlock_unlock(&ind->mi_rwlock);
1386
1646
xtPublic void xt_idx_prep_key(XTIndexPtr ind, register XTIdxSearchKeyPtr search_key, int flags, xtWord1 *in_key_buf, size_t in_key_length)
1388
1648
search_key->sk_key_value.sv_flags = flags;
1389
search_key->sk_key_value.sv_record = 0;
1649
search_key->sk_key_value.sv_rec_id = 0;
1650
search_key->sk_key_value.sv_row_id = 0;
1390
1651
search_key->sk_key_value.sv_key = search_key->sk_key_buf;
1391
1652
search_key->sk_key_value.sv_length = myxt_create_key_from_key(ind, search_key->sk_key_buf, in_key_buf, in_key_length);
1392
1653
search_key->sk_on_key = FALSE;
1656
xtPublic xtBool xt_idx_research(XTOpenTablePtr ot, XTIndexPtr ind)
1658
XTIdxSearchKeyRec search_key;
1660
search_key.sk_key_value.sv_flags = XT_SEARCH_WHOLE_KEY;
1661
xt_get_record_ref(&ot->ot_ind_rbuf.tb_data[ot->ot_ind_state.i_item_offset + ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE], &search_key.sk_key_value.sv_rec_id, &search_key.sk_key_value.sv_row_id);
1662
search_key.sk_key_value.sv_key = search_key.sk_key_buf;
1663
search_key.sk_key_value.sv_length = ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE;
1664
search_key.sk_on_key = FALSE;
1665
memcpy(search_key.sk_key_buf, &ot->ot_ind_rbuf.tb_data[ot->ot_ind_state.i_item_offset], search_key.sk_key_value.sv_length);
1666
return xt_idx_search(ot, ind, &search_key);
1396
1670
* Search for a given key and position the current pointer on the first
1397
1671
* key in the list of duplicates. If the key is not found the current
2102
/* Return TRUE if the record matches the current index search! */
2103
xtPublic xtBool xt_idx_match_search(register XTOpenTablePtr ot, register XTIndexPtr ind, register XTIdxSearchKeyPtr search_key, xtWord1 *buf, int mode)
2106
xtWord1 key_buf[XT_INDEX_MAX_KEY_SIZE];
2108
myxt_create_key_from_row(ind, key_buf, (xtWord1 *) buf, NULL);
2109
r = myxt_compare_key(ind, search_key->sk_key_value.sv_flags, search_key->sk_key_value.sv_length, search_key->sk_key_value.sv_key, key_buf);
2111
case XT_S_MODE_MATCH:
2113
case XT_S_MODE_NEXT:
2115
case XT_S_MODE_PREV:
2121
static void idx_set_index_selectivity(XTThreadPtr self, XTOpenTablePtr ot, XTIndexPtr ind)
2123
XTIdxSearchKeyRec search_key;
2124
XTIndexSegPtr key_seg;
2125
u_int select_count = 0;
2126
xtWord1 key_buf[XT_INDEX_MAX_KEY_SIZE];
2128
xtWord1 *next_key_buf;
2134
ind->mi_select_total = 0;
2135
key_seg = ind->mi_seg;
2136
for (i=0; i < ind->mi_seg_count; key_seg++, i++) {
2137
key_seg->is_selectivity = 1;
2138
key_seg->is_recs_in_range = 1;
2141
xt_idx_prep_key(ind, &search_key, XT_SEARCH_FIRST_FLAG, NULL, 0);
2142
if (!xt_idx_search(ot, ind, &search_key))
2145
/* Initialize the buffer with the first index valid index entry: */
2146
while (!select_count && ot->ot_curr_rec_id) {
2147
if (ot->ot_curr_row_id) {
2150
key_len = ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE;
2151
memcpy(key_buf, ot->ot_ind_rbuf.tb_data + ot->ot_ind_state.i_item_offset, key_len);
2153
if (!xt_idx_next(ot, ind, &search_key))
2157
while (select_count < 100 && ot->ot_curr_rec_id) {
2158
/* Check if the index entry is committed: */
2159
if (ot->ot_curr_row_id) {
2162
next_key_len = ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE;
2163
next_key_buf = ot->ot_ind_rbuf.tb_data + ot->ot_ind_state.i_item_offset;
2167
key_seg = ind->mi_seg;
2168
for (i=0; i < ind->mi_seg_count; key_seg++, i++) {
2169
curr_len += myxt_key_seg_length(key_seg, curr_len, key_buf);
2170
if (!diff && myxt_compare_key(ind, 0, curr_len, key_buf, next_key_buf) != 0)
2173
key_seg->is_selectivity++;
2176
/* Store the key for the next comparison: */
2177
key_len = next_key_len;
2178
memcpy(key_buf, next_key_buf, key_len);
2181
if (!xt_idx_next(ot, ind, &search_key))
2188
ind->mi_select_total = select_count;
2189
key_seg = ind->mi_seg;
2190
for (i=0; i < ind->mi_seg_count; key_seg++, i++) {
2191
recs = (u_int) ((double) select_count / (double) key_seg->is_selectivity + (double) 0.5);
2192
key_seg->is_recs_in_range = recs ? recs : 1;
2197
xtPublic void xt_ind_set_index_selectivity(XTThreadPtr self, XTOpenTablePtr ot)
2199
XTTableHPtr tab = ot->ot_table;
2203
for (i=0, ind=tab->tab_dic.dic_keys; i<tab->tab_dic.dic_key_count; i++, ind++)
2204
idx_set_index_selectivity(self, ot, *ind);
1813
2208
* -----------------------------------------------------------------------
1814
2209
* Print a b-tree
1817
#ifdef CHECK_AND_PRINT
1818
2212
static void idx_check_on_key(XTOpenTablePtr ot)
1820
u_int offs = ot->ot_ind_state.i_item_offset + ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE;
2214
u_int offs = ot->ot_ind_state.i_item_offset + ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE;
1823
if (ot->ot_curr_rec && ot->ot_ind_state.i_item_offset < ot->ot_ind_state.i_total_size) {
1824
record = XT_GET_RECORD_REF(&ot->ot_ind_rbuf.tb_data[offs]);
2218
if (ot->ot_curr_rec_id && ot->ot_ind_state.i_item_offset < ot->ot_ind_state.i_total_size) {
2219
xt_get_record_ref(&ot->ot_ind_rbuf.tb_data[offs], &rec_id, &row_id);
1826
ASSERT_NS(record == ot->ot_curr_rec);
2221
ASSERT_NS(rec_id == ot->ot_curr_rec_id);
1865
static void idx_print_index(XTOpenTablePtr ot, XTIndexPtr ind)
2260
static void idx_print_index(XTOpenTablePtr ot, XTIndexPtr ind, xtBool with_lock)
1867
2262
register XTTableHPtr tab = ot->ot_table;
1869
2264
IdxFreeBlockRec free_block;
1871
xt_rwlock_wrlock(&ind->mi_rwlock);
2267
xt_rwlock_wrlock(&ind->mi_rwlock);
1873
printf("INDEX -----------------------\n");
2269
printf("INDEX %04llu -----------------------\n", (u_llong) ind->mi_root);
1874
2270
if ((current = ind->mi_root))
1875
2271
idx_print_node(ot, ind, 0, current);
1877
xt_rwlock_unlock(&ind->mi_rwlock);
2274
xt_rwlock_unlock(&ind->mi_rwlock);
1879
xt_mutex_lock(&tab->tab_ind_lock);
2276
xt_lock_mutex_ns(&tab->tab_ind_lock);
1880
2277
printf("\nFREE: ");
1881
2278
current = tab->tab_ind_free;
1882
2279
while (current) {
1883
2280
printf("%04llu ", (u_llong) current);
1884
if (!xt_dc_read(ot->ot_ind_file, current, sizeof(IdxFreeBlockRec), (xtWord1 *) &free_block)) {
2281
if (!xt_ind_read(ot->ot_ind_file, current, sizeof(IdxFreeBlockRec), (xtWord1 *) &free_block)) {
1885
2282
xt_log_and_clear_exception_ns();
1888
2285
current = XT_GET_DISK_8(free_block.if_next_block_8);
1890
2287
printf("\n-----------------------------\n");
1891
xt_mutex_unlock(&tab->tab_ind_lock);
2288
xt_unlock_mutex_ns(&tab->tab_ind_lock);
1894
2291
static void idx_check_node(XTOpenTablePtr ot, XTIndexPtr ind, int depth, off_t node)
1896
xtWord1 nbuf[XT_IDX_PAGE_SIZE];
2293
xtWord1 nbuf[XT_INDEX_PAGE_SIZE];
1897
2294
XTIdxBranchDPtr branch = (XTIdxBranchDPtr) nbuf;
1898
2295
XTIdxResultRec result;
1900
2297
ASSERT_NS(node <= ot->ot_table->tab_ind_eof);
1901
if (!xt_dc_read_block(ot->ot_ind_file, node, (xtWord1 *) branch))
2298
if (!xt_ind_read_block(ot->ot_ind_file, node, (xtWord1 *) branch))
1903
2300
idx_first_branch_item(ind, branch, &result);
1904
ASSERT_NS(result.sr_item.i_total_size + offsetof(XTIdxBranchDRec, tb_data) <= XT_IDX_PAGE_SIZE);
2301
ASSERT_NS(result.sr_item.i_total_size + offsetof(XTIdxBranchDRec, tb_data) <= XT_INDEX_PAGE_SIZE);
1905
2302
if (result.sr_item.i_node_ref_size) {
1906
2303
idx_check_node(ot, ind, depth+1, result.sr_branch);
1927
2324
xt_rwlock_unlock(&ind->mi_rwlock);
1929
xt_mutex_lock(&tab->tab_ind_lock);
2326
xt_lock_mutex_ns(&tab->tab_ind_lock);
1930
2327
current = tab->tab_ind_free;
1931
2328
while (current) {
1932
if (!xt_dc_read(ot->ot_ind_file, current, sizeof(IdxFreeBlockRec), (xtWord1 *) &free_block)) {
2329
if (!xt_ind_read(ot->ot_ind_file, current, sizeof(IdxFreeBlockRec), (xtWord1 *) &free_block)) {
1933
2330
xt_log_and_clear_exception_ns();
1936
2333
current = XT_GET_DISK_8(free_block.if_next_block_8);
1938
xt_mutex_unlock(&tab->tab_ind_lock);
2335
xt_unlock_mutex_ns(&tab->tab_ind_lock);
2338
xtPublic void xt_print_index(XTOpenTablePtr ot, XTIndexPtr ind, xtBool with_lock)
2340
idx_print_index(ot, ind, with_lock);
2343
xtPublic void xt_print_indices(XTOpenTablePtr ot)
2347
ind = ot->ot_table->tab_dic.dic_keys;
2348
for (u_int i=0; i<ot->ot_table->tab_dic.dic_key_count; i++, ind++) {
2349
xt_print_index(ot, *ind, TRUE);