2015-03-04 10:47:53 +00:00
|
|
|
#include <DB/IO/ReadBufferAIO.h>
|
|
|
|
#include <DB/Common/ProfileEvents.h>
|
|
|
|
#include <DB/Core/ErrorCodes.h>
|
|
|
|
|
2015-03-05 16:20:15 +00:00
|
|
|
#include <Yandex/likely.h>
|
|
|
|
|
2015-03-04 10:47:53 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
ReadBufferAIO::ReadBufferAIO(const std::string & filename_, size_t buffer_size_, int flags_, mode_t mode_,
|
|
|
|
char * existing_memory_)
|
|
|
|
: BufferWithOwnMemory(buffer_size_, existing_memory_, BLOCK_SIZE),
|
|
|
|
fill_buffer(BufferWithOwnMemory(buffer_size_, existing_memory_, BLOCK_SIZE)),
|
|
|
|
filename(filename_)
|
|
|
|
{
|
|
|
|
ProfileEvents::increment(ProfileEvents::FileOpen);
|
|
|
|
|
|
|
|
int open_flags = ((flags_ == -1) ? O_RDONLY : flags_);
|
|
|
|
open_flags |= O_DIRECT;
|
|
|
|
|
2015-03-06 10:29:58 +00:00
|
|
|
fd = ::open(filename.c_str(), open_flags, mode_);
|
2015-03-04 10:47:53 +00:00
|
|
|
if (fd == -1)
|
2015-03-05 11:57:54 +00:00
|
|
|
{
|
|
|
|
got_exception = true;
|
2015-03-06 10:29:58 +00:00
|
|
|
throwFromErrno("Cannot open file " + filename, (errno == ENOENT) ? ErrorCodes::FILE_DOESNT_EXIST : ErrorCodes::CANNOT_OPEN_FILE);
|
2015-03-05 11:57:54 +00:00
|
|
|
}
|
2015-03-04 10:47:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ReadBufferAIO::~ReadBufferAIO()
|
|
|
|
{
|
2015-03-05 11:57:54 +00:00
|
|
|
if (!got_exception)
|
2015-03-04 10:47:53 +00:00
|
|
|
{
|
2015-03-05 11:57:54 +00:00
|
|
|
try
|
|
|
|
{
|
2015-03-05 14:21:55 +00:00
|
|
|
waitForCompletion();
|
2015-03-05 11:57:54 +00:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
tryLogCurrentException(__PRETTY_FUNCTION__);
|
|
|
|
}
|
2015-03-04 10:47:53 +00:00
|
|
|
}
|
|
|
|
|
2015-03-05 11:57:54 +00:00
|
|
|
if (fd != -1)
|
|
|
|
::close(fd);
|
2015-03-04 10:47:53 +00:00
|
|
|
}
|
|
|
|
|
2015-03-05 16:20:15 +00:00
|
|
|
void ReadBufferAIO::setMaxBytes(size_t max_bytes_read_)
|
|
|
|
{
|
|
|
|
if (is_started)
|
|
|
|
{
|
|
|
|
got_exception = true;
|
2015-03-06 10:29:58 +00:00
|
|
|
throw Exception("Illegal attempt to set the maximum number of bytes to read from file " + filename, ErrorCodes::LOGICAL_ERROR);
|
|
|
|
}
|
|
|
|
if ((max_bytes_read_ % BLOCK_SIZE) != 0)
|
|
|
|
{
|
|
|
|
got_exception = true;
|
|
|
|
throw Exception("Invalid maximum number of bytes to read from file " + filename, ErrorCodes::AIO_UNALIGNED_BUFFER_ERROR);
|
2015-03-05 16:20:15 +00:00
|
|
|
}
|
|
|
|
max_bytes_read = max_bytes_read_;
|
|
|
|
}
|
|
|
|
|
2015-03-05 14:21:55 +00:00
|
|
|
/// Если offset такой маленький, что мы не выйдем за пределы буфера, настоящий seek по файлу не делается.
|
|
|
|
off_t ReadBufferAIO::seek(off_t off, int whence)
|
|
|
|
{
|
|
|
|
waitForCompletion();
|
|
|
|
|
|
|
|
off_t new_pos = off;
|
|
|
|
if (whence == SEEK_CUR)
|
|
|
|
new_pos = pos_in_file - (working_buffer.end() - pos) + off;
|
|
|
|
else if (whence != SEEK_SET)
|
|
|
|
{
|
|
|
|
got_exception = true;
|
|
|
|
throw Exception("ReadBufferAIO::seek expects SEEK_SET or SEEK_CUR as whence", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Никуда не сдвинулись.
|
|
|
|
if ((new_pos + (working_buffer.end() - pos)) == pos_in_file)
|
|
|
|
return new_pos;
|
|
|
|
|
|
|
|
if (hasPendingData() && (new_pos <= pos_in_file) && (new_pos >= (pos_in_file - static_cast<off_t>(working_buffer.size()))))
|
|
|
|
{
|
|
|
|
/// Остались в пределах буфера.
|
|
|
|
pos = working_buffer.begin() + (new_pos - (pos_in_file - working_buffer.size()));
|
|
|
|
return new_pos;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ProfileEvents::increment(ProfileEvents::Seek);
|
|
|
|
|
|
|
|
pos = working_buffer.end();
|
|
|
|
off_t res = ::lseek(fd, new_pos, SEEK_SET);
|
|
|
|
if (res == -1)
|
|
|
|
{
|
|
|
|
got_exception = true;
|
2015-03-06 10:29:58 +00:00
|
|
|
throwFromErrno("Cannot seek through file " + filename, ErrorCodes::CANNOT_SEEK_THROUGH_FILE);
|
2015-03-05 14:21:55 +00:00
|
|
|
}
|
|
|
|
pos_in_file = new_pos;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-04 10:47:53 +00:00
|
|
|
bool ReadBufferAIO::nextImpl()
|
|
|
|
{
|
2015-03-05 14:21:55 +00:00
|
|
|
waitForCompletion();
|
|
|
|
|
|
|
|
if (is_eof)
|
2015-03-05 08:18:16 +00:00
|
|
|
return false;
|
|
|
|
|
2015-03-05 16:20:15 +00:00
|
|
|
if (likely(is_started))
|
|
|
|
swapBuffers();
|
2015-03-04 10:47:53 +00:00
|
|
|
|
|
|
|
// Create request.
|
2015-03-05 08:18:16 +00:00
|
|
|
::memset(&cb, 0, sizeof(cb));
|
2015-03-04 10:47:53 +00:00
|
|
|
|
|
|
|
cb.aio_lio_opcode = IOCB_CMD_PREAD;
|
|
|
|
cb.aio_fildes = fd;
|
2015-03-05 08:18:16 +00:00
|
|
|
cb.aio_buf = reinterpret_cast<UInt64>(fill_buffer.internalBuffer().begin());
|
|
|
|
cb.aio_nbytes = fill_buffer.internalBuffer().size();
|
2015-03-04 10:47:53 +00:00
|
|
|
cb.aio_offset = 0;
|
|
|
|
cb.aio_reqprio = 0;
|
|
|
|
|
|
|
|
// Submit request.
|
|
|
|
while (io_submit(aio_context.ctx, request_ptrs.size(), &request_ptrs[0]) < 0)
|
|
|
|
if (errno != EINTR)
|
2015-03-05 11:57:54 +00:00
|
|
|
{
|
|
|
|
got_exception = true;
|
2015-03-06 10:29:58 +00:00
|
|
|
throw Exception("Cannot submit request for asynchronous IO on file " + filename, ErrorCodes::AIO_SUBMIT_ERROR);
|
2015-03-05 11:57:54 +00:00
|
|
|
}
|
2015-03-04 10:47:53 +00:00
|
|
|
|
|
|
|
is_pending_read = true;
|
|
|
|
|
2015-03-05 16:20:15 +00:00
|
|
|
if (unlikely(!is_started))
|
|
|
|
is_started = true;
|
|
|
|
|
2015-03-04 10:47:53 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-03-05 14:21:55 +00:00
|
|
|
void ReadBufferAIO::waitForCompletion()
|
2015-03-04 10:47:53 +00:00
|
|
|
{
|
|
|
|
if (is_pending_read)
|
|
|
|
{
|
2015-03-05 08:18:16 +00:00
|
|
|
::memset(&events[0], 0, sizeof(events[0]) * events.size());
|
2015-03-04 10:47:53 +00:00
|
|
|
|
|
|
|
while (io_getevents(aio_context.ctx, events.size(), events.size(), &events[0], nullptr) < 0)
|
|
|
|
if (errno != EINTR)
|
2015-03-05 11:57:54 +00:00
|
|
|
{
|
|
|
|
got_exception = true;
|
2015-03-06 10:29:58 +00:00
|
|
|
throw Exception("Failed to wait for asynchronous IO completion on file " + filename, ErrorCodes::AIO_COMPLETION_ERROR);
|
2015-03-05 11:57:54 +00:00
|
|
|
}
|
2015-03-04 10:47:53 +00:00
|
|
|
|
2015-03-05 11:57:54 +00:00
|
|
|
is_pending_read = false;
|
|
|
|
|
2015-03-05 14:21:55 +00:00
|
|
|
size_t bytes_read = (events[0].res > 0) ? static_cast<size_t>(events[0].res) : 0;
|
|
|
|
pos_in_file += bytes_read;
|
|
|
|
|
|
|
|
if (bytes_read > 0)
|
|
|
|
fill_buffer.buffer().resize(bytes_read);
|
|
|
|
if (bytes_read < fill_buffer.internalBuffer().size())
|
|
|
|
is_eof = true;
|
2015-03-04 10:47:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-05 11:57:54 +00:00
|
|
|
void ReadBufferAIO::swapBuffers() noexcept
|
2015-03-04 10:47:53 +00:00
|
|
|
{
|
2015-03-05 08:18:16 +00:00
|
|
|
internalBuffer().swap(fill_buffer.internalBuffer());
|
|
|
|
buffer().swap(fill_buffer.buffer());
|
|
|
|
std::swap(position(), fill_buffer.position());
|
2015-03-04 10:47:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|