📄 db_iface.c
字号:
if (handle_check) __env_db_rep_exit(dbenv); return (ret);}/* * __db_c_get_arg -- * Common DBC->get argument checking, used by both DBC->get and DBC->pget. */static int__db_c_get_arg(dbc, key, data, flags) DBC *dbc; DBT *key, *data; u_int32_t flags;{ DB *dbp; DB_ENV *dbenv; int dirty, multi, ret; dbp = dbc->dbp; dbenv = dbp->dbenv; /* * Typically in checking routines that modify the flags, we have * to save them and restore them, because the checking routine * calls the work routine. However, this is a pure-checking * routine which returns to a function that calls the work routine, * so it's OK that we do not save and restore the flags, even though * we modify them. * * Check for read-modify-write validity. DB_RMW doesn't make sense * with CDB cursors since if you're going to write the cursor, you * had to create it with DB_WRITECURSOR. Regardless, we check for * LOCKING_ON and not STD_LOCKING, as we don't want to disallow it. * If this changes, confirm that DB does not itself set the DB_RMW * flag in a path where CDB may have been configured. */ dirty = 0; if (LF_ISSET(DB_DIRTY_READ | DB_RMW)) { if (!LOCKING_ON(dbenv)) return (__db_fnl(dbenv, "DBcursor->get")); if (LF_ISSET(DB_DIRTY_READ)) dirty = 1; LF_CLR(DB_DIRTY_READ | DB_RMW); } multi = 0; if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) { multi = 1; if (LF_ISSET(DB_MULTIPLE) && LF_ISSET(DB_MULTIPLE_KEY)) goto multi_err; LF_CLR(DB_MULTIPLE | DB_MULTIPLE_KEY); } /* Check for invalid function flags. */ switch (flags) { case DB_CONSUME: case DB_CONSUME_WAIT: if (dirty) { __db_err(dbenv, "DB_DIRTY_READ is not supported with DB_CONSUME or DB_CONSUME_WAIT"); return (EINVAL); } if (dbp->type != DB_QUEUE) goto err; break; case DB_CURRENT: case DB_FIRST: case DB_GET_BOTH: case DB_GET_BOTH_RANGE: case DB_NEXT: case DB_NEXT_DUP: case DB_NEXT_NODUP: case DB_SET: case DB_SET_RANGE: break; case DB_LAST: case DB_PREV: case DB_PREV_NODUP: if (multi)multi_err: return (__db_ferr(dbenv, "DBcursor->get", 1)); break; case DB_GET_BOTHC: if (dbp->type == DB_QUEUE) goto err; break; case DB_GET_RECNO: /* * The one situation in which this might be legal with a * non-RECNUM dbp is if dbp is a secondary and its primary is * DB_AM_RECNUM. */ if (!F_ISSET(dbp, DB_AM_RECNUM) && (!F_ISSET(dbp, DB_AM_SECONDARY) || !F_ISSET(dbp->s_primary, DB_AM_RECNUM))) goto err; break; case DB_SET_RECNO: if (!F_ISSET(dbp, DB_AM_RECNUM)) goto err; break; default:err: return (__db_ferr(dbenv, "DBcursor->get", 0)); } /* Check for invalid key/data flags. */ if ((ret = __dbt_ferr(dbp, "key", key, 0)) != 0) return (ret); if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0) return (ret); if (multi) { if (!F_ISSET(data, DB_DBT_USERMEM)) { __db_err(dbenv, "DB_MULTIPLE/DB_MULTIPLE_KEY require DB_DBT_USERMEM be set"); return (EINVAL); } if (F_ISSET(key, DB_DBT_PARTIAL) || F_ISSET(data, DB_DBT_PARTIAL)) { __db_err(dbenv, "DB_MULTIPLE/DB_MULTIPLE_KEY do not support DB_DBT_PARTIAL"); return (EINVAL); } if (data->ulen < 1024 || data->ulen < dbp->pgsize || data->ulen % 1024 != 0) { __db_err(dbenv, "%s%s", "DB_MULTIPLE/DB_MULTIPLE_KEY buffers must be ", "aligned, at least page size and multiples of 1KB"); return (EINVAL); } } /* * The cursor must be initialized for DB_CURRENT, DB_GET_RECNO and * DB_NEXT_DUP. Return EINVAL for an invalid cursor, otherwise 0. */ if (!IS_INITIALIZED(dbc) && (flags == DB_CURRENT || flags == DB_GET_RECNO || flags == DB_NEXT_DUP)) return (__db_curinval(dbenv)); /* Check for consistent transaction usage. */ if (LF_ISSET(DB_RMW) && (ret = __db_check_txn(dbp, dbc->txn, dbc->locker, 0)) != 0) return (ret); return (0);}/* * __db_secondary_close_pp -- * DB->close for secondaries * * PUBLIC: int __db_secondary_close_pp __P((DB *, u_int32_t)); */int__db_secondary_close_pp(dbp, flags) DB *dbp; u_int32_t flags;{ DB_ENV *dbenv; int handle_check, ret, t_ret; dbenv = dbp->dbenv; ret = 0; PANIC_CHECK(dbenv); /* * !!! * The actual argument checking is simple, do it inline. * * Validate arguments and complain if they're wrong, but as a DB * handle destructor, we can't fail. */ if (flags != 0 && flags != DB_NOSYNC && (t_ret = __db_ferr(dbenv, "DB->close", 0)) != 0 && ret == 0) ret = t_ret; /* Check for replication block. */ handle_check = IS_REPLICATED(dbenv, dbp); if (handle_check && (t_ret = __db_rep_enter(dbp, 0, 0, 0)) != 0) { handle_check = 0; if (ret == 0) ret = t_ret; } if ((t_ret = __db_secondary_close(dbp, flags)) != 0 && ret == 0) ret = t_ret; /* Release replication block. */ if (handle_check) __env_db_rep_exit(dbenv); return (ret);}/* * __db_c_pget_pp -- * DBC->c_pget pre/post processing. * * PUBLIC: int __db_c_pget_pp __P((DBC *, DBT *, DBT *, DBT *, u_int32_t)); */int__db_c_pget_pp(dbc, skey, pkey, data, flags) DBC *dbc; DBT *skey, *pkey, *data; u_int32_t flags;{ DB *dbp; DB_ENV *dbenv; int handle_check, ret; dbp = dbc->dbp; dbenv = dbp->dbenv; PANIC_CHECK(dbenv); if ((ret = __db_c_pget_arg(dbc, pkey, flags)) != 0) return (ret); if ((ret = __db_c_get_arg(dbc, skey, data, flags)) != 0) return (ret); /* Check for replication block. */ handle_check = IS_REPLICATED(dbenv, dbp); if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, dbc->txn != NULL)) != 0) return (ret); ret = __db_c_pget(dbc, skey, pkey, data, flags); /* Release replication block. */ if (handle_check) __env_db_rep_exit(dbenv); return (ret);}/* * __db_c_pget_arg -- * Check DBC->pget arguments. */static int__db_c_pget_arg(dbc, pkey, flags) DBC *dbc; DBT *pkey; u_int32_t flags;{ DB *dbp; DB_ENV *dbenv; int ret; dbp = dbc->dbp; dbenv = dbp->dbenv; if (!F_ISSET(dbp, DB_AM_SECONDARY)) { __db_err(dbenv, "DBcursor->pget may only be used on secondary indices"); return (EINVAL); } if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) { __db_err(dbenv, "DB_MULTIPLE and DB_MULTIPLE_KEY may not be used on secondary indices"); return (EINVAL); } switch (LF_ISSET(~DB_RMW)) { case DB_CONSUME: case DB_CONSUME_WAIT: /* These flags make no sense on a secondary index. */ return (__db_ferr(dbenv, "DBcursor->pget", 0)); case DB_GET_BOTH: /* DB_GET_BOTH is "get both the primary and the secondary". */ if (pkey == NULL) { __db_err(dbenv, "DB_GET_BOTH requires both a secondary and a primary key"); return (EINVAL); } break; default: /* __db_c_get_arg will catch the rest. */ break; } /* * We allow the pkey field to be NULL, so that we can make the * two-DBT get calls into wrappers for the three-DBT ones. */ if (pkey != NULL && (ret = __dbt_ferr(dbp, "primary key", pkey, 0)) != 0) return (ret); /* But the pkey field can't be NULL if we're doing a DB_GET_BOTH. */ if (pkey == NULL && (flags & DB_OPFLAGS_MASK) == DB_GET_BOTH) { __db_err(dbenv, "DB_GET_BOTH on a secondary index requires a primary key"); return (EINVAL); } return (0);}/* * __db_c_put_pp -- * DBC->put pre/post processing. * * PUBLIC: int __db_c_put_pp __P((DBC *, DBT *, DBT *, u_int32_t)); */int__db_c_put_pp(dbc, key, data, flags) DBC *dbc; DBT *key, *data; u_int32_t flags;{ DB *dbp; DB_ENV *dbenv; int handle_check, ret; dbp = dbc->dbp; dbenv = dbp->dbenv; PANIC_CHECK(dbenv); if ((ret = __db_c_put_arg(dbc, key, data, flags)) != 0) return (ret); /* Check for consistent transaction usage. */ if ((ret = __db_check_txn(dbp, dbc->txn, dbc->locker, 0)) != 0) return (ret); /* Check for replication block. */ handle_check = IS_REPLICATED(dbenv, dbp); if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, dbc->txn != NULL)) != 0) return (ret); DEBUG_LWRITE(dbc, dbc->txn, "DBcursor->put", flags == DB_KEYFIRST || flags == DB_KEYLAST || flags == DB_NODUPDATA || flags == DB_UPDATE_SECONDARY ? key : NULL, data, flags); ret =__db_c_put(dbc, key, data, flags); /* Release replication block. */ if (handle_check) __env_db_rep_exit(dbenv); return (ret);}/* * __db_c_put_arg -- * Check DBC->put arguments. */static int__db_c_put_arg(dbc, key, data, flags) DBC *dbc; DBT *key, *data; u_int32_t flags;{ DB *dbp; DB_ENV *dbenv; int key_flags, ret; dbp = dbc->dbp; dbenv = dbp->dbenv; key_flags = 0; /* Check for changes to a read-only tree. */ if (IS_READONLY(dbp)) return (__db_rdonly(dbenv, "c_put")); /* Check for puts on a secondary. */ if (F_ISSET(dbp, DB_AM_SECONDARY)) { if (flags == DB_UPDATE_SECONDARY) flags = DB_KEYLAST; else { __db_err(dbenv, "DBcursor->put forbidden on secondary indices"); return (EINVAL); } } /* Check for invalid function flags. */ switch (flags) { case DB_AFTER: case DB_BEFORE: switch (dbp->type) { case DB_BTREE: case DB_HASH: /* Only with unsorted duplicates. */ if (!F_ISSET(dbp, DB_AM_DUP)) goto err; if (dbp->dup_compare != NULL) goto err; break; case DB_QUEUE: /* Not permitted. */ goto err; case DB_RECNO: /* Only with mutable record numbers. */ if (!F_ISSET(dbp, DB_AM_RENUMBER)) goto err; key_flags = 1; break; case DB_UNKNOWN: default: goto err; } break; case DB_CURRENT: /* * If there is a comparison function, doing a DB_CURRENT * must not change the part of the data item that is used * for the comparison. */ break; case DB_NODUPDATA: if (!F_ISSET(dbp, DB_AM_DUPSORT)) goto err; /* FALLTHROUGH */ case DB_KEYFIRST: case DB_KEYLAST: key_flags = 1; break; default:err: return (__db_ferr(dbenv, "DBcursor->put", 0)); } /* Check for invalid key/data flags. */ if (key_flags && (ret = __dbt_ferr(dbp, "key", key, 0)) != 0) return (ret); if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0) return (ret); /* Keys shouldn't have partial flags during a put. */ if (F_ISSET(key, DB_DBT_PARTIAL)) return (__db_ferr(dbenv, "key DBT", 0)); /* * The cursor must be initialized for anything other than DB_KEYFIRST * and DB_KEYLAST, return EINVAL for an invalid cursor, otherwise 0. */ if (!IS_INITIALIZED(dbc) && flags != DB_KEYFIRST && flags != DB_KEYLAST && flags != DB_NODUPDATA) return (__db_curinval(dbenv)); return (0);}/* * __dbt_ferr -- * Check a DBT for flag errors. */static int__dbt_ferr(dbp, name, dbt, check_thread) const DB *dbp; const char *name; const DBT *dbt; int check_thread;{ DB_ENV *dbenv; int ret; dbenv = dbp->dbenv; /* * Check for invalid DBT flags. We allow any of the flags to be * specified to any DB or DBcursor call so that applications can * set DB_DBT_MALLOC when retrieving a data item from a secondary * database and then specify that same DBT as a key to a primary * database, without having to clear flags. */ if ((ret = __db_fchk(dbenv, name, dbt->flags, DB_DBT_APPMALLOC | DB_DBT_MALLOC | DB_DBT_DUPOK | DB_DBT_REALLOC | DB_DBT_USERMEM | DB_DBT_PARTIAL)) != 0) return (ret); switch (F_ISSET(dbt, DB_DBT_MALLOC | DB_DBT_REALLOC | DB_DBT_USERMEM)) { case 0: case DB_DBT_MALLOC: case DB_DBT_REALLOC: case DB_DBT_USERMEM: break; default: return (__db_ferr(dbenv, name, 1)); } if (check_thread && DB_IS_THREADED(dbp) && !F_ISSET(dbt, DB_DBT_MALLOC | DB_DBT_REALLOC | DB_DBT_USERMEM)) { __db_err(dbenv, "DB_THREAD mandates memory allocation flag on DBT %s", name); return (EINVAL); } return (0);}/* * __db_rdonly -- * Common readonly message. */static int__db_rdonly(dbenv, name) const DB_ENV *dbenv; const char *name;{ __db_err(dbenv, "%s: attempt to modify a read-only tree", name); return (EACCES);}/* * __db_curinval * Report that a cursor is in an invalid state. */static int__db_curinval(dbenv) const DB_ENV *dbenv;{ __db_err(dbenv, "Cursor position must be set before performing this operation"); return (EINVAL);}/* * __db_txn_auto_init -- * Handle DB_AUTO_COMMIT initialization. * * PUBLIC: int __db_txn_auto_init __P((DB_ENV *, DB_TXN **)); */int__db_txn_auto_init(dbenv, txnidp) DB_ENV *dbenv; DB_TXN **txnidp;{ if (*txnidp != NULL) { __db_err(dbenv, "DB_AUTO_COMMIT may not be specified along with a transaction handle"); return (EINVAL); } if (!TXN_ON(dbenv)) { __db_err(dbenv, "DB_AUTO_COMMIT may not be specified in non-transactional environment"); return (EINVAL); } /* * We're creating a transaction for the user, and we want it to block * if replication recovery is running. Call the user-level API. */ return (dbenv->txn_begin(dbenv, NULL, txnidp, 0));}/* * __db_txn_auto_resolve -- * Handle DB_AUTO_COMMIT resolution. * * PUBLIC: int __db_txn_auto_resolve __P((DB_ENV *, DB_TXN *, int, int)); */int__db_txn_auto_resolve(dbenv, txn, nosync, ret) DB_ENV *dbenv; DB_TXN *txn; int nosync, ret;{ int t_ret; /* * We're resolving a transaction for the user, and must decrement the * replication handle count. Call the user-level API. */ if (ret == 0) return (txn->commit(txn, nosync ? DB_TXN_NOSYNC : 0)); if ((t_ret = txn->abort(txn)) != 0) return (__db_panic(dbenv, t_ret)); return (ret);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -