/*
 * Copyright (c) 2003-2005 Sendmail, Inc. and its suppliers.
 *      All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 */

#include "sm/generic.h"
SM_RCSID("@(#)$Id: adblimits.c,v 1.9 2006/03/13 18:41:30 ca Exp $")
#include "sm/types.h"
#include "sm/assert.h"
#include "sm/magic.h"
#include "sm/memops.h"
#include "sm/actdb-int.h"

/*
**  AQ_RAISE_LIMIT -- Raise the limit (max. number of entries in AQ)
**
**	Parameters:
**		aq_ctx -- AQ context
**		limit -- new limit; 0/UINT_MAX: raise it gradually/to the max
**		locktype -- kind of locking
**
**	Returns:
**		usual sm_error code; SM_E_RANGE, (un)lock
**
**	Last code review: 2005-04-16 04:45:56
**	Last code change: 2005-04-20 23:38:56
*/

sm_ret_T
aq_raise_limit(aq_ctx_P aq_ctx, uint limit, thr_lock_T locktype)
{
	int r;
	sm_ret_T ret;

	SM_IS_AQ(aq_ctx);
	ret = SM_SUCCESS;
	if (thr_lock_it(locktype))
	{
		r = pthread_mutex_lock(&aq_ctx->aq_mutex);
		SM_LOCK_OK(r);
		if (r != 0)
			return sm_error_perm(SM_EM_AQ, r);
	}
	if (limit == UINT_MAX)
		aq_ctx->aq_limit = aq_ctx->aq_max_entries;
	else if (limit == 0)
	{
		if (aq_ctx->aq_limit < aq_ctx->aq_max_entries)
		{
			uint d;

			d = aq_ctx->aq_max_entries - aq_ctx->aq_limit;
			if (d < 10)
				aq_ctx->aq_limit = aq_ctx->aq_max_entries;
			else
			{
				aq_ctx->aq_limit += d / 2;
				if (aq_ctx->aq_limit > aq_ctx->aq_max_entries)
					aq_ctx->aq_limit =
							aq_ctx->aq_max_entries;
			}
		}
	}
	else if (limit > aq_ctx->aq_limit && limit <= aq_ctx->aq_max_entries)
		aq_ctx->aq_limit = limit;
	else if (limit > aq_ctx->aq_max_entries)
		ret = sm_error_temp(SM_EM_AQ, SM_E_RANGE);
	if ((!sm_is_err(ret) && thr_unl_no_err(locktype))
	    || (sm_is_err(ret) && thr_unl_if_err(locktype)))
	{
		r = pthread_mutex_unlock(&aq_ctx->aq_mutex);
		SM_ASSERT(r == 0);
		if (r != 0 && sm_is_success(ret))
			ret = sm_error_perm(SM_EM_AQ, r);
	}
	return ret;
}

/*
**  AQ_LOWER_LIMIT -- Lower the limit (max. number of entries in AQ)
**
**	Parameters:
**		aq_ctx -- AQ context
**		limit -- new limit, 0: use lowest possible value
**		locktype -- kind of locking
**
**	Returns:
**		usual sm_error code; SM_E_RANGE, (un)lock
**
**	Last code review: 2005-04-16 04:42:31
**	Last code change:
*/

#define MIN_AQ_ENTRIES	8

sm_ret_T
aq_lower_limit(aq_ctx_P aq_ctx, uint limit, thr_lock_T locktype)
{
	int r;
	sm_ret_T ret;

	SM_IS_AQ(aq_ctx);
	ret = SM_SUCCESS;
	if (thr_lock_it(locktype))
	{
		r = pthread_mutex_lock(&aq_ctx->aq_mutex);
		SM_LOCK_OK(r);
		if (r != 0)
			return sm_error_perm(SM_EM_AQ, r);
	}

	if (limit != 0 && limit < MIN_AQ_ENTRIES)
		ret = sm_error_perm(SM_EM_AQ, SM_E_RANGE);
	else if (limit < aq_ctx->aq_limit)
	{
		if (limit >= aq_ctx->aq_entries)
			aq_ctx->aq_limit = limit;
		else
			aq_ctx->aq_limit = SM_MAX(aq_ctx->aq_entries,
						MIN_AQ_ENTRIES);
	}
	if ((!sm_is_err(ret) && thr_unl_no_err(locktype))
	    || (sm_is_err(ret) && thr_unl_if_err(locktype)))
	{
		r = pthread_mutex_unlock(&aq_ctx->aq_mutex);
		SM_ASSERT(r == 0);
		if (r != 0 && sm_is_success(ret))
			ret = sm_error_perm(SM_EM_AQ, r);
	}
	return ret;
}

/*
**  AQ_GET_LIMITS -- return various limits
**
**	Parameters:
**		aq_ctx -- AQ context
**		pentries -- (pointer to) entries (output)
**		plimit -- (pointer to) limit (output)
**		pmax_entries -- (pointer to) max_entries (output)
**		locktype -- kind of locking
**
**	Returns:
**		usual sm_error code; only (un)lock
**
**	Last code review: 2005-04-16 04:50:02
**	Last code change:
*/

sm_ret_T
aq_get_limits(aq_ctx_P aq_ctx, uint *pentries, uint *plimit, uint *pmax_entries, thr_lock_T locktype)
{
	int r;
	sm_ret_T ret;

	SM_IS_AQ(aq_ctx);
	SM_REQUIRE(pentries != NULL);
	SM_REQUIRE(plimit != NULL);
	SM_REQUIRE(pmax_entries != NULL);
	ret = SM_SUCCESS;
	if (thr_lock_it(locktype))
	{
		r = pthread_mutex_lock(&aq_ctx->aq_mutex);
		SM_LOCK_OK(r);
		if (r != 0)
			return sm_error_perm(SM_EM_AQ, r);
	}

	*pentries =  aq_ctx->aq_entries;
	*plimit = aq_ctx->aq_limit;
	*pmax_entries = aq_ctx->aq_max_entries;

	if ((!sm_is_err(ret) && thr_unl_no_err(locktype))
	    || (sm_is_err(ret) && thr_unl_if_err(locktype)))
	{
		r = pthread_mutex_unlock(&aq_ctx->aq_mutex);
		SM_ASSERT(r == 0);
		if (r != 0 && sm_is_success(ret))
			ret = sm_error_perm(SM_EM_AQ, r);
	}
	return ret;
}


syntax highlighted by Code2HTML, v. 0.9.1