datastore_db.c

来自「一个C语言写的快速贝叶斯垃圾邮件过滤工具」· C语言 代码 · 共 1,187 行 · 第 1/2 页

C
1,187
字号
	uint32_t pagesize;	uint32_t retryflag = retryflags[idx];	handle = dbh_init(bfp);	if (handle == NULL)	    return NULL;	/* create DB handle */	dbe = dsm->dsm_get_env_dbe(env);	if ((ret = db_create (&dbp, dbe, 0)) != 0) {	    print_error(__FILE__, __LINE__, "(db) db_create, err: %d, %s",			ret, db_strerror(ret));	    goto open_err;	}	handle->dbp = dbp;	handle->dbenv = env;	handle->open_mode = open_mode;	db_file = dsm->dsm_database_name(handle->name);#ifdef	ENABLE_MEMDEBUG		if (eTransaction == T_DISABLED)	    dbp->set_alloc(dbp, md_malloc, md_realloc, md_free);	else	    dbe->set_alloc(dbe, md_malloc, md_realloc, md_free);#endifretry_db_open:	handle->created = false;	ret = DB_OPEN(dbp, bfp, NULL, dbtype, opt_flags | retryflag, DS_MODE);	/* Begin complex change ... */	if (ret != 0) {	    err = (ret != ENOENT) || (opt_flags == DB_RDONLY);	    if (!err) {		if (#if DB_EQUAL(4,1)		 (ret = DB_SET_FLAGS(dbp, DB_CHKSUM_SHA1)) != 0 ||#endif#if DB_AT_LEAST(4,2)		 (ret = DB_SET_FLAGS(dbp, DB_CHKSUM)) != 0 ||#endif		 (ret = DB_OPEN(dbp, bfp, NULL, dbtype, opt_flags | DB_CREATE | DB_EXCL | retryflag, DS_MODE)))		    err = true;		if (!err)		    handle->created = true;	    }	}	if (ret != 0) {	    if (ret == ENOENT && opt_flags != DB_RDONLY)		return NULL;	    else		err = true;	}	/* End complex change ... */	if (err)	{	    if (open_mode != DB_RDONLY && ret == EEXIST && --retries) {		/* sleep for 4 to 100 ms - this is just to give up the CPU		 * to another process and let it create the data base		 * file in peace */		rand_sleep(4 * 1000, 100 * 1000);		goto retry_db_open;	    }	    /* close again and bail out without further tries */	    if (DEBUG_DATABASE(0))		print_error(__FILE__, __LINE__, "DB->open(%s) - actually %s, directory %s, err %s",			    handle->name, db_file, env->directory, db_strerror(ret));	    dbp->close(dbp, 0);	    goto open_err;	}	/* see if the database byte order differs from that of the cpu's */#if DB_AT_LEAST(3,3)	ret = dbp->get_byteswapped (dbp, &is_swapped);#else	ret = 0;	is_swapped = dbp->get_byteswapped (dbp);#endif	handle->is_swapped = is_swapped ? true : false;	if (ret != 0) {	    print_error(__FILE__, __LINE__, "DB->get_byteswapped: %s",		      db_strerror(ret));	    db_close(handle);	    return NULL;		/* handle already freed, ok to return */	}	if (DEBUG_DATABASE(1))	    fprintf(dbgout, "DB->get_byteswapped: %s\n", is_swapped ? "true" : "false");	ret = dbp->fd(dbp, &handle->fd);	if (ret != 0) {	    print_error(__FILE__, __LINE__, "DB->fd: %s",		      db_strerror(ret));	    db_close(handle);	    return NULL;		/* handle already freed, ok to return */	}	if (DEBUG_DATABASE(1))	    fprintf(dbgout, "DB->fd: %d\n", handle->fd);	/* query page size */	pagesize = get_psize(dbp, false);	if (pagesize == 0xffffffff) {	    dbp->close(dbp, 0);	    goto open_err;	}	if (!pagesize)	    pagesize = 16384;	/* check file size limit */	if (open_mode != DS_READ) {	    if (!check_fsize_limit(handle->fd, pagesize)) {		open_mode = DS_READ;	    }	}	/* Begin complex change ... */	e = dsm->dsm_lock(handle, open_mode);	if (e == 0)	    break;	if (e != EAGAIN)	    return NULL;	handle = NULL;	/* End complex change ... */    } /* for idx over retryflags */    return handle; open_err:    handle_free(handle);    if (ret >= 0)	errno = ret;    else	errno = EINVAL;    return NULL;}int db_delete(void *vhandle, const dbv_t *token){    int ret = 0;    dbh_t *handle = vhandle;    DB *dbp = handle->dbp;    DBT db_key;    DBT_init(db_key);    assert(handle->magic == MAGIC_DBH);    assert((eTransaction == T_DISABLED) == (handle->txn == NULL));    db_key.data = token->data;    db_key.size = token->leng;    ret = dbp->del(dbp, handle->txn, &db_key, 0);    if (ret != 0 && ret != DB_NOTFOUND) {	print_error(__FILE__, __LINE__, "DB->del('%.*s'), err: %d, %s",		    CLAMP_INT_MAX(db_key.size),		    (const char *) db_key.data,    		    ret, db_strerror(ret));	exit(EX_ERROR);    }    if (DEBUG_DATABASE(3))	fprintf(dbgout, "DB->del(%.*s)\n", CLAMP_INT_MAX(db_key.size), (const char *) db_key.data);    return ret;		/* 0 if ok */}int db_get_dbvalue(void *vhandle, const dbv_t *token, /*@out@*/ dbv_t *val){    int ret = 0;    int rmw_flag;    DBT db_key;    DBT db_data;    dbh_t *handle = vhandle;    DB *dbp = handle->dbp;    assert(handle);    assert(handle->magic == MAGIC_DBH);    assert((eTransaction == T_DISABLED) == (handle->txn == NULL));    DBT_init(db_key);    DBT_init(db_data);    db_key.data = token->data;    db_key.size = token->leng;    db_data.data = val->data;    db_data.size = val->leng;		/* cur used */    db_data.ulen = val->leng;		/* max size */    db_data.flags = DB_DBT_USERMEM;	/* saves the memcpy */    /* DB_RMW can avoid deadlocks */    rmw_flag = dsm->dsm_get_rmw_flag(handle->open_mode);    ret = dbp->get(dbp, handle->txn, &db_key, &db_data, rmw_flag );    if (DEBUG_DATABASE(3))	fprintf(dbgout, "DB->get(%.*s): %s\n",		CLAMP_INT_MAX(token->leng), (char *) token->data, db_strerror(ret));    val->leng = db_data.size;		/* read count */    switch (ret) {    case 0:	break;    case DB_NOTFOUND:	ret = DS_NOTFOUND;	break;    case DB_LOCK_DEADLOCK:	dsm->dsm_abort(handle);	ret = DS_ABORT_RETRY;	break;    default:	print_error(__FILE__, __LINE__, "(db) DB->get(TXN=%lu,  '%.*s' ), err: %d, %s",		    (unsigned long)handle->txn, CLAMP_INT_MAX(token->leng),		    (char *) token->data, ret, db_strerror(ret));	dsm->dsm_abort(handle);	exit(EX_ERROR);    }    return ret;}int db_set_dbvalue(void *vhandle, const dbv_t *token, const dbv_t *val){    int ret;    DBT db_key;    DBT db_data;    dbh_t *handle = vhandle;    DB *dbp = handle->dbp;    assert(handle->magic == MAGIC_DBH);    assert((eTransaction == T_DISABLED) == (handle->txn == NULL));    DBT_init(db_key);    DBT_init(db_data);    db_key.data = token->data;    db_key.size = token->leng;    db_data.data = val->data;    db_data.size = val->leng;		/* write count */    ret = dbp->put(dbp, handle->txn, &db_key, &db_data, 0);    if (ret == DB_LOCK_DEADLOCK) {	dsm->dsm_abort(handle);	return DS_ABORT_RETRY;    }    if (ret != 0) {	print_error(__FILE__, __LINE__, "db_set_dbvalue( '%.*s' ), err: %d, %s",		    CLAMP_INT_MAX(token->leng), (char *)token->data, ret, db_strerror(ret));	exit(EX_ERROR);    }    if (DEBUG_DATABASE(3))	fprintf(dbgout, "DB->put(%.*s): %s\n",		CLAMP_INT_MAX(token->leng), (char *) token->data, db_strerror(ret));    return 0;}#if DB_AT_LEAST(4,2)/* get_flags is new in 4.2 */static uint32_t db_get_flags(DB *dbp, uint32_t test){    int ret;    uint32_t flags;    uint32_t mask = DB_NOSYNC;    ret = dbp->get_flags(dbp, &flags);    if (ret) {	print_error(__FILE__, __LINE__, "DB->get_flags returned error: %s",		    db_strerror(ret));	mask = 0;    } else {	if (flags & test)	    mask &= ~DB_NOSYNC;    }    return mask;}#endif/* Close files and clean up. */void db_close(void *vhandle){    int ret;    dbh_t *handle = vhandle;    DB *dbp = handle->dbp;    /* This is _ONLY_ safe as long as we're logging TXNs */    uint32_t flag = (eTransaction == T_ENABLED) ? DB_NOSYNC : 0;    assert(handle->magic == MAGIC_DBH);#ifdef	DB_TXN_NOT_DURABLE    /* DB_TXN_NOT_DURABLE is new in 4.2 */    flag &= db_get_flags(dbp, DB_TXN_NOT_DURABLE);#endif#ifdef	DB_LOG_INMEMORY    /* DB_LOG_INMEMORY is new in 4.3 */    flag &= db_get_flags(dbp, DB_LOG_INMEMORY);#endif    if (DEBUG_DATABASE(1))	fprintf(dbgout, "DB->close(%s, %s)\n",		handle->name, flag & DB_NOSYNC ? "DB_NOSYNC" : "0");    if (handle->txn) {	print_error(__FILE__, __LINE__, "db_close called with transaction still open, program fault!");    }    ret = dbp->close(dbp, flag);#if DB_AT_LEAST(3,2) && DB_AT_MOST(4,0)    /* ignore dirty pages in buffer pool */    if (ret == DB_INCOMPLETE)	ret = 0;#endif    if (dsm->dsm_sync != NULL)	ret = dsm->dsm_sync(handle->dbenv->dbe, ret);    if (ret)	print_error(__FILE__, __LINE__, "DB->close error: %s",		db_strerror(ret));    handle->dbp = NULL;    handle_free(handle);}/* flush any data in memory to disk*/void db_flush(void *vhandle){    int ret;    dbh_t *handle = vhandle;    DB *dbp = handle->dbp;    assert(handle->magic == MAGIC_DBH);    if (DEBUG_DATABASE(1))	fprintf(dbgout, "db_flush(%s)\n", handle->name);    ret = dbp->sync(dbp, 0);#if DB_AT_LEAST(3,2) && DB_AT_MOST(4,0)    /* ignore dirty pages in buffer pool */    if (ret == DB_INCOMPLETE)	ret = 0;#endif    ret = dsm->dsm_sync(handle->dbenv->dbe, ret);    if (DEBUG_DATABASE(1))	fprintf(dbgout, "DB->sync(%p): %s\n", (void *)dbp, db_strerror(ret));    if (ret)	print_error(__FILE__, __LINE__, "db_sync: err: %d, %s", ret, db_strerror(ret));    dsm->dsm_log_flush(handle->dbenv->dbe);}ex_t db_foreach(void *vhandle, db_foreach_t hook, void *userdata){    dbh_t *handle = vhandle;    DB *dbp = handle->dbp;    ex_t ret = EX_OK;    bool eflag = false;    DBC dbc;    DBC *dbcp = &dbc;    DBT key, data;    dbv_t dbv_key, dbv_data;    assert(handle->magic == MAGIC_DBH);    assert((eTransaction == T_DISABLED) == (handle->txn == NULL));    memset(&key, 0, sizeof(key));    memset(&data, 0, sizeof(data));    ret = dbp->cursor(dbp, handle->txn, &dbcp, 0);    if (ret) {	print_error(__FILE__, __LINE__, "(cursor): %s", handle->path);	return EX_ERROR;    }    for (ret =  dbcp->c_get(dbcp, &key, &data, DB_FIRST);	 ret == 0;	 ret =  dbcp->c_get(dbcp, &key, &data, DB_NEXT))    {	int rc;	/* Question: Is there a way to avoid using malloc/free? */	/* switch to "dbv_t *" variables */	dbv_key.leng = key.size;	dbv_key.data = xmalloc(dbv_key.leng+1);	memcpy(dbv_key.data, key.data, dbv_key.leng);	((char *)dbv_key.data)[dbv_key.leng] = '\0';	dbv_data.data = data.data;	dbv_data.leng = data.size;	/* call user function */	rc = hook(&dbv_key, &dbv_data, userdata);	xfree(dbv_key.data);	/* returns 0 if ok, 1 if not */	if (rc != 0)	    break;    }    switch (ret) {    case 0:    case DB_NOTFOUND:	/* OK */	ret = EX_OK;	break;    default:	print_error(__FILE__, __LINE__, "(c_get): %s", db_strerror(ret));	eflag = true;	break;    }    if ((ret = dbcp->c_close(dbcp))) {	print_error(__FILE__, __LINE__, "(c_close): %s", db_strerror(ret));	eflag = true;    }    return eflag ? EX_ERROR : ret;}const char *db_str_err(int e) {    return db_strerror(e);}bool is_file_or_missing(const char* path) /*@globals errno,stderr@*/{    int rc;    struct stat sb;    if (path == NULL || *path == '\0')	return false;    rc = stat(path, &sb);    if (rc == 0) {	return S_ISREG(sb.st_mode);    }    if (errno == ENOENT)	return true;    return false;}static u_int32_t db_do_getpsize(DB *db) {    return get_psize(db, true);}static u_int32_t db_dofile(bfpath *bfp, u_int32_t (*func)(DB *)){    DB_ENV *dbe = NULL;    DB *db;    int e;    u_int32_t s;    if (!is_file_or_missing(bfp->filename)) {	print_error(__FILE__, __LINE__, "\"%s\" is not a file.", bfp->filename);	return 0xffffffff;    }    dbe = dsm->dsm_recover_open(bfp);    e = db_create(&db, dbe, 0);    if (e != 0) {	print_error(__FILE__, __LINE__, "error creating DB handle: %s",		db_strerror(e));	exit(EX_ERROR);    }    e = DB_OPEN(db, bfp, NULL, dbtype, DB_RDONLY | DB_NOMMAP, DS_MODE);    if (e != 0) {	print_error(__FILE__, __LINE__, "cannot open database %s: %s",		bfp->filename, db_strerror(e));	exit(EX_ERROR);    }    s = func(db);    e = db->close(db, 0);    if (e != 0) {	print_error(__FILE__, __LINE__, "cannot close database %s: %s",		bfp->filename, db_strerror(e));	exit(EX_ERROR);    }    if (dsm->dsm_common_close)	e = dsm->dsm_common_close(dbe, bfp);    if (e != 0) {	print_error(__FILE__, __LINE__, "cannot close environment %s: %s",		    bfp->dirname, db_strerror(e));	exit(EX_ERROR);    }    return s;}u_int32_t db_pagesize(bfpath *bfp) {    return db_dofile(bfp, db_do_getpsize);}static u_int32_t db_do_leafpages(DB *dbp) {    int ret;    u_int32_t c;    DB_BTREE_STAT *dbstat = NULL;    ret = BF_DB_STAT(dbp, NULL, &dbstat, 0);    if (ret) {	print_error(__FILE__, __LINE__, "DB->stat");	return 0xffffffff;    }    c = dbstat->bt_leaf_pg;    free(dbstat);    return c;}u_int32_t db_leafpages(bfpath *bfp) {    return db_dofile(bfp, db_do_leafpages);}ex_t db_verify(bfpath *bfp){    DB_ENV *dbe = NULL;    DB *db;    int e;    assert(bfp->isfile == is_file_or_missing(bfp->filepath));    if (!bfp->isfile) {	print_error(__FILE__, __LINE__, "\"%s\" is not a file.", bfp->filename);	return EX_ERROR;    }    dbe = dsm->dsm_recover_open(bfp);    e = db_create(&db, NULL, 0); /* need not use environment here,				    DB->verify() does not lock anyways,				    we must hold the global lock instead */    if (e != 0) {	print_error(__FILE__, __LINE__, "error creating DB handle: %s",		db_strerror(e));	exit(EX_ERROR);    }    e = db->verify(db, bfp->filepath, NULL, NULL, 0);    if (e) {	print_error(__FILE__, __LINE__, "database %s does not verify: %s",		bfp->filename, db_strerror(e));	exit(EX_ERROR);    }    if (dsm->dsm_common_close)	e = dsm->dsm_common_close(dbe, bfp);    if (e == 0 && verbose)	printf("%s OK.\n", bfp->filename);    return e;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?