📄 blob.c
字号:
/** * Copyright (C) 2005-2007 Christoph Rupp (chris@crupp.de). * All rights reserved. See file LICENSE for licence and copyright * information. * */#include <string.h>#include <ham/hamsterdb.h>#include "os.h"#include "db.h"#include "blob.h"#include "error.h"#include "freelist.h"#include "mem.h"#include "page.h"#define SMALLEST_CHUNK_SIZE (sizeof(ham_offset_t)+sizeof(blob_t)+1)static ham_bool_tmy_blob_is_small(ham_db_t *db, ham_size_t size){ return (size<(ham_size_t)(db_get_pagesize(db)/3));}static ham_status_tmy_write_chunks(ham_db_t *db, ham_page_t *page, ham_offset_t addr, ham_u8_t **chunk_data, ham_size_t *chunk_size, ham_size_t chunks){ ham_size_t i; ham_status_t st; ham_offset_t pageid; ham_device_t *device=db_get_device(db); /* * for each chunk... */ for (i=0; i<chunks; i++) { while (chunk_size[i]) { /* * get the page-ID from this chunk */ pageid=(addr/db_get_pagesize(db))*db_get_pagesize(db); /* * is it the current page? if not, try to fetch the page from * the cache - but only read the page from disk, if the * chunk is small */ if (!(page && page_get_self(page)==pageid) || my_blob_is_small(db, chunk_size[i])) { page=db_fetch_page(db, pageid, my_blob_is_small(db, chunk_size[i]) ? 0 : DB_ONLY_FROM_CACHE); /* blob pages don't have a page header */ if (page) page_set_npers_flags(page, page_get_npers_flags(page)|PAGE_NPERS_NO_HEADER); } /* * if we have a page pointer: use it; otherwise write directly * to the device */ if (page) { ham_size_t writestart= (ham_size_t)(addr-page_get_self(page)); ham_size_t writesize = (ham_size_t)(db_get_pagesize(db)-writestart); if (writesize>chunk_size[i]) writesize=chunk_size[i]; memcpy(&page_get_raw_payload(page)[writestart], chunk_data[i], writesize); page_set_dirty(page, 1); addr+=writesize; chunk_data[i]+=writesize; chunk_size[i]-=writesize; } else { ham_size_t s=chunk_size[i]<db_get_pagesize(db) ? chunk_size[i] : db_get_pagesize(db); /* limit to the next page boundary */ if (s>pageid+db_get_pagesize(db)-addr) s=(ham_size_t)(pageid+db_get_pagesize(db)-addr); st=device->write(device, addr, chunk_data[i], s); if (st) return (st); addr+=s; chunk_data[i]+=s; chunk_size[i]-=s; } } } return (0);}static ham_status_tmy_read_chunk(ham_db_t *db, ham_offset_t addr, ham_u8_t *data, ham_size_t size){ ham_status_t st; ham_page_t *page=0; ham_offset_t pageid; ham_device_t *device=db_get_device(db); while (size) { /* * get the page-ID from this chunk */ pageid=(addr/db_get_pagesize(db))*db_get_pagesize(db); /* * is it the current page? if not, try to fetch the page from * the cache - but only read the page from disk, if the * chunk is small */ if (!(page && page_get_self(page)==pageid) || my_blob_is_small(db, size)) { page=db_fetch_page(db, pageid, my_blob_is_small(db, size) ? 0 : DB_ONLY_FROM_CACHE); /* blob pages don't have a page header */ if (page) page_set_npers_flags(page, page_get_npers_flags(page)|PAGE_NPERS_NO_HEADER); else if (db_get_error(db)) return (db_get_error(db)); } /* * if we have a page pointer: use it; otherwise read directly * from the device */ if (page) { ham_size_t readstart= (ham_size_t)(addr-page_get_self(page)); ham_size_t readsize = (ham_size_t)(db_get_pagesize(db)-readstart); if (readsize>size) readsize=size; memcpy(data, &page_get_raw_payload(page)[readstart], readsize); addr+=readsize; data+=readsize; size-=readsize; } else { ham_size_t s=size<db_get_pagesize(db) ? size : db_get_pagesize(db); /* limit to the next page boundary */ if (s>pageid+db_get_pagesize(db)-addr) s=(ham_size_t)(pageid+db_get_pagesize(db)-addr); st=device->read(device, addr, data, s); if (st) return (st); addr+=s; data+=s; size-=s; } } return (0);}ham_status_tblob_allocate(ham_db_t *db, ham_u8_t *data, ham_size_t size, ham_u32_t flags, ham_offset_t *blobid){ ham_status_t st; ham_page_t *page=0; ham_offset_t addr; blob_t hdr; ham_u8_t *chunk_data[2]; ham_size_t alloc_size, chunk_size[2]; ham_device_t *device=db_get_device(db); *blobid=0; /* * in-memory-database: the blobid is actually a pointer to the memory * buffer, in which the blob (with the blob-header) is stored */ if (db_get_rt_flags(db)&HAM_IN_MEMORY_DB) { blob_t *hdr; ham_u8_t *p=(ham_u8_t *)ham_mem_alloc(db, size+sizeof(blob_t)); if (!p) { db_set_error(db, HAM_OUT_OF_MEMORY); return (HAM_OUT_OF_MEMORY); } memcpy(p+sizeof(blob_t), data, size); /* initialize the header */ hdr=(blob_t *)p; memset(hdr, 0, sizeof(&hdr)); blob_set_self(hdr, (ham_offset_t)p); blob_set_alloc_size(hdr, size+sizeof(blob_t)); blob_set_real_size(hdr, size+sizeof(blob_t)); blob_set_user_size(hdr, size); *blobid=(ham_offset_t)p; return (0); } memset(&hdr, 0, sizeof(hdr)); /* * blobs are CHUNKSIZE-allocated */ alloc_size=sizeof(blob_t)+size; if (alloc_size%DB_CHUNKSIZE!=0) alloc_size=((alloc_size/DB_CHUNKSIZE)*DB_CHUNKSIZE)+DB_CHUNKSIZE; /* * check if we have space in the freelist */ addr=freel_alloc_area(db, alloc_size); if (!addr) { /* * if the blob is small, we load the page through the cache */ if (my_blob_is_small(db, alloc_size)) { page=db_alloc_page(db, PAGE_TYPE_B_INDEX|PAGE_IGNORE_FREELIST, 0); if (!page) return (db_get_error(db)); /* blob pages don't have a page header */ page_set_npers_flags(page, page_get_npers_flags(page)|PAGE_NPERS_NO_HEADER); addr=page_get_self(page); /* move the remaining space to the freelist */ (void)freel_mark_free(db, addr+alloc_size, db_get_pagesize(db)-alloc_size); blob_set_alloc_size(&hdr, alloc_size); } /* * otherwise use direct IO to allocate the space */ else { ham_size_t aligned=alloc_size; if (aligned%db_get_pagesize(db)) { aligned+=db_get_pagesize(db); aligned/=db_get_pagesize(db); aligned*=db_get_pagesize(db); } st=device->alloc(device, aligned, &addr); if (st) return (st); /* if aligned!=size, and the remaining chunk is large enough: * move it to the freelist */ if (aligned!=alloc_size) { ham_size_t diff=aligned-alloc_size; if (diff>SMALLEST_CHUNK_SIZE) { (void)freel_mark_free(db, addr+alloc_size, diff); blob_set_alloc_size(&hdr, aligned-diff); } else blob_set_alloc_size(&hdr, aligned); } else blob_set_alloc_size(&hdr, aligned);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -