1 /*
2    Copyright 2013-2014 EditShare, 2013-2015 Skytechnology sp. z o.o.
3 
4    This file is part of LizardFS.
5 
6    LizardFS is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation, version 3.
9 
10    LizardFS is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with LizardFS. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #pragma once
20 
21 #include "common/platform.h"
22 
23 #include <functional>
24 
25 #include "common/io_limiting.h"
26 #include "mount/mastercomm.h"
27 
28 namespace ioLimiting {
29 
30 // An object used locally in mount that communicates with a global limiter
31 // running in master
32 struct MasterLimiter : public Limiter {
33 	MasterLimiter();
34 	~MasterLimiter();
35 	// Passes a request to master
36 	uint64_t request(const IoLimitGroupId& groupId, uint64_t size) override;
37 private:
38 	class IolimitsConfigHandler : public PacketHandler {
39 	public:
IolimitsConfigHandlerMasterLimiter40 		IolimitsConfigHandler(MasterLimiter& parent) : parent_(parent) {}
41 
42 		bool handle(MessageBuffer buffer);
43 	private:
44 		MasterLimiter& parent_;
45 	};
46 
47 	IolimitsConfigHandler iolimitsConfigHandler_;
48 	uint32_t configVersion_;
49 };
50 
51 // The local limiter running in this mount instance (used in local I/O limiting)
52 struct MountLimiter : public Limiter {
53 	uint64_t request(const IoLimitGroupId& groupId, uint64_t size) override;
54 	void loadConfiguration(const IoLimitsConfigLoader& config);
55 private:
56 	IoLimitsDatabase database_;
57 };
58 
59 // This class is a proxy that locally handles calls to a possibly remote Limiter.
60 // It classifies clients into groups and performs required delays.
61 class LimiterProxy {
62 public:
LimiterProxy(Limiter & limiter,Clock & clock)63 	LimiterProxy(Limiter& limiter, Clock& clock) :
64 		shared_(limiter, std::chrono::milliseconds(100)),
65 		enabled_(true),
66 		clock_(clock)
67 	{
68 		using namespace std::placeholders;
69 		limiter.registerReconfigure(std::bind(
70 			&LimiterProxy::reconfigure,
71 			this,
72 			std::placeholders::_1,
73 			std::placeholders::_2,
74 			std::placeholders::_3));
75 	}
76 
77 	// Try to acquire an assignment of 'size' bytes. This method pauses a callee until a request
78 	// is satisfied or a deadline is exceeded. Return when returns MFS status
79 	uint8_t waitForRead(const pid_t pid, const uint64_t size, SteadyTimePoint deadline);
80 	// Works the same as waitForRead
81 	uint8_t waitForWrite(const pid_t pid, const uint64_t size, SteadyTimePoint deadline);
82 
83 private:
84 	typedef std::map<IoLimitGroupId, std::shared_ptr<Group>> Groups;
85 
86 	std::shared_ptr<Group> getGroup(const IoLimitGroupId& groupId) const;
87 	// Remove groups that were deleted, cancel queued operations assigned to them. Add new groups.
88 	// Update the delta_us parameter.
89 	// If subsystem was changed, cancel all queued operations and removed groups that were used.
90 	void reconfigure(uint32_t delta_us, const std::string& subsystem,
91 			const std::vector<IoLimitGroupId>& groupIds);
92 
93 	std::mutex mutex_;
94 	SharedState shared_;
95 	std::string subsystem_;
96 	Groups groups_;
97 	bool enabled_;
98 	Clock& clock_;
99 };
100 
101 } // namespace ioLimiting
102