/*
 * Copyright (c) 2003-2005 Sendmail, Inc. and its suppliers.
 *      All rights reserved.
 * Copyright (c) 2006 Claus Assmann
 *
 * 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.
 *
 *	$Id: aqrdq.h,v 1.19 2006/11/13 02:10:17 ca Exp $
 */

#ifndef SM_AQRDQ_H
#define SM_AQRDQ_H 1

#include "sm/generic.h"
#include "sm/magic.h"
#include "sm/types.h"
#include "sm/time.h"
#include "sm/pthread.h"
#include "sm/net.h"
#include "sm/bhtable.h"
#include "sm/ringhd.h"
#include "sm/queue.h"
#include "sm/actdb.h"
#include "sm/aqrdqstr.h"
#include "sm/log.h"

#ifndef AQRDQ_CHECK
# define AQRDQ_CHECK	1
#endif

/*
**  Active Queue Recipient Destination Queue
**  These entries are accessed via a hash table from AQ (aq_ctx->aq_rdq_ht).
**  They store information about (rcpt) entries in AQ that are
**  being sent/destined to the same destination (only IPv4 address currently).
**
**  XXX Note: DA idx is NOT used. It must be part of the key for lookups!
*/

struct aqrdq_ctx_S
{
#if AQRDQ_CHECK
	sm_magic_T	 sm_magic;
#endif
/*
	this probably needs individual locking!
	pthread_mutex_t	 aqrdq_mutex;
*/
	uint		 aqrdq_da;	/* DA index */
	ipv4_T		 aqrdq_srv_ipv4;	/* XXX HACK! */

	uint32_t	 aqrdq_flags;

	uint		 aqrdq_entries;
#if 0
//	uint		 aqrdq_entries_max;
#endif
	aq_rcpts_T	 aqrdq_rcpts;

	/*
	**  This is used to
	**  - keep a "cache" of aqrdq_ctx_P, compare
	**  occ_entry_P and libdadb/occh.c: occ_entry_new/free
	**  XXX not yet implemented.
	**  - link "used" entries together, then the scheduler
	**  can "walk" through the list.
	**  Use a double-linked list go get fancier operations, e.g.,
	**  "rotate" the queue, so the head points to the "next" ctx
	**  that should be scheduled (rotation would introduce some kind
	**  of fairness).
	*/

	TAILQ_ENTRY(aqrdq_ctx_S)	 aqrdq_link;
};

/* AQRDQ ctx flags */
#define AQRDQ_FL_NONE		0x0000	/* guess */
#define AQRDQ_FL_USED		0x0001	/* in use */
#define AQRDQ_FL_OCEXC		0x0002	/* number of open sessions exceeded */
/* not checked anywhere (yet) */

/* TA is waiting, inform scheduler when a transaction is done */
/* #define AQRDQ_FL_TA_WAIT	0x0004	* not yet used */

#define AQRDQ_SET_FLAG(aqrdq_ctx, fl) (aqrdq_ctx)->aqrdq_flags |= (fl)
#define AQRDQ_CLR_FLAG(aqrdq_ctx, fl) (aqrdq_ctx)->aqrdq_flags &= ~(fl)
#define AQRDQ_IS_FLAG(aqrdq_ctx, fl) (((aqrdq_ctx)->aqrdq_flags & (fl)) != 0)

#if 0
/* Operations on aq_rcpt lists */
//#define AQR_RDQ_INIT(hd)	SM_RINGHD_INIT(hd)
//#define AQR_RDQ_APP(hd, aq_rcpt)	SM_RINGHD_APPEND((hd), (aq_rcpt), aqr_dest_link)
//#define AQR_RDQ_DELENTRY(hd, aq_rcpt)	SM_RINGHD_DELENTRY((hd), AQR_DEST2R(aq_rcpt))
#endif /* 0 */

/* Operations on aq_rcpt lists (in AQ RDQ) */
#define AQ_RDQ_INIT(aqrdq)	TAILQ_INIT(&(aqrdq))
#define AQ_RDQ_EMPTY(aqrdq)	TAILQ_EMPTY(&(aqrdq))
#define AQ_RDQ_FIRST(aqrdq)	TAILQ_FIRST(&(aqrdq))
#define AQ_RDQ_END(aqrdq)	TAILQ_END(&(aqrdq))
#define AQ_RDQ_LAST(aqrdq)	TAILQ_LAST(&(aqrdq), aq_rcpts_S)
#define AQ_RDQ_NEXT(aq_rcpt)	TAILQ_NEXT(aq_rcpt, aqr_dest_link)
#define AQ_RDQ_INSERT_TAIL(aqrdq, aq_rcpt) TAILQ_INSERT_TAIL(&(aqrdq), aq_rcpt, aqr_dest_link)
#define AQ_RDQ_INSERT_HEAD(aqrdq, aq_rcpt) TAILQ_INSERT_HEAD(&(aqrdq), aq_rcpt, aqr_dest_link)
#define AQ_RDQ_REMOVE(aqrdq, aq_rcpt)	TAILQ_REMOVE(&(aqrdq), aq_rcpt, aqr_dest_link)

/* Operations on aqrdq_ctx lists (in AQ) */
#define AQ_RDQS_INIT(aqrdqs)	TAILQ_INIT(&(aqrdqs))
#define AQ_RDQS_FIRST(aqrdqs)	TAILQ_FIRST(&(aqrdqs))
#define AQ_RDQS_END(aqrdqs)	TAILQ_END(&(aqrdqs))
#define AQ_RDQS_NEXT(aqrdq_ctx)	TAILQ_NEXT(aqrdq_ctx, aqrdq_link)
#define AQ_RDQS_INSERT_TAIL(aqrdqs, aqrdq_ctx) TAILQ_INSERT_TAIL(&(aqrdqs), aqrdq_ctx, aqrdq_link)
#define AQ_RDQS_INSERT_HEAD(aqrdqs, aqrdq_ctx) TAILQ_INSERT_HEAD(&(aqrdqs), aqrdq_ctx, aqrdq_link)
#define AQ_RDQS_REMOVE(aqrdqs, aqrdq_ctx) TAILQ_REMOVE(&(aqrdqs), aqrdq_ctx, aqrdq_link)

#if AQRDQ_CHECK
# define SM_IS_AQRDQE(aqrdq_ctx) SM_REQUIRE_ISA((aqrdq_ctx), SM_AQRDQ_MAGIC)
#else
# define SM_IS_AQRDQE(aqrdq_ctx) SM_REQUIRE((aqrdq_ctx) != NULL)
#endif

sm_ret_T	 aq_rdq_add(aq_ctx_P _aq_ctx, aq_rcpt_P _aq_rcpt, uint32_t *_paqrdq_flags, thr_lock_T _locktype);
sm_ret_T	 aq_rdq_rm(aq_ctx_P _aq_ctx, aq_rcpt_P _aq_rcpt, thr_lock_T _locktype, sm_log_ctx_P _lctx);
sm_ret_T	 aq_rdq_find(aq_ctx_P _aq_ctx, ipv4_T _ipv4, aqrdq_ctx_P *_paqrdq_ctx, thr_lock_T _locktype);

#endif /* SM_AQRDQ_H */


syntax highlighted by Code2HTML, v. 0.9.1