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-13 11:02:43 +00:00
|
|
|
|
#include <DB/Core/Defines.h>
|
2015-03-04 10:47:53 +00:00
|
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
2015-04-06 15:10:09 +00:00
|
|
|
|
/// Примечание: выделяется дополнительная страница, которая содежрит те данные, которые
|
2015-04-04 22:24:41 +00:00
|
|
|
|
/// не влезают в основной буфер.
|
2015-03-30 22:10:59 +00:00
|
|
|
|
ReadBufferAIO::ReadBufferAIO(const std::string & filename_, size_t buffer_size_, int flags_,
|
2015-03-04 10:47:53 +00:00
|
|
|
|
char * existing_memory_)
|
2015-04-04 22:24:41 +00:00
|
|
|
|
: ReadBufferFromFileBase(buffer_size_ + DEFAULT_AIO_FILE_BLOCK_SIZE, existing_memory_, DEFAULT_AIO_FILE_BLOCK_SIZE),
|
2015-04-06 15:10:09 +00:00
|
|
|
|
fill_buffer(BufferWithOwnMemory<ReadBuffer>(this->memory.size(), nullptr, DEFAULT_AIO_FILE_BLOCK_SIZE)),
|
2015-03-16 10:49:27 +00:00
|
|
|
|
filename(filename_)
|
2015-03-04 10:47:53 +00:00
|
|
|
|
{
|
|
|
|
|
ProfileEvents::increment(ProfileEvents::FileOpen);
|
|
|
|
|
|
2015-03-11 11:31:09 +00:00
|
|
|
|
int open_flags = (flags_ == -1) ? O_RDONLY : flags_;
|
2015-03-04 10:47:53 +00:00
|
|
|
|
open_flags |= O_DIRECT;
|
|
|
|
|
|
2015-03-30 22:10:59 +00:00
|
|
|
|
fd = ::open(filename.c_str(), open_flags);
|
2015-03-04 10:47:53 +00:00
|
|
|
|
if (fd == -1)
|
2015-03-05 11:57:54 +00:00
|
|
|
|
{
|
2015-03-11 11:31:09 +00:00
|
|
|
|
auto error_code = (errno == ENOENT) ? ErrorCodes::FILE_DOESNT_EXIST : ErrorCodes::CANNOT_OPEN_FILE;
|
|
|
|
|
throwFromErrno("Cannot open file " + filename, error_code);
|
2015-03-05 11:57:54 +00:00
|
|
|
|
}
|
2015-03-04 10:47:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ReadBufferAIO::~ReadBufferAIO()
|
|
|
|
|
{
|
2015-04-05 17:09:23 +00:00
|
|
|
|
if (!aio_failed)
|
2015-03-04 10:47:53 +00:00
|
|
|
|
{
|
2015-04-05 17:09:23 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
(void) waitForAIOCompletion();
|
|
|
|
|
}
|
|
|
|
|
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)
|
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);
|
2015-03-05 16:20:15 +00:00
|
|
|
|
max_bytes_read = max_bytes_read_;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 10:47:53 +00:00
|
|
|
|
bool ReadBufferAIO::nextImpl()
|
|
|
|
|
{
|
2015-03-11 13:15:19 +00:00
|
|
|
|
/// Если конец файла уже был достигнут при вызове этой функции,
|
|
|
|
|
/// то текущий вызов ошибочен.
|
2015-03-05 14:21:55 +00:00
|
|
|
|
if (is_eof)
|
2015-03-05 08:18:16 +00:00
|
|
|
|
return false;
|
|
|
|
|
|
2015-04-06 15:19:10 +00:00
|
|
|
|
if (!is_aio)
|
2015-04-03 22:44:32 +00:00
|
|
|
|
{
|
|
|
|
|
synchronousRead();
|
2015-04-06 15:19:10 +00:00
|
|
|
|
is_aio = true;
|
2015-04-03 22:44:32 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2015-04-06 11:54:08 +00:00
|
|
|
|
receive();
|
2015-03-04 10:47:53 +00:00
|
|
|
|
|
2015-04-06 15:19:10 +00:00
|
|
|
|
is_started = true;
|
|
|
|
|
|
2015-03-11 13:15:19 +00:00
|
|
|
|
/// Если конец файла только что достигнут, больше ничего не делаем.
|
2015-03-10 11:43:30 +00:00
|
|
|
|
if (is_eof)
|
|
|
|
|
return true;
|
|
|
|
|
|
2015-04-04 22:24:41 +00:00
|
|
|
|
/// Создать асинхронный запрос.
|
2015-04-06 11:54:08 +00:00
|
|
|
|
prepare();
|
2015-04-03 22:44:32 +00:00
|
|
|
|
|
2015-04-04 22:24:41 +00:00
|
|
|
|
request.aio_lio_opcode = IOCB_CMD_PREAD;
|
2015-04-03 22:44:32 +00:00
|
|
|
|
request.aio_fildes = fd;
|
2015-04-04 22:24:41 +00:00
|
|
|
|
request.aio_buf = reinterpret_cast<UInt64>(buffer_begin);
|
|
|
|
|
request.aio_nbytes = region_aligned_size;
|
2015-04-03 22:44:32 +00:00
|
|
|
|
request.aio_offset = region_aligned_begin;
|
|
|
|
|
|
|
|
|
|
/// Отправить запрос.
|
|
|
|
|
while (io_submit(aio_context.ctx, request_ptrs.size(), &request_ptrs[0]) < 0)
|
|
|
|
|
{
|
|
|
|
|
if (errno != EINTR)
|
|
|
|
|
{
|
2015-04-05 17:09:23 +00:00
|
|
|
|
aio_failed = true;
|
2015-04-03 22:44:32 +00:00
|
|
|
|
throw Exception("Cannot submit request for asynchronous IO on file " + filename, ErrorCodes::AIO_SUBMIT_ERROR);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
is_pending_read = true;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-06 11:54:08 +00:00
|
|
|
|
off_t ReadBufferAIO::doSeek(off_t off, int whence)
|
|
|
|
|
{
|
|
|
|
|
off_t new_pos_in_file;
|
|
|
|
|
|
|
|
|
|
if (whence == SEEK_SET)
|
|
|
|
|
{
|
|
|
|
|
if (off < 0)
|
|
|
|
|
throw Exception("SEEK_SET underflow", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
|
|
|
|
new_pos_in_file = off;
|
|
|
|
|
}
|
|
|
|
|
else if (whence == SEEK_CUR)
|
|
|
|
|
{
|
|
|
|
|
if (off >= 0)
|
|
|
|
|
{
|
|
|
|
|
if (off > (std::numeric_limits<off_t>::max() - getPositionInFile()))
|
|
|
|
|
throw Exception("SEEK_CUR overflow", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
|
|
|
|
}
|
|
|
|
|
else if (off < -getPositionInFile())
|
|
|
|
|
throw Exception("SEEK_CUR underflow", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
|
|
|
|
new_pos_in_file = getPositionInFile() + off;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw Exception("ReadBufferAIO::seek expects SEEK_SET or SEEK_CUR as whence", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
|
|
|
|
|
|
|
|
|
if (new_pos_in_file != getPositionInFile())
|
|
|
|
|
{
|
2015-04-06 15:10:09 +00:00
|
|
|
|
off_t first_read_pos_in_file = first_unread_pos_in_file - static_cast<off_t>(working_buffer.size());
|
|
|
|
|
if (hasPendingData() && (new_pos_in_file >= first_read_pos_in_file) && (new_pos_in_file <= first_unread_pos_in_file))
|
2015-04-06 11:54:08 +00:00
|
|
|
|
{
|
|
|
|
|
/// Свдинулись, но остались в пределах буфера.
|
2015-04-06 15:10:09 +00:00
|
|
|
|
pos = working_buffer.begin() + (new_pos_in_file - first_read_pos_in_file);
|
2015-04-06 11:54:08 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-04-06 13:18:28 +00:00
|
|
|
|
/// Сдвинулись за пределы буфера.
|
2015-04-06 11:54:08 +00:00
|
|
|
|
pos = working_buffer.end();
|
2015-04-06 15:10:09 +00:00
|
|
|
|
first_unread_pos_in_file = new_pos_in_file;
|
2015-04-06 11:54:08 +00:00
|
|
|
|
|
2015-04-06 13:18:28 +00:00
|
|
|
|
/// Не можем использовать результат текущего асинхронного запроса.
|
|
|
|
|
skip();
|
|
|
|
|
}
|
2015-04-06 11:54:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new_pos_in_file;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-04 22:24:41 +00:00
|
|
|
|
void ReadBufferAIO::synchronousRead()
|
|
|
|
|
{
|
2015-04-06 11:54:08 +00:00
|
|
|
|
prepare();
|
2015-04-04 22:24:41 +00:00
|
|
|
|
bytes_read = ::pread(fd, buffer_begin, region_aligned_size, region_aligned_begin);
|
2015-04-16 12:06:05 +00:00
|
|
|
|
|
|
|
|
|
ProfileEvents::increment(ProfileEvents::ReadBufferAIORead);
|
|
|
|
|
ProfileEvents::increment(ProfileEvents::ReadBufferAIOReadBytes, bytes_read);
|
|
|
|
|
|
2015-04-07 12:36:51 +00:00
|
|
|
|
finalize();
|
2015-04-04 22:24:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-04-06 11:54:08 +00:00
|
|
|
|
void ReadBufferAIO::receive()
|
2015-04-05 15:54:16 +00:00
|
|
|
|
{
|
|
|
|
|
if (!waitForAIOCompletion())
|
|
|
|
|
return;
|
2015-04-07 12:36:51 +00:00
|
|
|
|
finalize();
|
2015-04-05 15:54:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-04-06 11:54:08 +00:00
|
|
|
|
void ReadBufferAIO::skip()
|
2015-04-05 15:54:16 +00:00
|
|
|
|
{
|
|
|
|
|
if (!waitForAIOCompletion())
|
|
|
|
|
return;
|
|
|
|
|
|
2015-04-06 15:19:10 +00:00
|
|
|
|
is_aio = false;
|
2015-04-05 15:54:16 +00:00
|
|
|
|
|
|
|
|
|
bytes_read = events[0].res;
|
|
|
|
|
if ((bytes_read < 0) || (static_cast<size_t>(bytes_read) < region_left_padding))
|
|
|
|
|
throw Exception("Asynchronous read error on file " + filename, ErrorCodes::AIO_READ_ERROR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ReadBufferAIO::waitForAIOCompletion()
|
|
|
|
|
{
|
|
|
|
|
if (is_eof || !is_pending_read)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
while (io_getevents(aio_context.ctx, events.size(), events.size(), &events[0], nullptr) < 0)
|
|
|
|
|
{
|
|
|
|
|
if (errno != EINTR)
|
|
|
|
|
{
|
2015-04-05 17:09:23 +00:00
|
|
|
|
aio_failed = true;
|
2015-04-05 15:54:16 +00:00
|
|
|
|
throw Exception("Failed to wait for asynchronous IO completion on file " + filename, ErrorCodes::AIO_COMPLETION_ERROR);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
is_pending_read = false;
|
|
|
|
|
bytes_read = events[0].res;
|
|
|
|
|
|
2015-04-16 12:06:05 +00:00
|
|
|
|
ProfileEvents::increment(ProfileEvents::ReadBufferAIORead);
|
|
|
|
|
ProfileEvents::increment(ProfileEvents::ReadBufferAIOReadBytes, bytes_read);
|
|
|
|
|
|
2015-04-05 15:54:16 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-06 11:54:08 +00:00
|
|
|
|
void ReadBufferAIO::prepare()
|
2015-04-03 22:44:32 +00:00
|
|
|
|
{
|
2015-04-04 22:24:41 +00:00
|
|
|
|
requested_byte_count = std::min(fill_buffer.internalBuffer().size() - DEFAULT_AIO_FILE_BLOCK_SIZE, max_bytes_read);
|
2015-03-17 13:57:24 +00:00
|
|
|
|
|
2015-04-03 11:51:41 +00:00
|
|
|
|
/// Регион диска, из которого хотим читать данные.
|
2015-04-06 15:10:09 +00:00
|
|
|
|
const off_t region_begin = first_unread_pos_in_file;
|
2015-04-06 12:27:11 +00:00
|
|
|
|
|
|
|
|
|
if ((requested_byte_count > std::numeric_limits<off_t>::max()) ||
|
2015-04-06 15:10:09 +00:00
|
|
|
|
(first_unread_pos_in_file > (std::numeric_limits<off_t>::max() - static_cast<off_t>(requested_byte_count))))
|
2015-04-06 12:27:11 +00:00
|
|
|
|
throw Exception("An overflow occurred during file operation", ErrorCodes::LOGICAL_ERROR);
|
|
|
|
|
|
2015-04-06 15:10:09 +00:00
|
|
|
|
const off_t region_end = first_unread_pos_in_file + requested_byte_count;
|
2015-04-03 11:51:41 +00:00
|
|
|
|
|
2015-04-06 13:05:26 +00:00
|
|
|
|
/// Выровненный регион диска, из которого будем читать данные.
|
2015-04-06 15:10:09 +00:00
|
|
|
|
region_left_padding = region_begin % DEFAULT_AIO_FILE_BLOCK_SIZE;
|
2015-04-03 11:51:41 +00:00
|
|
|
|
const size_t region_right_padding = (DEFAULT_AIO_FILE_BLOCK_SIZE - (region_end % DEFAULT_AIO_FILE_BLOCK_SIZE)) % DEFAULT_AIO_FILE_BLOCK_SIZE;
|
|
|
|
|
|
2015-04-03 22:44:32 +00:00
|
|
|
|
region_aligned_begin = region_begin - region_left_padding;
|
2015-04-06 12:27:11 +00:00
|
|
|
|
|
|
|
|
|
if (region_end > (std::numeric_limits<off_t>::max() - static_cast<off_t>(region_right_padding)))
|
|
|
|
|
throw Exception("An overflow occurred during file operation", ErrorCodes::LOGICAL_ERROR);
|
|
|
|
|
|
2015-04-03 11:51:41 +00:00
|
|
|
|
const off_t region_aligned_end = region_end + region_right_padding;
|
2015-04-04 22:24:41 +00:00
|
|
|
|
region_aligned_size = region_aligned_end - region_aligned_begin;
|
2015-04-03 11:51:41 +00:00
|
|
|
|
|
2015-04-04 22:24:41 +00:00
|
|
|
|
buffer_begin = fill_buffer.internalBuffer().begin();
|
2015-04-03 11:51:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-04-07 12:36:51 +00:00
|
|
|
|
void ReadBufferAIO::finalize()
|
2015-03-04 10:47:53 +00:00
|
|
|
|
{
|
2015-04-03 11:51:41 +00:00
|
|
|
|
if ((bytes_read < 0) || (static_cast<size_t>(bytes_read) < region_left_padding))
|
|
|
|
|
throw Exception("Asynchronous read error on file " + filename, ErrorCodes::AIO_READ_ERROR);
|
2015-03-17 12:44:49 +00:00
|
|
|
|
|
2015-04-03 11:51:41 +00:00
|
|
|
|
/// Игнорируем излишние байты слева.
|
|
|
|
|
bytes_read -= region_left_padding;
|
2015-03-17 11:30:23 +00:00
|
|
|
|
|
2015-04-03 11:51:41 +00:00
|
|
|
|
/// Игнорируем излишние байты справа.
|
|
|
|
|
bytes_read = std::min(bytes_read, static_cast<off_t>(requested_byte_count));
|
2015-03-17 11:30:23 +00:00
|
|
|
|
|
2015-04-03 11:51:41 +00:00
|
|
|
|
if (bytes_read > 0)
|
2015-04-05 20:04:55 +00:00
|
|
|
|
fill_buffer.buffer().resize(region_left_padding + bytes_read);
|
2015-04-03 11:51:41 +00:00
|
|
|
|
if (static_cast<size_t>(bytes_read) < requested_byte_count)
|
|
|
|
|
is_eof = true;
|
|
|
|
|
|
2015-04-06 15:10:09 +00:00
|
|
|
|
if (first_unread_pos_in_file > (std::numeric_limits<off_t>::max() - bytes_read))
|
2015-04-06 12:27:11 +00:00
|
|
|
|
throw Exception("An overflow occurred during file operation", ErrorCodes::LOGICAL_ERROR);
|
2015-04-06 11:54:08 +00:00
|
|
|
|
|
2015-04-06 15:10:09 +00:00
|
|
|
|
first_unread_pos_in_file += bytes_read;
|
2015-04-03 11:51:41 +00:00
|
|
|
|
total_bytes_read += bytes_read;
|
2015-04-05 20:04:55 +00:00
|
|
|
|
working_buffer_offset = region_left_padding;
|
2015-04-03 11:51:41 +00:00
|
|
|
|
|
|
|
|
|
if (total_bytes_read == max_bytes_read)
|
|
|
|
|
is_eof = true;
|
2015-04-06 11:54:08 +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
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|