📄 hamsterdb.c
字号:
/** * Copyright (C) 2005-2007 Christoph Rupp (chris@crupp.de). * All rights reserved. See file LICENSE for licence and copyright * information. * */#ifdef HAVE_MALLOC_H# include <malloc.h>#else# include <stdlib.h>#endif#include <string.h>#include <ham/hamsterdb.h>#include "config.h"#include "error.h"#include "mem.h"#include "env.h"#include "db.h"#include "page.h"#include "version.h"#include "txn.h"#include "cache.h"#include "blob.h"#include "freelist.h"#include "extkeys.h"#include "btree_cursor.h"#include "cursor.h"#include "util.h"#include "keys.h"/* private parameter list entry for ham_create_ex */#define HAM_PARAM_DBNAME (1000)/* a reserved database name for those databases, who're created without * an environment (and therefore don't have a name) */#define EMPTY_DATABASE_NAME (0xf000)/* a reserved database name for the first database in an environment */#define FIRST_DATABASE_NAME (0xf001)typedef struct free_cb_context_t{ ham_db_t *db; ham_bool_t is_leaf;} free_cb_context_t;/* * callback function for ham_dump */#ifdef HAM_ENABLE_INTERNALstatic voidmy_dump_cb(int event, void *param1, void *param2, void *context){ ham_size_t i, limit, keysize; ham_page_t *page; int_key_t *key; ham_u8_t *data; ham_dump_cb_t cb=(ham_dump_cb_t)context; switch (event) { case ENUM_EVENT_DESCEND: break; case ENUM_EVENT_PAGE_START: page=(ham_page_t *)param1; printf("\n------ page 0x%llx ---------------------------------------\n", (long long unsigned)page_get_self(page)); break; case ENUM_EVENT_ITEM: key=(int_key_t *)param1; data=key_get_key(key); keysize=key_get_size(key); if (cb) { cb(data, keysize); } else { printf(" %02d: ", *(int *)param2); printf(" key (%2d byte): ", key_get_size(key)); if (keysize>16) limit=16; else limit=keysize; for (i=0; i<limit; i++) printf("%02x ", data[i]); if (keysize>limit) printf("... (%d more bytes)\n", keysize-limit); else printf("\n"); printf(" ptr: 0x%llx\n", (long long unsigned)key_get_ptr(key)); } break; default: ham_assert(!"unknown callback event", ("")); break; }}#endif /* HAM_ENABLE_INTERNAL *//* * callback function for freeing blobs of an in-memory-database */static voidmy_free_cb(int event, void *param1, void *param2, void *context){ int_key_t *key; free_cb_context_t *c; c=(free_cb_context_t *)context; switch (event) { case ENUM_EVENT_DESCEND: break; case ENUM_EVENT_PAGE_START: c->is_leaf=*(ham_bool_t *)param2; break; case ENUM_EVENT_PAGE_STOP: /* * if this callback function is called from ham_env_erase_db: * move the page to the freelist */ if (!db_get_rt_flags(c->db)&HAM_IN_MEMORY_DB) { ham_page_t *page=(ham_page_t *)param1; (void)txn_free_page(db_get_txn(c->db), page); } break; case ENUM_EVENT_ITEM: key=(int_key_t *)param1; if (key_get_flags(key)&KEY_IS_EXTENDED) { ham_offset_t blobid=key_get_extended_rid(c->db, key); /* * delete the cached extended key */ if (db_get_extkey_cache(c->db)) (void)extkey_cache_remove(db_get_extkey_cache(c->db), blobid); /* * then delete the blob */ (void)blob_free(c->db, blobid, 0); } if (key_get_flags(key)&KEY_BLOB_SIZE_TINY || key_get_flags(key)&KEY_BLOB_SIZE_SMALL || key_get_flags(key)&KEY_BLOB_SIZE_EMPTY) break; /* * if we're in the leaf page, delete the blob */ if (c->is_leaf) (void)blob_free(c->db, key_get_ptr(key), 0); break; default: ham_assert(!"unknown callback event", ("")); break; }}const char *ham_strerror(ham_status_t result){ switch (result) { case HAM_SUCCESS: return ("Success"); case HAM_SHORT_READ: return ("Short read"); case HAM_SHORT_WRITE: return ("Short write"); case HAM_INV_KEYSIZE: return ("Invalid key size"); case HAM_INV_PAGESIZE: return ("Invalid page size"); case HAM_DB_ALREADY_OPEN: return ("Db already open"); case HAM_OUT_OF_MEMORY: return ("Out of memory"); case HAM_INV_INDEX: return ("Invalid index structure"); case HAM_INV_PARAMETER: return ("Invalid parameter"); case HAM_INV_FILE_HEADER: return ("Invalid database file header"); case HAM_INV_FILE_VERSION: return ("Invalid database file version"); case HAM_KEY_NOT_FOUND: return ("Key not found"); case HAM_DUPLICATE_KEY: return ("Duplicate key"); case HAM_INTEGRITY_VIOLATED: return ("Internal integrity violated"); case HAM_INTERNAL_ERROR: return ("Internal error"); case HAM_DB_READ_ONLY: return ("Database opened in read-only mode"); case HAM_BLOB_NOT_FOUND: return ("Data blob not found"); case HAM_PREFIX_REQUEST_FULLKEY: return ("Comparator function needs more data"); case HAM_IO_ERROR: return ("System I/O error"); case HAM_CACHE_FULL: return ("Database cache is full"); case HAM_NOT_IMPLEMENTED: return ("Operation not implemented"); case HAM_FILE_NOT_FOUND: return ("File not found"); case HAM_WOULD_BLOCK: return ("Operation would block"); case HAM_NOT_READY: return ("Object was not initialized correctly"); case HAM_CURSOR_IS_NIL: return ("Cursor points to NIL"); case HAM_ENV_NOT_EMPTY: return ("Not all databases were closed before " "closing the environment"); case HAM_DATABASE_NOT_FOUND: return ("Database not found"); case HAM_DATABASE_ALREADY_EXISTS: return ("Database name already exists"); case HAM_DATABASE_ALREADY_OPEN: return ("Database already open"); case HAM_ENV_FULL: return ("Environment is full"); default: return ("Unknown error"); }}static void__prepare_db(ham_db_t *db){ ham_env_t *env=db_get_env(db); ham_assert(db_get_env(db)!=0, ("")); if (env_get_header_page(env)) page_set_owner(env_get_header_page(env), db); if (env_get_extkey_cache(env)) extkey_cache_set_db(env_get_extkey_cache(env), db); if (env_get_txn(env)) txn_set_db(env_get_txn(env), db);}static ham_status_t __check_create_parameters(ham_bool_t is_env, const char *filename, ham_u32_t *flags, ham_parameter_t *param, ham_size_t *ppagesize, ham_u16_t *pkeysize, ham_size_t *pcachesize, ham_u16_t *pdbname){ ham_u32_t pagesize=0; ham_u16_t keysize=0, dbname=EMPTY_DATABASE_NAME; ham_size_t cachesize=0; ham_bool_t no_mmap=HAM_FALSE; /* * parse parameters */ if (param) { for (; param->name; param++) { switch (param->name) { case HAM_PARAM_CACHESIZE: cachesize=(ham_size_t)param->value; break; case HAM_PARAM_KEYSIZE: if (is_env) /* calling from ham_env_create_ex? */ return (HAM_INV_PARAMETER); else keysize=(ham_u16_t)param->value; break; case HAM_PARAM_PAGESIZE: pagesize=(ham_u32_t)param->value; break; case HAM_PARAM_DBNAME: dbname=(ham_u16_t)param->value; break; default: return (HAM_INV_PARAMETER); } } } if (dbname==EMPTY_DATABASE_NAME) { if (!filename && !((*flags)&HAM_IN_MEMORY_DB)) return (HAM_INV_PARAMETER); } /* * make sure that the pagesize is aligned to 1024k */ if (pagesize) { if (pagesize%1024) return (HAM_INV_PAGESIZE); } /* * in-memory-db? don't allow cache limits! */ if ((*flags)&HAM_IN_MEMORY_DB) { if (((*flags)&HAM_CACHE_STRICT) || cachesize!=0) return (HAM_INV_PARAMETER); } /* * in-memory-db? use the default pagesize of the system */ if ((*flags)&HAM_IN_MEMORY_DB) { if (!pagesize) { pagesize=os_get_pagesize(); if (!pagesize) { pagesize=1024*4; no_mmap=HAM_TRUE; } } } /* * can we use mmap? */#if HAVE_MMAP if (!((*flags)&HAM_DISABLE_MMAP)) { if (pagesize) { if (pagesize%os_get_pagesize()!=0) no_mmap=HAM_TRUE; } else { pagesize=os_get_pagesize(); if (!pagesize) { pagesize=1024*4; no_mmap=HAM_TRUE; } } }#else no_mmap=HAM_TRUE;#endif /* * if we still don't have a pagesize, try to get a good default value */ if (!pagesize) { pagesize=os_get_pagesize(); if (!pagesize) { pagesize=1024*4; no_mmap=HAM_TRUE; } } /* * set the database flags if we can't use mmapped I/O */ if (no_mmap) { (*flags)&=~DB_USE_MMAP; (*flags)|=HAM_DISABLE_MMAP; } /* * make sure that the pagesize is big enough for at least 5 keys */ if (keysize) if (pagesize/keysize<5) return (HAM_INV_KEYSIZE); /* * initialize the database with a good default value; * 32byte is the size of a first level cache line for most modern * processors; adjust the keysize, so the keys are aligned to * 32byte */ if (keysize==0) keysize=32-(sizeof(int_key_t)-1); /* * return the fixed parameters */ *pcachesize=cachesize; *pkeysize =keysize; *ppagesize =pagesize; if (pdbname) *pdbname=dbname; return (0);}voidham_get_version(ham_u32_t *major, ham_u32_t *minor, ham_u32_t *revision){ if (major) *major=HAM_VERSION_MAJ; if (minor) *minor=HAM_VERSION_MIN; if (revision) *revision=HAM_VERSION_REV;}ham_status_tham_env_new(ham_env_t **env){ if (!env) return (HAM_INV_PARAMETER); /* allocate memory for the ham_db_t-structure; * we can't use our allocator because it's not yet created! */ *env=(ham_env_t *)malloc(sizeof(ham_env_t)); if (!(*env)) return (HAM_OUT_OF_MEMORY); /* reset the whole structure */ memset(*env, 0, sizeof(ham_env_t)); return (0);}ham_status_tham_env_delete(ham_env_t *env){ if (!env) return (HAM_INV_PARAMETER); /* * close the device */ if (env_get_allocator(env)) { env_get_allocator(env)->close(env_get_allocator(env)); env_set_allocator(env, 0); } /* * close the allocator */ if (env_get_device(env)) { if (env_get_device(env)->is_open(env_get_device(env))) { (void)env_get_device(env)->flush(env_get_device(env)); (void)env_get_device(env)->close(env_get_device(env)); } (void)env_get_device(env)->destroy(env_get_device(env)); env_set_device(env, 0); } free(env); return (0);}ham_status_tham_env_create(ham_env_t *env, const char *filename, ham_u32_t flags, ham_u32_t mode){ return (ham_env_create_ex(env, filename, flags, mode, 0));}ham_status_tham_env_create_ex(ham_env_t *env, const char *filename, ham_u32_t flags, ham_u32_t mode, ham_parameter_t *param){ ham_status_t st; ham_size_t pagesize; ham_u16_t keysize; ham_size_t cachesize; ham_device_t *device; if (!env) return (HAM_INV_PARAMETER); /* * check (and modify) the parameters */ st=__check_create_parameters(HAM_TRUE, filename, &flags, param, &pagesize, &keysize, &cachesize, 0); if (st) return (st); /* * if we do not yet have an allocator: create a new one */ if (!env_get_allocator(env)) { env_set_allocator(env, ham_default_allocator_new()); if (!env_get_allocator(env)) return (HAM_OUT_OF_MEMORY); } /* * initialize the device */ device=ham_device_new(env_get_allocator(env), flags&HAM_IN_MEMORY_DB); if (!device) return (HAM_OUT_OF_MEMORY); env_set_device(env, device); /* * create the file */ st=device->create(device, filename, flags, mode); if (st) { (void)ham_env_close(env); return (st); } /* * store the parameters */ env_set_rt_flags(env, flags); env_set_pagesize(env, pagesize); env_set_keysize(env, keysize); env_set_cachesize(env, cachesize); return (HAM_SUCCESS);}ham_status_tham_env_create_db(ham_env_t *env, ham_db_t *db, ham_u16_t name, ham_u32_t flags, ham_parameter_t *param){ ham_status_t st; ham_u16_t keysize=env_get_keysize(env); if (!env || !db) return (HAM_INV_PARAMETER); if (!name || name>=EMPTY_DATABASE_NAME) return (HAM_INV_PARAMETER);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -