After the implementation of the code that uses the scollectd API was
modified, the get_collectd_value gets the collectd ID as a const
reference, to remove unnessary creation of shared_ptr.
Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
gate_closed_exception::what() is currently a private member, thus
calling the method when handling the exception isn't possible.
Signed-off-by: Raphael S. Carvalho <raphaelsc@cloudius-systems.com>
Execute a function making sure it is wrapped in a gate.
This can afford to be considerably simpler than do_with, since we are not
playing any games with object creation, and the gate itself can be assumed to
be relatively long lived.
Among other things, this will allow us to make changes to enter / leave without
breaking existing code, and experiment with stronger ways of doing leave - as
Avi suggested recently.
Signed-off-by: Glauber Costa <glommer@cloudius-systems.com>
.then()'s return type is a complex template, which needs to be mangled into
the function's name. Move the return type into a defaulted template type
parameter, so that the entire type expression is eliminated, being replaced
by the result type.
Saves about 1% compile time and 3% object size on futures_test.o.
We can use sstring as an argument to sprint. In some cases, we already have the
string in a variable and end up being forced to call c_str() from the caller
site. Accepting sstring as a parameter makes for a cleaner interface.
Signed-off-by: Glauber Costa <glommer@cloudius-systems.com>
This patch adds a "class future" method for handling an exception result
of the future. It is impossible to discard a future's exception while passing
through the value of the result (what will we pass in the case of
exception?), so we discard the result as well.
An example of how this can be used, to log an error (but otherwise do
nothing) if removing a file fails:
remove_file(filename).handle_exception(
[] (std::exception_ptr eptr) {
print("Exception when deleting file: %s", eptr);
});
Signed-off-by: Nadav Har'El <nyh@cloudius-systems.com>
Closing a file can both expose latent errors that did not have the
opportunity to be reported earlier, and also may block. While both
are unlikely in the case of O_DIRECT files, better not to risk it.
the file_data_sink_impl::put() code assumes it is always called on buffers
with size multiple of dma alignment (4096), except the *last* one. After
writing one unaligned-size buffer, further writes cannot continue because
the offset into the file no longer has the right alignment! If a caller
does try to do that, there is a bug in the caller (it's not a run-time error,
it's a design bug), and better discover it quickly with an assert, as I do
in this patch.
I had such a caller in an example application, and it took me a whole day
of debugging just to figure out that this is where the caller actually had
a bug.
Signed-off-by: Nadav Har'El <nyh@cloudius-systems.com>
Reviewed-by: Raphael S. Carvalho <raphaelsc@cloudius-systems.com>
Our file-output code contains various layers making sometimes contradictory
assumptions, and it is a real art-form to make it all work together.
They usually do work together well, but there was one undetected bug for
large writes to a file output stream:
The problem is what happens when we try to write a large buffer (larger
than the output stream's buffer) in one output_stream::write() call.
By default, output_stream uses the efficient, zero-copy, implementation
which calls the underlying data sink's put function on the entire written
buffer, without copying it to the stream's buffer first.
Unfortunately, this solution does NOT work on *file* output streams.
Because of our use of AIO and O_DIRECT, we can only write from aligned
buffers, and at aligned (multiple of dma_alignment) sizes. Even a large
size cannot be fully written if not a multiple of dma_alignment, and
the need to align the buffers, and data already on the output_stream,
complicate things further.
Amazingly, we already had an option "_trim_to_size" in output_stream to
do the right thing, and we just need to enable it for file output stream.
In special cases (aligned position, aligned input buffer) it might be
possible to do something even more efficient - zero copy and just one
write request - but in the general case, _trim_to_size is exactly what
we needed.
Signed-off-by: Nadav Har'El <nyh@cloudius-systems.com>
When creating a file object, we call fstat() to determine whether it's
a block device or a regular file. While unlikely, the fstat() call can
block. Use an ioctl() that we expect to fail on regular files instead.
Add a use_count() method for shared_ptr, like std::shared_ptr has.
We already had such a method for lw_shared_ptr, but not for shared_ptr.
Signed-off-by: Nadav Har'El <nyh@cloudius-systems.com>
When closing the read-end side of the pipe, we need to notify the writer
only if it was blocked in write() on a full pipe - because if it wasn't
blocked, it will get the broken pipe on the next write() attempt.
We used queue::abort() for that, which is fine, because this function
won't do anything if nobody is waiting on a full buffer. But we still
call std::make_exception_ptr() unconditionally, which is slow (involves
throwing an exception and catching it) and an annoying false-alarm when
trying to debug with gdb's "catch throw" (which stops on any throw).
So this patch does
if (_buf.full()) {
_buf.abort(std::make_exception_ptr(broken_pipe_exception()));
}
So that in the typical case when the buffer was not full (hopefully it
is empty), we don't do anything.
Signed-off-by: Nadav Har'El <nyh@cloudius-systems.com>
distributed<> has the connotation of being distributed across the network.
Sharded is more in line with seastar terms.
Keep the distributed<> name and header file as an alias, for
compatibility.
Similar to std::shared_mutex, allows shared and exclusive locking of a
resource (also known as a reader/writer lock). This implementation is
strictly FIFO.
When an exceptional future is ignored, we print a message, and for an
std::exception we print its what(). However, it would be useful to also
see the exception's type. We already had such exception type printing
code for engine_exit(), and this patch extracts that code into a separate
function, and also uses it to print the warning message when an exceptional
future is ignored.
For example, in one test before this patch I see:
WARNING: exceptional future ignored: _Map_base::at
After this patch,
WARNING: exceptional future ignored of type 'std::out_of_range': _Map_base::at
Signed-off-by: Nadav Har'El <nyh@cloudius-systems.com>
Our queue<T> is a convenient mechanism for passing data between a producer
fiber (a set of consecutive continuations) and a consumer fiber.
However, queue<T> is difficult to use *correctly*. The biggest problem is
how to handle premature stopping: What if one of the two fibers (the reader
or the writer) stops prematurely, and will never read or write any more?
When queue<T> is used naively, the other fiber will just hang indefinitely
while it waits to read from the empty queue, or write to the full queue.
The solution proposed in this patch is a new pipe mechanism, implemented
internally over a queue. pipe<T>() returns two separate objects - a pipe
reader, and a pipe writer. Typically each object is std::move()ed into a
different fiber. When a fiber stops and its captured variables are destroyed,
one end of the pipe is destroyed, and that causes the other end's operations
to return immediately (if the other end was already blocked, it will resume
immediately, and return an exceptions). This behavior is analogous to
Unix's EOF or broken-pipe behavior.
Signed-off-by: Nadav Har'El <nyh@cloudius-systems.com>
Otherwise tester may crash if _instances destructor is called when thread
responsible for the allocation (which tester spawned to run seastar in)
no longer running.
There are many situations in which we would like to make sure a directory
exists. We can do that by creating the directory we want, and just ignoring
the relevant error.
It is a lot of code though, and I believe it is an idiom common enough to exist
on its own.
Signed-off-by: Glauber Costa <glommer@cloudius-systems.com>
Reviewed-by: Nadav Har'El <nyh@cloudius-systems.com>
wait() with timeout takes reference to an entry, but when
circular_buffer is resized it may be moved, so freed instance will be
accessed on timeout. Fix it by using std::list instead.