Skip to content

Commit 18203e8

Browse files
Merge pull request ClickHouse#88459 from ClickHouse/backport/25.8/88217
Backport ClickHouse#88217 to 25.8: max_cpu_share alone should determine the hard cap in a workload setting, even if max_cpus is unset
2 parents 0b7fb42 + 02e8bae commit 18203e8

File tree

8 files changed

+68
-6
lines changed

8 files changed

+68
-6
lines changed

src/Common/Scheduler/IResourceManager.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include <Common/Scheduler/ResourceLink.h>
4+
#include <Common/Scheduler/WorkloadSettings.h>
45

56
#include <Poco/Util/AbstractConfiguration.h>
67

@@ -37,6 +38,8 @@ class IClassifier : private boost::noncopyable
3738
/// Returns ResourceLink that should be used to access resource.
3839
/// Returned link is valid until classifier destruction.
3940
virtual ResourceLink get(const String & resource_name) = 0;
41+
/// Returns settings that should be used to limit workload on given resource.
42+
virtual WorkloadSettings getWorkloadSettings(const String & resource_name) const = 0;
4043
};
4144

4245
using ClassifierPtr = std::shared_ptr<IClassifier>;

src/Common/Scheduler/Nodes/CustomResourceManager.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,12 @@ ResourceLink CustomResourceManager::Classifier::get(const String & resource_name
177177
return ResourceLink{}; // unlimited access
178178
}
179179

180+
WorkloadSettings CustomResourceManager::Classifier::getWorkloadSettings(const String & resource_name) const
181+
{
182+
UNUSED(resource_name);
183+
return {};
184+
}
185+
180186
CustomResourceManager::CustomResourceManager()
181187
: state(new State())
182188
{

src/Common/Scheduler/Nodes/CustomResourceManager.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class CustomResourceManager : public IResourceManager
8484
Classifier(const ClassifierSettings & settings_, const StatePtr & state_, const String & classifier_name);
8585
bool has(const String & resource_name) override;
8686
ResourceLink get(const String & resource_name) override;
87+
WorkloadSettings getWorkloadSettings(const String & resource_name) const override;
8788
private:
8889
const ClassifierSettings settings;
8990
std::unordered_map<String, ResourceLink> resources; // accessible resources by names

src/Common/Scheduler/Nodes/WorkloadResourceManager.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -423,11 +423,32 @@ ResourceLink WorkloadResourceManager::Classifier::get(const String & resource_na
423423
}
424424
}
425425

426-
void WorkloadResourceManager::Classifier::attach(const ResourcePtr & resource, const VersionPtr & version, ResourceLink link)
426+
WorkloadSettings WorkloadResourceManager::Classifier::getWorkloadSettings(const String & resource_name) const
427+
{
428+
std::unique_lock lock{mutex};
429+
auto iter = attachments.find(resource_name);
430+
if (iter != attachments.end())
431+
{
432+
// Extract settings from the attached resource
433+
return iter->second.settings;
434+
}
435+
return {};
436+
}
437+
438+
void WorkloadResourceManager::Classifier::attach(const ResourcePtr & resource, const VersionPtr & version, UnifiedSchedulerNode * node)
427439
{
428440
std::unique_lock lock{mutex};
429441
chassert(!attachments.contains(resource->getName()));
430-
attachments[resource->getName()] = Attachment{.resource = resource, .version = version, .link = link};
442+
ResourceLink link;
443+
WorkloadSettings wl_settings{};
444+
if (node)
445+
{
446+
auto queue = node->getQueue();
447+
if (queue)
448+
link = ResourceLink{.queue = queue.get()};
449+
wl_settings = node->getSettings();
450+
}
451+
attachments[resource->getName()] = Attachment{.resource = resource, .version = version, .link = link, .settings = wl_settings};
431452
}
432453

433454
void WorkloadResourceManager::Resource::updateResource(const ASTPtr & new_resource_entity)
@@ -447,11 +468,12 @@ std::future<void> WorkloadResourceManager::Resource::attachClassifier(Classifier
447468
{
448469
if (auto iter = node_for_workload.find(workload_name); iter != node_for_workload.end())
449470
{
471+
auto nodePtr = iter->second;
450472
auto queue = iter->second->getQueue();
451473
if (!queue)
452474
throw Exception(ErrorCodes::INVALID_SCHEDULER_NODE, "Unable to use workload '{}' that have children for resource '{}'",
453475
workload_name, resource_name);
454-
classifier.attach(shared_from_this(), current_version, ResourceLink{.queue = queue.get()});
476+
classifier.attach(shared_from_this(), current_version, nodePtr.get());
455477
}
456478
else
457479
{

src/Common/Scheduler/Nodes/WorkloadResourceManager.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,21 +241,23 @@ class WorkloadResourceManager : public IResourceManager
241241
/// NOTE: It is called from query threads (possibly multiple)
242242
bool has(const String & resource_name) override;
243243
ResourceLink get(const String & resource_name) override;
244+
WorkloadSettings getWorkloadSettings(const String & resource_name) const override;
244245

245246
/// Attaches/detaches a specific resource
246247
/// NOTE: It is called from scheduler threads (possibly multiple)
247-
void attach(const ResourcePtr & resource, const VersionPtr & version, ResourceLink link);
248+
void attach(const ResourcePtr & resource, const VersionPtr & version, UnifiedSchedulerNode * node);
248249
void detach(const ResourcePtr & resource);
249250

250251
private:
251252
const ClassifierSettings settings;
252253
WorkloadResourceManager * resource_manager;
253-
std::mutex mutex;
254+
mutable std::mutex mutex;
254255
struct Attachment
255256
{
256257
ResourcePtr resource;
257258
VersionPtr version;
258259
ResourceLink link;
260+
WorkloadSettings settings;
259261
};
260262
std::unordered_map<String, Attachment> attachments; // TSA_GUARDED_BY(mutex);
261263
};

src/Common/Scheduler/Nodes/tests/gtest_workload_resource_manager.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <Common/Scheduler/Nodes/tests/ResourceTest.h>
1919
#include <Common/Scheduler/Workload/WorkloadEntityStorageBase.h>
2020
#include <Common/Scheduler/Nodes/WorkloadResourceManager.h>
21+
#include <Common/getNumberOfCPUCoresToUse.h>
2122

2223
#include <base/scope_guard.h>
2324

@@ -1268,6 +1269,23 @@ TEST(SchedulerWorkloadResourceManager, CPUSchedulingIndependentPools)
12681269
t.wait();
12691270
}
12701271

1272+
TEST(SchedulerWorkloadResourceManager, MaxCPUsDerivedFromShare)
1273+
{
1274+
ResourceTest t;
1275+
1276+
t.query("CREATE RESOURCE cpu (MASTER THREAD, WORKER THREAD)");
1277+
// Only max_cpu_share is set, max_cpus is unset
1278+
t.query("CREATE WORKLOAD all SETTINGS max_cpu_share = 0.5");
1279+
ClassifierPtr c = t.manager->acquire("all");
1280+
1281+
// The expected hard cap is max_cpu_share * getNumberOfCPUCoresToUse()
1282+
WorkloadSettings settings = c->getWorkloadSettings("cpu");
1283+
double expected_cap = 0.5 * getNumberOfCPUCoresToUse();
1284+
double actual_cap = settings.max_cpus;
1285+
1286+
EXPECT_DOUBLE_EQ(actual_cap, expected_cap);
1287+
}
1288+
12711289
auto getAcquired()
12721290
{
12731291
return CurrentMetrics::get(CurrentMetrics::ConcurrencyControlAcquired);

src/Common/Scheduler/WorkloadSettings.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ void WorkloadSettings::initFromChanges(CostUnit unit_, const ASTCreateWorkloadQu
232232
if (share_limit > 0)
233233
{
234234
Float64 value = share_limit * getNumberOfCPUCoresToUse();
235-
if (value > 0 && value < limit)
235+
if (value > 0 && (limit == 0 || value < limit))
236236
limit = value;
237237
}
238238
max_cpus = limit;

src/Common/Scheduler/createResourceManager.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ class ResourceManagerDispatcher : public IResourceManager
5555
return ResourceLink{};
5656
}
5757

58+
WorkloadSettings getWorkloadSettings(const String & resource_name) const override
59+
{
60+
for (const auto & classifier : classifiers)
61+
{
62+
if (classifier->has(resource_name))
63+
return classifier->getWorkloadSettings(resource_name);
64+
}
65+
return {};
66+
}
67+
5868
private:
5969
const ClassifierSettings settings;
6070
std::vector<ClassifierPtr> classifiers; // should be constant after initialization to avoid races

0 commit comments

Comments
 (0)