/*
 * 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: aqrdqh.c,v 1.14 2006/11/13 02:10:21 ca Exp $")
#include "sm/types.h"
#include "sm/assert.h"
#include "sm/magic.h"
#include "sm/aqrdq.h"
#include "sm/actdb-int.h"
#include "aqrdq.h"

/* make this dependent on the size of AQ? */
#define AQ_RDQ_FREE_LIMIT	8

/*
**  AQ_RDQ_NEW -- get/allocate new rdq entry
**
**	Parameters:
**		aq_ctx -- AQ context
**		da_idx -- DA index
**		ipv4 -- IPv4 address of server
**		paqrdq_ctx -- (pointer to) AQ RDQ entry (output)
**
**	Returns:
**		usual sm_error code; ENOMEM
**
**	Locking: aq_ctx must be locked by caller.
**
**	Side Effects: none on error
**
**	Last code review: 2005-03-25 00:53:25
**	Last code change: 2006-11-11 18:26:01
*/

sm_ret_T
aq_rdq_new(aq_ctx_P aq_ctx, uint da_idx, ipv4_T ipv4, aqrdq_ctx_P *paqrdq_ctx)
{
	sm_ret_T ret;
	aqrdq_ctx_P aqrdq_ctx;
	bht_entry_P entry;

	SM_REQUIRE(paqrdq_ctx != NULL);
	if (aq_ctx->aq_rdq_free > 0)
	{
		aqrdq_ctx = AQ_RDQS_FIRST(aq_ctx->aq_rdqs_free);
		SM_IS_AQRDQE(aqrdq_ctx);
		AQ_RDQS_REMOVE(aq_ctx->aq_rdqs_free, aqrdq_ctx);
		--aq_ctx->aq_rdq_free;
	}
	else
	{
		aqrdq_ctx = (aqrdq_ctx_P) sm_zalloc(sizeof(*aqrdq_ctx));
		if (aqrdq_ctx == NULL)
			return sm_error_temp(SM_EM_AQ, ENOMEM);
	}

	AQ_RDQ_INIT(aqrdq_ctx->aqrdq_rcpts);
	aqrdq_ctx->aqrdq_da = da_idx;
	aqrdq_ctx->aqrdq_srv_ipv4 = ipv4;
	ret = bht_add(aq_ctx->aq_rdq_ht,
			(void *) &aqrdq_ctx->aqrdq_srv_ipv4,
			sizeof(aqrdq_ctx->aqrdq_srv_ipv4),
			aqrdq_ctx, &entry);
	if (sm_is_err(ret))
		goto error;
	AQ_RDQS_INSERT_TAIL(aq_ctx->aq_rdqs, aqrdq_ctx);
	++aq_ctx->aq_rdq_used;
	if (aq_ctx->aq_rdq_used > aq_ctx->aq_rdq_used_max)
		aq_ctx->aq_rdq_used_max = aq_ctx->aq_rdq_used;
#if AQRDQ_CHECK
	aqrdq_ctx->sm_magic = SM_AQRDQ_MAGIC;
#endif
	*paqrdq_ctx = aqrdq_ctx;
	return SM_SUCCESS;

  error:
	if (aqrdq_ctx != NULL)
		sm_free_size(aqrdq_ctx, sizeof(*aqrdq_ctx));
	return ret;
}

/*
**  AQ_RDQ_FREE -- free rdq entry (may append to "free-list")
**
**	Parameters:
**		aq_ctx -- AQ context
**		aqrdq_ctx -- AQ RDQ entry
**
**	Returns:
**		SM_SUCCESS
**
**	Locking: aq_ctx must be locked by caller.
**
**	Last code review: 2005-04-04 22:37:46
**	Last code change:
*/

sm_ret_T
aq_rdq_free(aq_ctx_P aq_ctx, aqrdq_ctx_P aqrdq_ctx)
{
	if (aqrdq_ctx == NULL)
		return SM_SUCCESS;

	SM_IS_AQ(aq_ctx);
	AQ_RDQS_REMOVE(aq_ctx->aq_rdqs, aqrdq_ctx);
	SM_ASSERT(aq_ctx->aq_rdq_used > 0);
	--aq_ctx->aq_rdq_used;
	if (aq_ctx->aq_rdq_free < AQ_RDQ_FREE_LIMIT)
	{
		++aq_ctx->aq_rdq_free;

		/*
		**  Clean out all data; maybe only a part?
		**  Counters should be down to zero, lists should be empty
		**  (however, the list operation may leave references
		**  to the wrong list in the entries).
		**  What else?
		*/

		sm_memzero(aqrdq_ctx, sizeof(*aqrdq_ctx));

		AQ_RDQS_INSERT_HEAD(aq_ctx->aq_rdqs_free, aqrdq_ctx);
#if AQRDQ_CHECK
		aqrdq_ctx->sm_magic = SM_AQRDQ_MAGIC;
#endif
	}
	else
	{
#if AQRDQ_CHECK
		aqrdq_ctx->sm_magic = SM_MAGIC_NULL;
#endif
		sm_free_size(aqrdq_ctx, sizeof(*aqrdq_ctx));
	}
	return SM_SUCCESS;
}

/*
**  AQ_RDQ_HT_FREE -- free rdq entry (wrapper for bht destroy callback)
**
**	Parameters:
**		value -- AQ RDQ entry
**		key -- unused
**		ctx -- AQ context
**
**	Returns:
**		usual sm_error code
**
**	Locking: aq_ctx must be locked by caller.
**
**	Last code review: 2005-04-04 22:38:24
**	Last code change:
*/

void
aq_rdq_ht_free(void *value, void *key, void *ctx)
{
	(void) aq_rdq_free((aq_ctx_P) ctx, (aqrdq_ctx_P) value);
	return;
}


syntax highlighted by Code2HTML, v. 0.9.1