/**                                                                 
 * flush the backend                                                
 *                                                                  
 * @remark this function is called during ham_flush                 

 @note This is a B+-tree 'backend' method.
 */                                                                 
static ham_status_t
my_fun_flush(ham_btree_t *be)
{
    ham_db_t *db=be_get_db(be);
    db_indexdata_t *indexdata=env_get_indexdata_ptr(db_get_env(db), 
                        db_get_indexdata_offset(db));

    /*
     * nothing to do if the backend was not touched
     */
    if (!be_is_dirty(be))
        return (0);

    index_set_max_keys(indexdata, btree_get_maxkeys(be));
    index_set_keysize(indexdata, be_get_keysize(be));
    index_set_self(indexdata, btree_get_rootpage(be));
    index_set_flags(indexdata, be_get_flags(be));
    index_set_recno(indexdata, be_get_recno(be));
    index_clear_reserved(indexdata);

    env_set_dirty(db_get_env(db));
    be_set_dirty(be, HAM_FALSE);

    return (0);
}
Example #2
0
ham_status_t
blob_get_datasize(ham_db_t *db, ham_offset_t blobid, ham_offset_t *size)
{
    ham_status_t st;
    ham_page_t *page;
    blob_t hdr;

    /*
     * in-memory-database: the blobid is actually a pointer to the memory
     * buffer, in which the blob is stored
     */
    if (env_get_rt_flags(db_get_env(db))&HAM_IN_MEMORY_DB) {
        blob_t *hdr=(blob_t *)U64_TO_PTR(blobid);
        *size=blob_get_size(hdr);
        return (0);
    }

    ham_assert(blobid%DB_CHUNKSIZE==0, ("blobid is %llu", blobid));

    /* read the blob header */
    st=__read_chunk(db_get_env(db), 0, &page, blobid, 
                    (ham_u8_t *)&hdr, sizeof(hdr));
    if (st)
        return (st);

    ham_assert(blob_get_alloc_size(&hdr)%DB_CHUNKSIZE==0, (0));
    if (blob_get_self(&hdr)!=blobid)
        return (HAM_BLOB_NOT_FOUND);

    *size=blob_get_size(&hdr);
    return (0);
}
/**                                                                 
 * estimate the number of keys per page, given the keysize          
 *                                                                  
 * @remark this function is only available when                        
 * hamsterdb is compiled with HAM_ENABLE_INTERNAL turned on.        
 *
 * @note This is a B+-tree 'backend' method.
 */                                                                 
static ham_status_t
my_fun_calc_keycount_per_page(ham_btree_t *be, ham_size_t *maxkeys, 
                ham_u16_t keysize)
{
    ham_db_t *db=be_get_db(be);

    if (keysize == 0) {
        *maxkeys=btree_get_maxkeys(be);
    }
    else {
        /* 
         * prevent overflow - maxkeys only has 16 bit! 
         */
        *maxkeys=btree_calc_maxkeys(env_get_pagesize(db_get_env(db)), keysize);
        if (*maxkeys>MAX_KEYS_PER_NODE) {
            ham_trace(("keysize/pagesize ratio too high"));
            return HAM_INV_KEYSIZE;
        }
        else if (*maxkeys==0) {
            ham_trace(("keysize too large for the current pagesize"));
            return HAM_INV_KEYSIZE;
        }
    }

    return (0);
}
Example #4
0
static ham_status_t
_remote_cursor_close(ham_cursor_t *cursor)
{
    ham_status_t st;
    ham_env_t *env=db_get_env(cursor_get_db(cursor));
    proto_wrapper_t *request, *reply;
    
    request=proto_init_cursor_close_request(cursor_get_remote_handle(cursor));

    st=_perform_request(env, env_get_curl(env), request, &reply);
    proto_delete(request);
    if (st) {
        if (reply)
            proto_delete(reply);
        return (st);
    }

    ham_assert(reply!=0, (""));
    ham_assert(proto_has_cursor_close_reply(reply)!=0, (""));

    st=proto_cursor_close_reply_get_status(reply);

    proto_delete(reply);

    return (st);
}
Example #5
0
static ham_status_t
_remote_cursor_move(ham_cursor_t *cursor, ham_key_t *key, 
                ham_record_t *record, ham_u32_t flags)
{
    ham_status_t st;
    ham_db_t *db=cursor_get_db(cursor);
    ham_env_t *env=db_get_env(db);
    proto_wrapper_t *request, *reply;
    
    request=proto_init_cursor_move_request(cursor_get_remote_handle(cursor), 
                        key, record, flags);

    st=_perform_request(env, env_get_curl(env), request, &reply);
    proto_delete(request);
    if (st) {
        if (reply)
            proto_delete(reply);
        return (st);
    }

    ham_assert(reply!=0, (""));
    ham_assert(proto_has_cursor_move_reply(reply)!=0, (""));

    st=proto_cursor_move_reply_get_status(reply);
    if (st) 
        goto bail;

    /* modify key/record, but make sure that USER_ALLOC is respected! */
    if (proto_cursor_move_reply_has_key(reply)) {
        ham_assert(key, (""));
        key->_flags=proto_cursor_move_reply_get_key_intflags(reply);
        key->size=proto_cursor_move_reply_get_key_size(reply);
        if (!(key->flags&HAM_KEY_USER_ALLOC)) {
            st=db_resize_key_allocdata(db, key->size);
            if (st)
                goto bail;
            key->data=db_get_key_allocdata(db);
        }
        memcpy(key->data, proto_cursor_move_reply_get_key_data(reply),
                key->size);
    }

    /* same for the record */
    if (proto_cursor_move_reply_has_record(reply)) {
        ham_assert(record, (""));
        record->size=proto_cursor_move_reply_get_record_size(reply);
        if (!(record->flags&HAM_RECORD_USER_ALLOC)) {
            st=db_resize_record_allocdata(db, record->size);
            if (st)
                goto bail;
            record->data=db_get_record_allocdata(db);
        }
        memcpy(record->data, proto_cursor_move_reply_get_record_data(reply),
                record->size);
    }

bail:
    proto_delete(reply);
    return (st);
}
Example #6
0
static ham_status_t
_remote_cursor_overwrite(ham_cursor_t *cursor, 
            ham_record_t *record, ham_u32_t flags)
{
    ham_status_t st;
    ham_db_t *db=cursor_get_db(cursor);
    ham_env_t *env=db_get_env(db);
    proto_wrapper_t *request, *reply;
    
    request=proto_init_cursor_overwrite_request(
                        cursor_get_remote_handle(cursor), record, flags);

    st=_perform_request(env, env_get_curl(env), request, &reply);
    proto_delete(request);
    if (st) {
        if (reply)
            proto_delete(reply);
        return (st);
    }

    ham_assert(reply!=0, (""));
    ham_assert(proto_has_cursor_overwrite_reply(reply)!=0, (""));

    st=proto_cursor_overwrite_reply_get_status(reply);

    proto_delete(reply);

    return (st);
}
void
extkey_cache_destroy(extkey_cache_t *cache)
{
    ham_size_t i;
    extkey_t *e, *n;
    ham_db_t *db=extkey_cache_get_db(cache);
	ham_env_t *env = db_get_env(db);

    /*
     * make sure that all entries are empty
     */
    for (i=0; i<extkey_cache_get_bucketsize(cache); i++) {
        e=extkey_cache_get_bucket(cache, i);
        while (e) {
#if HAM_DEBUG
            /*
             * make sure that the extkey-cache is empty - only for in-memory
             * databases and DEBUG builds.
             */
            if (env_get_rt_flags(env)&HAM_IN_MEMORY_DB)
                ham_assert(!"extkey-cache is not empty!", (0));
#endif
            n=extkey_get_next(e);
            allocator_free(env_get_allocator(env), e);
            e=n;
        }
    }

    allocator_free(env_get_allocator(env), cache);
}
ham_status_t
extkey_cache_insert(extkey_cache_t *cache, ham_offset_t blobid, 
            ham_size_t size, const ham_u8_t *data)
{
    ham_size_t h=my_calc_hash(cache, blobid);
    extkey_t *e;
    ham_db_t *db=extkey_cache_get_db(cache);
	ham_env_t *env = db_get_env(db);

    /*
     * DEBUG build: make sure that the item is not inserted twice!
     */
#ifdef HAM_DEBUG
    e=extkey_cache_get_bucket(cache, h);
    while (e) {
        ham_assert(extkey_get_blobid(e)!=blobid, (0));
        e=extkey_get_next(e);
    }
#endif

    e=(extkey_t *)allocator_alloc(env_get_allocator(env), SIZEOF_EXTKEY_T+size);
    if (!e)
        return HAM_OUT_OF_MEMORY;
    extkey_set_blobid(e, blobid);
    extkey_set_txn_id(e, env_get_txn_id(env));
    extkey_set_next(e, extkey_cache_get_bucket(cache, h));
    extkey_set_size(e, size);
    memcpy(extkey_get_data(e), data, size);

    extkey_cache_set_bucket(cache, h, e);
    extkey_cache_set_usedsize(cache, extkey_cache_get_usedsize(cache)+size);

    return (0);
}
ham_status_t
extkey_cache_purge(extkey_cache_t *cache)
{
    ham_size_t i;
    extkey_t *e, *n;
    ham_env_t *env;
	
	ham_assert(extkey_cache_get_db(cache), (0));
	env = db_get_env(extkey_cache_get_db(cache));

    /*
     * delete all entries which are "too old" (were not 
     * used in the last EXTKEY_MAX_AGE transactions)
     */
    for (i=0; i<extkey_cache_get_bucketsize(cache); i++) {
        extkey_t *p=0;
        e=extkey_cache_get_bucket(cache, i);
        while (e) {
            n=extkey_get_next(e);
            if (env_get_txn_id(env)-extkey_get_txn_id(e)>EXTKEY_MAX_AGE) {
                /* deleted the head element of the list? */
                if (!p)
                    extkey_cache_set_bucket(cache, i, n);
                else
                    extkey_set_next(p, n);
                allocator_free(env_get_allocator(env), e);
            }
            else
                p=e;
            e=n;
        }
    }

    return (0);
}
Example #10
0
static ham_status_t
_remote_fun_check_integrity(ham_db_t *db, ham_txn_t *txn)
{
    ham_status_t st;
    ham_env_t *env=db_get_env(db);
    proto_wrapper_t *request, *reply;
    
    request=proto_init_check_integrity_request(db_get_remote_handle(db), 
                        txn ? txn_get_remote_handle(txn) : 0);

    st=_perform_request(env, env_get_curl(env), request, &reply);
    proto_delete(request);
    if (st) {
        if (reply)
            proto_delete(reply);
        return (st);
    }

    ham_assert(reply!=0, (""));
    ham_assert(proto_has_check_integrity_reply(reply), (""));
    st=proto_check_integrity_reply_get_status(reply);

    proto_delete(reply);

    return (st);
}
Example #11
0
static ham_status_t
_remote_fun_get_key_count(ham_db_t *db, ham_txn_t *txn, ham_u32_t flags,
            ham_offset_t *keycount)
{
    ham_status_t st;
    ham_env_t *env=db_get_env(db);
    proto_wrapper_t *request, *reply;
    
    request=proto_init_db_get_key_count_request(db_get_remote_handle(db), 
                        txn ? txn_get_remote_handle(txn) : 0, flags);

    st=_perform_request(env, env_get_curl(env), request, &reply);
    proto_delete(request);
    if (st) {
        if (reply)
            proto_delete(reply);
        return (st);
    }

    ham_assert(reply!=0, (""));
    ham_assert(proto_has_db_get_key_count_reply(reply), (""));

    st=proto_db_get_key_count_reply_get_status(reply);
    if (!st)
        *keycount=proto_db_get_key_count_reply_get_key_count(reply);

    proto_delete(reply);

    return (st);
}
ham_status_t
extkey_cache_remove(extkey_cache_t *cache, ham_offset_t blobid)
{
	ham_db_t *db=extkey_cache_get_db(cache);
	ham_env_t *env = db_get_env(db);
    ham_size_t h=my_calc_hash(cache, blobid);
    extkey_t *e, *prev=0;

    e=extkey_cache_get_bucket(cache, h);
    while (e) {
        if (extkey_get_blobid(e)==blobid)
            break;
        prev=e;
        e=extkey_get_next(e);
    }

    if (!e)
        return (HAM_KEY_NOT_FOUND);

    if (prev)
        extkey_set_next(prev, extkey_get_next(e));
    else
        extkey_cache_set_bucket(cache, h, extkey_get_next(e));

    extkey_cache_set_usedsize(cache, 
            extkey_cache_get_usedsize(cache)-extkey_get_size(e));
    allocator_free(env_get_allocator(env), e);

    return (0);
}
/**                                                                 
 * open and initialize a backend                                    
 *                                                                  
 * @remark this function is called after the ham_db_structure       
 * was allocated and the file was opened                            

 @note This is a B+-tree 'backend' method.
 */                                                                 
static ham_status_t 
my_fun_open(ham_btree_t *be, ham_u32_t flags)
{
    ham_offset_t rootadd;
    ham_offset_t recno;
    ham_u16_t maxkeys;
    ham_u16_t keysize;
    ham_db_t *db=be_get_db(be);
    db_indexdata_t *indexdata=env_get_indexdata_ptr(db_get_env(db), 
                                    db_get_indexdata_offset(db));

    /*
     * load root address and maxkeys (first two bytes are the
     * database name)
     */
    maxkeys = index_get_max_keys(indexdata);
    keysize = index_get_keysize(indexdata);
    rootadd = index_get_self(indexdata);
    flags = index_get_flags(indexdata);
    recno = index_get_recno(indexdata);

    btree_set_rootpage(be, rootadd);
    btree_set_maxkeys(be, maxkeys);
    be_set_keysize(be, keysize);
    be_set_flags(be, flags);
    be_set_recno(be, recno);

    be_set_active(be, HAM_TRUE);

    return (0);
}
Example #14
0
static ham_status_t
_remote_fun_find(ham_db_t *db, ham_txn_t *txn, ham_key_t *key,
            ham_record_t *record, ham_u32_t flags)
{
    ham_status_t st;
    ham_env_t *env=db_get_env(db);
    proto_wrapper_t *request, *reply;

    request=proto_init_db_find_request(db_get_remote_handle(db), 
                        txn ? txn_get_remote_handle(txn) : 0, 
                        key, record, flags);

    st=_perform_request(env, env_get_curl(env), request, &reply);
    proto_delete(request);
    if (st) {
        if (reply)
            proto_delete(reply);
        return (st);
    }

    ham_assert(reply!=0, (""));
    ham_assert(proto_has_db_find_reply(reply)!=0, (""));

    st=proto_db_find_reply_get_status(reply);
    if (st==0) {
        /* approx. matching: need to copy the _flags and the key data! */
        if (proto_db_find_reply_has_key(reply)) {
            ham_assert(key, (""));
            key->_flags=proto_db_find_reply_get_key_intflags(reply);
            key->size=proto_db_find_reply_get_key_size(reply);
            if (!(key->flags&HAM_KEY_USER_ALLOC)) {
                st=db_resize_key_allocdata(db, key->size);
                if (st)
                    goto bail;
                key->data=db_get_key_allocdata(db);
            }
            memcpy(key->data, proto_db_find_reply_get_key_data(reply),
                    key->size);
        }
        if (proto_db_find_reply_has_record(reply)) {
            record->size=proto_db_find_reply_get_record_size(reply);
            if (!(record->flags&HAM_RECORD_USER_ALLOC)) {
                st=db_resize_record_allocdata(db, record->size);
                if (st)
                    goto bail;
                record->data=db_get_record_allocdata(db);
            }
            memcpy(record->data, proto_db_find_reply_get_record_data(reply),
                    record->size);
        }
    }

bail:
    proto_delete(reply);

    return (st);
}
ham_status_t
extkey_remove(ham_db_t *db, ham_offset_t blobid)
{
    ham_status_t st;

    if (db_get_extkey_cache(db)) {
        st=extkey_cache_remove(db_get_extkey_cache(db), blobid);
        if (st && st!=HAM_KEY_NOT_FOUND)
            return (st);
    }

    return (blob_free(db_get_env(db), db, blobid, 0));
}
/**                                                                    
 * Remove all extended keys for the given @a page from the            
 * extended key cache.                                                
 */                                                                    
static ham_status_t
my_fun_free_page_extkeys(ham_btree_t *be, ham_page_t *page, ham_u32_t flags)
{
    ham_db_t *db=be_get_db(be);
    
    ham_assert(page_get_owner(page) == db, (0));
    
    ham_assert(0 == (flags & ~DB_MOVE_TO_FREELIST), (0));

    /*
     * if this page has a header, and it's either a B-Tree root page or 
     * a B-Tree index page: remove all extended keys from the cache, 
     * and/or free their blobs
     */
    if (page_get_pers(page) 
            && (!(page_get_npers_flags(page)&PAGE_NPERS_NO_HEADER))
            && (page_get_type(page)==PAGE_TYPE_B_ROOT 
                || page_get_type(page)==PAGE_TYPE_B_INDEX)) 
    {
        ham_size_t i;
        ham_offset_t blobid;
        int_key_t *bte;
        btree_node_t *node=ham_page_get_btree_node(page);
        extkey_cache_t *c;

        ham_assert(db, ("Must be set as page owner when this is a Btree page"));
        ham_assert(db=page_get_owner(page), (""));
        c=db_get_extkey_cache(db);

        for (i=0; i<btree_node_get_count(node); i++) 
        {
            bte=btree_node_get_key(db, node, i);
            if (key_get_flags(bte)&KEY_IS_EXTENDED) 
            {
                blobid=key_get_extended_rid(db, bte);
                if (env_get_rt_flags(db_get_env(db))&HAM_IN_MEMORY_DB) 
                {
                    /* delete the blobid to prevent that it's freed twice */
                    *(ham_offset_t *)(key_get_key(bte)+
                        (db_get_keysize(db)-sizeof(ham_offset_t)))=0;
                }
                //(void)key_erase_record(db, bte, 0, BLOB_FREE_ALL_DUPES);
                if (c)
                    (void)extkey_cache_remove(c, blobid);
            }
        }
    }

    return (HAM_SUCCESS);
}
Example #17
0
static ham_status_t
_remote_cursor_find(ham_cursor_t *cursor, ham_key_t *key, 
                ham_record_t *record, ham_u32_t flags)
{
    ham_status_t st;
    ham_db_t *db=cursor_get_db(cursor);
    ham_env_t *env=db_get_env(db);
    proto_wrapper_t *request, *reply;

    request=proto_init_cursor_find_request(cursor_get_remote_handle(cursor), 
                        key, record, flags);
    
    st=_perform_request(env, env_get_curl(env), request, &reply);
    proto_delete(request);
    if (st) {
        if (reply)
            proto_delete(reply);
        return (st);
    }

    ham_assert(reply!=0, (""));
    ham_assert(proto_has_cursor_find_reply(reply)!=0, (""));

    st=proto_cursor_find_reply_get_status(reply);
    if (st) 
        goto bail;

    /* approx. matching: need to copy the _flags! */
    if (proto_cursor_find_reply_has_key(reply)) {
        key->_flags=proto_cursor_find_reply_get_key_intflags(reply);
    }
    if (proto_cursor_find_reply_has_record(reply)) {
        ham_assert(record, (""));
        record->size=proto_cursor_find_reply_get_record_size(reply);
        if (!(record->flags&HAM_RECORD_USER_ALLOC)) {
            st=db_resize_record_allocdata(db, record->size);
            if (st)
                goto bail;
            record->data=db_get_record_allocdata(db);
        }
        memcpy(record->data, proto_cursor_find_reply_get_record_data(reply),
                record->size);
    }

bail:
    proto_delete(reply);
    return (st);
}
/*
 * when the last hit leaf node is split or shrunk, blow it away for all operations!
 *
 * Also blow away a page when a transaction aborts which has modified this page. We'd rather
 * reconstruct our critical statistics then carry the wrong bounds, etc. around.
 *
 * This is done to prevent the hinter from hinting/pointing at an (by now)
 * INVALID btree node later on!
 */
void 
stats_page_is_nuked(ham_db_t *db, struct ham_page_t *page, ham_bool_t split)
{
    ham_runtime_statistics_dbdata_t *dbdata = db_get_db_perf_data(db);
    ham_env_t *env = db_get_env(db);
    int i;

    for (i = 0; i <= 2; i++)
    {
        ham_runtime_statistics_opdbdata_t *opstats = db_get_op_perf_data(db, i);

        ham_assert(i == HAM_OPERATION_STATS_FIND
                    || i == HAM_OPERATION_STATS_INSERT
                    || i == HAM_OPERATION_STATS_ERASE, (0));

        if (opstats->btree_last_page_addr == page_get_self(page))
        {
            opstats->btree_last_page_addr = 0;
            opstats->btree_last_page_sq_hits = 0;
        }
    }

    if (dbdata->lower_bound_page_address == page_get_self(page))
    {
        if (dbdata->lower_bound.data)
        {
            ham_assert(env_get_allocator(env) != 0, (0));
            allocator_free(env_get_allocator(env), dbdata->lower_bound.data);
        }
        memset(&dbdata->lower_bound, 0, sizeof(dbdata->lower_bound));
        dbdata->lower_bound_index = 0;
        dbdata->lower_bound_page_address = 0;
        dbdata->lower_bound_set = HAM_FALSE;
    }

	if (dbdata->upper_bound_page_address == page_get_self(page))
    {
        if (dbdata->upper_bound.data)
        {
            ham_assert(env_get_allocator(env) != 0, (0));
            allocator_free(env_get_allocator(env), dbdata->upper_bound.data);
        }
        memset(&dbdata->upper_bound, 0, sizeof(dbdata->upper_bound));
        dbdata->upper_bound_index = 0;
        dbdata->upper_bound_page_address = 0;
        dbdata->upper_bound_set = HAM_FALSE;
    }
}
void
stats_trash_dbdata(ham_db_t *db, ham_runtime_statistics_dbdata_t *dbdata)
{
    ham_env_t *env = db_get_env(db);

    /* trash the upper/lower bound keys, when set: */
    if (dbdata->upper_bound.data) {
        ham_assert(env_get_allocator(env) != 0, (0));
        allocator_free(env_get_allocator(env), dbdata->upper_bound.data);
    }
    if (dbdata->lower_bound.data) {
        ham_assert(env_get_allocator(env) != 0, (0));
        allocator_free(env_get_allocator(env), dbdata->lower_bound.data);
    }
    memset(dbdata, 0, sizeof(*dbdata));
}
Example #20
0
static ham_status_t
_remote_cursor_insert(ham_cursor_t *cursor, ham_key_t *key,
            ham_record_t *record, ham_u32_t flags)
{
    ham_status_t st;
    ham_db_t *db=cursor_get_db(cursor);
    ham_env_t *env=db_get_env(db);
    proto_wrapper_t *request, *reply;
    ham_bool_t send_key=HAM_TRUE;

    /* recno: do not send the key */
    if (db_get_rt_flags(db)&HAM_RECORD_NUMBER)
        send_key=HAM_FALSE;
    
    request=proto_init_cursor_insert_request(cursor_get_remote_handle(cursor), 
                        send_key ? key : 0, record, flags);

    st=_perform_request(env, env_get_curl(env), request, &reply);
    proto_delete(request);
    if (st) {
        if (reply)
            proto_delete(reply);
        return (st);
    }

    ham_assert(reply!=0, (""));
    ham_assert(proto_has_cursor_insert_reply(reply)!=0, (""));

    st=proto_cursor_insert_reply_get_status(reply);

    /* recno: the key was modified! */
    if (st==0 && proto_cursor_insert_reply_has_key(reply)) {
        if (proto_cursor_insert_reply_get_key_size(reply)
                ==sizeof(ham_offset_t)) {
            ham_assert(key->data!=0, (""));
            ham_assert(key->size==sizeof(ham_offset_t), (""));
            memcpy(key->data, proto_cursor_insert_reply_get_key_data(reply),
                    sizeof(ham_offset_t));
        }
    }

    proto_delete(reply);

    return (st);
}
extkey_cache_t *
extkey_cache_new(ham_db_t *db)
{
    extkey_cache_t *c;
    int memsize;

    memsize=sizeof(extkey_cache_t)+EXTKEY_CACHE_BUCKETSIZE*sizeof(extkey_t *);
    c=(extkey_cache_t *)allocator_calloc(env_get_allocator(db_get_env(db)), memsize);
    if (!c) {
        // HAM_OUT_OF_MEMORY;
        return (0);
    }

    extkey_cache_set_db(c, db);
    extkey_cache_set_bucketsize(c, EXTKEY_CACHE_BUCKETSIZE);

    return (c);
}
Example #22
0
static ham_status_t
_remote_fun_close(ham_db_t *db, ham_u32_t flags)
{
    ham_status_t st;
    ham_env_t *env=db_get_env(db);
    proto_wrapper_t *request, *reply;
    
    /*
     * auto-cleanup cursors?
     */
    if (flags&HAM_AUTO_CLEANUP) {
        ham_cursor_t *cursor=db_get_cursors(db);
        while ((cursor=db_get_cursors(db))) {
            (void)ham_cursor_close(cursor);
        }
    }
    else if (db_get_cursors(db)) {
        return (HAM_CURSOR_STILL_OPEN);
    }

    request=proto_init_db_close_request(db_get_remote_handle(db), flags);

    st=_perform_request(env, env_get_curl(env), request, &reply);
    proto_delete(request);
    if (st) {
        if (reply)
            proto_delete(reply);
        return (st);
    }

    ham_assert(reply!=0, (""));
    ham_assert(proto_has_db_close_reply(reply), (""));

    st=proto_db_close_reply_get_status(reply);

    proto_delete(reply);

    if (st==0)
        db_set_remote_handle(db, 0);

    return (st);
}
void
db_update_global_stats_erase_query(ham_db_t *db, ham_size_t key_size)
{
    ham_env_t *env = db_get_env(db);

    if (!(env_get_rt_flags(env)&HAM_IN_MEMORY_DB))
    {
        ham_runtime_statistics_globdata_t *globalstats = env_get_global_perf_data(env);
        ham_runtime_statistics_opdbdata_t *opstats = db_get_op_perf_data(db, HAM_OPERATION_STATS_ERASE);

#ifdef HAM_DEBUG
        ham_u16_t bucket = ham_bitcount2bucket_index(key_size / DB_CHUNKSIZE);
        ham_assert(bucket < HAM_FREELIST_SLOT_SPREAD, (0));
        //ham_assert(device_get_freelist_cache(dev), (0));
#endif

        globalstats->erase_query_count++;

        opstats->query_count++;
    }
}
Example #24
0
static ham_status_t
_remote_cursor_create(ham_db_t *db, ham_txn_t *txn, ham_u32_t flags,
        ham_cursor_t **cursor)
{
    ham_env_t *env=db_get_env(db);
    ham_status_t st;
    proto_wrapper_t *request, *reply;
    
    request=proto_init_cursor_create_request(db_get_remote_handle(db), 
                        txn ? txn_get_remote_handle(txn) : 0, flags);

    st=_perform_request(env, env_get_curl(env), request, &reply);
    proto_delete(request);
    if (st) {
        if (reply)
            proto_delete(reply);
        return (st);
    }

    ham_assert(reply!=0, (""));
    ham_assert(proto_has_cursor_create_reply(reply)!=0, (""));

    st=proto_cursor_create_reply_get_status(reply);
    if (st) {
        proto_delete(reply);
        return (st);
    }

    *cursor=(ham_cursor_t *)allocator_calloc(env_get_allocator(env), 
                            sizeof(ham_cursor_t));
    if (!(*cursor))
        return (HAM_OUT_OF_MEMORY);

    cursor_set_remote_handle(*cursor, 
                proto_cursor_create_reply_get_cursor_handle(reply));

    proto_delete(reply);

    return (st);
}
ham_status_t
btree_create(ham_backend_t **backend_ref, ham_db_t *db, ham_u32_t flags)
{
    ham_btree_t *btree;

    *backend_ref = 0;

    btree = (ham_btree_t *)allocator_calloc(env_get_allocator(db_get_env(db)), sizeof(*btree));
    if (!btree)
    {
        return HAM_OUT_OF_MEMORY;
    }

    /* initialize the backend */
    btree->_db=db;
    btree->_fun_create=my_fun_create;
    btree->_fun_open=my_fun_open;
    btree->_fun_close=my_fun_close;
    btree->_fun_flush=my_fun_flush;
    btree->_fun_delete=my_fun_delete;
    btree->_fun_find=btree_find;
    btree->_fun_insert=btree_insert;
    btree->_fun_erase=btree_erase;
    btree->_fun_enumerate=btree_enumerate;
#ifdef HAM_ENABLE_INTERNAL
    btree->_fun_check_integrity=btree_check_integrity;
    btree->_fun_calc_keycount_per_page=my_fun_calc_keycount_per_page;
#else
    btree->_fun_check_integrity=0;
    btree->_fun_calc_keycount_per_page=0;
#endif
    btree->_fun_cursor_create = my_fun_cursor_create;
    btree->_fun_close_cursors = my_fun_close_cursors;
    btree->_fun_uncouple_all_cursors=my_fun_uncouple_all_cursors;
    btree->_fun_free_page_extkeys=my_fun_free_page_extkeys;

    *backend_ref = (ham_backend_t *)btree;
    return HAM_SUCCESS;
}
Example #26
0
static ham_status_t
_remote_cursor_clone(ham_cursor_t *src, ham_cursor_t **dest)
{
    ham_env_t *env=db_get_env(cursor_get_db(src));
    ham_status_t st;
    proto_wrapper_t *request, *reply;
    
    request=proto_init_cursor_clone_request(cursor_get_remote_handle(src));

    st=_perform_request(env, env_get_curl(env), request, &reply);
    proto_delete(request);
    if (st) {
        if (reply)
            proto_delete(reply);
        return (st);
    }

    ham_assert(reply!=0, (""));
    ham_assert(proto_has_cursor_clone_reply(reply)!=0, (""));

    st=proto_cursor_clone_reply_get_status(reply);
    if (st) {
        proto_delete(reply);
        return (st);
    }

    *dest=(ham_cursor_t *)allocator_calloc(env_get_allocator(env), 
                            sizeof(ham_cursor_t));
    if (!(*dest))
        return (HAM_OUT_OF_MEMORY);

    cursor_set_remote_handle(*dest, 
                proto_cursor_clone_reply_get_cursor_handle(reply));

    proto_delete(reply);

    return (st);
}
ham_status_t
extkey_cache_fetch(extkey_cache_t *cache, ham_offset_t blobid, 
            ham_size_t *size, ham_u8_t **data)
{
    ham_size_t h=my_calc_hash(cache, blobid);
    extkey_t *e;

    e=extkey_cache_get_bucket(cache, h);
    while (e) {
        if (extkey_get_blobid(e)==blobid)
            break;
        e=extkey_get_next(e);
    }

    if (!e)
        return (HAM_KEY_NOT_FOUND);

    *size=extkey_get_size(e);
    *data=extkey_get_data(e);
    extkey_set_txn_id(e, env_get_txn_id(db_get_env(extkey_cache_get_db(cache))));

    return (0);
}
Example #28
0
ham_status_t
blob_read(ham_db_t *db, ham_offset_t blobid, 
        ham_record_t *record, ham_u32_t flags)
{
    ham_status_t st;
    ham_page_t *page;
    blob_t hdr;
    ham_size_t blobsize=0;

    /*
     * in-memory-database: the blobid is actually a pointer to the memory
     * buffer, in which the blob is stored
     */
    if (env_get_rt_flags(db_get_env(db))&HAM_IN_MEMORY_DB) {
        blob_t *hdr=(blob_t *)U64_TO_PTR(blobid);
        ham_u8_t *data=(ham_u8_t *)(U64_TO_PTR(blobid))+sizeof(blob_t);

        /* when the database is closing, the header is already deleted */
        if (!hdr) {
            record->size = 0;
            return (0);
        }

        blobsize = (ham_size_t)blob_get_size(hdr);

        if (flags&HAM_PARTIAL) {
            if (record->partial_offset>blobsize) {
                ham_trace(("partial offset is greater than the total "
                            "record size"));
                return (HAM_INV_PARAMETER);
            }
            if (record->partial_offset+record->partial_size>blobsize)
                blobsize=blobsize-record->partial_offset;
            else
                blobsize=record->partial_size;
        }

        if (!blobsize) {
            /* empty blob? */
            record->data = 0;
            record->size = 0;
        }
        else {
            ham_u8_t *d=data;
            if (flags&HAM_PARTIAL)
                d+=record->partial_offset;

            if ((flags&HAM_DIRECT_ACCESS) 
                    && !(record->flags&HAM_RECORD_USER_ALLOC)) {
                record->size=blobsize;
                record->data=d;
            }
            else {
                /* resize buffer, if necessary */
                if (!(record->flags & HAM_RECORD_USER_ALLOC)) {
                    st=db_resize_record_allocdata(db, blobsize);
                    if (st)
                        return (st);
                    record->data = db_get_record_allocdata(db);
                }
                /* and copy the data */
                memcpy(record->data, d, blobsize);
                record->size = blobsize;
            }
        }

        return (0);
    }

    ham_assert(blobid%DB_CHUNKSIZE==0, ("blobid is %llu", blobid));

    /*
     * first step: read the blob header 
     */
    st=__read_chunk(db_get_env(db), 0, &page, blobid, 
                    (ham_u8_t *)&hdr, sizeof(hdr));
    if (st)
        return (st);

    ham_assert(blob_get_alloc_size(&hdr)%DB_CHUNKSIZE==0, (0));

    /*
     * sanity check
     */
    if (blob_get_self(&hdr)!=blobid)
        return (HAM_BLOB_NOT_FOUND);

    blobsize = (ham_size_t)blob_get_size(&hdr);

    if (flags&HAM_PARTIAL) {
        if (record->partial_offset>blobsize) {
            ham_trace(("partial offset+size is greater than the total "
                        "record size"));
            return (HAM_INV_PARAMETER);
        }
        if (record->partial_offset+record->partial_size>blobsize)
            blobsize=blobsize-record->partial_offset;
        else
            blobsize=record->partial_size;
    }

    /* 
     * empty blob? 
     */
    if (!blobsize) {
        record->data = 0;
        record->size = 0;
        return (0);
    }

    /*
     * second step: resize the blob buffer
     */
    if (!(record->flags & HAM_RECORD_USER_ALLOC)) {
        st=db_resize_record_allocdata(db, blobsize);
        if (st)
            return (st);
        record->data = db_get_record_allocdata(db);
    }

    /*
     * third step: read the blob data
     */
    st=__read_chunk(db_get_env(db), page, 0, 
                    blobid+sizeof(blob_t)+(flags&HAM_PARTIAL 
                            ? record->partial_offset 
                            : 0),
                    record->data, blobsize);
    if (st)
        return (st);

    record->size = blobsize;

    return (0);
}
Example #29
0
ham_status_t
blob_duplicate_erase(ham_db_t *db, ham_offset_t table_id,
        ham_size_t position, ham_u32_t flags, ham_offset_t *new_table_id)
{
    ham_status_t st;
    ham_record_t rec;
    ham_size_t i;
    dupe_table_t *table;
    ham_offset_t rid;
	ham_env_t *env = db_get_env(db);

    /* store the public record pointer, otherwise it's destroyed */
    ham_size_t rs=db_get_record_allocsize(db);
    void      *rp=db_get_record_allocdata(db);
    db_set_record_allocdata(db, 0);
    db_set_record_allocsize(db, 0);

    memset(&rec, 0, sizeof(rec));

    if (new_table_id)
        *new_table_id=table_id;

    st=blob_read(db, table_id, &rec, 0);
    if (st)
        return (st);

    /* restore the public record pointer */
    db_set_record_allocsize(db, rs);
    db_set_record_allocdata(db, rp);

    table=(dupe_table_t *)rec.data;

    /*
     * if BLOB_FREE_ALL_DUPES is set *OR* if the last duplicate is deleted:
     * free the whole duplicate table
     */
    if (flags&BLOB_FREE_ALL_DUPES
            || (position==0 && dupe_table_get_count(table)==1)) {
        for (i=0; i<dupe_table_get_count(table); i++) {
            dupe_entry_t *e=dupe_table_get_entry(table, i);
            if (!(dupe_entry_get_flags(e)&(KEY_BLOB_SIZE_SMALL
                                        |KEY_BLOB_SIZE_TINY
                                        |KEY_BLOB_SIZE_EMPTY))) {
                st=blob_free(env, db, dupe_entry_get_rid(e), 0);
                if (st) {
                    allocator_free(env_get_allocator(env), table);
                    return (st);
                }
            }
        }
        st=blob_free(env, db, table_id, 0); /* [i_a] isn't this superfluous (& 
                                        * dangerous), thanks to the 
                                        * free_all_dupes loop above??? */
        allocator_free(env_get_allocator(env), table);
        if (st)
            return (st);

        if (new_table_id)
            *new_table_id=0;

        return (0);
    }
    else {
        ham_record_t rec={0};
        dupe_entry_t *e=dupe_table_get_entry(table, position);
        if (!(dupe_entry_get_flags(e)&(KEY_BLOB_SIZE_SMALL
                                    |KEY_BLOB_SIZE_TINY
                                    |KEY_BLOB_SIZE_EMPTY))) {
            st=blob_free(env, db, dupe_entry_get_rid(e), 0);
            if (st) {
                allocator_free(env_get_allocator(env), table);
                return (st);
            }
        }
        memmove(e, e+1,
            ((dupe_table_get_count(table)-position)-1)*sizeof(dupe_entry_t));
        dupe_table_set_count(table, dupe_table_get_count(table)-1);

        rec.data=(ham_u8_t *)table;
        rec.size=sizeof(dupe_table_t)
                    +(dupe_table_get_capacity(table)-1)*sizeof(dupe_entry_t);
        st=blob_overwrite(env, db, table_id, &rec, 0, &rid);
        if (st) {
            allocator_free(env_get_allocator(env), table);
            return (st);
        }
        if (new_table_id)
            *new_table_id=rid;
    }

    /*
     * return 0 as a rid if the table is empty
     */
    if (dupe_table_get_count(table)==0)
        if (new_table_id)
            *new_table_id=0;

    allocator_free(env_get_allocator(env), table);
    return (0);
}
Example #30
0
ham_status_t
blob_duplicate_insert(ham_db_t *db, ham_offset_t table_id, 
        ham_record_t *record, ham_size_t position, ham_u32_t flags, 
        dupe_entry_t *entries, ham_size_t num_entries, 
        ham_offset_t *rid, ham_size_t *new_position)
{
    ham_status_t st=0;
    dupe_table_t *table=0;
    ham_bool_t alloc_table=0;
	ham_bool_t resize=0;
    ham_page_t *page=0;
    ham_env_t *env=db_get_env(db);

    /*
     * create a new duplicate table if none existed, and insert
     * the first entry
     */
    if (!table_id) {
        ham_assert(num_entries==2, (""));
        /* allocates space for 8 (!) entries */
        table=allocator_calloc(env_get_allocator(env), 
                        sizeof(dupe_table_t)+7*sizeof(dupe_entry_t));
        if (!table)
            return HAM_OUT_OF_MEMORY;
        dupe_table_set_capacity(table, 8);
        dupe_table_set_count(table, 1);
        memcpy(dupe_table_get_entry(table, 0), &entries[0], 
                        sizeof(entries[0]));

        /* skip the first entry */
        entries++;
        num_entries--;
        alloc_table=1;
    }
    else {
        /*
         * otherwise load the existing table 
         */
        st=__get_duplicate_table(&table, &page, env, table_id);
		ham_assert(st ? table == NULL : 1, (0));
		ham_assert(st ? page == NULL : 1, (0));
        if (!table)
			return st ? st : HAM_INTERNAL_ERROR;
        if (!page && !(env_get_rt_flags(env)&HAM_IN_MEMORY_DB))
            alloc_table=1;
    }

    if (page)
        if ((st=ham_log_add_page_before(page)))
            return (st);

    ham_assert(num_entries==1, (""));

    /*
     * resize the table, if necessary
     */ 
    if (!(flags & HAM_OVERWRITE)
            && dupe_table_get_count(table)+1>=dupe_table_get_capacity(table)) {
        dupe_table_t *old=table;
        ham_size_t new_cap=dupe_table_get_capacity(table);

        if (new_cap < 3*8)
            new_cap += 8;
        else
            new_cap += new_cap/3;

        table=allocator_calloc(env_get_allocator(env), sizeof(dupe_table_t)+
                        (new_cap-1)*sizeof(dupe_entry_t));
        if (!table)
            return (HAM_OUT_OF_MEMORY);
        dupe_table_set_capacity(table, new_cap);
        dupe_table_set_count(table, dupe_table_get_count(old));
        memcpy(dupe_table_get_entry(table, 0), dupe_table_get_entry(old, 0),
                       dupe_table_get_count(old)*sizeof(dupe_entry_t));
        if (alloc_table)
            allocator_free(env_get_allocator(env), old);

        alloc_table=1;
        resize=1;
    }

    /*
     * insert sorted, unsorted or overwrite the entry at the requested position
     */
    if (flags&HAM_OVERWRITE) {
        dupe_entry_t *e=dupe_table_get_entry(table, position);

        if (!(dupe_entry_get_flags(e)&(KEY_BLOB_SIZE_SMALL
                                    |KEY_BLOB_SIZE_TINY
                                    |KEY_BLOB_SIZE_EMPTY))) {
            (void)blob_free(env, db, dupe_entry_get_rid(e), 0);
        }

        memcpy(dupe_table_get_entry(table, position), 
                        &entries[0], sizeof(entries[0]));
    }
    else {
        if (db_get_rt_flags(db)&HAM_SORT_DUPLICATES) {
            if (page)
                page_add_ref(page);
            position=__get_sorted_position(db, table, record, flags);
            if (page)
                page_release_ref(page);
            if (position<0)
                return ((ham_status_t)position);
        }
        else if (flags&HAM_DUPLICATE_INSERT_BEFORE) {
            /* do nothing, insert at the current position */
        }
        else if (flags&HAM_DUPLICATE_INSERT_AFTER) {
            position++;
            if (position > dupe_table_get_count(table))
                position=dupe_table_get_count(table);
        }
        else if (flags&HAM_DUPLICATE_INSERT_FIRST) {
            position=0;
        }
        else if (flags&HAM_DUPLICATE_INSERT_LAST) {
            position=dupe_table_get_count(table);
        }
        else {
            position=dupe_table_get_count(table);
        }

        if (position != dupe_table_get_count(table)) {
            memmove(dupe_table_get_entry(table, position+1), 
                dupe_table_get_entry(table, position), 
                sizeof(entries[0])*(dupe_table_get_count(table)-position));
        }

        memcpy(dupe_table_get_entry(table, position), 
                &entries[0], sizeof(entries[0]));

        dupe_table_set_count(table, dupe_table_get_count(table)+1);
    }

    /*
     * write the table back to disk and return the blobid of the table
     */
    if ((table_id && !page) || resize) {
        ham_record_t rec={0};
        rec.data=(ham_u8_t *)table;
        rec.size=sizeof(dupe_table_t)
                    +(dupe_table_get_capacity(table)-1)*sizeof(dupe_entry_t);
        st=blob_overwrite(env, db, table_id, &rec, 0, rid);
    }
    else if (!table_id) {
        ham_record_t rec={0};
        rec.data=(ham_u8_t *)table;
        rec.size=sizeof(dupe_table_t)
                    +(dupe_table_get_capacity(table)-1)*sizeof(dupe_entry_t);
        st=blob_allocate(env, db, &rec, 0, rid);
    }
    else if (table_id && page) {
        page_set_dirty(page, env);
    }
    else {
        ham_assert(!"shouldn't be here", (0));
	}

    if (alloc_table)
        allocator_free(env_get_allocator(env), table);

    if (new_position)
        *new_position=position;

    return (st);
}