~ubuntu-branches/ubuntu/utopic/mariadb-5.5/utopic-security

« back to all changes in this revision

Viewing changes to storage/tokudb/ft-index/ft/ft-ops.cc

  • Committer: Package Import Robot
  • Author(s): Otto Kekäläinen
  • Date: 2014-08-27 21:12:36 UTC
  • mfrom: (2.1.6 sid)
  • Revision ID: package-import@ubuntu.com-20140827211236-se41hwfe4xy0hpef
* d/control: Removed Provides: libmysqlclient-dev (Closes: #759309)
* d/control: Removed Provides: libmysqld-dev with same motivation
* Re-introduced tha HPPA build patch as the upstream fix wasn't complete
* Fixed all kFreeBSD build and test suite issues
* Added Italian translation (Closes: #759813)

Show diffs side-by-side

added added

removed removed

Lines of Context:
367
367
    STATUS_INIT(FT_PRO_NUM_DIDNT_WANT_PROMOTE,             PROMOTION_STOPPED_AFTER_LOCKING_CHILD, PARCOUNT, "promotion: stopped anyway, after locking the child", TOKU_ENGINE_STATUS|TOKU_GLOBAL_STATUS);
368
368
    STATUS_INIT(FT_BASEMENT_DESERIALIZE_FIXED_KEYSIZE,     BASEMENT_DESERIALIZATION_FIXED_KEY, PARCOUNT, "basement nodes deserialized with fixed-keysize", TOKU_ENGINE_STATUS|TOKU_GLOBAL_STATUS);
369
369
    STATUS_INIT(FT_BASEMENT_DESERIALIZE_VARIABLE_KEYSIZE,  BASEMENT_DESERIALIZATION_VARIABLE_KEY, PARCOUNT, "basement nodes deserialized with variable-keysize", TOKU_ENGINE_STATUS|TOKU_GLOBAL_STATUS);
 
370
    STATUS_INIT(FT_PRO_RIGHTMOST_LEAF_SHORTCUT_SUCCESS,    nullptr, PARCOUNT, "promotion: succeeded in using the rightmost leaf shortcut", TOKU_ENGINE_STATUS);
 
371
    STATUS_INIT(FT_PRO_RIGHTMOST_LEAF_SHORTCUT_FAIL_POS,   nullptr, PARCOUNT, "promotion: tried the rightmost leaf shorcut but failed (out-of-bounds)", TOKU_ENGINE_STATUS);
 
372
    STATUS_INIT(FT_PRO_RIGHTMOST_LEAF_SHORTCUT_FAIL_REACTIVE,nullptr, PARCOUNT, "promotion: tried the rightmost leaf shorcut but failed (child reactive)", TOKU_ENGINE_STATUS);
370
373
 
371
374
    ft_status.initialized = true;
372
375
}
890
893
    for (int i = 0; i < node->n_children-1; i++) {
891
894
        toku_clone_dbt(&cloned_node->childkeys[i], node->childkeys[i]);
892
895
    }
 
896
    if (node->height > 0) {
 
897
        // need to move messages here so that we don't serialize stale
 
898
        // messages to the fresh tree - ft verify code complains otherwise.
 
899
        toku_move_ftnode_messages_to_stale(ft, node);
 
900
    }
893
901
    // clone partition
894
902
    ftnode_clone_partitions(node, cloned_node);
895
903
 
932
940
    int height = ftnode->height;
933
941
    if (write_me) {
934
942
        toku_assert_entire_node_in_memory(ftnode);
935
 
        if (height == 0) {
 
943
        if (height > 0 && !is_clone) {
 
944
            // cloned nodes already had their stale messages moved, see toku_ftnode_clone_callback()
 
945
            toku_move_ftnode_messages_to_stale(h, ftnode);
 
946
        } else if (height == 0) {
936
947
            ft_leaf_run_gc(h, ftnode);
937
 
        }
938
 
        if (height == 0 && !is_clone) {
939
 
            ftnode_update_disk_stats(ftnode, h, for_checkpoint);
 
948
            if (!is_clone) {
 
949
                ftnode_update_disk_stats(ftnode, h, for_checkpoint);
 
950
            }
940
951
        }
941
952
        int r = toku_serialize_ftnode_to(fd, ftnode->thisnodename, ftnode, ndd, !is_clone, h, for_checkpoint);
942
953
        assert_zero(r);
1079
1090
    return;
1080
1091
}
1081
1092
 
 
1093
static void ft_bnc_move_messages_to_stale(FT ft, NONLEAF_CHILDINFO bnc);
 
1094
 
1082
1095
// replace the child buffer with a compressed version of itself.
1083
 
// @return the old child buffer
1084
 
static NONLEAF_CHILDINFO
 
1096
static void 
1085
1097
compress_internal_node_partition(FTNODE node, int i, enum toku_compression_method compression_method)
1086
1098
{
1087
1099
    // if we should evict, compress the
1092
1104
    sub_block_init(sb);
1093
1105
    toku_create_compressed_partition_from_available(node, i, compression_method, sb);
1094
1106
 
1095
 
    // now set the state to compressed and return the old, available partition
1096
 
    NONLEAF_CHILDINFO bnc = BNC(node, i);
 
1107
    // now set the state to compressed
1097
1108
    set_BSB(node, i, sb);
1098
1109
    BP_STATE(node,i) = PT_COMPRESSED;
1099
 
    return bnc;
1100
1110
}
1101
1111
 
1102
1112
void toku_evict_bn_from_memory(FTNODE node, int childnum, FT h) {
1149
1159
        for (int i = 0; i < node->n_children; i++) {
1150
1160
            if (BP_STATE(node,i) == PT_AVAIL) {
1151
1161
                if (BP_SHOULD_EVICT(node,i)) {
1152
 
                    NONLEAF_CHILDINFO bnc;
1153
 
                    if (ft_compress_buffers_before_eviction) {
1154
 
                        // When partially evicting, always compress with quicklz
1155
 
                        bnc = compress_internal_node_partition(
 
1162
                    NONLEAF_CHILDINFO bnc = BNC(node, i);
 
1163
                    if (ft_compress_buffers_before_eviction &&
 
1164
                        // We may not serialize and compress a partition in memory if its
 
1165
                        // in memory layout version is different than what's on disk (and
 
1166
                        // therefore requires upgrade).
 
1167
                        //
 
1168
                        // Auto-upgrade code assumes that if a node's layout version read
 
1169
                        // from disk is not current, it MUST require upgrade. Breaking
 
1170
                        // this rule would cause upgrade code to upgrade this partition
 
1171
                        // again after we serialize it as the current version, which is bad.
 
1172
                        node->layout_version == node->layout_version_read_from_disk) {
 
1173
                        ft_bnc_move_messages_to_stale(ft, bnc);
 
1174
                        compress_internal_node_partition(
1156
1175
                            node,
1157
1176
                            i,
 
1177
                            // Always compress with quicklz
1158
1178
                            TOKU_QUICKLZ_METHOD
1159
1179
                            );
1160
1180
                    } else {
1161
1181
                        // We're not compressing buffers before eviction. Simply
1162
1182
                        // detach the buffer and set the child's state to on-disk.
1163
 
                        bnc = BNC(node, i);
1164
1183
                        set_BNULL(node, i);
1165
1184
                        BP_STATE(node, i) = PT_ON_DISK;
1166
1185
                    }
1626
1645
 
1627
1646
    BLOCKNUM old_blocknum = oldroot->thisnodename;
1628
1647
    uint32_t old_fullhash = oldroot->fullhash;
1629
 
    PAIR old_pair = oldroot->ct_pair;
1630
1648
    
1631
1649
    int new_height = oldroot->height+1;
1632
1650
    uint32_t new_fullhash;
1633
1651
    BLOCKNUM new_blocknum;
1634
 
    PAIR new_pair = NULL;
1635
1652
 
1636
1653
    cachetable_put_empty_node_with_dep_nodes(
1637
1654
        ft,
1641
1658
        &new_fullhash,
1642
1659
        &newroot
1643
1660
        );
1644
 
    new_pair = newroot->ct_pair;
1645
1661
    
1646
1662
    assert(newroot);
1647
1663
    assert(new_height > 0);
1653
1669
        ft->h->layout_version, 
1654
1670
        ft->h->flags
1655
1671
        );
 
1672
    newroot->fullhash = new_fullhash;
1656
1673
    MSN msna = oldroot->max_msn_applied_to_node_on_disk;
1657
1674
    newroot->max_msn_applied_to_node_on_disk = msna;
1658
1675
    BP_STATE(newroot,0) = PT_AVAIL;
1659
1676
    newroot->dirty = 1;
1660
1677
 
1661
 
    // now do the "switcheroo"
1662
 
    BP_BLOCKNUM(newroot,0) = new_blocknum;
1663
 
    newroot->thisnodename = old_blocknum;
1664
 
    newroot->fullhash = old_fullhash;
1665
 
    newroot->ct_pair = old_pair;
1666
 
 
1667
 
    oldroot->thisnodename = new_blocknum;
1668
 
    oldroot->fullhash = new_fullhash;
1669
 
    oldroot->ct_pair = new_pair;
1670
 
 
1671
 
    toku_cachetable_swap_pair_values(old_pair, new_pair);
 
1678
    // Set the first child to have the new blocknum,
 
1679
    // and then swap newroot with oldroot. The new root
 
1680
    // will inherit the hash/blocknum/pair from oldroot,
 
1681
    // keeping the root blocknum constant.
 
1682
    BP_BLOCKNUM(newroot, 0) = new_blocknum;
 
1683
    toku_ftnode_swap_pair_values(newroot, oldroot);
1672
1684
 
1673
1685
    toku_ft_split_child(
1674
1686
        ft,
2757
2769
    // verify that msn of latest message was captured in root node
2758
2770
    paranoid_invariant(msg->msn.msn == node->max_msn_applied_to_node_on_disk.msn);
2759
2771
 
 
2772
    if (node->thisnodename.b == ft->rightmost_blocknum.b) {
 
2773
        if (ft->seqinsert_score < FT_SEQINSERT_SCORE_THRESHOLD) {
 
2774
            // we promoted to the rightmost leaf node and the seqinsert score has not yet saturated.
 
2775
            toku_sync_fetch_and_add(&ft->seqinsert_score, 1);
 
2776
        }
 
2777
    } else if (ft->seqinsert_score != 0) {
 
2778
        // we promoted to something other than the rightmost leaf node and the score should reset
 
2779
        ft->seqinsert_score = 0;
 
2780
    }
 
2781
 
2760
2782
    // if we call toku_ft_flush_some_child, then that function unpins the root
2761
2783
    // otherwise, we unpin ourselves
2762
2784
    if (node->height > 0 && toku_ft_nonleaf_is_gorged(node, ft->h->nodesize)) {
2913
2935
    return (height == 0 || (loc == NEITHER_EXTREME && (height <= 1 || depth >= 2)));
2914
2936
}
2915
2937
 
 
2938
static void ft_set_or_verify_rightmost_blocknum(FT ft, BLOCKNUM b)
 
2939
// Given: 'b', the _definitive_ and constant rightmost blocknum of 'ft'
 
2940
{
 
2941
    if (ft->rightmost_blocknum.b == RESERVED_BLOCKNUM_NULL) {
 
2942
        toku_ft_lock(ft);
 
2943
        if (ft->rightmost_blocknum.b == RESERVED_BLOCKNUM_NULL) {
 
2944
            ft->rightmost_blocknum = b;
 
2945
        }
 
2946
        toku_ft_unlock(ft);
 
2947
    }
 
2948
    // The rightmost blocknum only transitions from RESERVED_BLOCKNUM_NULL to non-null.
 
2949
    // If it's already set, verify that the stored value is consistent with 'b'
 
2950
    invariant(ft->rightmost_blocknum.b == b.b);
 
2951
}
 
2952
 
2916
2953
static void push_something_in_subtree(
2917
2954
    FT ft, 
2918
2955
    FTNODE subtree_root, 
2960
2997
        default:
2961
2998
            STATUS_INC(FT_PRO_NUM_INJECT_DEPTH_GT3, 1); break;
2962
2999
        }
 
3000
        // If the target node is a non-root leaf node on the right extreme,
 
3001
        // set the rightmost blocknum. We know there are no messages above us
 
3002
        // because promotion would not chose to inject directly into this leaf
 
3003
        // otherwise. We explicitly skip the root node because then we don't have
 
3004
        // to worry about changing the rightmost blocknum when the root splits.
 
3005
        if (subtree_root->height == 0 && loc == RIGHT_EXTREME && subtree_root->thisnodename.b != ft->h->root_blocknum.b) {
 
3006
            ft_set_or_verify_rightmost_blocknum(ft, subtree_root->thisnodename);
 
3007
        }
2963
3008
        inject_message_in_locked_node(ft, subtree_root, target_childnum, msg, flow_deltas, gc_info);
2964
3009
    } else {
2965
3010
        int r;
3230
3275
    }
3231
3276
}
3232
3277
 
3233
 
// Effect: Insert the key-val pair into ft.
 
3278
static int ft_compare_keys(FT ft, const DBT *a, const DBT *b)
 
3279
// Effect: Compare two keys using the given fractal tree's comparator/descriptor
 
3280
{
 
3281
    FAKE_DB(db, &ft->cmp_descriptor);
 
3282
    return ft->compare_fun(&db, a, b);
 
3283
}
 
3284
 
 
3285
static LEAFENTRY bn_get_le_and_key(BASEMENTNODE bn, int idx, DBT *key)
 
3286
// Effect: Gets the i'th leafentry from the given basement node and
 
3287
//         fill its key in *key
 
3288
// Requires: The i'th leafentry exists.
 
3289
{
 
3290
    LEAFENTRY le;
 
3291
    uint32_t le_len;
 
3292
    void *le_key;
 
3293
    int r = bn->data_buffer.fetch_klpair(idx, &le, &le_len, &le_key);
 
3294
    invariant_zero(r);
 
3295
    toku_fill_dbt(key, le_key, le_len);
 
3296
    return le;
 
3297
}
 
3298
 
 
3299
static LEAFENTRY ft_leaf_leftmost_le_and_key(FTNODE leaf, DBT *leftmost_key)
 
3300
// Effect: If a leftmost key exists in the given leaf, toku_fill_dbt()
 
3301
//         the key into *leftmost_key
 
3302
// Requires: Leaf is fully in memory and pinned for read or write.
 
3303
// Return: leafentry if it exists, nullptr otherwise
 
3304
{
 
3305
    for (int i = 0; i < leaf->n_children; i++) {
 
3306
        BASEMENTNODE bn = BLB(leaf, i);
 
3307
        if (bn->data_buffer.num_klpairs() > 0) {
 
3308
            // Get the first (leftmost) leafentry and its key
 
3309
            return bn_get_le_and_key(bn, 0, leftmost_key);
 
3310
        }
 
3311
    }
 
3312
    return nullptr;
 
3313
}
 
3314
 
 
3315
static LEAFENTRY ft_leaf_rightmost_le_and_key(FTNODE leaf, DBT *rightmost_key)
 
3316
// Effect: If a rightmost key exists in the given leaf, toku_fill_dbt()
 
3317
//         the key into *rightmost_key
 
3318
// Requires: Leaf is fully in memory and pinned for read or write.
 
3319
// Return: leafentry if it exists, nullptr otherwise
 
3320
{
 
3321
    for (int i = leaf->n_children - 1; i >= 0; i--) {
 
3322
        BASEMENTNODE bn = BLB(leaf, i);
 
3323
        size_t num_les = bn->data_buffer.num_klpairs();
 
3324
        if (num_les > 0) {
 
3325
            // Get the last (rightmost) leafentry and its key
 
3326
            return bn_get_le_and_key(bn, num_les - 1, rightmost_key);
 
3327
        }
 
3328
    }
 
3329
    return nullptr;
 
3330
}
 
3331
 
 
3332
static int ft_leaf_get_relative_key_pos(FT ft, FTNODE leaf, const DBT *key, bool *nondeleted_key_found, int *target_childnum)
 
3333
// Effect: Determines what the relative position of the given key is with
 
3334
//         respect to a leaf node, and if it exists.
 
3335
// Requires: Leaf is fully in memory and pinned for read or write.
 
3336
// Requires: target_childnum is non-null
 
3337
// Return: < 0 if key is less than the leftmost key in the leaf OR the relative position is unknown, for any reason.
 
3338
//         0 if key is in the bounds [leftmost_key, rightmost_key] for this leaf or the leaf is empty
 
3339
//         > 0 if key is greater than the rightmost key in the leaf
 
3340
//         *nondeleted_key_found is set (if non-null) if the target key was found and is not deleted, unmodified otherwise
 
3341
//         *target_childnum is set to the child that (does or would) contain the key, if calculated, unmodified otherwise
 
3342
{
 
3343
    DBT rightmost_key;
 
3344
    LEAFENTRY rightmost_le = ft_leaf_rightmost_le_and_key(leaf, &rightmost_key);
 
3345
    if (rightmost_le == nullptr) {
 
3346
        // If we can't get a rightmost key then the leaf is empty.
 
3347
        // In such a case, we don't have any information about what keys would be in this leaf.
 
3348
        // We have to assume the leaf node that would contain this key is to the left.
 
3349
        return -1;
 
3350
    }
 
3351
    // We have a rightmost leafentry, so it must exist in some child node
 
3352
    invariant(leaf->n_children > 0);
 
3353
 
 
3354
    int relative_pos = 0;
 
3355
    int c = ft_compare_keys(ft, key, &rightmost_key);
 
3356
    if (c > 0) {
 
3357
        relative_pos = 1;
 
3358
        *target_childnum = leaf->n_children - 1;
 
3359
    } else if (c == 0) {
 
3360
        if (nondeleted_key_found != nullptr && !le_latest_is_del(rightmost_le)) {
 
3361
            *nondeleted_key_found = true;
 
3362
        }
 
3363
        relative_pos = 0;
 
3364
        *target_childnum = leaf->n_children - 1;
 
3365
    } else {
 
3366
        // The key is less than the rightmost. It may still be in bounds if it's >= the leftmost.
 
3367
        DBT leftmost_key;
 
3368
        LEAFENTRY leftmost_le = ft_leaf_leftmost_le_and_key(leaf, &leftmost_key);
 
3369
        invariant_notnull(leftmost_le); // Must exist because a rightmost exists
 
3370
        c = ft_compare_keys(ft, key, &leftmost_key);
 
3371
        if (c > 0) {
 
3372
            if (nondeleted_key_found != nullptr) {
 
3373
                // The caller wants to know if a nondeleted key can be found.
 
3374
                LEAFENTRY target_le;
 
3375
                int childnum = toku_ftnode_which_child(leaf, key, &ft->cmp_descriptor, ft->compare_fun);
 
3376
                BASEMENTNODE bn = BLB(leaf, childnum);
 
3377
                struct msg_leafval_heaviside_extra extra = { ft->compare_fun, &ft->cmp_descriptor, key };
 
3378
                int r = bn->data_buffer.find_zero<decltype(extra), toku_msg_leafval_heaviside>(
 
3379
                    extra,
 
3380
                    &target_le,
 
3381
                    nullptr, nullptr, nullptr
 
3382
                    );
 
3383
                *target_childnum = childnum;
 
3384
                if (r == 0 && !le_latest_is_del(leftmost_le)) {
 
3385
                    *nondeleted_key_found = true;
 
3386
                }
 
3387
            }
 
3388
            relative_pos = 0;
 
3389
        } else if (c == 0) {
 
3390
            if (nondeleted_key_found != nullptr && !le_latest_is_del(leftmost_le)) {
 
3391
                *nondeleted_key_found = true;
 
3392
            }
 
3393
            relative_pos = 0;
 
3394
            *target_childnum = 0;
 
3395
        } else {
 
3396
            relative_pos = -1;
 
3397
        }
 
3398
    }
 
3399
 
 
3400
    return relative_pos;
 
3401
}
 
3402
 
 
3403
static void ft_insert_directly_into_leaf(FT ft, FTNODE leaf, int target_childnum, DBT *key, DBT *val,
 
3404
                                         XIDS message_xids, enum ft_msg_type type, txn_gc_info *gc_info);
 
3405
static int getf_nothing(ITEMLEN, bytevec, ITEMLEN, bytevec, void *, bool);
 
3406
 
 
3407
static int ft_maybe_insert_into_rightmost_leaf(FT ft, DBT *key, DBT *val, XIDS message_xids, enum ft_msg_type type,
 
3408
                                               txn_gc_info *gc_info, bool unique)
 
3409
// Effect: Pins the rightmost leaf node and attempts to do an insert.
 
3410
//         There are three reasons why we may not succeed.
 
3411
//         - The rightmost leaf is too full and needs a split. 
 
3412
//         - The key to insert is not within the provable bounds of this leaf node.
 
3413
//         - The key is within bounds, but it already exists.
 
3414
// Return: 0 if this function did insert, DB_KEYEXIST if a unique key constraint exists and
 
3415
//         some nondeleted leafentry with the same key exists
 
3416
//         < 0 if this function did not insert, for a reason other than DB_KEYEXIST.
 
3417
// Note: Treat this function as a possible, but not necessary, optimization for insert.
 
3418
// Rationale: We want O(1) insertions down the rightmost path of the tree.
 
3419
{
 
3420
    int r = -1;
 
3421
 
 
3422
    uint32_t rightmost_fullhash;
 
3423
    BLOCKNUM rightmost_blocknum = ft->rightmost_blocknum;
 
3424
    FTNODE rightmost_leaf = nullptr;
 
3425
 
 
3426
    // Don't do the optimization if our heurstic suggests that
 
3427
    // insertion pattern is not sequential.
 
3428
    if (ft->seqinsert_score < FT_SEQINSERT_SCORE_THRESHOLD) {
 
3429
        goto cleanup;
 
3430
    }
 
3431
 
 
3432
    // We know the seqinsert score is high enough that we should
 
3433
    // attemp to directly insert into the right most leaf. Because
 
3434
    // the score is non-zero, the rightmost blocknum must have been
 
3435
    // set. See inject_message_in_locked_node(), which only increases
 
3436
    // the score if the target node blocknum == rightmost_blocknum
 
3437
    invariant(rightmost_blocknum.b != RESERVED_BLOCKNUM_NULL);
 
3438
 
 
3439
    // Pin the rightmost leaf with a write lock.
 
3440
    rightmost_fullhash = toku_cachetable_hash(ft->cf, rightmost_blocknum);
 
3441
    struct ftnode_fetch_extra bfe;
 
3442
    fill_bfe_for_full_read(&bfe, ft);
 
3443
    toku_pin_ftnode(ft, rightmost_blocknum, rightmost_fullhash, &bfe, PL_WRITE_CHEAP, &rightmost_leaf, true);
 
3444
 
 
3445
    // The rightmost blocknum never chances once it is initialized to something
 
3446
    // other than null. Verify that the pinned node has the correct blocknum.
 
3447
    invariant(rightmost_leaf->thisnodename.b == rightmost_blocknum.b);
 
3448
 
 
3449
    // If the rightmost leaf is reactive, bail out out and let the normal promotion pass
 
3450
    // take care of it. This also ensures that if any of our ancestors are reactive,
 
3451
    // they'll be taken care of too.
 
3452
    if (get_leaf_reactivity(rightmost_leaf, ft->h->nodesize) != RE_STABLE) {
 
3453
        STATUS_INC(FT_PRO_RIGHTMOST_LEAF_SHORTCUT_FAIL_REACTIVE, 1);
 
3454
        goto cleanup;
 
3455
    }
 
3456
 
 
3457
    // The groundwork has been laid for an insertion directly into the rightmost
 
3458
    // leaf node. We know that it is pinned for write, fully in memory, has
 
3459
    // no messages above it, and is not reactive.
 
3460
    //
 
3461
    // Now, two more things must be true for this insertion to actually happen:
 
3462
    // 1. The key to insert is within the bounds of this leafnode, or to the right.
 
3463
    // 2. If there is a uniqueness constraint, it passes.
 
3464
    bool nondeleted_key_found;
 
3465
    int relative_pos;
 
3466
    int target_childnum;
 
3467
 
 
3468
    nondeleted_key_found = false;
 
3469
    target_childnum = -1;
 
3470
    relative_pos = ft_leaf_get_relative_key_pos(ft, rightmost_leaf, key,
 
3471
                                                unique ? &nondeleted_key_found : nullptr,
 
3472
                                                &target_childnum);
 
3473
    if (relative_pos >= 0) {
 
3474
        STATUS_INC(FT_PRO_RIGHTMOST_LEAF_SHORTCUT_SUCCESS, 1);
 
3475
        if (unique && nondeleted_key_found) {
 
3476
            r = DB_KEYEXIST;
 
3477
        } else {
 
3478
            ft_insert_directly_into_leaf(ft, rightmost_leaf, target_childnum,
 
3479
                                         key, val, message_xids, type, gc_info);
 
3480
            r = 0;
 
3481
        }
 
3482
    } else {
 
3483
        STATUS_INC(FT_PRO_RIGHTMOST_LEAF_SHORTCUT_FAIL_POS, 1);
 
3484
        r = -1;
 
3485
    }
 
3486
 
 
3487
cleanup:
 
3488
    // If we did the insert, the rightmost leaf was unpinned for us.
 
3489
    if (r != 0 && rightmost_leaf != nullptr) {
 
3490
        toku_unpin_ftnode(ft, rightmost_leaf);
 
3491
    }
 
3492
 
 
3493
    return r;
 
3494
}
 
3495
 
 
3496
static void ft_txn_log_insert(FT ft, DBT *key, DBT *val, TOKUTXN txn, bool do_logging, enum ft_msg_type type);
 
3497
 
 
3498
int toku_ft_insert_unique(FT_HANDLE ft_h, DBT *key, DBT *val, TOKUTXN txn, bool do_logging) {
 
3499
// Effect: Insert a unique key-val pair into the fractal tree.
 
3500
// Return: 0 on success, DB_KEYEXIST if the overwrite constraint failed
 
3501
    XIDS message_xids = txn != nullptr ? toku_txn_get_xids(txn) : xids_get_root_xids();
 
3502
 
 
3503
    TXN_MANAGER txn_manager = toku_ft_get_txn_manager(ft_h);
 
3504
    txn_manager_state txn_state_for_gc(txn_manager);
 
3505
 
 
3506
    TXNID oldest_referenced_xid_estimate = toku_ft_get_oldest_referenced_xid_estimate(ft_h);
 
3507
    txn_gc_info gc_info(&txn_state_for_gc,
 
3508
                        oldest_referenced_xid_estimate,
 
3509
                        // no messages above us, we can implicitly promote uxrs based on this xid
 
3510
                        oldest_referenced_xid_estimate,
 
3511
                        true);
 
3512
    int r = ft_maybe_insert_into_rightmost_leaf(ft_h->ft, key, val, message_xids, FT_INSERT, &gc_info, true);
 
3513
    if (r != 0 && r != DB_KEYEXIST) {
 
3514
        // Default to a regular unique check + insert algorithm if we couldn't
 
3515
        // do it based on the rightmost leaf alone.
 
3516
        int lookup_r = toku_ft_lookup(ft_h, key, getf_nothing, nullptr);
 
3517
        if (lookup_r == DB_NOTFOUND) {
 
3518
            toku_ft_send_insert(ft_h, key, val, message_xids, FT_INSERT, &gc_info);
 
3519
            r = 0;
 
3520
        } else {
 
3521
            r = DB_KEYEXIST;
 
3522
        }
 
3523
    }
 
3524
 
 
3525
    if (r == 0) {
 
3526
        ft_txn_log_insert(ft_h->ft, key, val, txn, do_logging, FT_INSERT);
 
3527
    }
 
3528
    return r;
 
3529
}
 
3530
 
 
3531
// Effect: Insert the key-val pair into an ft.
3234
3532
void toku_ft_insert (FT_HANDLE ft_handle, DBT *key, DBT *val, TOKUTXN txn) {
3235
3533
    toku_ft_maybe_insert(ft_handle, key, val, txn, false, ZERO_LSN, true, FT_INSERT);
3236
3534
}
3356
3654
    return txn_manager != nullptr ? toku_txn_manager_get_oldest_referenced_xid_estimate(txn_manager) : TXNID_NONE;
3357
3655
}
3358
3656
 
 
3657
static void ft_txn_log_insert(FT ft, DBT *key, DBT *val, TOKUTXN txn, bool do_logging, enum ft_msg_type type) {
 
3658
    paranoid_invariant(type == FT_INSERT || type == FT_INSERT_NO_OVERWRITE);
 
3659
 
 
3660
    //By default use committed messages
 
3661
    TXNID_PAIR xid = toku_txn_get_txnid(txn);
 
3662
    if (txn) {
 
3663
        BYTESTRING keybs = {key->size, (char *) key->data};
 
3664
        toku_logger_save_rollback_cmdinsert(txn, toku_cachefile_filenum(ft->cf), &keybs);
 
3665
        toku_txn_maybe_note_ft(txn, ft);
 
3666
    }
 
3667
    TOKULOGGER logger = toku_txn_logger(txn);
 
3668
    if (do_logging && logger) {
 
3669
        BYTESTRING keybs = {.len=key->size, .data=(char *) key->data};
 
3670
        BYTESTRING valbs = {.len=val->size, .data=(char *) val->data};
 
3671
        if (type == FT_INSERT) {
 
3672
            toku_log_enq_insert(logger, (LSN*)0, 0, txn, toku_cachefile_filenum(ft->cf), xid, keybs, valbs);
 
3673
        }
 
3674
        else {
 
3675
            toku_log_enq_insert_no_overwrite(logger, (LSN*)0, 0, txn, toku_cachefile_filenum(ft->cf), xid, keybs, valbs);
 
3676
        }
 
3677
    }
 
3678
}
 
3679
 
3359
3680
void toku_ft_maybe_insert (FT_HANDLE ft_h, DBT *key, DBT *val, TOKUTXN txn, bool oplsn_valid, LSN oplsn, bool do_logging, enum ft_msg_type type) {
3360
 
    paranoid_invariant(type==FT_INSERT || type==FT_INSERT_NO_OVERWRITE);
3361
 
    XIDS message_xids = xids_get_root_xids(); //By default use committed messages
3362
 
    TXNID_PAIR xid = toku_txn_get_txnid(txn);
3363
 
    if (txn) {
3364
 
        BYTESTRING keybs = {key->size, (char *) key->data};
3365
 
        toku_logger_save_rollback_cmdinsert(txn, toku_cachefile_filenum(ft_h->ft->cf), &keybs);
3366
 
        toku_txn_maybe_note_ft(txn, ft_h->ft);
3367
 
        message_xids = toku_txn_get_xids(txn);
3368
 
    }
3369
 
    TOKULOGGER logger = toku_txn_logger(txn);
3370
 
    if (do_logging && logger) {
3371
 
        BYTESTRING keybs = {.len=key->size, .data=(char *) key->data};
3372
 
        BYTESTRING valbs = {.len=val->size, .data=(char *) val->data};
3373
 
        if (type == FT_INSERT) {
3374
 
            toku_log_enq_insert(logger, (LSN*)0, 0, txn, toku_cachefile_filenum(ft_h->ft->cf), xid, keybs, valbs);
3375
 
        }
3376
 
        else {
3377
 
            toku_log_enq_insert_no_overwrite(logger, (LSN*)0, 0, txn, toku_cachefile_filenum(ft_h->ft->cf), xid, keybs, valbs);
3378
 
        }
3379
 
    }
 
3681
    ft_txn_log_insert(ft_h->ft, key, val, txn, do_logging, type);
3380
3682
 
3381
3683
    LSN treelsn;
3382
3684
    if (oplsn_valid && oplsn.lsn <= (treelsn = toku_ft_checkpoint_lsn(ft_h->ft)).lsn) {
3383
3685
        // do nothing
3384
3686
    } else {
 
3687
        XIDS message_xids = txn ? toku_txn_get_xids(txn) : xids_get_root_xids();
 
3688
 
3385
3689
        TXN_MANAGER txn_manager = toku_ft_get_txn_manager(ft_h);
3386
3690
        txn_manager_state txn_state_for_gc(txn_manager);
3387
3691
 
3391
3695
                            // no messages above us, we can implicitly promote uxrs based on this xid
3392
3696
                            oldest_referenced_xid_estimate,
3393
3697
                            txn != nullptr ? !txn->for_recovery : false);
3394
 
        toku_ft_send_insert(ft_h, key, val, message_xids, type, &gc_info);
 
3698
        int r = ft_maybe_insert_into_rightmost_leaf(ft_h->ft, key, val, message_xids, FT_INSERT, &gc_info, false);
 
3699
        if (r != 0) {
 
3700
            toku_ft_send_insert(ft_h, key, val, message_xids, type, &gc_info);
 
3701
        }
3395
3702
    }
3396
3703
}
3397
3704
 
 
3705
static void ft_insert_directly_into_leaf(FT ft, FTNODE leaf, int target_childnum, DBT *key, DBT *val,
 
3706
                                         XIDS message_xids, enum ft_msg_type type, txn_gc_info *gc_info)
 
3707
// Effect: Insert directly into a leaf node a fractal tree. Does not do any logging.
 
3708
// Requires: Leaf is fully in memory and pinned for write.
 
3709
// Requires: If this insertion were to happen through the root node, the promotion
 
3710
//           algorithm would have selected the given leaf node as the point of injection.
 
3711
//           That means this function relies on the current implementation of promotion.
 
3712
{
 
3713
    FT_MSG_S ftcmd = { type, ZERO_MSN, message_xids, .u = { .id = { key, val } } }; 
 
3714
    size_t flow_deltas[] = { 0, 0 }; 
 
3715
    inject_message_in_locked_node(ft, leaf, target_childnum, &ftcmd, flow_deltas, gc_info);
 
3716
}
 
3717
 
3398
3718
static void
3399
3719
ft_send_update_msg(FT_HANDLE ft_h, FT_MSG_S *msg, TOKUTXN txn) {
3400
3720
    msg->xids = (txn
4894
5214
    return 0;
4895
5215
}
4896
5216
 
 
5217
static void ft_bnc_move_messages_to_stale(FT ft, NONLEAF_CHILDINFO bnc) {
 
5218
    struct copy_to_stale_extra cts_extra = { .ft = ft, .bnc = bnc };
 
5219
    int r = bnc->fresh_message_tree.iterate_over_marked<struct copy_to_stale_extra, copy_to_stale>(&cts_extra);
 
5220
    invariant_zero(r);
 
5221
    bnc->fresh_message_tree.delete_all_marked();
 
5222
}
 
5223
 
4897
5224
__attribute__((nonnull))
4898
5225
void
4899
5226
toku_move_ftnode_messages_to_stale(FT ft, FTNODE node) {
4906
5233
        // We can't delete things out of the fresh tree inside the above
4907
5234
        // procedures because we're still looking at the fresh tree.  Instead
4908
5235
        // we have to move messages after we're done looking at it.
4909
 
        struct copy_to_stale_extra cts_extra = { .ft = ft, .bnc = bnc };
4910
 
        int r = bnc->fresh_message_tree.iterate_over_marked<struct copy_to_stale_extra, copy_to_stale>(&cts_extra);
4911
 
        invariant_zero(r);
4912
 
        bnc->fresh_message_tree.delete_all_marked();
 
5236
        ft_bnc_move_messages_to_stale(ft, bnc);
4913
5237
    }
4914
5238
}
4915
5239