⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sequence.c

📁 这是国外的resip协议栈
💻 C
字号:
/*- * See the file LICENSE for redistribution information. * * Copyright (c) 2004 *	Sleepycat Software.  All rights reserved. * * $Id: sequence.c,v 1.26 2004/10/25 17:59:28 bostic Exp $ */#include "db_config.h"#ifndef NO_SYSTEM_INCLUDES#include <sys/types.h>#include <stdlib.h>#include <string.h>#endif#include "db_int.h"#include "dbinc/db_shash.h"#include "dbinc/db_page.h"#include "dbinc/db_am.h"#include "dbinc/mp.h"#include "dbinc_auto/sequence_ext.h"#ifdef HAVE_SEQUENCE#define	SEQ_ILLEGAL_AFTER_OPEN(seq, name)				\	if (seq->seq_key.data != NULL)					\		return (__db_mi_open((seq)->seq_dbp->dbenv, name, 1));#define	SEQ_ILLEGAL_BEFORE_OPEN(seq, name)				\	if (seq->seq_key.data == NULL)					\		return (__db_mi_open((seq)->seq_dbp->dbenv, name, 0));static int __seq_close __P((DB_SEQUENCE *, u_int32_t));static int __seq_get __P((DB_SEQUENCE *,			    DB_TXN *, int32_t,  db_seq_t *, u_int32_t));static int __seq_get_cachesize __P((DB_SEQUENCE *, int32_t *));static int __seq_get_flags __P((DB_SEQUENCE *, u_int32_t *));static int __seq_get_key __P((DB_SEQUENCE *, DBT *));static int __seq_get_range __P((DB_SEQUENCE *, db_seq_t *, db_seq_t *));static int __seq_set_range __P((DB_SEQUENCE *, db_seq_t, db_seq_t));static int __seq_get_db __P((DB_SEQUENCE *, DB **));static int __seq_initial_value __P((DB_SEQUENCE *, db_seq_t));static int __seq_open __P((DB_SEQUENCE *, DB_TXN *, DBT *, u_int32_t));static int __seq_remove __P((DB_SEQUENCE *, DB_TXN *, u_int32_t));static int __seq_set_cachesize __P((DB_SEQUENCE *, int32_t));static int __seq_set_flags __P((DB_SEQUENCE *, u_int32_t));static int __seq_update __P((DB_SEQUENCE *, DB_TXN *, int32_t, u_int32_t));/* * db_sequence_create -- *	DB_SEQUENCE constructor. * * EXTERN: int db_sequence_create __P((DB_SEQUENCE **, DB *, u_int32_t)); */intdb_sequence_create(seqp, dbp, flags)	DB_SEQUENCE **seqp;	DB *dbp;	u_int32_t flags;{	DB_ENV *dbenv;	DB_SEQUENCE *seq;	int ret;	dbenv = dbp->dbenv;	/* Check for invalid function flags. */	switch (flags) {	case 0:		break;	default:		return (__db_ferr(dbenv, "db_sequence_create", 0));	}	DB_ILLEGAL_BEFORE_OPEN(dbp, "db_sequence_create");	/* Allocate the sequence. */	if ((ret = __os_calloc(dbenv, 1, sizeof(*seq), &seq)) != 0)		return (ret);	seq->seq_dbp = dbp;	seq->close = __seq_close;	seq->get = __seq_get;	seq->get_cachesize = __seq_get_cachesize;	seq->set_cachesize = __seq_set_cachesize;	seq->get_db = __seq_get_db;	seq->get_flags = __seq_get_flags;	seq->get_key = __seq_get_key;	seq->get_range = __seq_get_range;	seq->initial_value = __seq_initial_value;	seq->open = __seq_open;	seq->remove = __seq_remove;	seq->set_flags = __seq_set_flags;	seq->set_range = __seq_set_range;	seq->stat = __seq_stat;	seq->stat_print = __seq_stat_print;	seq->seq_rp = &seq->seq_record;	*seqp = seq;	return (0);}/* * __seq_open -- *	DB_SEQUENCE->open method. * */static int__seq_open(seq, txn, keyp, flags)	DB_SEQUENCE *seq;	DB_TXN *txn;	DBT *keyp;	u_int32_t flags;{	DB *dbp;	DB_ENV *dbenv;	DB_MPOOL *dbmp;	DB_SEQ_RECORD *rp;	u_int32_t tflags;	int ret;#define	SEQ_OPEN_FLAGS (DB_AUTO_COMMIT | DB_CREATE | DB_EXCL | DB_THREAD)	dbp = seq->seq_dbp;	dbenv = dbp->dbenv;	SEQ_ILLEGAL_AFTER_OPEN(seq, "DB_SEQUENCE->open");	if (keyp->size == 0) {		__db_err(dbenv, "Zero length sequence key specified");		return (EINVAL);	}	if (LF_ISSET(~SEQ_OPEN_FLAGS))		return (__db_ferr(dbenv, "DB_SEQUENCE->open", 0));	if ((ret = dbp->get_flags(dbp, &tflags)) != 0)		return (ret);	if (FLD_ISSET(tflags, DB_DUP)) {		__db_err(dbenv,	"Sequences not supported in databases configured for duplicate data");		return (EINVAL);	}	if (LF_ISSET(DB_THREAD)) {		dbmp = dbenv->mp_handle;		if ((ret = __db_mutex_setup(dbenv, dbmp->reginfo,		     &seq->seq_mutexp, MUTEX_ALLOC | MUTEX_THREAD)) != 0)			return (ret);	}	memset(&seq->seq_data, 0, sizeof(DBT));	seq->seq_data.data = &seq->seq_record;	seq->seq_data.size = seq->seq_data.ulen = sizeof(seq->seq_record);	seq->seq_data.flags = DB_DBT_USERMEM;	memset(&seq->seq_key, 0, sizeof(DBT));	if ((ret = __os_malloc(dbenv, keyp->size, &seq->seq_key.data)) != 0)		return (ret);	memcpy(seq->seq_key.data, keyp->data, keyp->size);	seq->seq_key.size = seq->seq_key.ulen = keyp->size;	seq->seq_key.flags = DB_DBT_USERMEM;	seq->seq_rp = rp = &seq->seq_record;retry:	if ((ret = dbp->get(dbp, txn, &seq->seq_key, &seq->seq_data, 0)) != 0) {		if (ret == DB_BUFFER_SMALL &&		    seq->seq_data.size > sizeof(seq->seq_record)) {			if ((ret = __os_malloc(dbenv,			    seq->seq_data.size, &seq->seq_data.data)) != 0)				goto err;			seq->seq_data.ulen = seq->seq_data.size;			rp = seq->seq_rp = seq->seq_data.data;			goto retry;		}		if ((ret != DB_NOTFOUND && ret != DB_KEYEMPTY) ||		    !LF_ISSET(DB_CREATE))			goto err;		ret = 0;		tflags = DB_NOOVERWRITE;		tflags |= LF_ISSET(DB_AUTO_COMMIT);		if (!F_ISSET(rp, DB_SEQ_RANGE_SET)) {			rp->seq_max = INT64_MAX;			rp->seq_min = INT64_MIN;		}		/* INC is the default. */		if (!F_ISSET(rp, DB_SEQ_DEC))			F_SET(rp, DB_SEQ_INC);		rp->seq_version = DB_SEQUENCE_VERSION;		if (rp->seq_value > rp->seq_max ||		    rp->seq_value < rp->seq_min) {			__db_err(dbenv, "Sequence value out of range");			ret = EINVAL;			goto err;		} else if ((ret = dbp->put(dbp, txn,		    &seq->seq_key, &seq->seq_data, tflags)) != 0) {			__db_err(dbenv, "Sequence create failed");			goto err;		}	} else if (LF_ISSET(DB_CREATE) && LF_ISSET(DB_EXCL)) {		ret = EEXIST;		goto err;	} else if (seq->seq_data.size < sizeof(seq->seq_record)) {		__db_err(dbenv, "Bad sequence record format");		ret = EINVAL;		goto err;	}	seq->seq_last_value = rp->seq_value;	if (F_ISSET(rp, DB_SEQ_INC))		seq->seq_last_value--;	else		seq->seq_last_value++;err:	if (ret != 0) {		__os_free(dbenv, seq->seq_key.data);		seq->seq_key.data = NULL;	}	return (ret);}/* * __seq_get_cachesize -- *	Accessor for value passed into DB_SEQUENCE->set_cachesize call. * */static int__seq_get_cachesize(seq, cachesize)	DB_SEQUENCE *seq;	int32_t *cachesize;{	SEQ_ILLEGAL_BEFORE_OPEN(seq, "DB_SEQUENCE->get_cachesize");	*cachesize = seq->seq_cache_size;	return (0);}/* * __seq_set_cachesize -- *	DB_SEQUENCE->set_cachesize. * */static int__seq_set_cachesize(seq, cachesize)	DB_SEQUENCE *seq;	int32_t cachesize;{	if (cachesize < 0) {		__db_err(seq->seq_dbp->dbenv,		     "Illegal cache size: %d", cachesize);		return (EINVAL);	}	seq->seq_cache_size = cachesize;	return (0);}#define	SEQ_SET_FLAGS	(DB_SEQ_WRAP | DB_SEQ_INC | DB_SEQ_DEC)/* * __seq_get_flags -- *	Accessor for flags passed into DB_SEQUENCE->open call * */static int__seq_get_flags(seq, flagsp)	DB_SEQUENCE *seq;	u_int32_t *flagsp;{	SEQ_ILLEGAL_BEFORE_OPEN(seq, "DB_SEQUENCE->get_flags");	*flagsp = F_ISSET(seq->seq_rp, SEQ_SET_FLAGS);	return (0);}/* * __seq_set_flags -- *	DB_SEQUENCE->set_flags. * */static int__seq_set_flags(seq, flags)	DB_SEQUENCE *seq;	u_int32_t flags;{	DB_ENV *dbenv;	DB_SEQ_RECORD *rp;	int ret;	dbenv = seq->seq_dbp->dbenv;	rp = seq->seq_rp;	SEQ_ILLEGAL_AFTER_OPEN(seq, "DB_SEQUENCE->set_flags");	if (LF_ISSET(~SEQ_SET_FLAGS))		return (__db_ferr(dbenv, "DB_SEQUENCE->set_flags", 0));	if ((ret = __db_fcchk(dbenv,	     "DB_SEQUENCE->set_flags", flags, DB_SEQ_DEC, DB_SEQ_INC)) != 0)		return (ret);	if (LF_ISSET(DB_SEQ_DEC | DB_SEQ_INC))		F_CLR(rp, DB_SEQ_DEC | DB_SEQ_INC);	F_SET(rp, flags);	return (0);}/* * __seq_initial_value -- *	DB_SEQUENCE->init_value. * */static int__seq_initial_value(seq, value)	DB_SEQUENCE *seq;	db_seq_t value;{	DB_ENV *dbenv;	DB_SEQ_RECORD *rp;	dbenv = seq->seq_dbp->dbenv;	SEQ_ILLEGAL_AFTER_OPEN(seq, "DB_SEQUENCE->init_value");	rp = seq->seq_rp;	if (F_ISSET(rp, DB_SEQ_RANGE_SET) &&	     (value > rp->seq_max || value < rp->seq_min)) {		__db_err(dbenv, "Sequence value out of range");		return (EINVAL);	}	rp->seq_value = value;	return (0);}/* * __seq_get_range -- *	Accessor for range passed into DB_SEQUENCE->set_range call * */static int__seq_get_range(seq, minp, maxp)	DB_SEQUENCE *seq;	db_seq_t *minp, *maxp;{	SEQ_ILLEGAL_BEFORE_OPEN(seq, "DB_SEQUENCE->get_range");	F_SET(seq->seq_rp, DB_SEQ_RANGE_SET);	*minp = seq->seq_record.seq_min;	*maxp = seq->seq_record.seq_max;	return (0);}/* * __seq_set_range -- *	SEQUENCE->set_range. * */static int__seq_set_range(seq, min, max)	DB_SEQUENCE *seq;	db_seq_t min, max;{	DB_ENV *dbenv;	dbenv = seq->seq_dbp->dbenv;	SEQ_ILLEGAL_AFTER_OPEN(seq, "DB_SEQUENCE->set_range");	if (min >= max) {		__db_err(dbenv, "Illegal sequence range");		return (EINVAL);	}	seq->seq_record.seq_min = min;	seq->seq_record.seq_max = max;	F_SET(seq->seq_rp, DB_SEQ_RANGE_SET);	return (0);}static int__seq_update(seq, txn, delta, flags)	DB_SEQUENCE *seq;	DB_TXN *txn;	int32_t delta;	u_int32_t flags;{	DB *dbp;	DB_ENV *dbenv;	DB_SEQ_RECORD *rp;	int32_t adjust;	int ret;	dbp = seq->seq_dbp;	dbenv = dbp->dbenv;	rp = seq->seq_rp;	if (LF_ISSET(DB_AUTO_COMMIT) &&	    (ret = __db_txn_auto_init(dbenv, &txn)) != 0)		return (ret);retry:	if ((ret = dbp->get(dbp, txn, &seq->seq_key, &seq->seq_data, 0)) != 0) {		if (ret == DB_BUFFER_SMALL &&		    seq->seq_data.size > sizeof(seq->seq_record)) {			if ((ret = __os_malloc(dbenv,			    seq->seq_data.size, &seq->seq_data.data)) != 0)				goto err;			seq->seq_data.ulen = seq->seq_data.size;			rp = seq->seq_rp = seq->seq_data.data;			goto retry;		}		goto err;	}	if (seq->seq_data.size < sizeof(seq->seq_record)) {		__db_err(dbenv, "Bad sequence record format");		ret = EINVAL;		goto err;	}	adjust = delta > seq->seq_cache_size ? delta : seq->seq_cache_size;	/*	 * Check whether this operation will cause the sequence to wrap.	 *	 * The sequence minimum and maximum values can be INT64_MIN and	 * INT64_MAX, so we need to do the test carefully to cope with	 * arithmetic overflow.  That means we need to check whether the value	 * is in a range, we can't get away with a single comparison.	 *	 * For example, if seq_value == -1 and seq_max == INT64_MAX, the first	 * test below will be true, since -1 - (INT64_MAX + 1) == INT64_MAX.	 * The second part of the test makes sure that seq_value is close	 * enough to the maximum to really cause wrapping.	 */	if (F_ISSET(rp, DB_SEQ_INC)) {		if (rp->seq_value - ((rp->seq_max - adjust) + 2) >= 0 &&		    (rp->seq_max + 1) - rp->seq_value >= 0) {			if (F_ISSET(rp, DB_SEQ_WRAP))				rp->seq_value = rp->seq_min;			else {overflow:			__db_err(dbenv, "Sequence overflow");				ret = EINVAL;				goto err;			}		}	} else {		if (rp->seq_value - (rp->seq_min - 1) >= 0 &&		    (rp->seq_min + adjust - 2) - rp->seq_value >= 0) {			if (F_ISSET(rp, DB_SEQ_WRAP))				rp->seq_value = rp->seq_max;			else				goto overflow;		}		adjust = -adjust;	}	rp->seq_value += adjust;	ret = dbp->put(dbp, txn, &seq->seq_key, &seq->seq_data, 0);	rp->seq_value -= adjust;	if (ret != 0) {		__db_err(dbenv, "Sequence update failed");		goto err;	}	seq->seq_last_value = rp->seq_value + adjust;	if (F_ISSET(rp, DB_SEQ_INC))		seq->seq_last_value--;	else		seq->seq_last_value++;err:	if (LF_ISSET(DB_AUTO_COMMIT))		ret = __db_txn_auto_resolve(dbenv,		    txn, LF_ISSET(DB_TXN_NOSYNC), ret);	return (ret);}static int__seq_get(seq, txn, delta, retp, flags)	DB_SEQUENCE *seq;	DB_TXN *txn;	int32_t delta;	db_seq_t *retp;	u_int32_t flags;{	DB *dbp;	DB_ENV *dbenv;	DB_SEQ_RECORD *rp;	int ret;	dbp = seq->seq_dbp;	dbenv = dbp->dbenv;	rp = seq->seq_rp;	ret = 0;	SEQ_ILLEGAL_BEFORE_OPEN(seq, "DB_SEQUENCE->get");	if (delta <= 0) {		__db_err(dbenv, "Sequence delta must be greater than 0");		return (EINVAL);	}	MUTEX_THREAD_LOCK(dbenv, seq->seq_mutexp);	if (rp->seq_min + delta > rp->seq_max) {		__db_err(dbenv, "Sequence overflow");		ret = EINVAL;		goto err;	}	if (F_ISSET(rp, DB_SEQ_INC)) {		if (seq->seq_last_value + 1 - rp->seq_value < delta &&		   (ret = __seq_update(seq, txn, delta, flags)) != 0)			goto err;		/* _update may change seq->seq_rp. */		rp = seq->seq_rp;		*retp = rp->seq_value;		rp->seq_value += delta;	} else {		if ((rp->seq_value - seq->seq_last_value) + 1 < delta &&		    (ret = __seq_update(seq, txn, delta, flags)) != 0)			goto err;		rp = seq->seq_rp;		*retp = rp->seq_value;		rp->seq_value -= delta;	}err:	MUTEX_THREAD_UNLOCK(dbenv, seq->seq_mutexp);	return (ret);}/* * __seq_get_db -- *	Accessor for dbp passed into DB_SEQUENCE->open call * */static int__seq_get_db(seq, dbpp)	DB_SEQUENCE *seq;	DB **dbpp;{	SEQ_ILLEGAL_BEFORE_OPEN(seq, "DB_SEQUENCE->get_db");	*dbpp = seq->seq_dbp;	return (0);}/* * __seq_get_key -- *	Accessor for key passed into DB_SEQUENCE->open call * */static int__seq_get_key(seq, key)	DB_SEQUENCE *seq;	DBT *key;{	SEQ_ILLEGAL_BEFORE_OPEN(seq, "DB_SEQUENCE->get_key");	key->data = seq->seq_key.data;	key->size = key->ulen = seq->seq_key.size;	key->flags = seq->seq_key.flags;	return (0);}/* * __seq_close -- *	Close a sequence * */static int__seq_close(seq, flags)	DB_SEQUENCE *seq;	u_int32_t flags;{	DB_ENV *dbenv;	DB_MPOOL *dbmp;	int ret;	ret = 0;	dbenv = seq->seq_dbp->dbenv;	if (flags != 0)		ret = __db_ferr(dbenv, "DB_SEQUENCE->close", 0);	if (seq->seq_mutexp != NULL) {		dbmp = dbenv->mp_handle;		__db_mutex_free(dbenv, dbmp->reginfo, seq->seq_mutexp);	}	if (seq->seq_key.data != NULL)		__os_free(dbenv, seq->seq_key.data);	if (seq->seq_data.data != &seq->seq_record)		__os_free(dbenv, seq->seq_data.data);	seq->seq_key.data = NULL;	memset(seq, CLEAR_BYTE, sizeof(*seq));	__os_free(dbenv, seq);	return (ret);}/* * __seq_remove -- *	Remove a sequence from the database. */static int__seq_remove(seq, txn, flags)	DB_SEQUENCE *seq;	DB_TXN *txn;	u_int32_t flags;{	DB *dbp;	DB_ENV *dbenv;	int ret, t_ret;	dbp = seq->seq_dbp;	dbenv = dbp->dbenv;	SEQ_ILLEGAL_BEFORE_OPEN(seq, "DB_SEQUENCE->remove");	if (LF_ISSET(DB_AUTO_COMMIT) &&	    (ret = __db_txn_auto_init(dbenv, &txn)) != 0)		goto err;	ret = dbp->del(dbp, txn, &seq->seq_key, 0);	if (LF_ISSET(DB_AUTO_COMMIT))		ret = __db_txn_auto_resolve(dbenv,		    txn, LF_ISSET(DB_TXN_NOSYNC), ret);err: if ((t_ret = __seq_close(seq, 0)) != 0 && ret == 0)		ret = t_ret;	return (ret);}#else /* !HAVE_SEQUENCE */intdb_sequence_create(seqp, dbp, flags)	DB_SEQUENCE **seqp;	DB *dbp;	u_int32_t flags;{	COMPQUIET(seqp, NULL);	COMPQUIET(flags, 0);	__db_err(dbp->dbenv,	    "library build did not include support for sequences");	return (DB_OPNOTSUP);}#endif /* HAVE_SEQUENCE */

⌨️ 快捷键说明

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