[GIO] Using GBufferedOutputStream



Hello,

I am a bit at a loss as to how GBufferedOutputStream is supposed to be
used. My aim is to have a simple high-level non-blocking
send_message() function that buffers a new message and flushes the
data on the background. A naive method of doing so could be the
following (partially-pseudo) code (assuming I understood the docs
right):


GOutputStream *out;

void on_connect() {
  out = g_buffered_output_stream_new(g_io_stream_get_output_stream(G_IO_STREAM(connection)));
  g_buffered_output_stream_set_auto_grow(G_BUFFERED_OUTPUT_STREAM(out), TRUE);
}

void handle_flush(..) {
  // close connection on error
}

void send_message(char *msg) {
  // this write should neither block nor fail, since we should be
writing to a buffer and "auto-grow" is true
  g_output_stream_write(out, msg, ..);
  g_output_stream_flush_async(out, .., handle_flush, ..);
}


The above method assumes that send_message() is not called before the
message of a previous call has been flushed. Otherwise the later flush
would, I assume, fail because there is a pending operation on the
stream. Now suppose I would want to handle this situation and allow
send_message() to be called at any time:


void handle_flush(..) {
  if(error)
    report_error_and_close_connection()
  else if(buffer_is_not_empty())
    g_output_stream_flush_async(out, .., handle_flush, ..);
}

void send_message(char *msg) {
  // this write should neither block nor fail, since we should be
writing to a buffer and "auto-grow" is true
  g_output_stream_write(out, msg, ..);
  if(!g_output_stream_has_pending(out))
    g_output_stream_flush_async(out, .., handle_flush, ..);
}


However, there are two issues with the above solution:
- GBufferedOutputStream does not provide any method to check whether
the buffer is empty, or whether there are any outstanding bytes that
need to be flushed. This is required in handle_flush() to determine
whether a new flush is required.
- Will GBufferedOutputStream correctly handle the situation where new
data is added to the buffer while it is performing a flush operation
on the background? I've skimmed a bit through the code, but get the
impression it is not supposed to be used like this.

I also just encountered a problem with g_output_stream_write(): in
some situations, it reports to have written less bytes than I asked it
to. I had assumed this to be impossible when writing to an
auto-growing buffer. I have not investigated this problem any furher
yet, though, and have no idea whether it is related to the above
problem.

Anyway, I have the impression that I'm trying to use
GBufferedOutputStream in a way it is not supposed to be used, yet I
don't think I'm trying to do anything obscure. I could have
send_message() queue messages in a separate queue and write() them in
the background from handle_flush(), but that is rather inefficient
(many of the messages are pretty small and could be combined in a
single write()) and would probably require more code than simply
implementing my own buffer.

I keep wondering if there is no better solution to do this, and how
GBufferedOutputStream *is* supposed to be used...


Ayo.



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]