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

« back to all changes in this revision

Viewing changes to pbxt/src/index_xt.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
 * PrimeBase XT
4
4
 *
41
41
 
42
42
#ifdef DEBUG
43
43
#define MAX_SEARCH_DEPTH                        32
 
44
//#define CHECK_AND_PRINT
44
45
#else
45
46
#define MAX_SEARCH_DEPTH                        100
46
47
#endif
55
56
        IdxStackItemRec                 s_elements[MAX_SEARCH_DEPTH];
56
57
} IdxBranchStackRec, *IdxBranchStackPtr;
57
58
 
58
 
#ifdef CHECK_AND_PRINT
 
59
#ifdef DEBUG
59
60
static void idx_check_on_key(XTOpenTablePtr ot);
60
 
static void idx_print_index(XTOpenTablePtr ot, XTIndexPtr ind);
 
61
static void idx_print_index(XTOpenTablePtr ot, XTIndexPtr ind, xtBool with_lock);
61
62
static void idx_check_index(XTOpenTablePtr ot, XTIndexPtr ind);
62
63
#endif
63
64
 
92
93
        return OK;
93
94
}
94
95
 
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))
96
97
 
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))
98
99
#endif
99
100
 
100
101
/*
153
154
        register XTTableHPtr    tab = ot->ot_table;
154
155
        off_t                                   wrote_pos;
155
156
 
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;
160
161
 
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))
162
163
                        goto failed;
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);
166
167
 
167
168
                *address = wrote_pos;
168
169
                return OK;
169
170
        }
170
171
 
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));
174
175
                goto failed;
175
176
        }
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;
179
180
 
180
 
        xt_mutex_unlock(&tab->tab_ind_lock);
 
181
        xt_unlock_mutex_ns(&tab->tab_ind_lock);
181
182
        return OK;
182
183
 
183
184
        failed:
184
 
        xt_mutex_unlock(&tab->tab_ind_lock);
 
185
        xt_unlock_mutex_ns(&tab->tab_ind_lock);
185
186
        return FAILED;
186
187
}
187
188
 
190
191
        register XTTableHPtr    tab = ot->ot_table;
191
192
        IdxFreeBlockRec                 free_block = { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } };
192
193
 
193
 
        xt_mutex_lock(&tab->tab_ind_lock);
 
194
        xt_lock_mutex_ns(&tab->tab_ind_lock);
194
195
 
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))
198
199
                goto failed;
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);
202
203
        return OK;
203
204
        
204
205
        failed:
205
 
        xt_mutex_unlock(&tab->tab_ind_lock);
 
206
        xt_unlock_mutex_ns(&tab->tab_ind_lock);
206
207
        return FAILED;
207
208
}
208
209
 
209
210
/*
210
211
 * -----------------------------------------------------------------------
 
212
 * Simple compare functions
 
213
 */
 
214
 
 
215
xtPublic int xt_compare_2_int4(XTIndexPtr ind, uint key_length, xtWord1 *key_value, xtWord1 *b_value)
 
216
{
 
217
        int r;
 
218
 
 
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) {
 
222
                key_value += 4;
 
223
                b_value += 4;
 
224
                r = (xtInt4) XT_GET_DISK_4(key_value) - (xtInt4) XT_GET_DISK_4(b_value);
 
225
        }
 
226
        return r;
 
227
}
 
228
 
 
229
xtPublic int xt_compare_3_int4(XTIndexPtr ind, uint key_length, xtWord1 *key_value, xtWord1 *b_value)
 
230
{
 
231
        int r;
 
232
 
 
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) {
 
236
                key_value += 4;
 
237
                b_value += 4;
 
238
                r = (xtInt4) XT_GET_DISK_4(key_value) - (xtInt4) XT_GET_DISK_4(b_value);
 
239
                if (r == 0 && key_length > 8) {
 
240
                        key_value += 4;
 
241
                        b_value += 4;
 
242
                        r = (xtInt4) XT_GET_DISK_4(key_value) - (xtInt4) XT_GET_DISK_4(b_value);
 
243
                }
 
244
        }
 
245
        return r;
 
246
}
 
247
 
 
248
/*
 
249
 * -----------------------------------------------------------------------
211
250
 * Tree branch sanning (searching nodes and leaves)
212
251
 */
213
252
 
227
266
        result->sr_found = FALSE;
228
267
        result->sr_duplicate = FALSE;
229
268
        result->sr_item.i_total_size = XT_GET_BRANCH_DATA_SIZE(branch_size);
230
 
        ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_IDX_PAGE_SIZE-2);
 
269
        ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_INDEX_PAGE_SIZE-2);
231
270
 
232
271
        result->sr_item.i_item_size = ind->mi_key_size + XT_RECORD_REF_SIZE;
233
272
        full_item_size = result->sr_item.i_item_size + node_ref_size;
243
282
                register u_int          guess;
244
283
                register u_int          count;
245
284
                register xtInt4         r;
246
 
                off_t                           key_record;
 
285
                xtRecordID                      key_record;
247
286
 
248
 
                key_record = value->sv_record;
 
287
                key_record = value->sv_rec_id;
249
288
                count = (result->sr_item.i_total_size - node_ref_size) / full_item_size;
250
289
 
251
290
                ASSERT_NS(ind);
274
313
                        }
275
314
                        if (r == 0) {
276
315
                                if (search_flags & XT_SEARCH_WHOLE_KEY) {
277
 
                                        off_t item_record = XT_GET_RECORD_REF(bitem + ind->mi_key_size);
 
316
                                        xtRecordID      item_record;
 
317
                                        xtRowID         row_id;
 
318
                                        
 
319
                                        xt_get_record_ref(bitem + ind->mi_key_size, &item_record, &row_id);
278
320
 
279
321
                                        /* This should not happen because we should never
280
322
                                         * try to insert the same record twice into the 
283
325
                                        result->sr_duplicate = TRUE;
284
326
                                        if (key_record == item_record) {
285
327
                                                result->sr_found = TRUE;
286
 
                                                result->sr_record = item_record;
 
328
                                                result->sr_rec_id = item_record;
 
329
                                                result->sr_row_id = row_id;
287
330
                                                result->sr_branch = XT_GET_NODE_REF(bitem - node_ref_size);
288
331
                                                result->sr_item.i_item_offset = node_ref_size + guess * full_item_size;
289
332
                                                return;
313
356
        }
314
357
 
315
358
        bitem = base + i * full_item_size;
316
 
        result->sr_record = XT_GET_RECORD_REF(bitem + ind->mi_key_size);
 
359
        xt_get_res_record_ref(bitem + ind->mi_key_size, result);
317
360
        result->sr_branch = XT_GET_NODE_REF(bitem - node_ref_size);                     /* Only valid if this is a node. */
318
361
        result->sr_item.i_item_offset = node_ref_size + i * full_item_size;
319
362
}
358
401
        result->sr_found = FALSE;
359
402
        result->sr_duplicate = FALSE;
360
403
        result->sr_item.i_total_size = XT_GET_BRANCH_DATA_SIZE(branch_size);
361
 
        ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_IDX_PAGE_SIZE-2);
 
404
        ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_INDEX_PAGE_SIZE-2);
362
405
 
363
406
        result->sr_item.i_item_size = ind->mi_key_size + XT_RECORD_REF_SIZE;
364
407
        full_item_size = result->sr_item.i_item_size + node_ref_size;
373
416
        else {
374
417
                register u_int          guess;
375
418
                register u_int          count;
376
 
                off_t                           key_record;
 
419
                xtRecordID                      key_record;
377
420
                int                                     r;
378
421
 
379
 
                key_record = value->sv_record;
 
422
                key_record = value->sv_rec_id;
380
423
                count = (result->sr_item.i_total_size - node_ref_size) / full_item_size;
381
424
 
382
425
                ASSERT_NS(ind);
390
433
 
391
434
                        if (r == 0) {
392
435
                                if (search_flags & XT_SEARCH_WHOLE_KEY) {
393
 
                                        off_t item_record = XT_GET_RECORD_REF(bitem + ind->mi_key_size);
394
 
 
395
 
                                        /* This should not happen because we should never
396
 
                                         * try to insert the same record twice into the 
397
 
                                         * index!
398
 
                                         */
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;
405
 
                                                return;
406
 
                                        }
407
 
                                        if (key_record < item_record)
408
 
                                                r = -1;
409
 
                                        else
410
 
                                                r = 1;
411
 
                                }
412
 
                                else {
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.
416
 
                                        */
417
 
                                        if (search_flags & XT_SEARCH_AFTER_KEY)
418
 
                                                r = 1;
419
 
                                        else
420
 
                                                r = -1;
421
 
                                }
422
 
                        }
423
 
 
424
 
                        if (r < 0)
425
 
                                count = guess;
426
 
                        else
427
 
                                i = guess + 1;
428
 
                }
429
 
        }
430
 
 
431
 
        bitem = base + i * full_item_size;
432
 
        result->sr_record = XT_GET_RECORD_REF(bitem + ind->mi_key_size);
 
436
                                        xtRecordID      item_record;
 
437
                                        xtRowID         row_id;
 
438
 
 
439
                                        xt_get_record_ref(bitem + ind->mi_key_size, &item_record, &row_id);
 
440
 
 
441
                                        /* This should not happen because we should never
 
442
                                         * try to insert the same record twice into the 
 
443
                                         * index!
 
444
                                         */
 
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;
 
452
                                                return;
 
453
                                        }
 
454
                                        if (key_record < item_record)
 
455
                                                r = -1;
 
456
                                        else
 
457
                                                r = 1;
 
458
                                }
 
459
                                else {
 
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.
 
463
                                        */
 
464
                                        if (search_flags & XT_SEARCH_AFTER_KEY)
 
465
                                                r = 1;
 
466
                                        else
 
467
                                                r = -1;
 
468
                                }
 
469
                        }
 
470
 
 
471
                        if (r < 0)
 
472
                                count = guess;
 
473
                        else
 
474
                                i = guess + 1;
 
475
                }
 
476
        }
 
477
 
 
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;
 
482
}
 
483
 
 
484
xtPublic void xt_scan_branch_fix_simple(XTIndexPtr ind, XTIdxBranchDPtr branch, register XTIdxKeyValuePtr value, register XTIdxResultRec *result)
 
485
{
 
486
        u_int                           branch_size;
 
487
        u_int                           node_ref_size;
 
488
        u_int                           full_item_size;
 
489
        int                                     search_flags;
 
490
        xtWord1                         *base;
 
491
        register u_int          i;
 
492
        xtWord1                         *bitem;
 
493
 
 
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;
 
496
 
 
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);
 
501
 
 
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;
 
505
 
 
506
        search_flags = value->sv_flags;
 
507
        base = branch->tb_data + node_ref_size;
 
508
        if (search_flags & XT_SEARCH_FIRST_FLAG)
 
509
                i = 0;
 
510
        else if (search_flags & XT_SEARCH_AFTER_LAST_FLAG)
 
511
                i = (result->sr_item.i_total_size - node_ref_size) / full_item_size;
 
512
        else {
 
513
                register u_int          guess;
 
514
                register u_int          count;
 
515
                xtRecordID                      key_record;
 
516
                int                                     r;
 
517
 
 
518
                key_record = value->sv_rec_id;
 
519
                count = (result->sr_item.i_total_size - node_ref_size) / full_item_size;
 
520
 
 
521
                ASSERT_NS(ind);
 
522
                i = 0;
 
523
                while (i < count) {
 
524
                        guess = (i + count - 1) >> 1;
 
525
 
 
526
                        bitem = base + guess * full_item_size;
 
527
 
 
528
                        r = ind->mi_simple_comp_key(ind, value->sv_length, value->sv_key, bitem);
 
529
 
 
530
                        if (r == 0) {
 
531
                                if (search_flags & XT_SEARCH_WHOLE_KEY) {
 
532
                                        xtRecordID      item_record;
 
533
                                        xtRowID         row_id;
 
534
 
 
535
                                        xt_get_record_ref(bitem + ind->mi_key_size, &item_record, &row_id);
 
536
 
 
537
                                        /* This should not happen because we should never
 
538
                                         * try to insert the same record twice into the 
 
539
                                         * index!
 
540
                                         */
 
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;
 
548
                                                return;
 
549
                                        }
 
550
                                        if (key_record < item_record)
 
551
                                                r = -1;
 
552
                                        else
 
553
                                                r = 1;
 
554
                                }
 
555
                                else {
 
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.
 
559
                                        */
 
560
                                        if (search_flags & XT_SEARCH_AFTER_KEY)
 
561
                                                r = 1;
 
562
                                        else
 
563
                                                r = -1;
 
564
                                }
 
565
                        }
 
566
 
 
567
                        if (r < 0)
 
568
                                count = guess;
 
569
                        else
 
570
                                i = guess + 1;
 
571
                }
 
572
        }
 
573
 
 
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;
435
578
}
454
597
        result->sr_found = FALSE;
455
598
        result->sr_duplicate = FALSE;
456
599
        result->sr_item.i_total_size = XT_GET_BRANCH_DATA_SIZE(branch_size);
457
 
        ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_IDX_PAGE_SIZE-2);
 
600
        ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_INDEX_PAGE_SIZE-2);
458
601
 
459
602
        result->sr_item.i_node_ref_size = node_ref_size;
460
603
 
473
616
                ilen = 0;
474
617
        }
475
618
        else {
476
 
                off_t           key_record;
 
619
                xtRecordID      key_record;
477
620
                int                     r;
478
621
 
479
 
                key_record = value->sv_record;
 
622
                key_record = value->sv_rec_id;
480
623
 
481
624
                ASSERT_NS(ind);
482
625
                while (bitem < bend) {
484
627
                        r = myxt_compare_key(ind, search_flags, value->sv_length, value->sv_key, bitem);
485
628
                        if (r == 0) {
486
629
                                if (search_flags & XT_SEARCH_WHOLE_KEY) {
487
 
                                        off_t item_record = XT_GET_RECORD_REF(bitem + ilen);
 
630
                                        xtRecordID      item_record;
 
631
                                        xtRowID         row_id;
 
632
 
 
633
                                        xt_get_record_ref(bitem + ilen, &item_record, &row_id);
488
634
 
489
635
                                        /* This should not happen because we should never
490
636
                                         * try to insert the same record twice into the 
494
640
                                        if (key_record == item_record) {
495
641
                                                result->sr_found = TRUE;
496
642
                                                result->sr_item.i_item_size = ilen + XT_RECORD_REF_SIZE;;
497
 
                                                result->sr_record = item_record;
 
643
                                                result->sr_rec_id = item_record;
 
644
                                                result->sr_row_id = row_id;
498
645
                                                result->sr_branch = XT_GET_NODE_REF(bitem - node_ref_size);
499
646
                                                result->sr_item.i_item_offset = bitem - branch->tb_data;
500
647
                                                return;
523
670
 
524
671
        done_ok:
525
672
        result->sr_item.i_item_size = ilen + XT_RECORD_REF_SIZE;
526
 
        result->sr_record = XT_GET_RECORD_REF(bitem + ilen);
 
673
        xt_get_res_record_ref(bitem + ilen, result);
527
674
        result->sr_branch = XT_GET_NODE_REF(bitem - node_ref_size);                     /* Only valid if this is a node. */
528
675
        result->sr_item.i_item_offset = bitem - branch->tb_data;
529
676
}
542
689
                ilen = myxt_get_key_length(ind, bitem) + XT_RECORD_REF_SIZE;
543
690
                result->sr_item.i_item_size = ilen;
544
691
        }
545
 
        result->sr_record = XT_GET_RECORD_REF(bitem + ilen - XT_RECORD_REF_SIZE); /* (Only valid if i_item_offset < i_total_size) */
 
692
        xt_get_res_record_ref(bitem + ilen - XT_RECORD_REF_SIZE, result); /* (Only valid if i_item_offset < i_total_size) */
546
693
        result->sr_branch = XT_GET_NODE_REF(bitem - result->sr_item.i_node_ref_size);
547
694
}
548
695
 
550
697
{
551
698
        ASSERT_NS(result->sr_item.i_item_offset >= result->sr_item.i_item_size + result->sr_item.i_node_ref_size + result->sr_item.i_node_ref_size);
552
699
        result->sr_item.i_item_offset -= (result->sr_item.i_item_size + result->sr_item.i_node_ref_size);
553
 
        result->sr_record = XT_GET_RECORD_REF(branch->tb_data + result->sr_item.i_item_offset + result->sr_item.i_item_size - XT_RECORD_REF_SIZE); /* (Only valid if i_item_offset < i_total_size) */
 
700
        xt_get_res_record_ref(branch->tb_data + result->sr_item.i_item_offset + result->sr_item.i_item_size - XT_RECORD_REF_SIZE, result); /* (Only valid if i_item_offset < i_total_size) */
554
701
        result->sr_branch = XT_GET_NODE_REF(branch->tb_data + result->sr_item.i_item_offset - result->sr_item.i_node_ref_size);
555
702
}
556
703
 
570
717
        }
571
718
 
572
719
        result->sr_item.i_item_size = ilen + XT_RECORD_REF_SIZE;
573
 
        result->sr_record = XT_GET_RECORD_REF(bitem + ilen); /* (Only valid if i_item_offset < i_total_size) */
 
720
        xt_get_res_record_ref(bitem + ilen, result); /* (Only valid if i_item_offset < i_total_size) */
574
721
        result->sr_branch = XT_GET_NODE_REF(bitem - result->sr_item.i_node_ref_size);
575
722
        result->sr_item.i_item_offset = bitem - branch->tb_data;
576
723
}
587
734
        result->sr_found = FALSE;
588
735
        result->sr_duplicate = FALSE;
589
736
        result->sr_item.i_total_size = XT_GET_BRANCH_DATA_SIZE(branch_size);
590
 
        ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_IDX_PAGE_SIZE-2);
 
737
        ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_INDEX_PAGE_SIZE-2);
591
738
 
592
739
        if (ind->mi_fix_key)
593
740
                key_data_size = ind->mi_key_size;
604
751
        result->sr_item.i_item_size = key_data_size + XT_RECORD_REF_SIZE;
605
752
        result->sr_item.i_node_ref_size = node_ref_size;
606
753
 
607
 
        result->sr_record = XT_GET_RECORD_REF(branch->tb_data + node_ref_size + key_data_size);
 
754
        xt_get_res_record_ref(branch->tb_data + node_ref_size + key_data_size, result);
608
755
        result->sr_branch = XT_GET_NODE_REF(branch->tb_data);                           /* Only valid if this is a node. */
609
756
        result->sr_item.i_item_offset = node_ref_size;
610
757
}
623
770
        result->sr_found = FALSE;
624
771
        result->sr_duplicate = FALSE;
625
772
        result->sr_item.i_total_size = XT_GET_BRANCH_DATA_SIZE(branch_size);
626
 
        ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_IDX_PAGE_SIZE-2);
 
773
        ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_INDEX_PAGE_SIZE-2);
627
774
 
628
775
        result->sr_item.i_item_size = ind->mi_key_size + XT_RECORD_REF_SIZE;
629
776
        result->sr_item.i_node_ref_size = node_ref_size;
635
782
        else {
636
783
                if (result->sr_item.i_total_size) {
637
784
                        result->sr_item.i_item_offset = result->sr_item.i_total_size - result->sr_item.i_item_size;
638
 
                        result->sr_record = XT_GET_RECORD_REF(branch->tb_data + result->sr_item.i_item_offset + ind->mi_key_size);
 
785
                        xt_get_res_record_ref(branch->tb_data + result->sr_item.i_item_offset + ind->mi_key_size, result);
639
786
                }
640
787
                else
641
788
                        /* Leaf is empty: */
654
801
        result->sr_found = FALSE;
655
802
        result->sr_duplicate = FALSE;
656
803
        result->sr_item.i_total_size = XT_GET_BRANCH_DATA_SIZE(branch_size);
657
 
        ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_IDX_PAGE_SIZE-2);
 
804
        ASSERT_NS((int) result->sr_item.i_total_size >= 0 && result->sr_item.i_total_size <= XT_INDEX_PAGE_SIZE-2);
658
805
 
659
806
        result->sr_item.i_node_ref_size = node_ref_size;
660
807
 
682
829
                        }
683
830
 
684
831
                        result->sr_item.i_item_offset = bitem - branch->tb_data;
685
 
                        result->sr_record = XT_GET_RECORD_REF(bitem + ilen);
 
832
                        xt_get_res_record_ref(bitem + ilen, result);
686
833
                        result->sr_item.i_item_size = ilen + XT_RECORD_REF_SIZE;
687
834
                }
688
835
                else {
698
845
 */
699
846
static xtBool idx_remove_branch_item_right(XTOpenTablePtr ot, XTIndexPtr ind, off_t address, XTIdxBranchDPtr branch, register XTIdxItemPtr item)
700
847
{
 
848
        u_int size = item->i_item_size + item->i_node_ref_size;
 
849
 
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);
708
857
}
709
858
 
710
859
static xtBool idx_remove_branch_item_left(XTOpenTablePtr ot, XTIndexPtr ind, off_t address, XTIdxBranchDPtr branch, register XTIdxItemPtr item)
711
860
{
 
861
        u_int size = item->i_item_size + item->i_node_ref_size;
 
862
 
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);
719
870
}
720
871
 
721
872
static void idx_insert_leaf_item(XTIndexPtr ind, XTIdxBranchDPtr leaf, XTIdxKeyValuePtr value, XTIdxResultPtr result)
723
874
        xtWord1 *item;
724
875
 
725
876
        /* This will ensure we do not overwrite the end of the buffer: */
726
 
        ASSERT_NS(value->sv_length <= XT_IDX_MAX_KEY_SIZE);
 
877
        ASSERT_NS(value->sv_length <= XT_INDEX_MAX_KEY_SIZE);
727
878
        memmove(&leaf->tb_data[result->sr_item.i_item_offset + value->sv_length + XT_RECORD_REF_SIZE],
728
879
                &leaf->tb_data[result->sr_item.i_item_offset],
729
880
                result->sr_item.i_total_size - result->sr_item.i_item_offset);
730
881
        item = &leaf->tb_data[result->sr_item.i_item_offset];
731
882
        memcpy(item, value->sv_key, value->sv_length);
732
 
        XT_SET_RECORD_REF(item + value->sv_length, value->sv_record);
 
883
        xt_set_val_record_ref(item + value->sv_length, value);
733
884
        result->sr_item.i_total_size += value->sv_length + XT_RECORD_REF_SIZE;
734
885
        XT_SET_DISK_2(leaf->tb_size_2, XT_MAKE_LEAF_SIZE(result->sr_item.i_total_size));
735
886
}
739
890
        xtWord1 *item;
740
891
 
741
892
        /* This will ensure we do not overwrite the end of the buffer: */
742
 
        ASSERT_NS(value->sv_length <= XT_IDX_MAX_KEY_SIZE);
 
893
        ASSERT_NS(value->sv_length <= XT_INDEX_MAX_KEY_SIZE);
743
894
        memmove(&leaf->tb_data[result->sr_item.i_item_offset + value->sv_length + XT_RECORD_REF_SIZE + result->sr_item.i_node_ref_size],
744
895
                &leaf->tb_data[result->sr_item.i_item_offset],
745
896
                result->sr_item.i_total_size - result->sr_item.i_item_offset);
746
897
        item = &leaf->tb_data[result->sr_item.i_item_offset];
747
898
        memcpy(item, value->sv_key, value->sv_length);
748
 
        XT_SET_RECORD_REF(item + value->sv_length, value->sv_record);
 
899
        xt_set_val_record_ref(item + value->sv_length, value);
749
900
        XT_SET_NODE_REF(item + value->sv_length + XT_RECORD_REF_SIZE, branch);
750
901
        result->sr_item.i_total_size += value->sv_length + XT_RECORD_REF_SIZE + result->sr_item.i_node_ref_size;
751
902
        XT_SET_DISK_2(leaf->tb_size_2, XT_MAKE_NODE_SIZE(result->sr_item.i_total_size));
764
915
                bitem = &branch->tb_data[result->sr_item.i_item_offset];
765
916
                value->sv_flags = XT_SEARCH_WHOLE_KEY;
766
917
                value->sv_length = result->sr_item.i_item_size - XT_RECORD_REF_SIZE;
767
 
                value->sv_record = XT_GET_RECORD_REF(bitem + value->sv_length);
 
918
                xt_get_record_ref(bitem + value->sv_length, &value->sv_rec_id, &value->sv_row_id);
768
919
                memcpy(value->sv_key, bitem, value->sv_length);
769
920
        }
770
921
        else {
790
941
 
791
942
                value->sv_flags = XT_SEARCH_WHOLE_KEY;
792
943
                value->sv_length = ilen;
793
 
                value->sv_record = XT_GET_RECORD_REF(bitem + ilen);
 
944
                xt_get_record_ref(bitem + ilen, &value->sv_rec_id, &value->sv_row_id);
794
945
                memcpy(value->sv_key, bitem, value->sv_length);
795
946
        }
796
947
}
798
949
static size_t idx_write_branch_item(XTIndexPtr ind, xtWord1 *item, XTIdxKeyValuePtr value)
799
950
{
800
951
        memcpy(item, value->sv_key, value->sv_length);
801
 
        XT_SET_RECORD_REF(item + value->sv_length, value->sv_record);
 
952
        xt_set_val_record_ref(item + value->sv_length, value);
802
953
        return value->sv_length + XT_RECORD_REF_SIZE;
803
954
}
804
955
 
811
962
        u_int                           new_size;
812
963
        XTIdxBranchDPtr         new_branch_ptr;
813
964
        XTIdxKeyValueRec        key_value;
814
 
        xtWord1                         key_buf[XT_IDX_MAX_KEY_SIZE];
 
965
        xtWord1                         key_buf[XT_INDEX_MAX_KEY_SIZE];
815
966
 
816
 
        if (!xt_dc_read_block(ot->ot_ind_file, current, (xtWord1 *) branch))
 
967
        if (!xt_ind_read_block(ot->ot_ind_file, current, (xtWord1 *) branch))
817
968
                return FAILED;
818
969
        memmove(&branch->tb_data[item->i_pos.i_item_offset + item_size],
819
970
                &branch->tb_data[item->i_pos.i_item_offset + item->i_pos.i_item_size],
823
974
        item->i_pos.i_total_size = item->i_pos.i_total_size + item_size - item->i_pos.i_item_size;
824
975
        XT_SET_DISK_2(branch->tb_size_2, XT_MAKE_NODE_SIZE(item->i_pos.i_total_size));
825
976
 
826
 
        if (item->i_pos.i_total_size <= XT_IDX_PAGE_DATA_SIZE)
827
 
                return xt_dc_write(ot->ot_ind_file, current, offsetof(XTIdxBranchDRec, tb_data) + item->i_pos.i_total_size, (xtWord1 *) branch);
 
977
        if (item->i_pos.i_total_size <= XT_INDEX_PAGE_DATA_SIZE)
 
978
                return xt_ind_write(ot->ot_ind_file, current, offsetof(XTIdxBranchDRec, tb_data) + item->i_pos.i_total_size, (xtWord1 *) branch);
828
979
 
829
980
        /* The node has overflowed!! */
830
981
        result.sr_item = item->i_pos;
845
996
 
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);
850
1001
 
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))
853
1004
                goto failed_2;
854
1005
 
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))
858
1009
                goto failed_2;
859
1010
 
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))
911
1062
                        goto failed_2;
912
1063
                ind->mi_root = new_branch;
913
 
                ot->ot_table->tab_head_dirty = TRUE;
 
1064
                ot->ot_table->tab_ind_head_dirty = TRUE;
914
1065
                goto done_ok;
915
1066
        }
916
1067
 
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))
919
1070
                goto failed;
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);
922
1073
 
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))
926
1077
                        goto failed;
927
1078
                goto done_ok;
928
1079
        }
935
1086
 
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);
940
1091
 
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))
943
1094
                goto failed_2;
944
1095
 
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))
948
1099
                goto failed_2;
949
1100
 
950
1101
        /* Insert the new branch into the parent node, using the new middle key value: */
977
1128
        off_t                           current;
978
1129
        XTIdxResultRec          result;
979
1130
        xtBool                          on_key = FALSE;
980
 
        xtWord8                         xn_id;
 
1131
        xtXactID                        xn_id;
981
1132
        int                                     save_flags;                             
982
1133
 
983
1134
        retry:
990
1141
        key_value->sv_flags = 0;
991
1142
 
992
1143
        while (current) {
993
 
                if (!xt_dc_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_wbuf)) {
 
1144
                if (!xt_ind_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_wbuf)) {
994
1145
                        key_value->sv_flags = save_flags;
995
1146
                        return FAILED;
996
1147
                }
1023
1174
                        while ((node = idx_pop(&stack))) {
1024
1175
                                if (node->i_pos.i_item_offset < node->i_pos.i_total_size) {
1025
1176
                                        current = node->i_branch;
1026
 
                                        if (!xt_dc_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_wbuf))
 
1177
                                        if (!xt_ind_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_wbuf))
1027
1178
                                                return FAILED;
1028
 
                                        result.sr_record = XT_GET_RECORD_REF(&ot->ot_ind_wbuf.tb_data[node->i_pos.i_item_offset + node->i_pos.i_item_size - XT_RECORD_REF_SIZE]);
 
1179
                                        xt_get_res_record_ref(&ot->ot_ind_wbuf.tb_data[node->i_pos.i_item_offset + node->i_pos.i_item_size - XT_RECORD_REF_SIZE], &result);
1029
1180
                                        result.sr_item = node->i_pos;
1030
1181
                                        goto check_value;
1031
1182
                                }
1044
1195
                        break;
1045
1196
                */
1046
1197
 
1047
 
                switch (xt_tab_maybe_committed(ot, result.sr_record, &xn_id, NULL, NULL)) {
 
1198
                switch (xt_tab_maybe_committed(ot, result.sr_rec_id, &xn_id, NULL, NULL)) {
1048
1199
                        case XT_MAYBE:
1049
1200
                                /* Record is not committed, wait for the transaction. */
1050
1201
                                xt_rwlock_unlock(&ind->mi_rwlock);
1051
 
                                if (!xt_xn_wait_for_xact(ot->ot_thread, xn_id)) {
 
1202
                                if (!xt_xn_wait_for_xact(ot->ot_thread, xn_id, FALSE)) {
1052
1203
                                        xt_rwlock_wrlock(&ind->mi_rwlock);
1053
1204
                                        return FAILED;
1054
1205
                                }
1059
1210
                                return FAILED;
1060
1211
                        case TRUE:
1061
1212
                                /* Record is committed or belongs to me, duplicate key: */
1062
 
                                XT_DEBUG_TRACE(("DUPLICATE KEY tx=%d rec=%d\n", (int) ot->ot_thread->st_xact_data->xd_start_id, (int) result.sr_record));
1063
 
                                //xt_dump_trace();
 
1213
                                XT_DEBUG_TRACE(("DUPLICATE KEY tx=%d rec=%d\n", (int) ot->ot_thread->st_xact_data->xd_start_xn_id, (int) result.sr_rec_id));
1064
1214
                                xt_register_xterr(XT_REG_CONTEXT, XT_ERR_DUPLICATE_KEY);
1065
1215
                                return FAILED;
1066
1216
                        case FALSE:
1076
1226
                                if (!idx_push(&stack, current, &result.sr_item))
1077
1227
                                        return FAILED;
1078
1228
                                current = result.sr_branch;
1079
 
                                if (!xt_dc_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_wbuf))
 
1229
                                if (!xt_ind_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_wbuf))
1080
1230
                                        return FAILED;
1081
1231
                                idx_first_branch_item(ind, &ot->ot_ind_wbuf, &result);
1082
1232
                                if (!result.sr_item.i_node_ref_size)
1090
1240
/*
1091
1241
 * Insert a value into the given index. Return FALSE if an error occurs.
1092
1242
 */
1093
 
xtPublic xtBool xt_idx_insert(XTOpenTablePtr ot, XTIndexPtr ind, off_t address, xtWord1 *rec_buf, xtWord1 *bef_buf)
 
1243
xtPublic xtBool xt_idx_insert(XTOpenTablePtr ot, XTIndexPtr ind, xtRecordID rec_id, xtWord1 *rec_buf, xtWord1 *bef_buf, xtBool allow_dups)
1094
1244
{
1095
1245
        XTIdxKeyValueRec        key_value;
1096
 
        xtWord1                         key_buf[XT_IDX_MAX_KEY_SIZE];
 
1246
        xtWord1                         key_buf[XT_INDEX_MAX_KEY_SIZE];
1097
1247
        IdxBranchStackRec       stack;
1098
1248
        off_t                           current;
1099
1249
        off_t                           new_branch;
1101
1251
        XTIdxResultRec          result;
1102
1252
        size_t                          new_size;
1103
1253
        XTIdxBranchDPtr         new_branch_ptr;
1104
 
        xtBool                          check_for_dups = ind->mi_flags & (HA_UNIQUE_CHECK | HA_NOSAME);
 
1254
        xtBool                          check_for_dups = ind->mi_flags & (HA_UNIQUE_CHECK | HA_NOSAME) && !allow_dups;
1105
1255
 
1106
 
#ifdef DEBUG
1107
 
        //idx_print_index(ot, ind);
 
1256
#ifdef CHECK_AND_PRINT
 
1257
        //idx_print_index(ot, ind, TRUE);
1108
1258
#endif
1109
1259
 
1110
1260
        key_value.sv_flags = XT_SEARCH_WHOLE_KEY;
1111
 
        key_value.sv_record = address;
 
1261
        key_value.sv_rec_id = rec_id;
 
1262
        key_value.sv_row_id = 0;                /* Always set the row ID to zero on insert (will be update by sweeper later). */
1112
1263
        key_value.sv_key = key_buf;
1113
1264
        key_value.sv_length = myxt_create_key_from_row(ind, key_buf, rec_buf, &check_for_dups);
1114
1265
 
1117
1268
                /* If we have a before image, and we are required to check for duplicates.
1118
1269
                 * then compare the before image key with the after image key.
1119
1270
                 */
1120
 
                xtWord1 bef_key_buf[XT_IDX_MAX_KEY_SIZE];
 
1271
                xtWord1 bef_key_buf[XT_INDEX_MAX_KEY_SIZE];
1121
1272
                u_int   len;
1122
1273
                xtBool  has_no_null = TRUE;
1123
1274
 
1141
1292
                        goto failed;
1142
1293
                size = idx_write_branch_item(ind, ot->ot_ind_wbuf.tb_data, &key_value);
1143
1294
                XT_SET_DISK_2(ot->ot_ind_wbuf.tb_size_2, XT_MAKE_LEAF_SIZE(size));
1144
 
                if (!xt_dc_write(ot->ot_ind_file, new_branch, offsetof(XTIdxBranchDRec, tb_data) + size, (xtWord1 *) &ot->ot_ind_wbuf))
 
1295
                if (!xt_ind_write(ot->ot_ind_file, new_branch, offsetof(XTIdxBranchDRec, tb_data) + size, (xtWord1 *) &ot->ot_ind_wbuf))
1145
1296
                        goto failed_2;
1146
1297
                ind->mi_root = new_branch;
1147
 
                ot->ot_table->tab_head_dirty = TRUE;
 
1298
                ot->ot_table->tab_ind_head_dirty = TRUE;
1148
1299
                goto done_ok;
1149
1300
        }
1150
1301
 
1151
1302
        while (current) {
1152
 
                if (!xt_dc_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_wbuf))
 
1303
                if (!xt_ind_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_wbuf))
1153
1304
                        goto failed;
1154
1305
                ind->mi_scan_branch(ind, &ot->ot_ind_wbuf, &key_value, &result);
1155
1306
                if (result.sr_duplicate) {
1168
1319
                        }
1169
1320
                }
1170
1321
                if (result.sr_found) {
1171
 
                        /* Node found (should not happen) */
1172
 
                        ASSERT_NS(!result.sr_found);
 
1322
                        /* Node found, can happen during recovery of indexes! */
1173
1323
                        goto done_ok;
1174
1324
                }
1175
1325
                /* Stop when we get to a leaf: */
1181
1331
        }
1182
1332
 
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))
1186
1336
                        goto failed;
1187
1337
                goto done_ok;
1188
1338
        }
1189
1339
 
 
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;
 
1344
#endif
 
1345
 
1190
1346
        /* Key does not fit, must split... */
1191
1347
        idx_get_middle_branch_item(ind, &ot->ot_ind_wbuf, &key_value, &result);
1192
1348
 
1193
1349
        if (!idx_new_branch(ot, &new_branch))
1194
1350
                goto failed;
1195
1351
 
 
1352
#ifdef XT_INDEX_LOG_CHANGES
 
1353
        /* Note: the middle item is not copied into any of the
 
1354
         * 2 resulting nodes.
 
1355
         */
 
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;
 
1359
 
 
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]);
 
1366
                }
 
1367
                /* Set the current node size. */
 
1368
                XT_SET_NODE_SIZE(current, result.sr_item.i_item_offset);
 
1369
        }
 
1370
        else {
 
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;
 
1374
 
 
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);
 
1378
 
 
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]);
 
1381
        }
 
1382
#endif
 
1383
 
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);
1200
1388
 
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))
1203
1391
                goto failed_2;
1204
1392
 
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))
1208
1396
                goto failed_2;
1209
1397
 
1210
1398
        /* Insert the new branch into the parent node, using the new middle key value: */
1217
1405
 
1218
1406
#ifdef DEBUG
1219
1407
        //printf("INSERT OK\n");
1220
 
        //idx_print_index(ot, ind);
 
1408
        //idx_print_index(ot, ind, TRUE);
1221
1409
        //idx_check_index(ot, ind);
1222
1410
#endif
1223
1411
        return OK;
1233
1421
 
1234
1422
#ifdef DEBUG
1235
1423
        //printf("INSERT FAILED\n");
1236
 
        //idx_print_index(ot, ind);
 
1424
        //idx_print_index(ot, ind, TRUE);
1237
1425
#endif
1238
1426
        return FAILED;
1239
1427
}
1254
1442
                goto done_ok;
1255
1443
 
1256
1444
        while (current) {
1257
 
                if (!xt_dc_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_wbuf))
 
1445
                if (!xt_ind_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_wbuf))
1258
1446
                        goto failed;
1259
1447
                ind->mi_scan_branch(ind, &ot->ot_ind_wbuf, key_value, &result);
1260
1448
                if (!result.sr_item.i_node_ref_size) {
1281
1469
        /* Go down the left-hand side until we reach a leaf: */
1282
1470
        while (current) {
1283
1471
                current = result.sr_branch;
1284
 
                if (!xt_dc_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_wbuf))
 
1472
                if (!xt_ind_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_wbuf))
1285
1473
                        goto failed;
1286
1474
                idx_first_branch_item(ind, &ot->ot_ind_wbuf, &result);
1287
1475
                if (!result.sr_item.i_node_ref_size)
1311
1499
 
1312
1500
                current_top = idx_pop(&stack);
1313
1501
                current = current_top->i_branch;
1314
 
                if (!xt_dc_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_wbuf))
 
1502
                if (!xt_ind_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_wbuf))
1315
1503
                        goto failed;
1316
1504
                
1317
1505
                if (current_top == delete_node) {
1338
1526
 
1339
1527
#ifdef DEBUG
1340
1528
        //printf("DELETE OK\n");
1341
 
        //idx_print_index(ot, ind);
 
1529
        //idx_print_index(ot, ind, TRUE);
1342
1530
        //idx_check_index(ot, ind);
1343
1531
#endif
1344
1532
        return OK;
1351
1539
xtPublic void xt_idx_delete_current(XTOpenTablePtr ot, XTIndexPtr ind)
1352
1540
{
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;
1355
1544
 
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;
1361
1551
 
1362
1552
        if (!idx_delete(ot, ind, &key_value))
1363
1553
                xt_log_and_clear_exception_ns();
1364
1554
 
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.
 
1558
         *
 
1559
         * I assume that what I am trying to do is restore
 
1560
         * the search value, to that which we had before the
 
1561
         * delete.
 
1562
         *
 
1563
         * The problem is, key_buf can be changed by idx_delete().
 
1564
         *
 
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);
 
1572
         */
 
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!
 
1576
         */
 
1577
        ot->ot_ind_state.i_node_ref_size = XT_NODE_REF_SIZE;
1371
1578
}
1372
1579
 
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)
1374
1581
{
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];
1377
1584
 
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);
1382
1590
 
1383
1591
        return idx_delete(ot, ind, &key_value);
1384
1592
}
1385
1593
 
 
1594
xtPublic xtBool xt_idx_update_row_id(XTOpenTablePtr ot, XTIndexPtr ind, xtRecordID rec_id, xtRowID row_id, xtWord1 *rec_buf)
 
1595
{
 
1596
        off_t                           current;
 
1597
        XTIdxResultRec          result;
 
1598
        XTIdxKeyValueRec        key_value;
 
1599
        xtWord1                         key_buf[XT_INDEX_MAX_KEY_SIZE + XT_MAX_RECORD_REF_SIZE];
 
1600
 
 
1601
#ifdef CHECK_AND_PRINT
 
1602
        idx_print_index(ot, ind, TRUE);
 
1603
#endif
 
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);
 
1609
 
 
1610
        /* NOTE: Only a read lock is required for this!! */
 
1611
        xt_rwlock_rdlock(&ind->mi_rwlock);
 
1612
 
 
1613
        if (!(current = ind->mi_root))
 
1614
                goto done_ok;
 
1615
 
 
1616
        while (current) {
 
1617
                if (!xt_ind_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_rbuf))
 
1618
                        goto failed;
 
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)
 
1621
                        break;
 
1622
                current = result.sr_branch;
 
1623
        }
 
1624
 
 
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))
 
1628
                        goto failed;
 
1629
        }
 
1630
 
 
1631
        done_ok:
 
1632
        xt_rwlock_unlock(&ind->mi_rwlock);
 
1633
 
 
1634
#ifdef DEBUG
 
1635
        //idx_print_index(ot, ind, TRUE);
 
1636
        //idx_check_index(ot, ind);
 
1637
        //idx_check_on_key(ot);
 
1638
#endif
 
1639
        return OK;
 
1640
 
 
1641
        failed:
 
1642
        xt_rwlock_unlock(&ind->mi_rwlock);
 
1643
        return FAILED;
 
1644
}
 
1645
 
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)
1387
1647
{
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;
1393
1654
}
1394
1655
 
 
1656
xtPublic xtBool xt_idx_research(XTOpenTablePtr ot, XTIndexPtr ind)
 
1657
{
 
1658
        XTIdxSearchKeyRec search_key;
 
1659
 
 
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);
 
1667
}
 
1668
 
1395
1669
/*
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
1404
1678
        XTIdxResultRec          result;
1405
1679
 
1406
1680
#ifdef DEBUG
1407
 
        //idx_print_index(ot, ind);
 
1681
        //idx_print_index(ot, ind, TRUE);
1408
1682
#endif
1409
1683
 
 
1684
        /* Calling from recovery, this is not the case.
 
1685
         * But the index read does not require a transaction!
 
1686
         * Only insert requires this to check for duplicates.
1410
1687
        if (!ot->ot_thread->st_xact_data) {
1411
1688
                xt_register_xterr(XT_REG_CONTEXT, XT_ERR_NO_TRANSACTION);
1412
1689
                return FAILED;
1413
1690
        }
 
1691
        */
1414
1692
 
1415
1693
        idx_newstack(&stack);
1416
1694
 
1417
 
        ot->ot_curr_rec = 0;
 
1695
        ot->ot_curr_rec_id = 0;
 
1696
        ot->ot_curr_row_id = 0;
1418
1697
 
1419
1698
        xt_rwlock_rdlock(&ind->mi_rwlock);
1420
1699
 
1422
1701
                goto done_ok;
1423
1702
 
1424
1703
        while (current) {
1425
 
                if (!xt_dc_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_rbuf))
 
1704
                if (!xt_ind_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_rbuf))
1426
1705
                        goto failed;
1427
1706
                ind->mi_scan_branch(ind, &ot->ot_ind_rbuf, &search_key->sk_key_value, &result);
1428
1707
                if (result.sr_found)
1444
1723
                 */
1445
1724
                while ((node = idx_pop(&stack))) {
1446
1725
                        if (node->i_pos.i_item_offset < node->i_pos.i_total_size) {
1447
 
                                if (!xt_dc_read_block(ot->ot_ind_file, node->i_branch, (xtWord1 *) &ot->ot_ind_rbuf))
 
1726
                                xtRecordID rec_id;
 
1727
 
 
1728
                                if (!xt_ind_read_block(ot->ot_ind_file, node->i_branch, (xtWord1 *) &ot->ot_ind_rbuf))
1448
1729
                                        goto failed;
1449
 
                                ot->ot_curr_rec = XT_GET_RECORD_REF(&ot->ot_ind_rbuf.tb_data[node->i_pos.i_item_offset + node->i_pos.i_item_size - XT_RECORD_REF_SIZE]);
 
1730
                                xt_get_record_ref(&ot->ot_ind_rbuf.tb_data[node->i_pos.i_item_offset + node->i_pos.i_item_size - XT_RECORD_REF_SIZE], &rec_id, &ot->ot_curr_row_id);
 
1731
                                ot->ot_curr_rec_id = rec_id;
1450
1732
                                ot->ot_ind_state = node->i_pos;
1451
1733
                                break;
1452
1734
                        }
1453
1735
                }
1454
1736
        }
1455
1737
        else {
1456
 
                ot->ot_curr_rec = result.sr_record;
 
1738
                ot->ot_curr_rec_id = result.sr_rec_id;
 
1739
                ot->ot_curr_row_id = result.sr_row_id;
1457
1740
                ot->ot_ind_state = result.sr_item;
1458
1741
        }
1459
1742
 
1461
1744
        xt_rwlock_unlock(&ind->mi_rwlock);
1462
1745
 
1463
1746
#ifdef DEBUG
1464
 
        //idx_print_index(ot, ind);
 
1747
        //idx_print_index(ot, ind, TRUE);
1465
1748
        //idx_check_index(ot, ind);
1466
1749
        //idx_check_on_key(ot);
1467
1750
#endif
1479
1762
        XTIdxResultRec          result;
1480
1763
 
1481
1764
#ifdef DEBUG
1482
 
        //idx_print_index(ot, ind);
 
1765
        //idx_print_index(ot, ind, TRUE);
1483
1766
#endif
1484
1767
 
1485
1768
        if (!ot->ot_thread->st_xact_data) {
1489
1772
 
1490
1773
        idx_newstack(&stack);
1491
1774
 
1492
 
        ot->ot_curr_rec = 0;
 
1775
        ot->ot_curr_rec_id = 0;
 
1776
        ot->ot_curr_row_id = 0;
1493
1777
 
1494
1778
        xt_rwlock_rdlock(&ind->mi_rwlock);
1495
1779
 
1497
1781
                goto done_ok;
1498
1782
 
1499
1783
        while (current) {
1500
 
                if (!xt_dc_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_rbuf))
 
1784
                if (!xt_ind_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_rbuf))
1501
1785
                        goto failed;
1502
1786
                ind->mi_scan_branch(ind, &ot->ot_ind_rbuf, &search_key->sk_key_value, &result);
1503
1787
                if (result.sr_found)
1519
1803
                 */
1520
1804
                while ((node = idx_pop(&stack))) {
1521
1805
                        if (node->i_pos.i_item_offset > node->i_pos.i_node_ref_size) {
1522
 
                                if (!xt_dc_read_block(ot->ot_ind_file, node->i_branch, (xtWord1 *) &ot->ot_ind_rbuf))
 
1806
                                if (!xt_ind_read_block(ot->ot_ind_file, node->i_branch, (xtWord1 *) &ot->ot_ind_rbuf))
1523
1807
                                        goto failed;
1524
1808
                                result.sr_item = node->i_pos;
1525
1809
                                ind->mi_prev_item(ind, &ot->ot_ind_rbuf, &result);
1533
1817
        ind->mi_prev_item(ind, &ot->ot_ind_rbuf, &result);
1534
1818
 
1535
1819
        record_found:
1536
 
        ot->ot_curr_rec = result.sr_record;
 
1820
        ot->ot_curr_rec_id = result.sr_rec_id;
 
1821
        ot->ot_curr_row_id = result.sr_row_id;
1537
1822
        ot->ot_ind_state = result.sr_item;
1538
1823
 
1539
1824
        done_ok:
1540
1825
        xt_rwlock_unlock(&ind->mi_rwlock);
1541
1826
 
1542
1827
#ifdef DEBUG
1543
 
        //idx_print_index(ot, ind);
 
1828
        //idx_print_index(ot, ind, TRUE);
1544
1829
        //idx_check_index(ot, ind);
1545
1830
        //idx_check_on_key(ot);
1546
1831
#endif
1569
1854
xtPublic xtBool xt_idx_next(register XTOpenTablePtr ot, register XTIndexPtr ind, register XTIdxSearchKeyPtr search_key)
1570
1855
{
1571
1856
        XTIdxKeyValueRec        key_value;
1572
 
        xtWord1                         key_buf[XT_IDX_MAX_KEY_SIZE];
 
1857
        xtWord1                         key_buf[XT_INDEX_MAX_KEY_SIZE];
1573
1858
        XTIdxResultRec          result;
1574
1859
        IdxBranchStackRec       stack;
1575
1860
        off_t                           current;
1585
1870
        }
1586
1871
 
1587
1872
        key_value.sv_flags = XT_SEARCH_WHOLE_KEY;
1588
 
        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]);
 
1873
        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);
1589
1874
        key_value.sv_key = key_buf;
1590
1875
        key_value.sv_length = ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE;
1591
1876
        memcpy(key_buf, &ot->ot_ind_rbuf.tb_data[ot->ot_ind_state.i_item_offset], key_value.sv_length);
1600
1885
        }
1601
1886
 
1602
1887
        while (current) {
1603
 
                if (!xt_dc_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_rbuf))
 
1888
                if (!xt_ind_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_rbuf))
1604
1889
                        goto failed;
1605
1890
                ind->mi_scan_branch(ind, &ot->ot_ind_rbuf, &key_value, &result);
1606
1891
                if (result.sr_item.i_node_ref_size) {
1613
1898
                                        if (!idx_push(&stack, current, &result.sr_item))
1614
1899
                                                goto failed;
1615
1900
                                        current = result.sr_branch;
1616
 
                                        if (!xt_dc_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_rbuf))
 
1901
                                        if (!xt_ind_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_rbuf))
1617
1902
                                                goto failed;
1618
1903
                                        idx_first_branch_item(ind, &ot->ot_ind_rbuf, &result);
1619
1904
                                        if (!result.sr_item.i_node_ref_size)
1650
1935
                 */
1651
1936
                while ((node = idx_pop(&stack))) {
1652
1937
                        if (node->i_pos.i_item_offset < node->i_pos.i_total_size) {
1653
 
                                if (!xt_dc_read_block(ot->ot_ind_file, node->i_branch, (xtWord1 *) &ot->ot_ind_rbuf))
 
1938
                                if (!xt_ind_read_block(ot->ot_ind_file, node->i_branch, (xtWord1 *) &ot->ot_ind_rbuf))
1654
1939
                                        goto failed;
1655
1940
                                result.sr_item = node->i_pos;
1656
 
                                result.sr_record = XT_GET_RECORD_REF(&ot->ot_ind_rbuf.tb_data[result.sr_item.i_item_offset + result.sr_item.i_item_size - XT_RECORD_REF_SIZE]);
 
1941
                                xt_get_res_record_ref(&ot->ot_ind_rbuf.tb_data[result.sr_item.i_item_offset + result.sr_item.i_item_size - XT_RECORD_REF_SIZE], &result);
1657
1942
                                xt_rwlock_unlock(&ind->mi_rwlock);
1658
1943
                                goto check_on_key;
1659
1944
                        }
1662
1947
                /* No more keys: */
1663
1948
                if (search_key)
1664
1949
                        search_key->sk_on_key = FALSE;
1665
 
                ot->ot_curr_rec = 0;
 
1950
                ot->ot_curr_rec_id = 0;
 
1951
                ot->ot_curr_row_id = 0;
1666
1952
                xt_rwlock_unlock(&ind->mi_rwlock);
1667
1953
                return OK;
1668
1954
        }
1685
1971
                search_key->sk_on_key = myxt_compare_key(ind, search_key->sk_key_value.sv_flags, search_key->sk_key_value.sv_length,
1686
1972
                        search_key->sk_key_value.sv_key, &ot->ot_ind_rbuf.tb_data[result.sr_item.i_item_offset]) == 0;
1687
1973
        }
1688
 
        ot->ot_curr_rec = result.sr_record;
 
1974
        ot->ot_curr_rec_id = result.sr_rec_id;
 
1975
        ot->ot_curr_row_id = result.sr_row_id;
1689
1976
        ot->ot_ind_state = result.sr_item;
1690
1977
 
1691
1978
        return OK;
1698
1985
xtPublic xtBool xt_idx_prev(XTOpenTablePtr ot, XTIndexPtr ind, register XTIdxSearchKeyPtr search_key)
1699
1986
{
1700
1987
        XTIdxKeyValueRec        key_value;
1701
 
        xtWord1                         key_buf[XT_IDX_MAX_KEY_SIZE];
 
1988
        xtWord1                         key_buf[XT_INDEX_MAX_KEY_SIZE];
1702
1989
        XTIdxResultRec          result;
1703
1990
        IdxBranchStackRec       stack;
1704
1991
        off_t                           current;
1714
2001
        }
1715
2002
 
1716
2003
        key_value.sv_flags = XT_SEARCH_WHOLE_KEY;
1717
 
        key_value.sv_record = ot->ot_curr_rec;
 
2004
        key_value.sv_rec_id = ot->ot_curr_rec_id;
 
2005
        key_value.sv_row_id = 0;
1718
2006
        key_value.sv_key = key_buf;
1719
2007
        key_value.sv_length = ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE;
1720
2008
        memcpy(key_buf, &ot->ot_ind_rbuf.tb_data[ot->ot_ind_state.i_item_offset], key_value.sv_length);
1729
2017
        }
1730
2018
 
1731
2019
        while (current) {
1732
 
                if (!xt_dc_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_rbuf))
 
2020
                if (!xt_ind_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_rbuf))
1733
2021
                        goto failed;
1734
2022
                ind->mi_scan_branch(ind, &ot->ot_ind_rbuf, &key_value, &result);
1735
2023
                if (result.sr_item.i_node_ref_size) {
1741
2029
                                        if (!idx_push(&stack, current, &result.sr_item))
1742
2030
                                                goto failed;
1743
2031
                                        current = result.sr_branch;
1744
 
                                        if (!xt_dc_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_rbuf))
 
2032
                                        if (!xt_ind_read_block(ot->ot_ind_file, current, (xtWord1 *) &ot->ot_ind_rbuf))
1745
2033
                                                goto failed;
1746
2034
                                        ind->mi_last_item(ind, &ot->ot_ind_rbuf, &result);
1747
2035
                                        if (!result.sr_item.i_node_ref_size)
1775
2063
         */
1776
2064
        while ((node = idx_pop(&stack))) {
1777
2065
                if (node->i_pos.i_item_offset > node->i_pos.i_node_ref_size) {
1778
 
                        if (!xt_dc_read_block(ot->ot_ind_file, node->i_branch, (xtWord1 *) &ot->ot_ind_rbuf))
 
2066
                        if (!xt_ind_read_block(ot->ot_ind_file, node->i_branch, (xtWord1 *) &ot->ot_ind_rbuf))
1779
2067
                                goto failed;
1780
2068
                        result.sr_item = node->i_pos;
1781
2069
                        ind->mi_prev_item(ind, &ot->ot_ind_rbuf, &result);
1786
2074
        /* No more keys: */
1787
2075
        if (search_key)
1788
2076
                search_key->sk_on_key = FALSE;
1789
 
        ot->ot_curr_rec = 0;
 
2077
        ot->ot_curr_rec_id = 0;
 
2078
        ot->ot_curr_row_id = 0;
1790
2079
 
1791
2080
        xt_rwlock_unlock(&ind->mi_rwlock);
1792
2081
        return OK;
1800
2089
                search_key->sk_on_key = myxt_compare_key(ind, search_key->sk_key_value.sv_flags, search_key->sk_key_value.sv_length,
1801
2090
                        search_key->sk_key_value.sv_key, &ot->ot_ind_rbuf.tb_data[result.sr_item.i_item_offset]) == 0;
1802
2091
        }
1803
 
        ot->ot_curr_rec = result.sr_record;
 
2092
        ot->ot_curr_rec_id = result.sr_rec_id;
 
2093
        ot->ot_curr_row_id = result.sr_row_id;
1804
2094
        ot->ot_ind_state = result.sr_item;
1805
2095
        return OK;
1806
2096
 
1809
2099
        return FAILED;
1810
2100
}
1811
2101
 
 
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)
 
2104
{
 
2105
        int             r;
 
2106
        xtWord1 key_buf[XT_INDEX_MAX_KEY_SIZE];
 
2107
 
 
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);
 
2110
        switch (mode) {
 
2111
                case XT_S_MODE_MATCH:
 
2112
                        return r == 0;
 
2113
                case XT_S_MODE_NEXT:
 
2114
                        return r <= 0;
 
2115
                case XT_S_MODE_PREV:
 
2116
                        return r >= 0;
 
2117
        }
 
2118
        return FALSE;
 
2119
}
 
2120
 
 
2121
static void idx_set_index_selectivity(XTThreadPtr self, XTOpenTablePtr ot, XTIndexPtr ind)
 
2122
{
 
2123
        XTIdxSearchKeyRec       search_key;
 
2124
        XTIndexSegPtr           key_seg;
 
2125
        u_int                           select_count = 0;
 
2126
        xtWord1                         key_buf[XT_INDEX_MAX_KEY_SIZE];
 
2127
        u_int                           key_len;
 
2128
        xtWord1                         *next_key_buf;
 
2129
        u_int                           next_key_len;
 
2130
        u_int                           curr_len;
 
2131
        u_int                           diff;
 
2132
        u_int                           i;
 
2133
 
 
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;
 
2139
        }
 
2140
 
 
2141
        xt_idx_prep_key(ind, &search_key, XT_SEARCH_FIRST_FLAG, NULL, 0);
 
2142
        if (!xt_idx_search(ot, ind, &search_key))
 
2143
                return;
 
2144
 
 
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) {
 
2148
                        select_count++;
 
2149
 
 
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);
 
2152
                }
 
2153
                if (!xt_idx_next(ot, ind, &search_key))
 
2154
                        return;
 
2155
        }
 
2156
 
 
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) {
 
2160
                        select_count++;
 
2161
 
 
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;
 
2164
                
 
2165
                        curr_len = 0;
 
2166
                        diff = FALSE;
 
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)
 
2171
                                        diff = i+1;
 
2172
                                if (diff)
 
2173
                                        key_seg->is_selectivity++;
 
2174
                        }
 
2175
 
 
2176
                        /* Store the key for the next comparison: */
 
2177
                        key_len = next_key_len;
 
2178
                        memcpy(key_buf, next_key_buf, key_len);
 
2179
                }
 
2180
 
 
2181
                if (!xt_idx_next(ot, ind, &search_key))
 
2182
                        break;
 
2183
        }
 
2184
 
 
2185
        if (select_count) {
 
2186
                u_int recs;
 
2187
 
 
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;
 
2193
                }
 
2194
        }
 
2195
}
 
2196
 
 
2197
xtPublic void xt_ind_set_index_selectivity(XTThreadPtr self, XTOpenTablePtr ot)
 
2198
{
 
2199
        XTTableHPtr             tab = ot->ot_table;
 
2200
        XTIndexPtr              *ind;
 
2201
        u_int                   i;
 
2202
 
 
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);
 
2205
}
 
2206
 
1812
2207
/*
1813
2208
 * -----------------------------------------------------------------------
1814
2209
 * Print a b-tree
1815
2210
 */
1816
2211
 
1817
 
#ifdef CHECK_AND_PRINT
1818
2212
static void idx_check_on_key(XTOpenTablePtr ot)
1819
2213
{
1820
 
        u_int   offs = ot->ot_ind_state.i_item_offset + ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE;
1821
 
        off_t   record;
 
2214
        u_int           offs = ot->ot_ind_state.i_item_offset + ot->ot_ind_state.i_item_size - XT_RECORD_REF_SIZE;
 
2215
        xtRecordID      rec_id;
 
2216
        xtRowID         row_id;
1822
2217
        
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);
1825
2220
                
1826
 
                ASSERT_NS(record == ot->ot_curr_rec);
 
2221
                ASSERT_NS(rec_id == ot->ot_curr_rec_id);
1827
2222
        }
1828
2223
}
1829
2224
 
1835
2230
 
1836
2231
static void idx_print_node(XTOpenTablePtr ot, XTIndexPtr ind, int depth, off_t node)
1837
2232
{
1838
 
        xtWord1                 nbuf[XT_IDX_PAGE_SIZE];
 
2233
        xtWord1                 nbuf[XT_INDEX_PAGE_SIZE];
1839
2234
        XTIdxBranchDPtr branch = (XTIdxBranchDPtr) nbuf;
1840
2235
        XTIdxResultRec  result;
1841
2236
 
1842
 
        if (!xt_dc_read_block(ot->ot_ind_file, node, (xtWord1 *) branch))
 
2237
        if (!xt_ind_read_block(ot->ot_ind_file, node, (xtWord1 *) branch))
1843
2238
                return;
1844
2239
        idx_first_branch_item(ind, branch, &result);
1845
2240
        if (result.sr_item.i_node_ref_size) {
1850
2245
 
1851
2246
        while (result.sr_item.i_item_offset < result.sr_item.i_total_size) {
1852
2247
                idx_print_space(depth);
1853
 
                printf("%llu# ", (u_llong) result.sr_record);
 
2248
                printf("%llu# row=%lu ", (u_llong) result.sr_rec_id, (u_long) result.sr_row_id);
1854
2249
                myxt_print_key(ind, &branch->tb_data[result.sr_item.i_item_offset]);
1855
2250
                printf("\n");
1856
2251
                idx_next_branch_item(ind, branch, &result);
1862
2257
        }
1863
2258
}
1864
2259
 
1865
 
static void idx_print_index(XTOpenTablePtr ot, XTIndexPtr ind)
 
2260
static void idx_print_index(XTOpenTablePtr ot, XTIndexPtr ind, xtBool with_lock)
1866
2261
{
1867
2262
        register XTTableHPtr    tab = ot->ot_table;
1868
2263
        off_t                                   current;
1869
2264
        IdxFreeBlockRec                 free_block;
1870
2265
 
1871
 
        xt_rwlock_wrlock(&ind->mi_rwlock);
 
2266
        if (with_lock)
 
2267
                xt_rwlock_wrlock(&ind->mi_rwlock);
1872
2268
 
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);
1876
2272
 
1877
 
        xt_rwlock_unlock(&ind->mi_rwlock);
 
2273
        if (with_lock)
 
2274
                xt_rwlock_unlock(&ind->mi_rwlock);
1878
2275
 
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();
1886
2283
                        break;
1887
2284
                }
1888
2285
                current = XT_GET_DISK_8(free_block.if_next_block_8);
1889
2286
        }
1890
2287
        printf("\n-----------------------------\n");
1891
 
        xt_mutex_unlock(&tab->tab_ind_lock);
 
2288
        xt_unlock_mutex_ns(&tab->tab_ind_lock);
1892
2289
}
1893
2290
 
1894
2291
static void idx_check_node(XTOpenTablePtr ot, XTIndexPtr ind, int depth, off_t node)
1895
2292
{
1896
 
        xtWord1                 nbuf[XT_IDX_PAGE_SIZE];
 
2293
        xtWord1                 nbuf[XT_INDEX_PAGE_SIZE];
1897
2294
        XTIdxBranchDPtr branch = (XTIdxBranchDPtr) nbuf;
1898
2295
        XTIdxResultRec  result;
1899
2296
 
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))
1902
2299
                return;
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);
1907
2304
        }
1926
2323
 
1927
2324
        xt_rwlock_unlock(&ind->mi_rwlock);
1928
2325
 
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();
1934
2331
                        break;
1935
2332
                }
1936
2333
                current = XT_GET_DISK_8(free_block.if_next_block_8);
1937
2334
        }
1938
 
        xt_mutex_unlock(&tab->tab_ind_lock);
1939
 
}
1940
 
#endif
 
2335
        xt_unlock_mutex_ns(&tab->tab_ind_lock);
 
2336
}
 
2337
 
 
2338
xtPublic void xt_print_index(XTOpenTablePtr ot, XTIndexPtr ind, xtBool with_lock)
 
2339
{
 
2340
        idx_print_index(ot, ind, with_lock);
 
2341
}
 
2342
 
 
2343
xtPublic void xt_print_indices(XTOpenTablePtr ot)
 
2344
{
 
2345
        XTIndexPtr      *ind;
 
2346
 
 
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);
 
2350
        }
 
2351
}
1941
2352
 
1942
2353