/*
 * libnqs/queue/openqord.c
 * 
 * DESCRIPTION:
 *
 *	Open the queue ordering file for the specified queue descriptor,
 *	if there are requests in the queue.
 *
 *	Original Author:
 *	-------
 *	Brent A. Kingsbury, Sterling Software Incorporated.
 *	August 12, 1985.
 */

#include <libnqs/license.h>
#include <libnqs/proto.h>
#include <libnqs/nqsxdirs.h>		/* NQS directories */
#include <string.h>

/*
 *	Configurable parameters.
 */
#define	MAX_RETRY	50	/* Maximum queue ordering file retry limit */


/*** openqord
 *
 *
 *	int openqord():
 *
 *	Open the queue ordering file for the specified queue descriptor,
 *	of there are requests in the queue.
 *
 *	Returns:
 *	      >=0: if the queue has requests, and the queue ordering
 *		   file was successfully opened.  The value returned
 *		   is the file descriptor opened to read the queue
 *		   ordering file.
 *	       -1: if there are no requests in the queue (no queue
 *		   ordering file is opened).
 *	       -2: if there ARE requests in the queue, but some terrible
 *		   error prevented us from opening the queue ordering
 *		   file.
 *	       -3: if the queue has been deleted.
 */
int openqord (struct confd *queuefile, struct gendescr *descr)
{
	char path [MAX_PATHNAME+1];	/* Queue ordering file pathname */
	char quename [MAX_QUEUENAME+1];	/* Name of queue */
	register int fd;		/* Queue ordering file descriptor */
	int retry;			/* Race condition retry */
	long position;			/* Offset in NQS database file of */
					/* the queue file descriptor */
	long blockpos;			/* The block offset in the NQS */
					/* queue file descriptor file of the */
					/* queue descriptor */

  	assert (queuefile != NULL);
  	assert (descr     != NULL);
  
	position = telldb (queuefile);	/* Remember offset of descriptor */
	blockpos = blockdb (position) * ATOMICBLKSIZ;
	strcpy (quename, descr->v.que.namev.name);
	/*
	 *  Open the request queue ordering file.
	 */
	retry = 0;			/* Retry count */
	fd = -1;			/* Queue ordering file not open */
	while (retry <= MAX_RETRY &&
	      (descr->v.que.departcount || descr->v.que.runcount ||
	       descr->v.que.stagecount || descr->v.que.queuedcount ||
	       descr->v.que.waitcount || descr->v.que.holdcount ||
	       descr->v.que.arrivecount)) {
		if (descr->v.que.type == QUE_NET) {
			sprintf (path, "%s/n%08lx%04x", Nqs_qorder,
				 telldb(queuefile), descr->v.que.orderversion);
		}
		else {
			sprintf (path, "%s/q%08lx%04x", Nqs_qorder,
				 telldb(queuefile), descr->v.que.orderversion);
		}
		if ((fd = open (path, O_RDONLY)) == -1) {
			/*
			 *  We did not succeed in opening the queue
			 *  ordering file (because a queue update JUST
			 *  occurred)....  We may get in a race here
			 *  with the daemon.  However the likelihood
			 *  of this race going on for more than 1 or
			 *  2 iterations is VERY low.  We are simply
			 *  paying the price for not using locks (which
			 *  would also slow everyone down all of the
			 *  time, and make this whole thing less portable....
			 */
			seekdb (queuefile, blockpos);	/* Seek back to load */
							/* block */
			descr = nextdb (queuefile);	/* Read descr */
			while (descr != (struct gendescr *)0 &&
			       telldb (queuefile) < position) {
				descr = nextdb (queuefile);
			}
			if (descr == (struct gendescr *)0 ||
			    telldb(queuefile) > position ||
			    strcmp (descr->v.que.namev.name, quename)) {
				/*
				 *  The queue has been deleted, or
				 *  replaced by another queue!
				 */
				return (-3);		/* No such queue */
			}
			else retry += 1;		/* Keep counter */
		} 
		else retry = MAX_RETRY+1;		/* Set for exit */
	}
	if (fd == -1) {			/* Queue ordering file not open */
		if (descr->v.que.departcount || descr->v.que.runcount ||
		    descr->v.que.stagecount || descr->v.que.queuedcount ||
		    descr->v.que.waitcount || descr->v.que.holdcount ||
		    descr->v.que.arrivecount) {
			/*
			 *  Something is wrong since the queue exists and
			 *  has reqs, but no queue ordering file.
			 */
			return (-2);	/* Unable to open queue file! */
		}
		return (-1);		/* No requests in the queue */
	}
	return (fd);			/* Return the opened file descriptor */
}
