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 + -
显示快捷键?