/*-------------------------------------------------------------------------------------- * Purpose: Write a new item into the queue * Input: queue to write item and the item itself * Output: returns 0, exits on fatal error if write fails * He Yan @ June 15, 2008 * -------------------------------------------------------------------------------------*/ int writeQueue( QueueWriter writer, void *item ) { int i; // lock the queue Queue q = writer->queue; if ( pthread_mutex_lock( &q->queueLock ) ) log_fatal( "lockQueue: failed"); // if the queue is full, move the positions of slowest readers to the tail if (( q->tail - q->head) >= QUEUE_MAX_ITEMS ) { #ifdef DEBUG log_warning("queue %s is full, head=%ld, tail=%ld; adjusting slowest readers", q->name, q->head, q->tail); #endif for ( i = 0; i < MAX_QUEUE_READERS; i++ ) { #ifdef DEBUG debug(__FUNCTION__, "queue %s's head is %ld", q->name, q->head); if (q->nextItem[i] >= 0) { debug(__FUNCTION__, "queue %s's reader %d's next item is %ld", q->name, i, q->nextItem[i]); } #endif // if this reader is the slowest one, adjust it if ( q->head == q->nextItem[i] ) { if(q->newPacingEnable == FALSE) adjustSlowestQueueReader(q, i); else { long j = q->nextItem[i] % QUEUE_MAX_ITEMS; q->items[j].count--; if ( q->items[j].count == 0 ) { free( q->items[j].messagBuf ); q->items[j].messagBuf = NULL; q->head++; } q->nextItem[i]++; #ifdef DEBUG log_warning("Move the slowest client 1 pos forward"); #endif } } } } // should not happen, fatal error if it happens if (( q->tail - q->head ) >= QUEUE_MAX_ITEMS ) log_fatal("%s queue is still FULL after adjusting readers", q->name); // not reached // old pacing: update pacing limit and reset readcout and writecount if needed // new pacing: update write count moveing average updateInterval(q); // only for the new pacing algorithm if(q->newPacingEnable == TRUE) { if ( ( (float)(q->tail - q->head)/(float)QUEUE_MAX_ITEMS ) >= QueueConfig.pacingOnThresh) { #ifdef DEBUG log_warning("queue %s is over pacing threshold, head=%ld, tail=%ld; adjusting slowest readers", q->name, QueueConfig.pacingOnThresh, q->head, q->tail); #endif for ( i = 0; i < MAX_QUEUE_READERS; i++ ) { #ifdef DEBUG debug(__FUNCTION__, "queue %s's head is %ld", q->name, q->head); if (q->nextItem[i] >= 0) { debug(__FUNCTION__, "queue %s's reader %d's next item is %ld", q->name, i, q->nextItem[i]); } #endif // if this reader is the slowest one, adjust it if ( q->head == q->nextItem[i] ) { adjustSlowestQueueReader(q, i); } } } } // only for the old pacing algorithm, otherwise skip this step if(q->newPacingEnable == FALSE) { // check if need to stop pacing if( checkPacingStop(q) ) log_fatal("%s queue error stopping pacing rules", q->name); } // write the data to the next spot in the queue q->writeCount++; if( q->readercount > 0 ) { q->writeCounts[writer->index]++; long l = q->tail % QUEUE_MAX_ITEMS; q->items[l].count = q->readercount; q->items[l].messagBuf = (void *)item; q->tail++; if ( (q->tail - q->head) > q->logMaxItems) q->logMaxItems = q->tail - q->head; } else free( item ); // only if use the old pacing, otherwise skip this step if(q->newPacingEnable == FALSE) { // apply pacing rules to the current writer if ( applyPacing(q, writer->index) ) log_fatal("%s queue error applying pacing rules", q->name); // not reached } // unlock the queue if ( pthread_mutex_unlock( &q->queueLock ) ) log_fatal( "unlockQueue: failed"); // notify blocked readers new data has appeared if( q->readercount > 0 ) pthread_cond_broadcast( &q->queueCond ); #ifdef DEBUG debug(__FUNCTION__, "Writer %d (%d writes in last interval(%d)) wrote to queue %s; tail/head: %ld/%ld ", writer->index, q->writeCounts[writer->index], QueueConfig.pacingInterval, q->name, q->tail, q->head); #endif /* log a message if we are past the log interval */ int now = time( NULL ); if ( now > q->lastLogTime + QueueConfig.logInterval) { q->lastLogTime = now; log_msg("Queue %s status: tail=%ld head=%ld", q->name, q->tail, q->head); log_msg("Queue %s usage: currentItems=%ld, usedBytes=%ld, peakItems=%ld, allowedItems=%ld", q->name, getItemsUsed(q->name), getBytesUsed(q->name), q->logMaxItems, QUEUE_MAX_ITEMS); log_msg("Queue %s writers: current=%d, peak=%d, allowed=%d", q->name, getWriterCount(q->name), q->logMaxWriters, MAX_QUEUE_WRITERS); log_msg("Queue %s readers: current=%d, peak=%d, allowed=%d", q->name, getReaderCount(q->name), q->logMaxReaders, MAX_QUEUE_READERS); } return(0); }
/*-------------------------------------------------------------------------------------- * Purpose: Write a new item into the queue * Input: queue to write item and the item itself * Output: returns 0 on success, 1 on queue_full, but success, -1 on failure * He Yan @ June 15, 2008 * -------------------------------------------------------------------------------------*/ int writeQueue( QueueWriter writer, void *item ) { Queue q = writer->queue; // lock the queue if ( pthread_mutex_lock( &q->queueLock ) ){ log_warning( "lockQueue: failed"); return -1; } int q_full = pacing_write_post_lock(q); // write the data to the next spot in the queue q->writeCount++; if( q->readercount > 0 ){ q->writeCounts[writer->index]++; long l = q->tail % QUEUE_MAX_ITEMS; q->items[l].count = q->readercount; q->items[l].messagBuf = (void *)item; q->tail++; if ( (q->tail - q->head) > q->logMaxItems){ q->logMaxItems = q->tail - q->head; } } else{ free( item ); } pacing_write_post_write(q,writer->index); // unlock the queue if ( pthread_mutex_unlock( &q->queueLock ) ){ log_warning( "unlockQueue: failed"); return -1; } // notify blocked readers new data has appeared if( q->readercount > 0 ){ pthread_cond_broadcast( q->queueGroupCond ); } #ifdef DEBUG debug(__FUNCTION__, "Writer %d (%d writes in last interval(%d)) wrote to queue %s; tail/head: %ld/%ld ", writer->index, q->writeCounts[writer->index], QueueConfig.pacingInterval, q->name, q->tail, q->head); #endif /* log a message if we are past the log interval */ int now = time( NULL ); if ( now > q->lastLogTime + QueueConfig.logInterval) { q->lastLogTime = now; log_msg("Queue %s status: tail=%ld head=%ld", q->name, q->tail, q->head); log_msg("Queue %s usage: currentItems=%ld, usedBytes=%ld, peakItems=%ld, allowedItems=%ld", q->name, getItemsUsed(q->name), getBytesUsed(q->name), q->logMaxItems, QUEUE_MAX_ITEMS); log_msg("Queue %s writers: current=%d, peak=%d, allowed=%d", q->name, getWriterCount(q->name), q->logMaxWriters, MAX_QUEUE_WRITERS); log_msg("Queue %s readers: current=%d, peak=%d, allowed=%d", q->name, getReaderCount(q->name), q->logMaxReaders, MAX_QUEUE_READERS); } return q_full; }