Beispiel #1
0
void oc_bpt_test_fs_inc_refcount(struct Oc_wu *wu_p, uint64 addr)
{
    oc_utl_assert(ctx_p);

    oc_utl_assert(ctx_p->fs_array[addr] > 0);
    ctx_p->fs_array[addr]++;
}
Beispiel #2
0
void oc_xt_test_nd_dealloc(Oc_wu *wu_p, uint64 addr)
{
    Oc_xt_test_node *tnode_p;
    char *data;
    
    if (wu_p->po_id != 0)
        if (random_choose(2) == 0)
            oc_crt_yield_task();

    // extract the node fromt the table prior to removal
    tnode_p = vd_node_lookup(addr);
    
    // remove the node from the virtual-disk
    vd_node_remove(addr);

    oc_utl_assert(tnode_p);
    oc_utl_assert(tnode_p->node.data);
    oc_utl_assert(tnode_p->magic == MAGIC);

    // mess up the node so that errors will occur on illegal accesses
    tnode_p->magic = -1;
    data = tnode_p->node.data;
    tnode_p->node.data = NULL;
    tnode_p->node.lock.counter = 100;
    tnode_p->node.disk_addr = 0;
    
    free(data);
    free(tnode_p);
}
Beispiel #3
0
static void node_dealloc(Oc_wu *wu_p, uint64 addr)
{
    if (wu_p->po_id != 0)
        if (oc_bpt_test_utl_random_number(2) == 0)
            oc_crt_yield_task();

    oc_bpt_test_fs_dealloc(addr);
    
    if (oc_bpt_test_fs_get_refcount(wu_p, addr) == 0)
    {
        // Free the block only if it's ref-count is zero
        Oc_bpt_test_node *tnode_p;
        char *data;
        
        // extract the node from the table prior to removal
        tnode_p = vd_node_lookup(addr);
        
        // remove the node from the virtual-disk
        vd_node_remove(addr);
        
        oc_utl_assert(tnode_p);
        oc_utl_assert(tnode_p->node.data);
        oc_utl_assert(tnode_p->magic == MAGIC);
        
        // mess up the node so that errors will occur on illegal accesses
        tnode_p->magic = -1;
        data = tnode_p->node.data;
        tnode_p->node.data = NULL;
        tnode_p->node.disk_addr = 0;
        
        free(data);
        free(tnode_p);
    }
}
Beispiel #4
0
// remove a node
static void vd_node_remove(uint64 addr)
{
    bool rc;

    rc = oc_utl_htbl_remove(&vd_htbl, (void*)&addr);
    oc_utl_assert(rc);
}
Beispiel #5
0
static void *wrap_malloc(int size)
{
    void *p = malloc(size);

    oc_utl_assert(p != NULL);
    return p;
}
Beispiel #6
0
// allocate a block 
uint64 oc_bpt_test_fs_alloc(void)
{
    int i, loc;

    oc_utl_assert(ctx_p);
        
    if (ctx_p->verbose) {
        printf("// alloc [%s]\n", ctx_p->desc);
        fflush(stdout);
    }
    
    /* look for a free block. Start searching from the beginning
     * so as to flush out any error in freeing blocks too early. 
     */
    for (i=0, loc=-1 ; i<ctx_p->num_blocks; i++) {
        if (!ctx_p->fs_array[i]) {
            loc = i;
            break;
        }
    }

    if (loc != -1) {
        // found a free block
        ctx_p->tot_alloc++;
        ctx_p->fs_array[loc] = 1;
        return (uint64)loc;
    }
    else {
        ERR(("Free space has run out of pages, it curently has %d."
             "Either run a smaller test or increase the size of the FS.",
             ctx_p->num_blocks));
    }
}
Beispiel #7
0
// Display the set of clones together in one tree
void oc_bpt_test_utl_display_all(
    int n_clones,
    Oc_bpt_test_state* clone_array[])
{
    struct Oc_bpt_state *bpt_array[100];
    int i;
    char tag[10];
        
    oc_utl_assert(n_clones <= 100);

    memset(tag, 0, 10);
    g_cnt++;
    snprintf(tag, 10, "X%d", g_cnt);
    
    // setup an array of b-tree states 
    for (i=0; i<n_clones; i++) {
        bpt_array[i] = &clone_array[i]->bpt_s;
    }

    // pass it into the the output_dot_clones function
    oc_bpt_dbg_output_clones_b(&utl_wu,
                               n_clones,
                               bpt_array,
                               tag);
}
Beispiel #8
0
static void node_release(Oc_wu *wu_p, Oc_bpt_node *node_p)
{
    oc_utl_trk_crt_unlock(wu_p, &node_p->lock);
    
    g_refcnt--;
    oc_utl_assert(g_refcnt>=0);
}
Beispiel #9
0
// deallocate a block
void oc_bpt_test_fs_dealloc(uint64 loc)
{
    oc_utl_assert(ctx_p);
    oc_utl_assert(0 <= loc && loc < ctx_p->num_blocks);
    
    if (ctx_p->verbose) {
        printf("// dealloc [%s] (loc=%Lu)\n", ctx_p->desc, loc);
        fflush(stdout);
    }

    oc_utl_assert(ctx_p->fs_array[loc] > 0);
    ctx_p->fs_array[loc]--;

    if (0 == ctx_p->fs_array[loc])
        ctx_p->tot_alloc--;
    
    oc_utl_assert(ctx_p->tot_alloc >= 0);
}
Beispiel #10
0
// allocate an extent of [len] units in free-space [ctx_p]
uint32 oc_xt_test_fs_alloc(struct Oc_xt_test_fs_ctx *ctx_p,
                           uint32 len)
{
    int i,j;
    uint32 ofs;

    if (ctx_p->verbose) {
        printf("// alloc [%s] (len=%lu)\n", ctx_p->desc, len);
        fflush(stdout);
    }
    
    // look for an existing contiguous extent of size [len]
    for (i=0, j=0, ofs=0; i<ctx_p->len; i++) {
        if (!ctx_p->fs_array[i]) {
            if (0 == j) {
                ofs = i;
                j++;
            }
            else {
                j++;
            }
            
            if (len == j) {
                // found a contiguous unallocated area, mark it
                // as allocated
                int k;
                
                for (k=ofs; k<ofs+len; k++)
                    ctx_p->fs_array[k] = TRUE;
                goto done;
            }
        }
        else {
            // zero out the count
            j=0;
            ofs = 0;
        }
    }

    // if not found, double the size of [fs_array]
    printf("// resize FS, now=%u\n", ctx_p->len *2);
    ctx_p->fs_array = (char*) realloc(ctx_p->fs_array, ctx_p->len *2);
    oc_utl_assert(ctx_p);
    memset(&ctx_p->fs_array[ctx_p->len], 0, ctx_p->len);

    // allocate in the new area 
    ofs = ctx_p->len+1;
    for (i=ctx_p->len+1; i<=ctx_p->len + len; i++)
        ctx_p->fs_array[i] = TRUE;

    ctx_p->len = 2 * ctx_p->len;

done:
    ctx_p->tot_alloc += len;
    return ofs;
}
Beispiel #11
0
Oc_xt_node* oc_xt_test_nd_get(Oc_wu *wu_p, uint64 addr)
{
    Oc_xt_test_node *tnode_p;
    
    oc_utl_assert(addr != 0);

    if (wu_p->po_id != 0)
        if (random_choose(2) == 0)
            oc_crt_yield_task();

    g_refcnt++;
    tnode_p = vd_node_lookup(addr);
    if (NULL == tnode_p) {
        printf("error, did not find a b-tree node at address=%Lu po=%lu\n",
               addr, wu_p->po_id);
        oc_utl_assert(0);
    }
    oc_utl_assert(MAGIC == tnode_p->magic);
    return &tnode_p->node;
}
Beispiel #12
0
// deallocate an extent of [len] units in free-space [ctx_p]
void oc_xt_test_fs_dealloc(struct Oc_xt_test_fs_ctx *ctx_p,
                           uint32 ofs,
                           uint32 len)
{
    uint32 i;

    if (ctx_p->verbose) {
        printf("// dealloc [%s] (ofs=%lu, len=%lu)\n", ctx_p->desc, ofs, len);
        fflush(stdout);
    }
    
    // set to FALSE the state of all the units in the range
    for (i=ofs; i<ofs+len; i++) {
        oc_utl_assert(ctx_p->fs_array[i]);
        ctx_p->fs_array[i] = FALSE;
    }

    ctx_p->tot_alloc -= len;
    oc_utl_assert(ctx_p->tot_alloc >= 0);
}
Beispiel #13
0
void oc_crt_init_full(Oc_crt_config * config_p)
{
    pthread_t id;

    config = *config_p;

    printf("sizeof(oc_crt_rwlock) = %ld\n", sizeof(Oc_crt_rw_lock));
    printf("sizeof(pthread_rwlock_t) = %ld\n", sizeof(pthread_rwlock_t));
    printf("sizeof(oc_crt_sema) = %ld\n", sizeof(Oc_crt_sema));
    printf("sizeof(sem_t) = %ld\n", sizeof(sem_t));

    oc_utl_assert(sizeof(Oc_crt_rw_lock) >= sizeof(pthread_rwlock_t));
    oc_utl_assert(sizeof(Oc_crt_sema) >= sizeof(sem_t));

    pthread_attr_t attr;
    pthread_attr_init(&attr);
    if (pthread_create(&id, &attr, config_p->init_fun, NULL) != 0)
        ERR(("could not open main thread"));
    pthread_attr_destroy(&attr);
}
Beispiel #14
0
uint64 oc_bpt_clone_b(
    struct Oc_wu *wu_p,
    Oc_bpt_state *src_p,
    Oc_bpt_state *trg_p)
{
    // make sure the configurations are equivalent
    oc_utl_assert(trg_p->cfg_p == src_p->cfg_p);

    oc_bpt_trace_wu_lvl(2, OC_EV_BPT_CLONE, wu_p,
                        "tid=%Lu -> tid=%Lu",
                        src_p->tid, trg_p->tid); 
        
    oc_utl_debugassert(src_p->cfg_p->initialized);
    oc_utl_debugassert(trg_p->cfg_p->initialized);
    oc_utl_assert(NULL == trg_p->root_node_p);
        
    oc_utl_trk_crt_lock_write(wu_p, &src_p->lock);
    oc_bpt_nd_clone_root(wu_p, src_p, trg_p);
    oc_utl_trk_crt_unlock(wu_p, &src_p->lock);

    return trg_p->root_node_p->disk_addr;
}
Beispiel #15
0
uint64 oc_bpt_create_b(
    struct Oc_wu *wu_p,
    Oc_bpt_state *s_p)
{
    oc_utl_assert(NULL == s_p->root_node_p);
    oc_utl_debugassert(s_p->cfg_p->initialized);
        
    oc_utl_trk_crt_lock_write(wu_p, &s_p->lock);
    {
        s_p->root_node_p = s_p->cfg_p->node_alloc(wu_p);
        oc_bpt_nd_create_root(wu_p, s_p, s_p->root_node_p);
        oc_utl_trk_crt_unlock(wu_p, &s_p->root_node_p->lock);
    }
    oc_utl_trk_crt_unlock(wu_p, &s_p->lock);

    return s_p->root_node_p->disk_addr;
}
Beispiel #16
0
struct Oc_xt_test_fs_ctx *oc_xt_test_fs_create(
    char *str_desc_p,
    bool verbose)
{
    struct Oc_xt_test_fs_ctx *ctx_p;
    
    ctx_p = (struct Oc_xt_test_fs_ctx *) malloc(sizeof(struct Oc_xt_test_fs_ctx));
    oc_utl_assert(ctx_p);
    memset(ctx_p, 0, sizeof(struct Oc_xt_test_fs_ctx));
    ctx_p->len = INIT_LEN;
    ctx_p->fs_array = (char*) malloc(INIT_LEN);
    memset(ctx_p->fs_array, 0, INIT_LEN);
    memset(ctx_p->desc, 0, 30);
    strncpy(ctx_p->desc, str_desc_p, 30);
    ctx_p->verbose = verbose;
    
    return ctx_p;
}
Beispiel #17
0
void oc_bpt_cow_root_and_update_b(
    struct Oc_wu *wu_p,
    struct Oc_bpt_state *s_p,
    struct Oc_bpt_data *father_data_p,
    int size)
{
    // Old disk-addr stored as data in father
    uint64 prev_addr = *((uint64*)father_data_p); 
    Oc_bpt_node *node_p;   
    int fs_refcnt;
    
    oc_bpt_trace_wu_lvl(2, OC_EV_BPT_COW_ROOT_AND_UPDATE, wu_p,
                        "lba of root as appers in father (before update):%llu",
                        prev_addr);
    oc_utl_assert(NULL != s_p->root_node_p);
    oc_utl_trk_crt_lock_write(wu_p, &s_p->lock);

    node_p = s_p->cfg_p->node_get_xl(wu_p, s_p->root_node_p->disk_addr);
    oc_utl_debugassert(node_p == s_p->root_node_p);

    fs_refcnt = s_p->cfg_p->fs_get_refcount(
        wu_p,
        s_p->root_node_p->disk_addr);
    s_p->cfg_p->node_mark_dirty(wu_p, s_p->root_node_p, (fs_refcnt > 1));

    if (s_p->root_node_p->disk_addr != prev_addr)
    {
        uint64 new_addr = s_p->root_node_p->disk_addr;
        memcpy((char*)father_data_p, &new_addr, size);
    }
    oc_bpt_trace_wu_lvl(2, OC_EV_BPT_COW_ROOT_AND_UPDATE, wu_p,
                        "lba of root as appers in father (AFTER update):%llu",
                        *((uint64*)father_data_p));
    
    oc_bpt_nd_release(wu_p, s_p, s_p->root_node_p);// Dalit: may not be needed
    oc_utl_trk_crt_unlock(wu_p, &s_p->lock);   // Dalit: may not be needed

}
Beispiel #18
0
// Initialize the alternate block-map
void oc_bpt_test_fs_alt_create(void)
{
    oc_utl_assert(ctx_p);
    oc_utl_assert(NULL == alt_p);
    alt_p = fs_create("alternate", ctx_p->num_blocks, FALSE);
}
Beispiel #19
0
// query function
void oc_bpt_query_b(
    struct Oc_wu *wu_p,
    Oc_bpt_cfg *cfg_p, 
    struct Oc_rm_resource *r_p,
    Oc_bpt_fid fid_i,
    void *param)
{
    int nkeys, num_iters;
    
    switch (fid_i) {
    case OC_BPT_FN_CREATE:
        // the root is allocated
        r_p->pm_pages++;
        r_p->fs_pages++;
        break;

    case OC_BPT_FN_CREATE_AT:
        // the root is pre-allocated
        r_p->pm_pages++;
        break;

    case OC_BPT_FN_DELETE:
        // A b-tree path is kept in memory. 
        r_p->pm_pages += OC_BPT_MAX_HEIGHT;
        break;

    case OC_BPT_FN_INSERT_KEY:
        /* During an insert we might hold three PM pages in case of split.
         * The worst case for the number of allocated disk pages is that the
         * whole tree path will be split.
         */
        r_p->pm_pages += 3;
        r_p->fs_pages += OC_BPT_MAX_HEIGHT;
        break;
        
    case OC_BPT_FN_LOOKUP_KEY:
        // Since crabbing is used only two pages are ever held simultaneous
        r_p->pm_pages += 2;
        break;
        
    case OC_BPT_FN_LOOKUP_KEY_WITH_COW:
        /* During a lookup_withcow we might hold two PM pages due to the 
         * Write lock.
         * The worst case for the number of allocated disk pages is that the
         * whole tree path will be COWed.
         */
        r_p->pm_pages += 2;
        r_p->fs_pages += OC_BPT_MAX_HEIGHT;
        break;
                
    case OC_BPT_FN_REMOVE_KEY:
        /* During remove-key we might hold three PM pages in case of merge.
         * The worst case for the number of allocated disk pages is that the
         * whole tree path will be merged. We take into account here snapshots. 
         */
        r_p->pm_pages += 3;
        r_p->fs_pages += OC_BPT_MAX_HEIGHT;
        break;

    case OC_BPT_FN_DBG_OUTPUT:
        // A b-tree path is kept in memory. 
        r_p->pm_pages += OC_BPT_MAX_HEIGHT;
        break;
        
    case OC_BPT_FN_DBG_VALIDATE:
        // A b-tree path is kept in memory. 
        r_p->pm_pages += OC_BPT_MAX_HEIGHT;
        break;

    case OC_BPT_FN_LOOKUP_RANGE:
        /* Mostly, two pages are used. The worst case is three; this 
         * occurs when the range overlaps a page-boundary.
         */
        r_p->pm_pages += 3;
        break;

    case OC_BPT_FN_INSERT_RANGE:
        /* we always crawl on a single tree path. The possiblity for splits
         * increases the worst case from two to three modified pages. 
         */
        r_p->pm_pages += 3;   

        // the number of disk-pages needed depends on the number of inserted keys
        nkeys = (int) param;
        num_iters = 1 + (nkeys / (cfg_p->max_num_ent_leaf_node/2));
        r_p->fs_pages += num_iters * OC_BPT_MAX_HEIGHT;
        break;
        
    case OC_BPT_FN_REMOVE_RANGE:
        // We might hold a page, its father, and its two siblings. 
        r_p->pm_pages += 4;

        // per tree level we might remove two disk pages and mark another page dirty
        r_p->fs_pages += 3 * OC_BPT_MAX_HEIGHT;
        break;
        
    default:
        oc_utl_assert(0);
    }
    
    oc_bpt_trace_wu_lvl(3, OC_EV_BPT_QUERY, wu_p, 
                        "pm_write_pages=%d  pm_read_pages=%d  disk_pages=%d", 
                        r_p->pm_pages, 
                        r_p->pm_pages,
                        r_p->fs_pages);
}
Beispiel #20
0
void oc_bpt_test_utl_finalize(int refcnt)
{
    oc_utl_assert(refcnt == g_refcnt);
}
Beispiel #21
0
void oc_xt_test_nd_release(Oc_wu *wu_p, Oc_xt_node *node_p)
{
    g_refcnt--;
    oc_utl_assert(g_refcnt>=0);
}
Beispiel #22
0
int oc_bpt_test_fs_get_refcount(struct Oc_wu *wu_p, uint64 addr)
{
    oc_utl_assert(ctx_p);
    
    return (int)ctx_p->fs_array[addr];
}
Beispiel #23
0
void oc_bpt_test_fs_verify(num_blocks)
{
    oc_utl_debugassert(ctx_p);
    oc_utl_assert(num_blocks == ctx_p->tot_alloc);
}
Beispiel #24
0
void oc_bpt_init_config(Oc_bpt_cfg *cfg_p)
{
    int max_num_ent_root_leaf_node, max_num_ent_root_index_node;

    oc_utl_assert(cfg_p->node_alloc);
    oc_utl_assert(cfg_p->node_dealloc);
    oc_utl_assert(cfg_p->node_get_sl);
    oc_utl_assert(cfg_p->node_get_xl);
    oc_utl_assert(cfg_p->node_release);
    oc_utl_assert(cfg_p->node_mark_dirty);
    oc_utl_assert(cfg_p->fs_inc_refcount);
    oc_utl_assert(cfg_p->fs_get_refcount);
    oc_utl_assert(cfg_p->key_compare);
    oc_utl_assert(cfg_p->key_inc);
    oc_utl_assert(cfg_p->key_to_string);

    
    // The data-release function can be null.
    // oc_utl_assert(cfg_p->data_release);
    oc_utl_assert(cfg_p->data_to_string);
    
    if (cfg_p->key_size % 4 != 0 ||
        cfg_p->data_size % 4 != 0 ||
        cfg_p->node_size % 4 != 0 )
        ERR(("key/data/node size are misaligned; not divisible by 4"));

    if ( cfg_p->node_size < (int)sizeof(Oc_bpt_nd_hdr) )
        ERR(("node size is too tmall. smaller then Oc_bpt_nd_hdr"));
    if ( cfg_p->node_size < (int)sizeof(Oc_bpt_nd_hdr_root) )
        ERR(("node size is too tmall. smaller then Oc_bpt_nd_hdr_root"));
        
    cfg_p->leaf_ent_size = cfg_p->key_size + cfg_p->data_size;
    cfg_p->index_ent_size = sizeof(uint64) + cfg_p->key_size;
    
    cfg_p->max_num_ent_leaf_node =
        (cfg_p->node_size - sizeof(Oc_bpt_nd_hdr)) /
        cfg_p->leaf_ent_size;
    
    cfg_p->max_num_ent_index_node =
        (cfg_p->node_size - sizeof(Oc_bpt_nd_hdr)) /
        cfg_p->index_ent_size;
        
    max_num_ent_root_leaf_node =
        (cfg_p->node_size - sizeof(Oc_bpt_nd_hdr_root)) /
        cfg_p->leaf_ent_size;
        
    max_num_ent_root_index_node =
        (cfg_p->node_size - sizeof(Oc_bpt_nd_hdr_root)) /
        cfg_p->index_ent_size;

    cfg_p->max_num_ent_root_node =
        MIN(max_num_ent_root_leaf_node, max_num_ent_root_index_node);
        
    if (cfg_p->root_fanout > cfg_p->non_root_fanout)
        ERR(("The root-fanout cannot be larger than the node fanout"));
        
    if (cfg_p->root_fanout > 0)
        cfg_p->max_num_ent_root_node = MIN( cfg_p->root_fanout, 
                                            cfg_p->max_num_ent_root_node );

    if (cfg_p->non_root_fanout > 0) {    
        cfg_p->max_num_ent_leaf_node =
            MIN(cfg_p->max_num_ent_leaf_node, cfg_p->non_root_fanout);
        cfg_p->max_num_ent_index_node =
            MIN(cfg_p->max_num_ent_index_node, cfg_p->non_root_fanout);
    }

    if (cfg_p->max_num_ent_leaf_node > 256 ||
        cfg_p->max_num_ent_index_node > 256 ||
        cfg_p->max_num_ent_root_node > 256)
        printf("Warning: Fanout of a b-tree node is larger than 256."
               "The code will not be able to use these many entries;"
               "it is limited to 256.\n");
    
    cfg_p->max_num_ent_leaf_node =
        MIN(cfg_p->max_num_ent_leaf_node, 256);
    cfg_p->max_num_ent_index_node =
        MIN(cfg_p->max_num_ent_index_node, 256);
    cfg_p->max_num_ent_root_node =
        MIN(cfg_p->max_num_ent_root_node, 256);
    
    if (cfg_p->max_num_ent_leaf_node < 5 ||
        cfg_p->max_num_ent_index_node < 5 ||
        cfg_p->max_num_ent_root_node < 5)
        ERR(("Fanout of a b-tree node cannot be smaller than 5 in any of its nodes"));
    
    // We want the number of entries in a node to be between b and 3b.
    if (0 == cfg_p->min_num_ent)
        cfg_p->min_num_ent = MIN(
            MIN(cfg_p->max_num_ent_leaf_node/3,
                cfg_p->max_num_ent_index_node/3),
            cfg_p->max_num_ent_root_node/3
            );

    if (cfg_p->min_num_ent < 2) {
        // we didn't manage to create a range of [b .. 3b]. Now try [b .. 2b+1].
        cfg_p->min_num_ent = MIN(
            MIN((cfg_p->max_num_ent_leaf_node-1)/2,
                (cfg_p->max_num_ent_index_node-1)/2),
            (cfg_p->max_num_ent_root_node-1)/2
            );
    }
    
    if (cfg_p->min_num_ent < 2)
        ERR(("The minimal number of entries cannot be smaller than 2"));

    /* For correctness, the number of entries in the btree has to be between
     * b and 2b+1.
     */
    if (cfg_p->min_num_ent * 2 + 1 > cfg_p->max_num_ent_leaf_node ||
        cfg_p->min_num_ent * 2 + 1 > cfg_p->max_num_ent_index_node ||
        cfg_p->min_num_ent * 2 + 1 > cfg_p->max_num_ent_root_node)
        ERR(("The number of entries in a node is not (even) between b and 2b+1"));
    
    oc_bpt_trace_wu_lvl(
        1, OC_EV_BPT_INIT_CFG, NULL,
        "max_num_ent_leaf_node=%lu  max_num_ent_index_node=%lu max_num_ent_root=%lu\n",
        cfg_p->max_num_ent_leaf_node,
        cfg_p->max_num_ent_index_node,  
        cfg_p->max_num_ent_root_node);

    cfg_p->initialized = TRUE;
}
Beispiel #25
0
/* A limited lookup that searches in a tree of height 2.
 * 
 * prerequisites:
 *   - a tree of height more than 1
 *
 * Decend in the tree using lock coupling with locks taken in
 * read-mode. Stop when you reach a leaf C. Mark the father as
 * F. Search for matches in C then continue into the
 * other children of F. 
 *
 */
static bool mini_lookup_b(
    struct Oc_wu *wu_p,
    Oc_xt_state *s_p,
    Oc_xt_op_lookup_range *lkr_p )    
{
    Oc_xt_node *father_p, *child_p, *hi_p = NULL;
    bool rc;
    
    oc_xt_trace_wu_lvl(
        3, OC_EV_XT_LOOKUP_RNG_MINI, wu_p, "range=[%s]",
        oc_xt_nd_string_of_2key (s_p, lkr_p->min_key_p, lkr_p->max_key_p));

    oc_xt_nd_get_for_read(wu_p, s_p, s_p->root_node_p->disk_addr);

    // 1. base case, this is the root node and the root is a leaf
    if (oc_xt_nd_is_leaf(s_p, s_p->root_node_p))
    {
        rc = search_in_leaf(wu_p, s_p, s_p->root_node_p, lkr_p);
        oc_xt_nd_release(wu_p, s_p, s_p->root_node_p);
        return rc;
    }

    father_p = s_p->root_node_p;

    // iteration
    while (1) {
        int loc_lo, loc_hi;
        uint64 addr;
        struct Oc_xt_key *dummy_key_p;
        
        oc_xt_trace_wu_lvl(3, OC_EV_XT_LOOKUP_RNG_MINI_ITER, wu_p, "");

        // compute the upper and lower bounds
        loc_lo = oc_xt_nd_index_lookup_le_key(wu_p, s_p, father_p, lkr_p->min_key_p);
        loc_hi = oc_xt_nd_index_lookup_ge_key(wu_p, s_p, father_p, lkr_p->min_key_p);
        oc_utl_assert(loc_lo != -1 ||
                      loc_hi != -1);
        if (-1 == loc_lo)
            loc_lo = loc_hi;
        if (-1 == loc_hi)
            loc_hi = loc_lo;

        // start by assuming that the lower-bound is the right direction
        oc_xt_nd_index_get_kth(s_p, father_p, loc_lo, &dummy_key_p, &addr);
        child_p = oc_xt_nd_get_for_read(wu_p, s_p, addr);

        /* If [child_p] contains [min_key_p] then don't bother with the 
         * high bound.
         */
        if (check_in_bounds(s_p, child_p, lkr_p->min_key_p))
            if (hi_p) {
                oc_xt_nd_release(wu_p, s_p, hi_p);
                hi_p = NULL;
            }
        
        if (loc_hi != loc_lo &&
            !check_in_bounds(s_p, child_p, lkr_p->min_key_p))
        {
            /* we are running the risk of missing some search hits.
             * Take a read-lock on the page with the high-bound.
             * Hold on to this page until further notice. 
             */
            oc_xt_trace_wu_lvl(3, OC_EV_XT_LOOKUP_RNG_MINI_SPLIT, wu_p, "");
            if (hi_p)
                oc_xt_nd_release(wu_p, s_p, hi_p);
            oc_xt_nd_index_get_kth(s_p, father_p, loc_hi, &dummy_key_p, &addr);
            hi_p = oc_xt_nd_get_for_read(wu_p, s_p, addr);
        }
        
        // continue descent with [child_p] only

        if (oc_xt_nd_is_leaf(s_p, child_p)) {
            // found a leaf with some keys
            rc = search_in_leaf(wu_p, s_p, child_p, lkr_p);
            oc_xt_nd_release(wu_p, s_p, father_p);
            oc_xt_nd_release(wu_p, s_p, child_p);
            break;
        }

        // release the father
        oc_xt_nd_release(wu_p, s_p, father_p);
        
        // switch places between father and son.
        father_p = child_p;
    }

    if (hi_p) {
        // We might have missed the search so we try the high bound as well.
        rc |= simple_descent_b(wu_p, s_p, hi_p, lkr_p);
    }
    
    return rc;
}
Beispiel #26
0
// Increase the ref-count for one of the blocks
void oc_bpt_test_fs_alt_inc_refcount(struct Oc_wu *wu_p, uint64 addr)
{
    oc_utl_assert(0 <= addr && addr < alt_p->num_blocks);
    alt_p->fs_array[addr]++;
}