Beispiel #1
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);
}
Beispiel #2
0
static ham_status_t
__get_duplicate_table(dupe_table_t **table_ref, ham_page_t **page, ham_env_t *env, ham_u64_t table_id)
{
    ham_status_t st;
    blob_t hdr;
    ham_page_t *hdrpage=0;
    dupe_table_t *table;

	*page = 0;
    if (env_get_rt_flags(env)&HAM_IN_MEMORY_DB) {
        ham_u8_t *p=(ham_u8_t *)U64_TO_PTR(table_id); 
        *table_ref = (dupe_table_t *)(p+sizeof(hdr));
		return HAM_SUCCESS;
    }

	*table_ref = 0;

    /*
     * load the blob header
     */
    st=__read_chunk(env, 0, &hdrpage, table_id, (ham_u8_t *)&hdr, sizeof(hdr));
    if (st) {
        return st;
    }

    /*
     * if the whole table is in a page (and not split between several
     * pages), just return a pointer directly in the page
     */
    if (page_get_self(hdrpage)+env_get_usable_pagesize(env) >=
            table_id+blob_get_size(&hdr)) 
    {
        ham_u8_t *p=page_get_raw_payload(hdrpage);
        /* yes, table is in the page */
        *page=hdrpage;
        *table_ref = (dupe_table_t *)
                &p[table_id-page_get_self(hdrpage)+sizeof(hdr)];
		return HAM_SUCCESS;
    }

    /*
     * otherwise allocate memory for the table
     */
    table=allocator_alloc(env_get_allocator(env), (ham_size_t)blob_get_size(&hdr));
    if (!table) {
        return HAM_OUT_OF_MEMORY;
    }

    /*
     * then read the rest of the blob
     */
    st=__read_chunk(env, hdrpage, 0, table_id+sizeof(hdr), 
            (ham_u8_t *)table, (ham_size_t)blob_get_size(&hdr));
    if (st) {
        return st;
    }

    *table_ref = table;
	return HAM_SUCCESS;
}
Beispiel #3
0
void *realloc(void *ptr, size_t size) {
  if (size == 0) {
    free(ptr);
    return NULL;
  }
  if (!ptr) return malloc(size);

  struct bucket_header *header = util_ptr_to_header(ptr);
  size_t max_avail;
  if (header->type == BUCKET_TYPE_BLOB) {
    max_avail = blob_get_size(header);
  } else {
    max_avail = bucket_get_record_size(header->type);
  }
  if (max_avail >= size) return ptr;

  void *new_address = malloc(size);
  if (ptr) memcpy(new_address, ptr, max_avail);
  free(ptr);

  dprint("DEBUG: realloc(%p, %zu) = %p\n", ptr, size, new_address);
  return new_address;
}
Beispiel #4
0
ham_status_t
blob_overwrite(ham_env_t *env, ham_db_t *db, ham_offset_t old_blobid, 
        ham_record_t *record, ham_u32_t flags, ham_offset_t *new_blobid)
{
    ham_status_t st;
    ham_size_t alloc_size;
    blob_t old_hdr;
    blob_t new_hdr;
    ham_page_t *page;

    /*
     * PARTIAL WRITE
     * 
     * if offset+partial_size equals the full record size, then we won't 
     * have any gaps. In this case we just write the full record and ignore
     * the partial parameters.
     */
    if (flags&HAM_PARTIAL) {
        if (record->partial_offset==0 
                && record->partial_offset+record->partial_size==record->size)
            flags&=~HAM_PARTIAL;
    }

    /*
     * inmemory-databases: free the old blob, 
     * allocate a new blob (but if both sizes are equal, just overwrite
     * the data)
     */
    if (env_get_rt_flags(env)&HAM_IN_MEMORY_DB) 
    {
        blob_t *nhdr, *phdr=(blob_t *)U64_TO_PTR(old_blobid);

        if (blob_get_size(phdr)==record->size) {
            ham_u8_t *p=(ham_u8_t *)phdr;
            if (flags&HAM_PARTIAL) {
                memmove(p+sizeof(blob_t)+record->partial_offset, 
                        record->data, record->partial_size);
            }
            else {
                memmove(p+sizeof(blob_t), record->data, record->size);
            }
            *new_blobid=(ham_offset_t)PTR_TO_U64(phdr);
        }
        else {
            st=blob_allocate(env, db, record, flags, new_blobid);
            if (st)
                return (st);
            nhdr=(blob_t *)U64_TO_PTR(*new_blobid);
            blob_set_flags(nhdr, blob_get_flags(phdr));

            allocator_free(env_get_allocator(env), phdr);
        }

        return (HAM_SUCCESS);
    }

    ham_assert(old_blobid%DB_CHUNKSIZE==0, (0));

    /*
     * blobs are CHUNKSIZE-allocated 
     */
    alloc_size=sizeof(blob_t)+record->size;
    alloc_size += DB_CHUNKSIZE - 1;
    alloc_size -= alloc_size % DB_CHUNKSIZE;

    /*
     * first, read the blob header; if the new blob fits into the 
     * old blob, we overwrite the old blob (and add the remaining
     * space to the freelist, if there is any)
     */
    st=__read_chunk(env, 0, &page, old_blobid, (ham_u8_t *)&old_hdr, 
            sizeof(old_hdr));
    if (st)
        return (st);

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

    /*
     * sanity check
     */
    ham_verify(blob_get_self(&old_hdr)==old_blobid, 
            ("invalid blobid %llu != %llu", blob_get_self(&old_hdr), 
            old_blobid));
    if (blob_get_self(&old_hdr)!=old_blobid)
        return (HAM_BLOB_NOT_FOUND);

    /*
     * now compare the sizes; does the new data fit in the old allocated
     * space?
     */
    if (alloc_size<=blob_get_alloc_size(&old_hdr)) 
    {
        ham_u8_t *chunk_data[2];
        ham_size_t chunk_size[2];

        /* 
         * setup the new blob header
         */
        blob_set_self(&new_hdr, blob_get_self(&old_hdr));
        blob_set_size(&new_hdr, record->size);
        blob_set_flags(&new_hdr, blob_get_flags(&old_hdr));
        if (blob_get_alloc_size(&old_hdr)-alloc_size>SMALLEST_CHUNK_SIZE)
            blob_set_alloc_size(&new_hdr, alloc_size);
        else
            blob_set_alloc_size(&new_hdr, blob_get_alloc_size(&old_hdr));

        /*
         * PARTIAL WRITE
         *
         * if we have a gap at the beginning, then we have to write the
         * blob header and the blob data in two steps; otherwise we can
         * write both immediately
         */
        if ((flags&HAM_PARTIAL) && (record->partial_offset)) {
            chunk_data[0]=(ham_u8_t *)&new_hdr;
            chunk_size[0]=sizeof(new_hdr);
            st=__write_chunks(env, page, blob_get_self(&new_hdr), HAM_FALSE,
                    HAM_FALSE, chunk_data, chunk_size, 1);
            if (st)
                return (st);

            chunk_data[0]=record->data;
            chunk_size[0]=record->partial_size;
            st=__write_chunks(env, page, 
                    blob_get_self(&new_hdr)+sizeof(new_hdr)
                            +record->partial_offset, 
                    HAM_FALSE, HAM_FALSE, chunk_data, chunk_size, 1);
            if (st)
                return (st);
        }
        else {
            chunk_data[0]=(ham_u8_t *)&new_hdr;
            chunk_size[0]=sizeof(new_hdr);
            chunk_data[1]=record->data;
            chunk_size[1]=(flags&HAM_PARTIAL) 
                                ? record->partial_size 
                                : record->size;

            st=__write_chunks(env, page, blob_get_self(&new_hdr), HAM_FALSE,
                    HAM_FALSE, chunk_data, chunk_size, 2);
            if (st)
                return (st);
        }

        /*
         * move remaining data to the freelist
         */
        if (blob_get_alloc_size(&old_hdr)!=blob_get_alloc_size(&new_hdr)) {
            (void)freel_mark_free(env, db,
                  blob_get_self(&new_hdr)+blob_get_alloc_size(&new_hdr), 
                  (ham_size_t)(blob_get_alloc_size(&old_hdr)-
                  blob_get_alloc_size(&new_hdr)), HAM_FALSE);
        }

        /*
         * the old rid is the new rid
         */
        *new_blobid=blob_get_self(&new_hdr);

        return (HAM_SUCCESS);
    }
    else {
        /* 
         * when the new data is larger, allocate a fresh space for it 
         * and discard the old;
         'overwrite' has become (delete + insert) now.
         */
        st=blob_allocate(env, db, record, flags, new_blobid);
        if (st)
            return (st);

        (void)freel_mark_free(env, db, old_blobid, 
                (ham_size_t)blob_get_alloc_size(&old_hdr), HAM_FALSE);
    }

    return (HAM_SUCCESS);
}
Beispiel #5
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);
}