diff --git a/libursa/CMakeLists.txt b/libursa/CMakeLists.txt index a457448..c83c59f 100644 --- a/libursa/CMakeLists.txt +++ b/libursa/CMakeLists.txt @@ -29,6 +29,8 @@ add_library( IndexBuilder.h Indexer.cpp Indexer.h + IoPrio.cpp + IoPrio.h Json.h MemMap.cpp MemMap.h diff --git a/libursa/Daemon.cpp b/libursa/Daemon.cpp index 0e2e9ff..e5fa0d1 100644 --- a/libursa/Daemon.cpp +++ b/libursa/Daemon.cpp @@ -17,6 +17,7 @@ #include "Command.h" #include "Database.h" #include "DatasetBuilder.h" +#include "IoPrio.h" #include "OnDiskDataset.h" #include "QueryParser.h" #include "Responses.h" @@ -62,6 +63,8 @@ Response execute_command(const IteratorPopCommand &cmd, Task *task, Response execute_command(const IndexFromCommand &cmd, Task *task, const DatabaseSnapshot *snap) { + auto idle_guard = IoPriority(IoPriorityClass::Idle); + const auto &path_list_fname = cmd.get_path_list_fname(); std::vector paths; @@ -95,6 +98,8 @@ Response execute_command(const IndexFromCommand &cmd, Task *task, Response execute_command(const IndexCommand &cmd, Task *task, const DatabaseSnapshot *snap) { + auto idle_guard = IoPriority(IoPriorityClass::Idle); + if (cmd.ensure_unique()) { snap->recursive_index_paths(task, cmd.get_index_types(), cmd.taints(), cmd.get_paths()); @@ -140,6 +145,8 @@ Response execute_command(const ConfigSetCommand &cmd, Task *task, Response execute_command(const ReindexCommand &cmd, Task *task, const DatabaseSnapshot *snap) { + auto idle_guard = IoPriority(IoPriorityClass::Idle); + const std::string &dataset_id = cmd.dataset_id(); snap->reindex_dataset(task, cmd.get_index_types(), dataset_id); @@ -148,6 +155,8 @@ Response execute_command(const ReindexCommand &cmd, Task *task, Response execute_command([[maybe_unused]] const CompactCommand &cmd, Task *task, const DatabaseSnapshot *snap) { + auto idle_guard = IoPriority(IoPriorityClass::Idle); + snap->compact_locked_datasets(task); return Response::ok(); } @@ -251,6 +260,8 @@ std::vector acquire_locks( std::vector acquire_locks(const CompactCommand &cmd, const DatabaseSnapshot *snap) { + auto idle_guard = IoPriority(IoPriorityClass::Idle); + std::vector to_lock; if (cmd.get_type() == CompactType::Smart) { to_lock = snap->compact_smart_candidates(); diff --git a/libursa/IoPrio.cpp b/libursa/IoPrio.cpp new file mode 100644 index 0000000..151efc3 --- /dev/null +++ b/libursa/IoPrio.cpp @@ -0,0 +1,57 @@ +#include +#include + +#include "IoPrio.h" +#include "spdlog/spdlog.h" + +// Reference: https://www.kernel.org/doc/html/latest/block/ioprio.html + +static inline int ioprio_set(int which, int who, int ioprio) { + return syscall(__NR_ioprio_set, which, who, ioprio); +} + +static inline int ioprio_get(int which, int who) { + return syscall(__NR_ioprio_get, which, who); +} + +// Copied from include/linux/ioprio.h +enum { + IOPRIO_WHO_PROCESS = 1, + IOPRIO_WHO_PGRP, + IOPRIO_WHO_USER, +}; + +enum { + IOPRIO_CLASS_NONE, + IOPRIO_CLASS_RT, + IOPRIO_CLASS_BE, + IOPRIO_CLASS_IDLE, +}; + +constexpr int IOPRIO_CLASS_SHIFT = 13; + +// Change ioprio for the current process, and save the current PID. +IoPriority::IoPriority(IoPriorityClass ioprio) { + _old_pid = getpid(); + _old_ioprio = ioprio_get(IOPRIO_WHO_PROCESS, _old_pid); + int ioprio_value = 0; + if (ioprio == IoPriorityClass::BestEffort) { + ioprio_value = (IOPRIO_CLASS_BE << IOPRIO_CLASS_SHIFT) | 0; + } else if (ioprio == IoPriorityClass::Idle) { + ioprio_value = (IOPRIO_CLASS_IDLE << IOPRIO_CLASS_SHIFT) | 7; + } else { + throw std::runtime_error("Invalid IoPriorityClass"); + } + ioprio_set(IOPRIO_WHO_PROCESS, _old_pid, ioprio_value); +} + +// Restore ioprio for the current process (and check it's still the same PID). +IoPriority::~IoPriority() { + pid_t current_pid = getpid(); + ioprio_set(IOPRIO_WHO_PROCESS, current_pid, _old_ioprio); + if (current_pid != _old_pid) { + // This should not happen. Maybe we should just raise an error, + // but instead let's just try to the right thing and keep going. + spdlog::error("Thread forked in IoPriority context."); + } +} diff --git a/libursa/IoPrio.h b/libursa/IoPrio.h new file mode 100644 index 0000000..7e14972 --- /dev/null +++ b/libursa/IoPrio.h @@ -0,0 +1,16 @@ +#include +#include + +// Strongly typed wrapper for IOPRIO enum in the Linux kernel. +enum class IoPriorityClass { Idle, BestEffort }; + +// RAII class for setting the current thread's IO priority. +// Will change thread's ioprio in the constructor, and restore in destructor. +class IoPriority { + int _old_ioprio; + pid_t _old_pid; + + public: + IoPriority(IoPriorityClass ioprio); + ~IoPriority(); +};