Beispiel #1
0
/** Find the next empty write chunk, sets self->writerChunk to it and returns * it.
 *
 * We only use the next one if it is empty. If not, we essentially just filled
 * up the last chunk and wrapped around to the socket reader. In that case, we
 * either create a new chunk if the overall buffer can still grow, or we drop
 * the data from the current one.
 *
 * \warning A lock on the current writer chunk should be held prior to calling
 * this function. It will be released, and the returned writerChunk will be
 * similarly locked.
 *
 * \param self BufferedWriter pointer
 * \param current locked BufferChunk to use or from which to find the next
 * \return a locked BufferChunk in which data can be stored
 */
BufferChunk*
getNextWriteChunk(BufferedWriter* self, BufferChunk* current) {
  int nlost;
  BufferChunk* nextBuffer;

  assert(current != NULL);
  nextBuffer = current->next;
  oml_unlock(&current->lock, __FUNCTION__);
  assert(nextBuffer != NULL);

  oml_lock(&self->lock, __FUNCTION__);
  if (nextBuffer == self->nextReaderChunk) {
    if (self->unallocatedBuffers > 0) {
      /* The next buffer is the next to be read, but we can allocate more,
       * allocate a new buffer, insert it after the current writer, and use it */
      nextBuffer = createBufferChunk(self);
      assert(nextBuffer); /** \todo Use existing buffer if allocation fails */
      oml_unlock(&self->lock, __FUNCTION__);

      oml_lock(&current->lock, __FUNCTION__);
      nextBuffer->next = current->next;
      current->next = nextBuffer; /* we have a lock on this one */
      oml_unlock(&current->lock, __FUNCTION__);

      oml_lock(&self->lock, __FUNCTION__);

    } else {
      /* The next buffer is the next to be read, and we cannot allocate more,
       * use it, dropping unread data, and advance the read pointer */
      self->nextReaderChunk = nextBuffer->next;
    }
  }

  self->writerChunk = nextBuffer;
  nlost = bw_msgcount_reset(self);
  self->nlost += nlost;
  oml_unlock(&self->lock, __FUNCTION__);
  oml_lock(&nextBuffer->lock, __FUNCTION__);
  if (nlost) {
    logwarn("%s: Dropping %d samples (%dB)\n", self->outStream->dest, nlost, mbuf_fill(nextBuffer->mbuf));
  }
  mbuf_clear2(nextBuffer->mbuf, 0);

  // Now we just need to copy the message from current to self->writerChunk
  int msgSize = mbuf_message_length(current->mbuf);
  if (msgSize > 0) {
    mbuf_write(nextBuffer->mbuf, mbuf_message(current->mbuf), msgSize);
    mbuf_reset_write(current->mbuf);
  }

  return nextBuffer;
}
Beispiel #2
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;
}
Beispiel #3
0
// This function finds the next empty write chain, sets +self->writeChain+ to
// it and returns.
//
// We only use the next one if it is empty. If not, we
// essentially just filled up the last chain and wrapped
// around to the socket reader. In that case, we either create a new chain
// if the overall buffer can still grow, or we drop the data from the current one.
//
// This assumes that the current thread holds the +self->lock+ and the lock on
// the +self->writeChain+.
//
BufferChain*
getNextWriteChain(
  BufferedWriter* self,
  BufferChain* current
) {
  assert(current != NULL);
  BufferChain* nextBuffer = current->next;
  assert(nextBuffer != NULL);

  BufferChain* resChain = NULL;
  if (mbuf_remaining(nextBuffer->mbuf) == 0) {
    // It's empty, we can use it
    mbuf_clear2(nextBuffer->mbuf, 0);
    resChain = nextBuffer;
  } else if (self->chainsAvailable > 0) {
    // insert new chain between current and next one.
    BufferChain* newBuffer = createBufferChain(self);
    newBuffer->next = nextBuffer;
    current->next = newBuffer;
    resChain = newBuffer;
  } else {
    // Filled up buffer, time to drop data and reuse current buffer
    // Current buffer holds most recent added data (we drop from the queue's tail
    //assert(current->reading == 0);
    assert(current->reading == 0);
    o_log (O_LOG_WARN, "Dropping %d bytes of measurement data\n", mbuf_fill(current->mbuf));
    mbuf_repack_message2(current->mbuf);
    return current;
  }
  // Now we just need to copy the +message+ from +current+ to +resChain+
  int msgSize = mbuf_message_length(current->mbuf);
  if (msgSize > 0) {
    mbuf_write(resChain->mbuf, mbuf_message(current->mbuf), msgSize);
    mbuf_reset_write(current->mbuf);
  }
  return resChain;
}