Пример #1
0
void LLMediaDataClient::swapCurrentQueue()
{
	// Swap
	mCurrentQueueIsTheSortedQueue = !mCurrentQueueIsTheSortedQueue;
	// If its empty, swap back
	if (getCurrentQueue()->empty()) 
	{
		mCurrentQueueIsTheSortedQueue = !mCurrentQueueIsTheSortedQueue;
	}
}
Пример #2
0
void AsyncFileWriter::ioThread() {
  folly::setThreadName("log_writer");

  while (true) {
    // With the lock held, grab a pointer to the current queue, then increment
    // the ioThreadCounter index so that other threads will write into the
    // other queue as we process this one.
    std::vector<std::string>* ioQueue;
    size_t numDiscarded;
    bool stop;
    {
      auto data = data_.lock();
      ioQueue = data->getCurrentQueue();
      while (ioQueue->empty() && !data->stop) {
        messageReady_.wait(data.getUniqueLock());
      }

      ++data->ioThreadCounter;
      numDiscarded = data->numDiscarded;
      data->numDiscarded = 0;
      data->currentBufferSize = 0;
      stop = data->stop;
    }
    ioCV_.notify_all();

    // Write the log messages now that we have released the lock
    try {
      performIO(ioQueue);
    } catch (const std::exception& ex) {
      onIoError(ex);
    }

    // clear() empties the vector, but the allocated capacity remains so we can
    // just reuse it without having to re-allocate in most cases.
    ioQueue->clear();

    if (numDiscarded > 0) {
      auto msg = getNumDiscardedMsg(numDiscarded);
      if (!msg.empty()) {
        auto ret = folly::writeFull(file_.fd(), msg.data(), msg.size());
        // We currently ignore errors from writeFull() here.
        // There's not much we can really do.
        (void)ret;
      }
    }

    if (stop) {
      data_->ioThreadDone = true;
      break;
    }
  }
}
Пример #3
0
void AsyncFileWriter::writeMessage(std::string&& buffer, uint32_t flags) {
  auto data = data_.lock();
  if ((data->currentBufferSize >= data->maxBufferBytes) &&
      !(flags & NEVER_DISCARD)) {
    ++data->numDiscarded;
    return;
  }

  data->currentBufferSize += buffer.size();
  auto* queue = data->getCurrentQueue();
  queue->emplace_back(std::move(buffer));
  messageReady_.notify_one();
}
Пример #4
0
void AsyncFileWriter::flush() {
  auto data = data_.lock();
  auto start = data->ioThreadCounter;

  // Wait until ioThreadCounter increments by at least two.
  // Waiting for a single increment is not sufficient, as this happens after
  // the I/O thread has swapped the queues, which is before it has actually
  // done the I/O.
  while (data->ioThreadCounter < start + 2) {
    if (data->ioThreadDone) {
      return;
    }

    // Enqueue an empty string and wake the I/O thread.
    // The empty string ensures that the I/O thread will break out of its wait
    // loop and increment the ioThreadCounter, even if there is no other work
    // to do.
    data->getCurrentQueue()->emplace_back();
    messageReady_.notify_one();

    // Wait for notification from the I/O thread that it has done work.
    ioCV_.wait(data.getUniqueLock());
  }
}
Пример #5
0
void LLMediaDataClient::serviceQueue()
{	
	request_queue_t *queue_p = getCurrentQueue();
	
	// quick retry loop for cases where we shouldn't wait for the next timer tick
	while(true)
	{
		if (queue_p->empty())
		{
			LL_DEBUGS("LLMediaDataClient") << "queue empty: " << (*queue_p) << LL_ENDL;
			break;
		}
		
		// Peel one off of the items from the queue, and execute request
		request_ptr_t request = queue_p->front();
		llassert(!request.isNull());
		const LLMediaDataClientObject *object = (request.isNull()) ? NULL : request->getObject();
		llassert(NULL != object);
		
		// Check for conditions that would make us just pop and rapidly loop through
		// the queue.
		if(request.isNull() ||
		   request->isMarkedSent() ||
		   NULL == object ||
		   object->isDead() ||
		   !object->hasMedia())
		{
			if (request.isNull()) 
			{
				LL_WARNS("LLMediaDataClient") << "Skipping NULL request" << LL_ENDL;
			}
			else {
				LL_INFOS("LLMediaDataClient") << "Skipping : " << *request << " " 
				<< ((request->isMarkedSent()) ? " request is marked sent" :
					((NULL == object) ? " object is NULL " :
					 ((object->isDead()) ? "object is dead" : 
					  ((!object->hasMedia()) ? "object has no media!" : "BADNESS!")))) << LL_ENDL;
			}
			queue_p->pop_front();
			continue;	// jump back to the start of the quick retry loop
		}
		
		// Next, ask if this is "interesting enough" to fetch.  If not, just stop
		// and wait for the next timer go-round.  Only do this for the sorted 
		// queue.
		if (mCurrentQueueIsTheSortedQueue && !object->isInterestingEnough())
		{
			LL_DEBUGS("LLMediaDataClient") << "Not fetching " << *request << ": not interesting enough" << LL_ENDL;
			break;
		}
		
		// Finally, try to send the HTTP message to the cap url
		std::string url = request->getCapability();
		bool maybe_retry = false;
		if (!url.empty())
		{
			const LLSD &sd_payload = request->getPayload();
			LL_INFOS("LLMediaDataClient") << "Sending request for " << *request << LL_ENDL;
			
			// Call the subclass for creating the responder
			LLHTTPClient::post(url, sd_payload, createResponder(request));
		}
		else {
			LL_INFOS("LLMediaDataClient") << "NOT Sending request for " << *request << ": empty cap url!" << LL_ENDL;
			maybe_retry = true;
		}

		bool exceeded_retries = request->getRetryCount() > mMaxNumRetries;
		if (maybe_retry && ! exceeded_retries) // Try N times before giving up 
		{
			// We got an empty cap, but in that case we will retry again next
			// timer fire.
			request->incRetryCount();
		}
		else {
			if (exceeded_retries)
			{
				LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " for " 
					<< mMaxNumRetries << " tries...popping object id " << object->getID() << LL_ENDL; 
				// XXX Should we bring up a warning dialog??
			}
			
			queue_p->pop_front();
			
			if (! mCurrentQueueIsTheSortedQueue) {
				// Round robin
				request->markSent(true);
				mRoundRobinQueue.push_back(request);				
			}
		}
		
 		// end of quick loop -- any cases where we want to loop will use 'continue' to jump back to the start.
 		break;
	}
	
	swapCurrentQueue();
}