Example #1
0
// return 1 if chain has been fully sent, 0 otherwise
int
processChain(
  BufferedWriter* self,
  BufferChain* chain
) {
  uint8_t* buf = mbuf_rdptr(chain->mbuf);
  size_t size = mbuf_message_offset(chain->mbuf) - mbuf_read_offset(chain->mbuf);
  size_t sent = 0;
  chain->reading = 1;
  oml_unlock(&self->lock, "processChain"); /* don't keep lock while transmitting */
  MBuffer* meta = self->meta_buf;

  while (size > sent) {
    long cnt = self->writeFunc(self->writeFuncHdl, (void*)(buf + sent), size - sent,
                               meta->rdptr, meta->fill);
    if (cnt > 0) {
      sent += cnt;
    } else {
      /* ERROR: Sleep a bit and try again */
      /* To be on the safe side, we rewind to the beginning of the
       * chain and try to resend everything - this is especially important
       * if the underlying stream needs to reopen and resync.
       */
      mbuf_reset_read(chain->mbuf);
      size = mbuf_message_offset(chain->mbuf) - mbuf_read_offset(chain->mbuf);
      sent = 0;
      sleep(1);
    }
  }
  // get lock back to see what happened while we were busy
  oml_lock_persistent(self);
  mbuf_read_skip(chain->mbuf, sent);
  if (mbuf_write_offset(chain->mbuf) == mbuf_read_offset(chain->mbuf)) {
    // seem to have sent everything so far, reset chain
    //    mbuf_clear2(chain->mbuf, 0);
    mbuf_clear2(chain->mbuf, 1);
    chain->reading = 0;
    return 1;
  }
  return 0;
}
Example #2
0
/** Send data contained in one chunk.
 *
 * \warning This function acquires the lock on the BufferedWriter for the time
 * it takes to check the double-buffer.
 *
 * \warning This function acquires the lock on the chunk being processed for
 * the time it takes to check it and swap the double buffer.
 *
 * \bug The meta buffer should also be protected.
 *
 * \param self BufferedWriter to process
 * \param chunk link of the chunk to process
 *
 * \return 1 if chunk has been fully sent, 0 if not, -1 on continuing back-off, -2 otherwise
 * \see oml_outs_write_f
 */
static int
processChunk(BufferedWriter* self, BufferChunk* chunk)
{
  time_t now;
  int ret = -2;
  ssize_t cnt = 0;
  MBuffer *read_buf = NULL;
  assert(self);
  assert(self->meta_buf);
  assert(self->read_buf);
  assert(chunk);
  assert(chunk->mbuf);

  oml_lock(&self->lock, __FUNCTION__);
  if (mbuf_message(self->read_buf) > mbuf_rdptr(self->read_buf)) {
    /* There is unread data in the double buffer */
    read_buf = self->read_buf;
  }
  oml_unlock(&self->lock, __FUNCTION__);

  oml_lock(&chunk->lock, __FUNCTION__);
  if ((NULL == read_buf) && (mbuf_message(chunk->mbuf) >= mbuf_rdptr(chunk->mbuf))) {
    /* There is unread data in the read buffer, swap MBuffers */
    read_buf = chunk->mbuf;
    chunk->mbuf = self->read_buf;
  }
  oml_unlock(&chunk->lock, __FUNCTION__);

  oml_lock(&self->lock, __FUNCTION__);
  self->read_buf = read_buf;
  oml_unlock(&self->lock, __FUNCTION__);

  if (NULL == read_buf) {
    /* The current message is not after the read pointer,
     * we must be on the writer chunk */
    ret = 1;
    goto processChunk_cleanup;
  }

  time(&now);
  if (difftime(now, self->last_failure_time) < self->backoff) {
    logdebug("%s: Still in back-off period (%ds)\n", self->outStream->dest, self->backoff);
    ret = -1;
    goto processChunk_cleanup;
  }

  while (mbuf_write_offset(read_buf) > mbuf_read_offset(read_buf)) {
    oml_lock(&self->meta_lock, __FUNCTION__);
    cnt = self->outStream->write(self->outStream,
        mbuf_rdptr(read_buf), mbuf_message_offset(read_buf) - mbuf_read_offset(read_buf),
        mbuf_rdptr(self->meta_buf), mbuf_fill(self->meta_buf));
    oml_unlock(&self->meta_lock, __FUNCTION__);

    if (cnt > 0) {
      mbuf_read_skip(read_buf, cnt);
      if (self->backoff) {
        self->backoff = 0;
        loginfo("%s: Connected\n", self->outStream->dest);
      }

    } else {
      self->last_failure_time = now;
      if (!self->backoff) {
        self->backoff = 1;
      } else if (self->backoff < UINT8_MAX) {
        self->backoff *= 2;
      }
      logwarn("%s: Error sending, backing off for %ds\n", self->outStream->dest, self->backoff);
      goto processChunk_cleanup;
    }
  }
  ret = 1;

processChunk_cleanup:
  return ret;
}