1#pragma once
2
3#include <Disks/IDisk.h>
4#include <IO/WriteHelpers.h>
5#include <Common/CurrentMetrics.h>
6#include <Common/Exception.h>
7#include <Common/formatReadable.h>
8#include <common/logger_useful.h>
9
10#include <memory>
11#include <mutex>
12#include <unistd.h>
13#include <boost/noncopyable.hpp>
14#include <Poco/Util/AbstractConfiguration.h>
15
16
17namespace DB
18{
19namespace ErrorCodes
20{
21 extern const int LOGICAL_ERROR;
22 extern const int NOT_ENOUGH_SPACE;
23 extern const int NOT_IMPLEMENTED;
24 extern const int SYSTEM_ERROR;
25 extern const int UNKNOWN_ELEMENT_IN_CONFIG;
26 extern const int EXCESSIVE_ELEMENT_IN_CONFIG;
27 extern const int UNKNOWN_POLICY;
28 extern const int UNKNOWN_DISK;
29}
30
31/// Parse .xml configuration and store information about disks
32/// Mostly used for introspection.
33class DiskSelector
34{
35public:
36 DiskSelector(const Poco::Util::AbstractConfiguration & config, const String & config_prefix, const Context & context);
37
38 /// Get disk by name
39 const DiskPtr & operator[](const String & name) const;
40
41 /// Get all disks with names
42 const auto & getDisksMap() const { return disks; }
43
44private:
45 std::map<String, DiskPtr> disks;
46};
47
48/**
49 * Disks group by some (user) criteria. For example,
50 * - Volume("slow_disks", [d1, d2], 100)
51 * - Volume("fast_disks", [d3, d4], 200)
52 * Cannot store parts larger than max_data_part_size.
53 */
54class Volume : public Space
55{
56 friend class StoragePolicy;
57
58public:
59 Volume(String name_, std::vector<DiskPtr> disks_, UInt64 max_data_part_size_)
60 : max_data_part_size(max_data_part_size_), disks(std::move(disks_)), name(std::move(name_))
61 {
62 }
63
64 Volume(
65 String name_,
66 const Poco::Util::AbstractConfiguration & config,
67 const String & config_prefix,
68 const DiskSelector & disk_selector);
69
70 /// Uses Round-robin to choose disk for reservation.
71 /// Returns valid reservation or nullptr if there is no space left on any disk.
72 ReservationPtr reserve(UInt64 bytes) override;
73
74 /// Return biggest unreserved space across all disks
75 UInt64 getMaxUnreservedFreeSpace() const;
76
77 /// Volume name from config
78 const String & getName() const override { return name; }
79
80 /// Max size of reservation
81 UInt64 max_data_part_size = 0;
82
83 /// Disks in volume
84 Disks disks;
85
86private:
87 mutable std::atomic<size_t> last_used = 0;
88 const String name;
89};
90
91using VolumePtr = std::shared_ptr<Volume>;
92using Volumes = std::vector<VolumePtr>;
93
94
95/**
96 * Contains all information about volumes configuration for Storage.
97 * Can determine appropriate Volume and Disk for each reservation.
98 */
99class StoragePolicy
100{
101public:
102 StoragePolicy(String name_, const Poco::Util::AbstractConfiguration & config, const String & config_prefix, const DiskSelector & disks);
103
104 StoragePolicy(String name_, Volumes volumes_, double move_factor_);
105
106 bool isDefaultPolicy() const;
107
108 /// Returns disks ordered by volumes priority
109 Disks getDisks() const;
110
111 /// Returns any disk
112 /// Used when it's not important, for example for
113 /// mutations files
114 DiskPtr getAnyDisk() const;
115
116 DiskPtr getDiskByName(const String & disk_name) const;
117
118 /// Get free space from most free disk
119 UInt64 getMaxUnreservedFreeSpace() const;
120
121 const String & getName() const { return name; }
122
123 /// Returns valid reservation or null
124 ReservationPtr reserve(UInt64 bytes) const;
125
126 /// Reserve space on any volume with index > min_volume_index
127 ReservationPtr reserve(UInt64 bytes, size_t min_volume_index) const;
128
129 /// Find volume index, which contains disk
130 size_t getVolumeIndexByDisk(const DiskPtr & disk_ptr) const;
131
132 /// Reserves 0 bytes on disk with max available space
133 /// Do not use this function when it is possible to predict size.
134 ReservationPtr makeEmptyReservationOnLargestDisk() const;
135
136 const Volumes & getVolumes() const { return volumes; }
137
138 /// Returns number [0., 1.] -- fraction of free space on disk
139 /// which should be kept with help of background moves
140 double getMoveFactor() const { return move_factor; }
141
142 /// Get volume by index from storage_policy
143 VolumePtr getVolume(size_t i) const { return (i < volumes_names.size() ? volumes[i] : VolumePtr()); }
144
145 VolumePtr getVolumeByName(const String & volume_name) const
146 {
147 auto it = volumes_names.find(volume_name);
148 if (it == volumes_names.end())
149 return {};
150 return getVolume(it->second);
151 }
152
153private:
154 Volumes volumes;
155 const String name;
156 std::map<String, size_t> volumes_names;
157
158 /// move_factor from interval [0., 1.]
159 /// We move something if disk from this policy
160 /// filled more than total_size * move_factor
161 double move_factor = 0.1; /// by default move factor is 10%
162};
163
164
165using StoragePolicyPtr = std::shared_ptr<const StoragePolicy>;
166
167/// Parse .xml configuration and store information about policies
168/// Mostly used for introspection.
169class StoragePolicySelector
170{
171public:
172 StoragePolicySelector(const Poco::Util::AbstractConfiguration & config, const String & config_prefix, const DiskSelector & disks);
173
174 /// Policy by name
175 const StoragePolicyPtr & operator[](const String & name) const;
176
177 /// All policies
178 const std::map<String, StoragePolicyPtr> & getPoliciesMap() const { return policies; }
179
180private:
181 std::map<String, StoragePolicyPtr> policies;
182};
183
184}
185