From add380b944ac1646781c670d202c7792b95cd6a8 Mon Sep 17 00:00:00 2001 From: msm Date: Sat, 18 Feb 2023 20:05:15 +0100 Subject: [PATCH 1/2] Lower iopriority when indexing to IDLE --- libursa/CMakeLists.txt | 2 ++ libursa/Daemon.cpp | 11 +++++++++++ libursa/IoPrio.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ libursa/IoPrio.h | 28 ++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+) create mode 100644 libursa/IoPrio.cpp create mode 100644 libursa/IoPrio.h 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..6799733 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) { + 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) { + 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) { + 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) { + 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) { + 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..92d1613 --- /dev/null +++ b/libursa/IoPrio.cpp @@ -0,0 +1,40 @@ +#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, +}; + +// 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); + ioprio_set(IOPRIO_WHO_PROCESS, _old_pid, (int)ioprio); +} + +// 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..9715a9a --- /dev/null +++ b/libursa/IoPrio.h @@ -0,0 +1,28 @@ +#include +#include + +// Copied from include/linux/ioprio.h +enum { + IOPRIO_CLASS_NONE, + IOPRIO_CLASS_RT, + IOPRIO_CLASS_BE, + IOPRIO_CLASS_IDLE, +}; + +// Strongly typed wrapper for IOPRIO enum in the Linux kernel. +enum class IoPriorityClass { + Idle = IOPRIO_CLASS_IDLE, + BestEffort = IOPRIO_CLASS_BE + // IOPRIO_CLASS_RT not needed, and not defined intentionally. +}; + +// 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(); +}; From f97912394edd342247b381d3ceea55e89af0eaa0 Mon Sep 17 00:00:00 2001 From: msm Date: Sat, 18 Feb 2023 21:56:16 +0100 Subject: [PATCH 2/2] Fix the guards --- libursa/Daemon.cpp | 10 +++++----- libursa/IoPrio.cpp | 19 ++++++++++++++++++- libursa/IoPrio.h | 14 +------------- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/libursa/Daemon.cpp b/libursa/Daemon.cpp index 6799733..e5fa0d1 100644 --- a/libursa/Daemon.cpp +++ b/libursa/Daemon.cpp @@ -63,7 +63,7 @@ Response execute_command(const IteratorPopCommand &cmd, Task *task, Response execute_command(const IndexFromCommand &cmd, Task *task, const DatabaseSnapshot *snap) { - IoPriority(IoPriorityClass::Idle); + auto idle_guard = IoPriority(IoPriorityClass::Idle); const auto &path_list_fname = cmd.get_path_list_fname(); @@ -98,7 +98,7 @@ Response execute_command(const IndexFromCommand &cmd, Task *task, Response execute_command(const IndexCommand &cmd, Task *task, const DatabaseSnapshot *snap) { - IoPriority(IoPriorityClass::Idle); + auto idle_guard = IoPriority(IoPriorityClass::Idle); if (cmd.ensure_unique()) { snap->recursive_index_paths(task, cmd.get_index_types(), cmd.taints(), @@ -145,7 +145,7 @@ Response execute_command(const ConfigSetCommand &cmd, Task *task, Response execute_command(const ReindexCommand &cmd, Task *task, const DatabaseSnapshot *snap) { - IoPriority(IoPriorityClass::Idle); + auto idle_guard = IoPriority(IoPriorityClass::Idle); const std::string &dataset_id = cmd.dataset_id(); snap->reindex_dataset(task, cmd.get_index_types(), dataset_id); @@ -155,7 +155,7 @@ Response execute_command(const ReindexCommand &cmd, Task *task, Response execute_command([[maybe_unused]] const CompactCommand &cmd, Task *task, const DatabaseSnapshot *snap) { - IoPriority(IoPriorityClass::Idle); + auto idle_guard = IoPriority(IoPriorityClass::Idle); snap->compact_locked_datasets(task); return Response::ok(); @@ -260,7 +260,7 @@ std::vector acquire_locks( std::vector acquire_locks(const CompactCommand &cmd, const DatabaseSnapshot *snap) { - IoPriority(IoPriorityClass::Idle); + auto idle_guard = IoPriority(IoPriorityClass::Idle); std::vector to_lock; if (cmd.get_type() == CompactType::Smart) { diff --git a/libursa/IoPrio.cpp b/libursa/IoPrio.cpp index 92d1613..151efc3 100644 --- a/libursa/IoPrio.cpp +++ b/libursa/IoPrio.cpp @@ -21,11 +21,28 @@ enum { 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); - ioprio_set(IOPRIO_WHO_PROCESS, _old_pid, (int)ioprio); + 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). diff --git a/libursa/IoPrio.h b/libursa/IoPrio.h index 9715a9a..7e14972 100644 --- a/libursa/IoPrio.h +++ b/libursa/IoPrio.h @@ -1,20 +1,8 @@ #include #include -// Copied from include/linux/ioprio.h -enum { - IOPRIO_CLASS_NONE, - IOPRIO_CLASS_RT, - IOPRIO_CLASS_BE, - IOPRIO_CLASS_IDLE, -}; - // Strongly typed wrapper for IOPRIO enum in the Linux kernel. -enum class IoPriorityClass { - Idle = IOPRIO_CLASS_IDLE, - BestEffort = IOPRIO_CLASS_BE - // IOPRIO_CLASS_RT not needed, and not defined intentionally. -}; +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.