| 1 | #pragma once |
| 2 | |
| 3 | #include <Common/SimpleIncrement.h> |
| 4 | #include <Interpreters/Context.h> |
| 5 | #include <Interpreters/ExpressionActions.h> |
| 6 | #include <Storages/IStorage.h> |
| 7 | #include <Storages/MergeTree/MergeTreeIndices.h> |
| 8 | #include <Storages/MergeTree/MergeTreePartInfo.h> |
| 9 | #include <Storages/MergeTree/MergeTreeSettings.h> |
| 10 | #include <Storages/MergeTree/MergeTreeMutationStatus.h> |
| 11 | #include <Storages/MergeTree/MergeList.h> |
| 12 | #include <Storages/MergeTree/PartDestinationType.h> |
| 13 | #include <IO/ReadBufferFromString.h> |
| 14 | #include <IO/WriteBufferFromFile.h> |
| 15 | #include <IO/ReadBufferFromFile.h> |
| 16 | #include <DataTypes/DataTypeString.h> |
| 17 | #include <DataTypes/DataTypesNumber.h> |
| 18 | #include <DataStreams/GraphiteRollupSortedBlockInputStream.h> |
| 19 | #include <Storages/MergeTree/MergeTreeDataPart.h> |
| 20 | #include <Storages/IndicesDescription.h> |
| 21 | #include <Storages/MergeTree/MergeTreePartsMover.h> |
| 22 | #include <Interpreters/PartLog.h> |
| 23 | #include <Disks/DiskSpaceMonitor.h> |
| 24 | |
| 25 | #include <boost/multi_index_container.hpp> |
| 26 | #include <boost/multi_index/ordered_index.hpp> |
| 27 | #include <boost/multi_index/global_fun.hpp> |
| 28 | #include <boost/range/iterator_range_core.hpp> |
| 29 | |
| 30 | |
| 31 | namespace DB |
| 32 | { |
| 33 | |
| 34 | class MergeListEntry; |
| 35 | class AlterCommands; |
| 36 | class MergeTreePartsMover; |
| 37 | |
| 38 | namespace ErrorCodes |
| 39 | { |
| 40 | extern const int LOGICAL_ERROR; |
| 41 | extern const int INVALID_PARTITION_NAME; |
| 42 | extern const int NO_SUCH_DATA_PART; |
| 43 | extern const int DUPLICATE_DATA_PART; |
| 44 | extern const int DIRECTORY_ALREADY_EXISTS; |
| 45 | extern const int TOO_MANY_UNEXPECTED_DATA_PARTS; |
| 46 | extern const int NO_SUCH_COLUMN_IN_TABLE; |
| 47 | extern const int TABLE_DIFFERS_TOO_MUCH; |
| 48 | } |
| 49 | |
| 50 | |
| 51 | /// Data structure for *MergeTree engines. |
| 52 | /// Merge tree is used for incremental sorting of data. |
| 53 | /// The table consists of several sorted parts. |
| 54 | /// During insertion new data is sorted according to the primary key and is written to the new part. |
| 55 | /// Parts are merged in the background according to a heuristic algorithm. |
| 56 | /// For each part the index file is created containing primary key values for every n-th row. |
| 57 | /// This allows efficient selection by primary key range predicate. |
| 58 | /// |
| 59 | /// Additionally: |
| 60 | /// |
| 61 | /// The date column is specified. For each part min and max dates are remembered. |
| 62 | /// Essentially it is an index too. |
| 63 | /// |
| 64 | /// Data is partitioned by the value of the partitioning expression. |
| 65 | /// Parts belonging to different partitions are not merged - for the ease of administration (data sync and backup). |
| 66 | /// |
| 67 | /// File structure of old-style month-partitioned tables (format_version = 0): |
| 68 | /// Part directory - / min-date _ max-date _ min-id _ max-id _ level / |
| 69 | /// Inside the part directory: |
| 70 | /// checksums.txt - contains the list of all files along with their sizes and checksums. |
| 71 | /// columns.txt - contains the list of all columns and their types. |
| 72 | /// primary.idx - contains the primary index. |
| 73 | /// [Column].bin - contains compressed column data. |
| 74 | /// [Column].mrk - marks, pointing to seek positions allowing to skip n * k rows. |
| 75 | /// |
| 76 | /// File structure of tables with custom partitioning (format_version >= 1): |
| 77 | /// Part directory - / partiiton-id _ min-id _ max-id _ level / |
| 78 | /// Inside the part directory: |
| 79 | /// The same files as for month-partitioned tables, plus |
| 80 | /// count.txt - contains total number of rows in this part. |
| 81 | /// partition.dat - contains the value of the partitioning expression. |
| 82 | /// minmax_[Column].idx - MinMax indexes (see MergeTreeDataPart::MinMaxIndex class) for the columns required by the partitioning expression. |
| 83 | /// |
| 84 | /// Several modes are implemented. Modes determine additional actions during merge: |
| 85 | /// - Ordinary - don't do anything special |
| 86 | /// - Collapsing - collapse pairs of rows with the opposite values of sign_columns for the same values |
| 87 | /// of primary key (cf. CollapsingSortedBlockInputStream.h) |
| 88 | /// - Replacing - for all rows with the same primary key keep only the latest one. Or, if the version |
| 89 | /// column is set, keep the latest row with the maximal version. |
| 90 | /// - Summing - sum all numeric columns not contained in the primary key for all rows with the same primary key. |
| 91 | /// - Aggregating - merge columns containing aggregate function states for all rows with the same primary key. |
| 92 | /// - Graphite - performs coarsening of historical data for Graphite (a system for quantitative monitoring). |
| 93 | |
| 94 | /// The MergeTreeData class contains a list of parts and the data structure parameters. |
| 95 | /// To read and modify the data use other classes: |
| 96 | /// - MergeTreeDataSelectExecutor |
| 97 | /// - MergeTreeDataWriter |
| 98 | /// - MergeTreeDataMergerMutator |
| 99 | |
| 100 | class MergeTreeData : public IStorage |
| 101 | { |
| 102 | public: |
| 103 | /// Function to call if the part is suspected to contain corrupt data. |
| 104 | using BrokenPartCallback = std::function<void (const String &)>; |
| 105 | using DataPart = MergeTreeDataPart; |
| 106 | |
| 107 | using MutableDataPartPtr = std::shared_ptr<DataPart>; |
| 108 | using MutableDataPartsVector = std::vector<MutableDataPartPtr>; |
| 109 | /// After the DataPart is added to the working set, it cannot be changed. |
| 110 | using DataPartPtr = std::shared_ptr<const DataPart>; |
| 111 | |
| 112 | using DataPartState = MergeTreeDataPart::State; |
| 113 | using DataPartStates = std::initializer_list<DataPartState>; |
| 114 | using DataPartStateVector = std::vector<DataPartState>; |
| 115 | |
| 116 | /// Auxiliary structure for index comparison. Keep in mind lifetime of MergeTreePartInfo. |
| 117 | struct DataPartStateAndInfo |
| 118 | { |
| 119 | DataPartState state; |
| 120 | const MergeTreePartInfo & info; |
| 121 | }; |
| 122 | |
| 123 | /// Auxiliary structure for index comparison |
| 124 | struct DataPartStateAndPartitionID |
| 125 | { |
| 126 | DataPartState state; |
| 127 | String partition_id; |
| 128 | }; |
| 129 | |
| 130 | STRONG_TYPEDEF(String, PartitionID) |
| 131 | |
| 132 | struct LessDataPart |
| 133 | { |
| 134 | using is_transparent = void; |
| 135 | |
| 136 | bool operator()(const DataPartPtr & lhs, const MergeTreePartInfo & rhs) const { return lhs->info < rhs; } |
| 137 | bool operator()(const MergeTreePartInfo & lhs, const DataPartPtr & rhs) const { return lhs < rhs->info; } |
| 138 | bool operator()(const DataPartPtr & lhs, const DataPartPtr & rhs) const { return lhs->info < rhs->info; } |
| 139 | bool operator()(const MergeTreePartInfo & lhs, const PartitionID & rhs) const { return lhs.partition_id < rhs.toUnderType(); } |
| 140 | bool operator()(const PartitionID & lhs, const MergeTreePartInfo & rhs) const { return lhs.toUnderType() < rhs.partition_id; } |
| 141 | }; |
| 142 | |
| 143 | struct LessStateDataPart |
| 144 | { |
| 145 | using is_transparent = void; |
| 146 | |
| 147 | bool operator() (const DataPartStateAndInfo & lhs, const DataPartStateAndInfo & rhs) const |
| 148 | { |
| 149 | return std::forward_as_tuple(static_cast<UInt8>(lhs.state), lhs.info) |
| 150 | < std::forward_as_tuple(static_cast<UInt8>(rhs.state), rhs.info); |
| 151 | } |
| 152 | |
| 153 | bool operator() (DataPartStateAndInfo info, const DataPartState & state) const |
| 154 | { |
| 155 | return static_cast<size_t>(info.state) < static_cast<size_t>(state); |
| 156 | } |
| 157 | |
| 158 | bool operator() (const DataPartState & state, DataPartStateAndInfo info) const |
| 159 | { |
| 160 | return static_cast<size_t>(state) < static_cast<size_t>(info.state); |
| 161 | } |
| 162 | |
| 163 | bool operator() (const DataPartStateAndInfo & lhs, const DataPartStateAndPartitionID & rhs) const |
| 164 | { |
| 165 | return std::forward_as_tuple(static_cast<UInt8>(lhs.state), lhs.info.partition_id) |
| 166 | < std::forward_as_tuple(static_cast<UInt8>(rhs.state), rhs.partition_id); |
| 167 | } |
| 168 | |
| 169 | bool operator() (const DataPartStateAndPartitionID & lhs, const DataPartStateAndInfo & rhs) const |
| 170 | { |
| 171 | return std::forward_as_tuple(static_cast<UInt8>(lhs.state), lhs.partition_id) |
| 172 | < std::forward_as_tuple(static_cast<UInt8>(rhs.state), rhs.info.partition_id); |
| 173 | } |
| 174 | }; |
| 175 | |
| 176 | using DataParts = std::set<DataPartPtr, LessDataPart>; |
| 177 | using DataPartsVector = std::vector<DataPartPtr>; |
| 178 | |
| 179 | using DataPartsLock = std::unique_lock<std::mutex>; |
| 180 | DataPartsLock lockParts() const { return DataPartsLock(data_parts_mutex); } |
| 181 | |
| 182 | /// Auxiliary object to add a set of parts into the working set in two steps: |
| 183 | /// * First, as PreCommitted parts (the parts are ready, but not yet in the active set). |
| 184 | /// * Next, if commit() is called, the parts are added to the active set and the parts that are |
| 185 | /// covered by them are marked Outdated. |
| 186 | /// If neither commit() nor rollback() was called, the destructor rollbacks the operation. |
| 187 | class Transaction : private boost::noncopyable |
| 188 | { |
| 189 | public: |
| 190 | Transaction(MergeTreeData & data_) : data(data_) {} |
| 191 | |
| 192 | DataPartsVector commit(MergeTreeData::DataPartsLock * acquired_parts_lock = nullptr); |
| 193 | |
| 194 | void rollback(); |
| 195 | |
| 196 | size_t size() const { return precommitted_parts.size(); } |
| 197 | bool isEmpty() const { return precommitted_parts.empty(); } |
| 198 | |
| 199 | ~Transaction() |
| 200 | { |
| 201 | try |
| 202 | { |
| 203 | rollback(); |
| 204 | } |
| 205 | catch (...) |
| 206 | { |
| 207 | tryLogCurrentException("~MergeTreeData::Transaction" ); |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | private: |
| 212 | friend class MergeTreeData; |
| 213 | |
| 214 | MergeTreeData & data; |
| 215 | DataParts precommitted_parts; |
| 216 | |
| 217 | void clear() { precommitted_parts.clear(); } |
| 218 | }; |
| 219 | |
| 220 | /// An object that stores the names of temporary files created in the part directory during ALTER of its |
| 221 | /// columns. |
| 222 | class AlterDataPartTransaction : private boost::noncopyable |
| 223 | { |
| 224 | public: |
| 225 | /// Renames temporary files, finishing the ALTER of the part. |
| 226 | void commit(); |
| 227 | |
| 228 | /// If commit() was not called, deletes temporary files, canceling the ALTER. |
| 229 | ~AlterDataPartTransaction(); |
| 230 | |
| 231 | const String & getPartName() const { return data_part->name; } |
| 232 | |
| 233 | /// Review the changes before the commit. |
| 234 | const NamesAndTypesList & getNewColumns() const { return new_columns; } |
| 235 | const DataPart::Checksums & getNewChecksums() const { return new_checksums; } |
| 236 | |
| 237 | AlterDataPartTransaction(DataPartPtr data_part_) : data_part(data_part_) {} |
| 238 | const DataPartPtr & getDataPart() const { return data_part; } |
| 239 | bool isValid() const; |
| 240 | |
| 241 | private: |
| 242 | friend class MergeTreeData; |
| 243 | void clear(); |
| 244 | |
| 245 | bool valid = true; |
| 246 | |
| 247 | DataPartPtr data_part; |
| 248 | |
| 249 | DataPart::Checksums new_checksums; |
| 250 | NamesAndTypesList new_columns; |
| 251 | /// If the value is an empty string, the file is not temporary, and it must be deleted. |
| 252 | NameToNameMap rename_map; |
| 253 | }; |
| 254 | |
| 255 | using AlterDataPartTransactionPtr = std::unique_ptr<AlterDataPartTransaction>; |
| 256 | |
| 257 | struct PartsTemporaryRename : private boost::noncopyable |
| 258 | { |
| 259 | PartsTemporaryRename( |
| 260 | const MergeTreeData & storage_, |
| 261 | const String & source_dir_) |
| 262 | : storage(storage_) |
| 263 | , source_dir(source_dir_) |
| 264 | { |
| 265 | } |
| 266 | |
| 267 | void addPart(const String & old_name, const String & new_name); |
| 268 | |
| 269 | /// Renames part from old_name to new_name |
| 270 | void tryRenameAll(); |
| 271 | |
| 272 | /// Renames all added parts from new_name to old_name if old name is not empty |
| 273 | ~PartsTemporaryRename(); |
| 274 | |
| 275 | const MergeTreeData & storage; |
| 276 | const String source_dir; |
| 277 | std::vector<std::pair<String, String>> old_and_new_names; |
| 278 | std::unordered_map<String, String> old_part_name_to_full_path; |
| 279 | bool renamed = false; |
| 280 | }; |
| 281 | |
| 282 | /// Parameters for various modes. |
| 283 | struct MergingParams |
| 284 | { |
| 285 | /// Merging mode. See above. |
| 286 | enum Mode |
| 287 | { |
| 288 | Ordinary = 0, /// Enum values are saved. Do not change them. |
| 289 | Collapsing = 1, |
| 290 | Summing = 2, |
| 291 | Aggregating = 3, |
| 292 | Replacing = 5, |
| 293 | Graphite = 6, |
| 294 | VersionedCollapsing = 7, |
| 295 | }; |
| 296 | |
| 297 | Mode mode; |
| 298 | |
| 299 | /// For Collapsing and VersionedCollapsing mode. |
| 300 | String sign_column; |
| 301 | |
| 302 | /// For Summing mode. If empty - columns_to_sum is determined automatically. |
| 303 | Names columns_to_sum; |
| 304 | |
| 305 | /// For Replacing and VersionedCollapsing mode. Can be empty for Replacing. |
| 306 | String version_column; |
| 307 | |
| 308 | /// For Graphite mode. |
| 309 | Graphite::Params graphite_params; |
| 310 | |
| 311 | /// Check that needed columns are present and have correct types. |
| 312 | void check(const NamesAndTypesList & columns) const; |
| 313 | |
| 314 | String getModeName() const; |
| 315 | }; |
| 316 | |
| 317 | /// Attach the table corresponding to the directory in full_path inside policy (must end with /), with the given columns. |
| 318 | /// Correctness of names and paths is not checked. |
| 319 | /// |
| 320 | /// date_column_name - if not empty, the name of the Date column used for partitioning by month. |
| 321 | /// Otherwise, partition_by_ast is used for partitioning. |
| 322 | /// |
| 323 | /// order_by_ast - a single expression or a tuple. It is used as a sorting key |
| 324 | /// (an ASTExpressionList used for sorting data in parts); |
| 325 | /// primary_key_ast - can be nullptr, an expression, or a tuple. |
| 326 | /// Used to determine an ASTExpressionList values of which are written in the primary.idx file |
| 327 | /// for one row in every `index_granularity` rows to speed up range queries. |
| 328 | /// Primary key must be a prefix of the sorting key; |
| 329 | /// If it is nullptr, then it will be determined from order_by_ast. |
| 330 | /// |
| 331 | /// require_part_metadata - should checksums.txt and columns.txt exist in the part directory. |
| 332 | /// attach - whether the existing table is attached or the new table is created. |
| 333 | MergeTreeData(const String & database_, const String & table_, |
| 334 | const String & relative_data_path_, |
| 335 | const StorageInMemoryMetadata & metadata, |
| 336 | Context & context_, |
| 337 | const String & date_column_name, |
| 338 | const MergingParams & merging_params_, |
| 339 | std::unique_ptr<MergeTreeSettings> settings_, |
| 340 | bool require_part_metadata_, |
| 341 | bool attach, |
| 342 | BrokenPartCallback broken_part_callback_ = [](const String &){}); |
| 343 | |
| 344 | |
| 345 | StorageInMemoryMetadata getInMemoryMetadata() const override; |
| 346 | ASTPtr getPartitionKeyAST() const override { return partition_by_ast; } |
| 347 | ASTPtr getSortingKeyAST() const override { return sorting_key_expr_ast; } |
| 348 | ASTPtr getPrimaryKeyAST() const override { return primary_key_expr_ast; } |
| 349 | ASTPtr getSamplingKeyAST() const override { return sample_by_ast; } |
| 350 | |
| 351 | Names getColumnsRequiredForPartitionKey() const override { return (partition_key_expr ? partition_key_expr->getRequiredColumns() : Names{}); } |
| 352 | Names getColumnsRequiredForSortingKey() const override { return sorting_key_expr->getRequiredColumns(); } |
| 353 | Names getColumnsRequiredForPrimaryKey() const override { return primary_key_expr->getRequiredColumns(); } |
| 354 | Names getColumnsRequiredForSampling() const override { return columns_required_for_sampling; } |
| 355 | Names getColumnsRequiredForFinal() const override { return sorting_key_expr->getRequiredColumns(); } |
| 356 | Names getSortingKeyColumns() const override { return sorting_key_columns; } |
| 357 | |
| 358 | StoragePolicyPtr getStoragePolicy() const override { return storage_policy; } |
| 359 | |
| 360 | bool supportsPrewhere() const override { return true; } |
| 361 | bool supportsSampling() const override { return sample_by_ast != nullptr; } |
| 362 | |
| 363 | bool supportsFinal() const override |
| 364 | { |
| 365 | return merging_params.mode == MergingParams::Collapsing |
| 366 | || merging_params.mode == MergingParams::Summing |
| 367 | || merging_params.mode == MergingParams::Aggregating |
| 368 | || merging_params.mode == MergingParams::Replacing |
| 369 | || merging_params.mode == MergingParams::VersionedCollapsing; |
| 370 | } |
| 371 | |
| 372 | bool supportsSettings() const override { return true; } |
| 373 | |
| 374 | bool mayBenefitFromIndexForIn(const ASTPtr & left_in_operand, const Context &) const override; |
| 375 | |
| 376 | NameAndTypePair getColumn(const String & column_name) const override |
| 377 | { |
| 378 | if (column_name == "_part" ) |
| 379 | return NameAndTypePair("_part" , std::make_shared<DataTypeString>()); |
| 380 | if (column_name == "_part_index" ) |
| 381 | return NameAndTypePair("_part_index" , std::make_shared<DataTypeUInt64>()); |
| 382 | if (column_name == "_partition_id" ) |
| 383 | return NameAndTypePair("_partition_id" , std::make_shared<DataTypeString>()); |
| 384 | if (column_name == "_sample_factor" ) |
| 385 | return NameAndTypePair("_sample_factor" , std::make_shared<DataTypeFloat64>()); |
| 386 | |
| 387 | return getColumns().getPhysical(column_name); |
| 388 | } |
| 389 | |
| 390 | bool hasColumn(const String & column_name) const override |
| 391 | { |
| 392 | return getColumns().hasPhysical(column_name) |
| 393 | || column_name == "_part" |
| 394 | || column_name == "_part_index" |
| 395 | || column_name == "_partition_id" |
| 396 | || column_name == "_sample_factor" ; |
| 397 | } |
| 398 | |
| 399 | String getDatabaseName() const override { return database_name; } |
| 400 | String getTableName() const override { return table_name; } |
| 401 | |
| 402 | /// Load the set of data parts from disk. Call once - immediately after the object is created. |
| 403 | void loadDataParts(bool skip_sanity_checks); |
| 404 | |
| 405 | String getLogName() const { return log_name; } |
| 406 | |
| 407 | Int64 getMaxBlockNumber() const; |
| 408 | |
| 409 | /// Returns a copy of the list so that the caller shouldn't worry about locks. |
| 410 | DataParts getDataParts(const DataPartStates & affordable_states) const; |
| 411 | /// Returns sorted list of the parts with specified states |
| 412 | /// out_states will contain snapshot of each part state |
| 413 | DataPartsVector getDataPartsVector(const DataPartStates & affordable_states, DataPartStateVector * out_states = nullptr) const; |
| 414 | |
| 415 | /// Returns absolutely all parts (and snapshot of their states) |
| 416 | DataPartsVector getAllDataPartsVector(DataPartStateVector * out_states = nullptr) const; |
| 417 | |
| 418 | /// Returns all detached parts |
| 419 | DetachedPartsInfo getDetachedParts() const; |
| 420 | |
| 421 | void validateDetachedPartName(const String & name) const; |
| 422 | |
| 423 | void dropDetached(const ASTPtr & partition, bool part, const Context & context); |
| 424 | |
| 425 | MutableDataPartsVector tryLoadPartsToAttach(const ASTPtr & partition, bool attach_part, |
| 426 | const Context & context, PartsTemporaryRename & renamed_parts); |
| 427 | |
| 428 | /// Returns Committed parts |
| 429 | DataParts getDataParts() const; |
| 430 | DataPartsVector getDataPartsVector() const; |
| 431 | |
| 432 | /// Returns a committed part with the given name or a part containing it. If there is no such part, returns nullptr. |
| 433 | DataPartPtr getActiveContainingPart(const String & part_name) const; |
| 434 | DataPartPtr getActiveContainingPart(const MergeTreePartInfo & part_info) const; |
| 435 | DataPartPtr getActiveContainingPart(const MergeTreePartInfo & part_info, DataPartState state, DataPartsLock & lock) const; |
| 436 | |
| 437 | /// Swap part with it's identical copy (possible with another path on another disk). |
| 438 | /// If original part is not active or doesn't exist exception will be thrown. |
| 439 | void swapActivePart(MergeTreeData::DataPartPtr part_copy); |
| 440 | |
| 441 | /// Returns all parts in specified partition |
| 442 | DataPartsVector getDataPartsVectorInPartition(DataPartState state, const String & partition_id); |
| 443 | |
| 444 | /// Returns the part with the given name and state or nullptr if no such part. |
| 445 | DataPartPtr getPartIfExists(const String & part_name, const DataPartStates & valid_states); |
| 446 | DataPartPtr getPartIfExists(const MergeTreePartInfo & part_info, const DataPartStates & valid_states); |
| 447 | |
| 448 | /// Total size of active parts in bytes. |
| 449 | size_t getTotalActiveSizeInBytes() const; |
| 450 | |
| 451 | size_t getTotalActiveSizeInRows() const; |
| 452 | |
| 453 | size_t getPartsCount() const; |
| 454 | size_t getMaxPartsCountForPartition() const; |
| 455 | |
| 456 | /// Get min value of part->info.getDataVersion() for all active parts. |
| 457 | /// Makes sense only for ordinary MergeTree engines because for them block numbering doesn't depend on partition. |
| 458 | std::optional<Int64> getMinPartDataVersion() const; |
| 459 | |
| 460 | /// If the table contains too many active parts, sleep for a while to give them time to merge. |
| 461 | /// If until is non-null, wake up from the sleep earlier if the event happened. |
| 462 | void delayInsertOrThrowIfNeeded(Poco::Event * until = nullptr) const; |
| 463 | void throwInsertIfNeeded() const; |
| 464 | |
| 465 | /// Renames temporary part to a permanent part and adds it to the parts set. |
| 466 | /// It is assumed that the part does not intersect with existing parts. |
| 467 | /// If increment != nullptr, part index is determing using increment. Otherwise part index remains unchanged. |
| 468 | /// If out_transaction != nullptr, adds the part in the PreCommitted state (the part will be added to the |
| 469 | /// active set later with out_transaction->commit()). |
| 470 | /// Else, commits the part immediately. |
| 471 | void renameTempPartAndAdd(MutableDataPartPtr & part, SimpleIncrement * increment = nullptr, Transaction * out_transaction = nullptr); |
| 472 | |
| 473 | /// The same as renameTempPartAndAdd but the block range of the part can contain existing parts. |
| 474 | /// Returns all parts covered by the added part (in ascending order). |
| 475 | /// If out_transaction == nullptr, marks covered parts as Outdated. |
| 476 | DataPartsVector renameTempPartAndReplace( |
| 477 | MutableDataPartPtr & part, SimpleIncrement * increment = nullptr, Transaction * out_transaction = nullptr); |
| 478 | |
| 479 | /// Low-level version of previous one, doesn't lock mutex |
| 480 | void renameTempPartAndReplace( |
| 481 | MutableDataPartPtr & part, SimpleIncrement * increment, Transaction * out_transaction, DataPartsLock & lock, |
| 482 | DataPartsVector * out_covered_parts = nullptr); |
| 483 | |
| 484 | /// Removes parts from the working set parts. |
| 485 | /// Parts in add must already be in data_parts with PreCommitted, Committed, or Outdated states. |
| 486 | /// If clear_without_timeout is true, the parts will be deleted at once, or during the next call to |
| 487 | /// clearOldParts (ignoring old_parts_lifetime). |
| 488 | void removePartsFromWorkingSet(const DataPartsVector & remove, bool clear_without_timeout, DataPartsLock * acquired_lock = nullptr); |
| 489 | void removePartsFromWorkingSet(const DataPartsVector & remove, bool clear_without_timeout, DataPartsLock & acquired_lock); |
| 490 | |
| 491 | /// Removes all parts from the working set parts |
| 492 | /// for which (partition_id = drop_range.partition_id && min_block >= drop_range.min_block && max_block <= drop_range.max_block). |
| 493 | /// If a part intersecting drop_range.max_block is found, an exception will be thrown. |
| 494 | /// Used in REPLACE PARTITION command; |
| 495 | DataPartsVector removePartsInRangeFromWorkingSet(const MergeTreePartInfo & drop_range, bool clear_without_timeout, |
| 496 | bool skip_intersecting_parts, DataPartsLock & lock); |
| 497 | |
| 498 | /// Renames the part to detached/<prefix>_<part> and removes it from working set. |
| 499 | void removePartsFromWorkingSetAndCloneToDetached(const DataPartsVector & parts, bool clear_without_timeout, const String & prefix = "" ); |
| 500 | |
| 501 | /// Renames the part to detached/<prefix>_<part> and removes it from data_parts, |
| 502 | //// so it will not be deleted in clearOldParts. |
| 503 | /// If restore_covered is true, adds to the working set inactive parts, which were merged into the deleted part. |
| 504 | void forgetPartAndMoveToDetached(const DataPartPtr & part, const String & prefix = "" , bool restore_covered = false); |
| 505 | |
| 506 | /// If the part is Obsolete and not used by anybody else, immediately delete it from filesystem and remove from memory. |
| 507 | void tryRemovePartImmediately(DataPartPtr && part); |
| 508 | |
| 509 | /// Returns old inactive parts that can be deleted. At the same time removes them from the list of parts |
| 510 | /// but not from the disk. |
| 511 | DataPartsVector grabOldParts(); |
| 512 | |
| 513 | /// Reverts the changes made by grabOldParts(), parts should be in Deleting state. |
| 514 | void rollbackDeletingParts(const DataPartsVector & parts); |
| 515 | |
| 516 | /// Removes parts from data_parts, they should be in Deleting state |
| 517 | void removePartsFinally(const DataPartsVector & parts); |
| 518 | |
| 519 | /// Delete irrelevant parts from memory and disk. |
| 520 | void clearOldPartsFromFilesystem(); |
| 521 | void clearPartsFromFilesystem(const DataPartsVector & parts); |
| 522 | |
| 523 | /// Delete all directories which names begin with "tmp" |
| 524 | /// Set non-negative parameter value to override MergeTreeSettings temporary_directories_lifetime |
| 525 | /// Must be called with locked lockStructureForShare(). |
| 526 | void clearOldTemporaryDirectories(ssize_t custom_directories_lifetime_seconds = -1); |
| 527 | |
| 528 | /// After the call to dropAllData() no method can be called. |
| 529 | /// Deletes the data directory and flushes the uncompressed blocks cache and the marks cache. |
| 530 | void dropAllData(); |
| 531 | |
| 532 | /// Moves the entire data directory. |
| 533 | /// Flushes the uncompressed blocks cache and the marks cache. |
| 534 | /// Must be called with locked lockStructureForAlter(). |
| 535 | void rename(const String & new_path_to_table_data, const String & new_database_name, |
| 536 | const String & new_table_name, TableStructureWriteLockHolder &) override; |
| 537 | |
| 538 | /// Check if the ALTER can be performed: |
| 539 | /// - all needed columns are present. |
| 540 | /// - all type conversions can be done. |
| 541 | /// - columns corresponding to primary key, indices, sign, sampling expression and date are not affected. |
| 542 | /// If something is wrong, throws an exception. |
| 543 | void checkAlterIsPossible(const AlterCommands & commands, const Settings & settings) override; |
| 544 | |
| 545 | /// Performs ALTER of the data part, writes the result to temporary files. |
| 546 | /// Returns an object allowing to rename temporary files to permanent files. |
| 547 | /// If the number of affected columns is suspiciously high and skip_sanity_checks is false, throws an exception. |
| 548 | /// If no data transformations are necessary, returns nullptr. |
| 549 | void alterDataPart( |
| 550 | const NamesAndTypesList & new_columns, |
| 551 | const IndicesASTs & new_indices, |
| 552 | bool skip_sanity_checks, |
| 553 | AlterDataPartTransactionPtr& transaction); |
| 554 | |
| 555 | /// Change MergeTreeSettings |
| 556 | void changeSettings( |
| 557 | const ASTPtr & new_changes, |
| 558 | TableStructureWriteLockHolder & table_lock_holder); |
| 559 | |
| 560 | /// Remove columns, that have been marked as empty after zeroing values with expired ttl |
| 561 | void removeEmptyColumnsFromPart(MergeTreeData::MutableDataPartPtr & data_part); |
| 562 | |
| 563 | /// Freezes all parts. |
| 564 | void freezeAll(const String & with_name, const Context & context, TableStructureReadLockHolder & table_lock_holder); |
| 565 | |
| 566 | /// Should be called if part data is suspected to be corrupted. |
| 567 | void reportBrokenPart(const String & name) const |
| 568 | { |
| 569 | broken_part_callback(name); |
| 570 | } |
| 571 | |
| 572 | /** Get the key expression AST as an ASTExpressionList. |
| 573 | * It can be specified in the tuple: (CounterID, Date), |
| 574 | * or as one column: CounterID. |
| 575 | */ |
| 576 | static ASTPtr (const ASTPtr & node); |
| 577 | |
| 578 | bool hasSortingKey() const { return !sorting_key_columns.empty(); } |
| 579 | bool hasPrimaryKey() const { return !primary_key_columns.empty(); } |
| 580 | bool hasSkipIndices() const { return !skip_indices.empty(); } |
| 581 | bool hasTableTTL() const { return ttl_table_ast != nullptr; } |
| 582 | bool hasAnyColumnTTL() const { return !column_ttl_entries_by_name.empty(); } |
| 583 | |
| 584 | /// Check that the part is not broken and calculate the checksums for it if they are not present. |
| 585 | MutableDataPartPtr loadPartAndFixMetadata(const DiskPtr & disk, const String & relative_path); |
| 586 | void loadPartAndFixMetadata(MutableDataPartPtr part); |
| 587 | |
| 588 | /** Create local backup (snapshot) for parts with specified prefix. |
| 589 | * Backup is created in directory clickhouse_dir/shadow/i/, where i - incremental number, |
| 590 | * or if 'with_name' is specified - backup is created in directory with specified name. |
| 591 | */ |
| 592 | void freezePartition(const ASTPtr & partition, const String & with_name, const Context & context, TableStructureReadLockHolder & table_lock_holder); |
| 593 | |
| 594 | |
| 595 | public: |
| 596 | /// Moves partition to specified Disk |
| 597 | void movePartitionToDisk(const ASTPtr & partition, const String & name, bool moving_part, const Context & context); |
| 598 | |
| 599 | /// Moves partition to specified Volume |
| 600 | void movePartitionToVolume(const ASTPtr & partition, const String & name, bool moving_part, const Context & context); |
| 601 | |
| 602 | size_t getColumnCompressedSize(const std::string & name) const |
| 603 | { |
| 604 | auto lock = lockParts(); |
| 605 | const auto it = column_sizes.find(name); |
| 606 | return it == std::end(column_sizes) ? 0 : it->second.data_compressed; |
| 607 | } |
| 608 | |
| 609 | ColumnSizeByName getColumnSizes() const override |
| 610 | { |
| 611 | auto lock = lockParts(); |
| 612 | return column_sizes; |
| 613 | } |
| 614 | |
| 615 | /// Calculates column sizes in compressed form for the current state of data_parts. |
| 616 | void recalculateColumnSizes() |
| 617 | { |
| 618 | auto lock = lockParts(); |
| 619 | calculateColumnSizesImpl(); |
| 620 | } |
| 621 | |
| 622 | /// For ATTACH/DETACH/DROP PARTITION. |
| 623 | String getPartitionIDFromQuery(const ASTPtr & partition, const Context & context); |
| 624 | |
| 625 | /// Extracts MergeTreeData of other *MergeTree* storage |
| 626 | /// and checks that their structure suitable for ALTER TABLE ATTACH PARTITION FROM |
| 627 | /// Tables structure should be locked. |
| 628 | MergeTreeData & checkStructureAndGetMergeTreeData(const StoragePtr & source_table) const; |
| 629 | |
| 630 | MergeTreeData::MutableDataPartPtr cloneAndLoadDataPartOnSameDisk( |
| 631 | const MergeTreeData::DataPartPtr & src_part, const String & tmp_part_prefix, const MergeTreePartInfo & dst_part_info); |
| 632 | |
| 633 | virtual std::vector<MergeTreeMutationStatus> getMutationsStatus() const = 0; |
| 634 | |
| 635 | /// Returns true if table can create new parts with adaptive granularity |
| 636 | /// Has additional constraint in replicated version |
| 637 | virtual bool canUseAdaptiveGranularity() const |
| 638 | { |
| 639 | const auto settings = getSettings(); |
| 640 | return settings->index_granularity_bytes != 0 && |
| 641 | (settings->enable_mixed_granularity_parts || !has_non_adaptive_index_granularity_parts); |
| 642 | } |
| 643 | |
| 644 | /// Get constant pointer to storage settings. |
| 645 | /// Copy this pointer into your scope and you will |
| 646 | /// get consistent settings. |
| 647 | MergeTreeSettingsPtr getSettings() const |
| 648 | { |
| 649 | return storage_settings.get(); |
| 650 | } |
| 651 | |
| 652 | /// Get table path on disk |
| 653 | String getFullPathOnDisk(const DiskPtr & disk) const; |
| 654 | |
| 655 | /// Get disk for part. Looping through directories on FS because some parts maybe not in |
| 656 | /// active dataparts set (detached) |
| 657 | DiskPtr getDiskForPart(const String & part_name, const String & relative_path = "" ) const; |
| 658 | |
| 659 | /// Get full path for part. Uses getDiskForPart and returns the full path |
| 660 | String getFullPathForPart(const String & part_name, const String & relative_path = "" ) const; |
| 661 | |
| 662 | Strings getDataPaths() const override; |
| 663 | |
| 664 | using PathWithDisk = std::pair<String, DiskPtr>; |
| 665 | using PathsWithDisks = std::vector<PathWithDisk>; |
| 666 | PathsWithDisks getDataPathsWithDisks() const; |
| 667 | |
| 668 | /// Reserves space at least 1MB. |
| 669 | ReservationPtr reserveSpace(UInt64 expected_size) const; |
| 670 | |
| 671 | /// Reserves space at least 1MB on specific disk or volume. |
| 672 | ReservationPtr reserveSpace(UInt64 expected_size, SpacePtr space) const; |
| 673 | ReservationPtr tryReserveSpace(UInt64 expected_size, SpacePtr space) const; |
| 674 | |
| 675 | /// Reserves space at least 1MB preferring best destination according to `ttl_infos`. |
| 676 | ReservationPtr reserveSpacePreferringTTLRules(UInt64 expected_size, |
| 677 | const MergeTreeDataPart::TTLInfos & ttl_infos, |
| 678 | time_t time_of_move) const; |
| 679 | ReservationPtr tryReserveSpacePreferringTTLRules(UInt64 expected_size, |
| 680 | const MergeTreeDataPart::TTLInfos & ttl_infos, |
| 681 | time_t time_of_move) const; |
| 682 | /// Choose disk with max available free space |
| 683 | /// Reserves 0 bytes |
| 684 | ReservationPtr makeEmptyReservationOnLargestDisk() { return storage_policy->makeEmptyReservationOnLargestDisk(); } |
| 685 | |
| 686 | MergeTreeDataFormatVersion format_version; |
| 687 | |
| 688 | Context & global_context; |
| 689 | |
| 690 | /// Merging params - what additional actions to perform during merge. |
| 691 | const MergingParams merging_params; |
| 692 | |
| 693 | bool is_custom_partitioned = false; |
| 694 | ExpressionActionsPtr partition_key_expr; |
| 695 | Block partition_key_sample; |
| 696 | |
| 697 | ExpressionActionsPtr minmax_idx_expr; |
| 698 | Names minmax_idx_columns; |
| 699 | DataTypes minmax_idx_column_types; |
| 700 | Int64 minmax_idx_date_column_pos = -1; /// In a common case minmax index includes a date column. |
| 701 | Int64 minmax_idx_time_column_pos = -1; /// In other cases, minmax index often includes a dateTime column. |
| 702 | |
| 703 | /// Secondary (data skipping) indices for MergeTree |
| 704 | MergeTreeIndices skip_indices; |
| 705 | |
| 706 | ExpressionActionsPtr primary_key_and_skip_indices_expr; |
| 707 | ExpressionActionsPtr sorting_key_and_skip_indices_expr; |
| 708 | |
| 709 | /// Names of columns for primary key + secondary sorting columns. |
| 710 | Names sorting_key_columns; |
| 711 | ASTPtr sorting_key_expr_ast; |
| 712 | ExpressionActionsPtr sorting_key_expr; |
| 713 | |
| 714 | /// Names of columns for primary key. |
| 715 | Names primary_key_columns; |
| 716 | ASTPtr primary_key_expr_ast; |
| 717 | ExpressionActionsPtr primary_key_expr; |
| 718 | Block primary_key_sample; |
| 719 | DataTypes primary_key_data_types; |
| 720 | |
| 721 | struct TTLEntry |
| 722 | { |
| 723 | ExpressionActionsPtr expression; |
| 724 | String result_column; |
| 725 | |
| 726 | /// Name and type of a destination are only valid in table-level context. |
| 727 | PartDestinationType destination_type; |
| 728 | String destination_name; |
| 729 | |
| 730 | ASTPtr entry_ast; |
| 731 | |
| 732 | /// Returns destination disk or volume for this rule. |
| 733 | SpacePtr getDestination(const StoragePolicyPtr & policy) const; |
| 734 | |
| 735 | /// Checks if given part already belongs destination disk or volume for this rule. |
| 736 | bool isPartInDestination(const StoragePolicyPtr & policy, const MergeTreeDataPart & part) const; |
| 737 | }; |
| 738 | |
| 739 | const TTLEntry * selectTTLEntryForTTLInfos(const MergeTreeDataPart::TTLInfos & ttl_infos, time_t time_of_move) const; |
| 740 | |
| 741 | using TTLEntriesByName = std::unordered_map<String, TTLEntry>; |
| 742 | TTLEntriesByName column_ttl_entries_by_name; |
| 743 | |
| 744 | TTLEntry ttl_table_entry; |
| 745 | std::vector<TTLEntry> move_ttl_entries; |
| 746 | |
| 747 | String sampling_expr_column_name; |
| 748 | Names columns_required_for_sampling; |
| 749 | |
| 750 | /// Limiting parallel sends per one table, used in DataPartsExchange |
| 751 | std::atomic_uint current_table_sends {0}; |
| 752 | |
| 753 | /// For generating names of temporary parts during insertion. |
| 754 | SimpleIncrement insert_increment; |
| 755 | |
| 756 | bool has_non_adaptive_index_granularity_parts = false; |
| 757 | |
| 758 | /// Parts that currently moving from disk/volume to another. |
| 759 | /// This set have to be used with `currently_processing_in_background_mutex`. |
| 760 | /// Moving may conflict with merges and mutations, but this is OK, because |
| 761 | /// if we decide to move some part to another disk, than we |
| 762 | /// assuredly will choose this disk for containing part, which will appear |
| 763 | /// as result of merge or mutation. |
| 764 | DataParts currently_moving_parts; |
| 765 | |
| 766 | /// Mutex for currently_moving_parts |
| 767 | mutable std::mutex moving_parts_mutex; |
| 768 | |
| 769 | protected: |
| 770 | |
| 771 | friend struct MergeTreeDataPart; |
| 772 | friend class MergeTreeDataMergerMutator; |
| 773 | friend class ReplicatedMergeTreeAlterThread; |
| 774 | friend struct ReplicatedMergeTreeTableMetadata; |
| 775 | friend class StorageReplicatedMergeTree; |
| 776 | |
| 777 | ASTPtr partition_by_ast; |
| 778 | ASTPtr order_by_ast; |
| 779 | ASTPtr primary_key_ast; |
| 780 | ASTPtr sample_by_ast; |
| 781 | ASTPtr ttl_table_ast; |
| 782 | ASTPtr settings_ast; |
| 783 | |
| 784 | bool require_part_metadata; |
| 785 | |
| 786 | String database_name; |
| 787 | String table_name; |
| 788 | String relative_data_path; |
| 789 | |
| 790 | |
| 791 | /// Current column sizes in compressed and uncompressed form. |
| 792 | ColumnSizeByName column_sizes; |
| 793 | |
| 794 | /// Engine-specific methods |
| 795 | BrokenPartCallback broken_part_callback; |
| 796 | |
| 797 | String log_name; |
| 798 | Logger * log; |
| 799 | |
| 800 | /// Storage settings. |
| 801 | /// Use get and set to receive readonly versions. |
| 802 | MultiVersion<MergeTreeSettings> storage_settings; |
| 803 | |
| 804 | StoragePolicyPtr storage_policy; |
| 805 | |
| 806 | /// Work with data parts |
| 807 | |
| 808 | struct TagByInfo{}; |
| 809 | struct TagByStateAndInfo{}; |
| 810 | |
| 811 | static const MergeTreePartInfo & dataPartPtrToInfo(const DataPartPtr & part) |
| 812 | { |
| 813 | return part->info; |
| 814 | } |
| 815 | |
| 816 | static DataPartStateAndInfo dataPartPtrToStateAndInfo(const DataPartPtr & part) |
| 817 | { |
| 818 | return {part->state, part->info}; |
| 819 | } |
| 820 | |
| 821 | using DataPartsIndexes = boost::multi_index_container<DataPartPtr, |
| 822 | boost::multi_index::indexed_by< |
| 823 | /// Index by Info |
| 824 | boost::multi_index::ordered_unique< |
| 825 | boost::multi_index::tag<TagByInfo>, |
| 826 | boost::multi_index::global_fun<const DataPartPtr &, const MergeTreePartInfo &, dataPartPtrToInfo> |
| 827 | >, |
| 828 | /// Index by (State, Info), is used to obtain ordered slices of parts with the same state |
| 829 | boost::multi_index::ordered_unique< |
| 830 | boost::multi_index::tag<TagByStateAndInfo>, |
| 831 | boost::multi_index::global_fun<const DataPartPtr &, DataPartStateAndInfo, dataPartPtrToStateAndInfo>, |
| 832 | LessStateDataPart |
| 833 | > |
| 834 | > |
| 835 | >; |
| 836 | |
| 837 | /// Current set of data parts. |
| 838 | mutable std::mutex data_parts_mutex; |
| 839 | DataPartsIndexes data_parts_indexes; |
| 840 | DataPartsIndexes::index<TagByInfo>::type & data_parts_by_info; |
| 841 | DataPartsIndexes::index<TagByStateAndInfo>::type & data_parts_by_state_and_info; |
| 842 | |
| 843 | MergeTreePartsMover parts_mover; |
| 844 | |
| 845 | using DataPartIteratorByInfo = DataPartsIndexes::index<TagByInfo>::type::iterator; |
| 846 | using DataPartIteratorByStateAndInfo = DataPartsIndexes::index<TagByStateAndInfo>::type::iterator; |
| 847 | |
| 848 | boost::iterator_range<DataPartIteratorByStateAndInfo> getDataPartsStateRange(DataPartState state) const |
| 849 | { |
| 850 | auto begin = data_parts_by_state_and_info.lower_bound(state, LessStateDataPart()); |
| 851 | auto end = data_parts_by_state_and_info.upper_bound(state, LessStateDataPart()); |
| 852 | return {begin, end}; |
| 853 | } |
| 854 | |
| 855 | boost::iterator_range<DataPartIteratorByInfo> getDataPartsPartitionRange(const String & partition_id) const |
| 856 | { |
| 857 | auto begin = data_parts_by_info.lower_bound(PartitionID(partition_id), LessDataPart()); |
| 858 | auto end = data_parts_by_info.upper_bound(PartitionID(partition_id), LessDataPart()); |
| 859 | return {begin, end}; |
| 860 | } |
| 861 | |
| 862 | static decltype(auto) getStateModifier(DataPartState state) |
| 863 | { |
| 864 | return [state] (const DataPartPtr & part) { part->state = state; }; |
| 865 | } |
| 866 | |
| 867 | void modifyPartState(DataPartIteratorByStateAndInfo it, DataPartState state) |
| 868 | { |
| 869 | if (!data_parts_by_state_and_info.modify(it, getStateModifier(state))) |
| 870 | throw Exception("Can't modify " + (*it)->getNameWithState(), ErrorCodes::LOGICAL_ERROR); |
| 871 | } |
| 872 | |
| 873 | void modifyPartState(DataPartIteratorByInfo it, DataPartState state) |
| 874 | { |
| 875 | if (!data_parts_by_state_and_info.modify(data_parts_indexes.project<TagByStateAndInfo>(it), getStateModifier(state))) |
| 876 | throw Exception("Can't modify " + (*it)->getNameWithState(), ErrorCodes::LOGICAL_ERROR); |
| 877 | } |
| 878 | |
| 879 | void modifyPartState(const DataPartPtr & part, DataPartState state) |
| 880 | { |
| 881 | auto it = data_parts_by_info.find(part->info); |
| 882 | if (it == data_parts_by_info.end() || (*it).get() != part.get()) |
| 883 | throw Exception("Part " + part->name + " doesn't exist" , ErrorCodes::LOGICAL_ERROR); |
| 884 | |
| 885 | if (!data_parts_by_state_and_info.modify(data_parts_indexes.project<TagByStateAndInfo>(it), getStateModifier(state))) |
| 886 | throw Exception("Can't modify " + (*it)->getNameWithState(), ErrorCodes::LOGICAL_ERROR); |
| 887 | } |
| 888 | |
| 889 | /// Used to serialize calls to grabOldParts. |
| 890 | std::mutex grab_old_parts_mutex; |
| 891 | /// The same for clearOldTemporaryDirectories. |
| 892 | std::mutex clear_old_temporary_directories_mutex; |
| 893 | /// Mutex for settings usage |
| 894 | |
| 895 | void setProperties(const StorageInMemoryMetadata & metadata, bool only_check = false); |
| 896 | |
| 897 | void initPartitionKey(); |
| 898 | |
| 899 | void setTTLExpressions(const ColumnsDescription::ColumnTTLs & new_column_ttls, |
| 900 | const ASTPtr & new_ttl_table_ast, bool only_check = false); |
| 901 | |
| 902 | /// Expression for column type conversion. |
| 903 | /// If no conversions are needed, out_expression=nullptr. |
| 904 | /// out_rename_map maps column files for the out_expression onto new table files. |
| 905 | /// out_force_update_metadata denotes if metadata must be changed even if out_rename_map is empty (used |
| 906 | /// for transformation-free changing of Enum values list). |
| 907 | /// Files to be deleted are mapped to an empty string in out_rename_map. |
| 908 | /// If part == nullptr, just checks that all type conversions are possible. |
| 909 | void createConvertExpression(const DataPartPtr & part, const NamesAndTypesList & old_columns, const NamesAndTypesList & new_columns, |
| 910 | const IndicesASTs & old_indices, const IndicesASTs & new_indices, |
| 911 | ExpressionActionsPtr & out_expression, NameToNameMap & out_rename_map, bool & out_force_update_metadata) const; |
| 912 | |
| 913 | /// Calculates column sizes in compressed form for the current state of data_parts. Call with data_parts mutex locked. |
| 914 | void calculateColumnSizesImpl(); |
| 915 | /// Adds or subtracts the contribution of the part to compressed column sizes. |
| 916 | void addPartContributionToColumnSizes(const DataPartPtr & part); |
| 917 | void removePartContributionToColumnSizes(const DataPartPtr & part); |
| 918 | |
| 919 | /// If there is no part in the partition with ID `partition_id`, returns empty ptr. Should be called under the lock. |
| 920 | DataPartPtr getAnyPartInPartition(const String & partition_id, DataPartsLock & data_parts_lock); |
| 921 | |
| 922 | /// Return parts in the Committed set that are covered by the new_part_info or the part that covers it. |
| 923 | /// Will check that the new part doesn't already exist and that it doesn't intersect existing part. |
| 924 | DataPartsVector getActivePartsToReplace( |
| 925 | const MergeTreePartInfo & new_part_info, |
| 926 | const String & new_part_name, |
| 927 | DataPartPtr & out_covering_part, |
| 928 | DataPartsLock & data_parts_lock) const; |
| 929 | |
| 930 | /// Checks whether the column is in the primary key, possibly wrapped in a chain of functions with single argument. |
| 931 | bool isPrimaryOrMinMaxKeyColumnPossiblyWrappedInFunctions(const ASTPtr & node) const; |
| 932 | |
| 933 | /// Common part for |freezePartition()| and |freezeAll()|. |
| 934 | using MatcherFn = std::function<bool(const DataPartPtr &)>; |
| 935 | void freezePartitionsByMatcher(MatcherFn matcher, const String & with_name, const Context & context); |
| 936 | |
| 937 | bool canReplacePartition(const DataPartPtr & data_part) const; |
| 938 | |
| 939 | void writePartLog( |
| 940 | PartLogElement::Type type, |
| 941 | const ExecutionStatus & execution_status, |
| 942 | UInt64 elapsed_ns, |
| 943 | const String & new_part_name, |
| 944 | const DataPartPtr & result_part, |
| 945 | const DataPartsVector & source_parts, |
| 946 | const MergeListEntry * merge_entry); |
| 947 | |
| 948 | /// If part is assigned to merge or mutation (possibly replicated) |
| 949 | /// Should be overriden by childs, because they can have different |
| 950 | /// mechanisms for parts locking |
| 951 | virtual bool partIsAssignedToBackgroundOperation(const DataPartPtr & part) const = 0; |
| 952 | |
| 953 | /// Moves part to specified space, used in ALTER ... MOVE ... queries |
| 954 | bool movePartsToSpace(const DataPartsVector & parts, SpacePtr space); |
| 955 | |
| 956 | /// Selects parts for move and moves them, used in background process |
| 957 | bool selectPartsAndMove(); |
| 958 | |
| 959 | bool areBackgroundMovesNeeded() const; |
| 960 | |
| 961 | private: |
| 962 | /// RAII Wrapper for atomic work with currently moving parts |
| 963 | /// Acuire them in constructor and remove them in destructor |
| 964 | /// Uses data.currently_moving_parts_mutex |
| 965 | struct CurrentlyMovingPartsTagger |
| 966 | { |
| 967 | MergeTreeMovingParts parts_to_move; |
| 968 | MergeTreeData & data; |
| 969 | CurrentlyMovingPartsTagger(MergeTreeMovingParts && moving_parts_, MergeTreeData & data_); |
| 970 | |
| 971 | CurrentlyMovingPartsTagger(const CurrentlyMovingPartsTagger & other) = delete; |
| 972 | ~CurrentlyMovingPartsTagger(); |
| 973 | }; |
| 974 | |
| 975 | /// Move selected parts to corresponding disks |
| 976 | bool moveParts(CurrentlyMovingPartsTagger && parts_to_move); |
| 977 | |
| 978 | /// Select parts for move and disks for them. Used in background moving processes. |
| 979 | CurrentlyMovingPartsTagger selectPartsForMove(); |
| 980 | |
| 981 | /// Check selected parts for movements. Used by ALTER ... MOVE queries. |
| 982 | CurrentlyMovingPartsTagger checkPartsForMove(const DataPartsVector & parts, SpacePtr space); |
| 983 | }; |
| 984 | |
| 985 | } |
| 986 | |