5
5
#include < Common/escapeForFileName.h>
6
6
#include < Common/logger_useful.h>
7
7
8
+ /* *
9
+ * When ClickHouse has frozen data on remote storage it required 'smart' data removing during UNFREEZE.
10
+ * For remote storage actually frozen not remote data but local metadata with referrers on remote data.
11
+ * So remote data can be referred from working and frozen data sets (or two frozen) at same time.
12
+ * In this case during UNFREEZE ClickHouse should remove only local metadata and keep remote data.
13
+ * But when data was already removed from working data set ClickHouse should remove remote data too.
14
+ * To detect is current data used or not in some other place ClickHouse uses
15
+ * - ref_count from metadata to check if data used in some other metadata on the same replica;
16
+ * - Keeper record to check if data used on other replica.
17
+ * StorageReplicatedMergeTree::removeSharedDetachedPart makes required checks, so here this method
18
+ * called for each frozen part.
19
+ */
20
+
8
21
namespace DB
9
22
{
23
+
24
+ namespace ErrorCodes
25
+ {
26
+ extern const int SUPPORT_IS_DISABLED;
27
+ }
28
+
10
29
void FreezeMetaData::fill (const StorageReplicatedMergeTree & storage)
11
30
{
12
- is_replicated = storage.supportsReplication ();
13
- is_remote = storage.isRemote ();
14
31
replica_name = storage.getReplicaName ();
15
32
zookeeper_name = storage.getZooKeeperName ();
16
33
table_shared_id = storage.getTableSharedID ();
@@ -26,11 +43,17 @@ void FreezeMetaData::save(DiskPtr data_disk, const String & path) const
26
43
27
44
writeIntText (version, buffer);
28
45
buffer.write (" \n " , 1 );
29
- writeBoolText (is_replicated, buffer);
30
- buffer.write (" \n " , 1 );
31
- writeBoolText (is_remote, buffer);
32
- buffer.write (" \n " , 1 );
33
- writeString (replica_name, buffer);
46
+ if (version == 1 )
47
+ {
48
+ // / is_replicated and is_remote are not used
49
+ bool is_replicated = true ;
50
+ writeBoolText (is_replicated, buffer);
51
+ buffer.write (" \n " , 1 );
52
+ bool is_remote = true ;
53
+ writeBoolText (is_remote, buffer);
54
+ buffer.write (" \n " , 1 );
55
+ }
56
+ writeString (escapeForFileName (replica_name), buffer);
34
57
buffer.write (" \n " , 1 );
35
58
writeString (zookeeper_name, buffer);
36
59
buffer.write (" \n " , 1 );
@@ -51,17 +74,25 @@ bool FreezeMetaData::load(DiskPtr data_disk, const String & path)
51
74
auto metadata_str = metadata_storage->readFileToString (file_path);
52
75
ReadBufferFromString buffer (metadata_str);
53
76
readIntText (version, buffer);
54
- if (version != 1 )
77
+ if (version < 1 || version > 2 )
55
78
{
56
- LOG_ERROR (&Poco::Logger::get (" FreezeMetaData" ), " Unknown freezed metadata version: {}" , version);
79
+ LOG_ERROR (&Poco::Logger::get (" FreezeMetaData" ), " Unknown frozen metadata version: {}" , version);
57
80
return false ;
58
81
}
59
82
DB::assertChar (' \n ' , buffer);
60
- readBoolText (is_replicated, buffer);
61
- DB::assertChar (' \n ' , buffer);
62
- readBoolText (is_remote, buffer);
63
- DB::assertChar (' \n ' , buffer);
64
- readString (replica_name, buffer);
83
+ if (version == 1 )
84
+ {
85
+ // / is_replicated and is_remote are not used
86
+ bool is_replicated;
87
+ readBoolText (is_replicated, buffer);
88
+ DB::assertChar (' \n ' , buffer);
89
+ bool is_remote;
90
+ readBoolText (is_remote, buffer);
91
+ DB::assertChar (' \n ' , buffer);
92
+ }
93
+ std::string unescaped_replica_name;
94
+ readString (unescaped_replica_name, buffer);
95
+ replica_name = unescapeForFileName (unescaped_replica_name);
65
96
DB::assertChar (' \n ' , buffer);
66
97
readString (zookeeper_name, buffer);
67
98
DB::assertChar (' \n ' , buffer);
@@ -87,43 +118,62 @@ String FreezeMetaData::getFileName(const String & path)
87
118
return fs::path (path) / " frozen_metadata.txt" ;
88
119
}
89
120
90
- BlockIO Unfreezer::unfreeze (const String & backup_name, ContextPtr local_context)
121
+ Unfreezer::Unfreezer (ContextPtr context) : local_context(context)
122
+ {
123
+ if (local_context->hasZooKeeper ())
124
+ zookeeper = local_context->getZooKeeper ();
125
+ }
126
+
127
+ BlockIO Unfreezer::systemUnfreeze (const String & backup_name)
91
128
{
92
- LOG_DEBUG (log, " Unfreezing backup {}" , backup_name);
129
+ LOG_DEBUG (log, " Unfreezing backup {}" , escapeForFileName (backup_name));
130
+
131
+ const auto & config = local_context->getConfigRef ();
132
+ static constexpr auto config_key = " enable_system_unfreeze" ;
133
+ if (!config.getBool (config_key, false ))
134
+ {
135
+ throw Exception (ErrorCodes::SUPPORT_IS_DISABLED, " Support for SYSTEM UNFREEZE query is disabled. You can enable it via '{}' server setting" , config_key);
136
+ }
137
+
93
138
auto disks_map = local_context->getDisksMap ();
94
139
Disks disks;
95
140
for (auto & [name, disk]: disks_map)
96
141
{
97
142
disks.push_back (disk);
98
143
}
99
144
auto backup_path = fs::path (backup_directory_prefix) / escapeForFileName (backup_name);
100
- auto store_path = backup_path / " store" ;
145
+ auto store_paths = { backup_path / " store" , backup_path / " data " } ;
101
146
102
147
PartitionCommandsResultInfo result_info;
103
148
104
149
for (const auto & disk: disks)
105
150
{
106
- if (!disk->exists (store_path))
107
- continue ;
108
- for (auto prefix_it = disk->iterateDirectory (store_path); prefix_it->isValid (); prefix_it->next ())
151
+ for (const auto & store_path: store_paths)
109
152
{
110
- auto prefix_directory = store_path / prefix_it->name ();
111
- for (auto table_it = disk->iterateDirectory (prefix_directory); table_it->isValid (); table_it->next ())
153
+ if (!disk->exists (store_path))
154
+ continue ;
155
+ for (auto prefix_it = disk->iterateDirectory (store_path); prefix_it->isValid (); prefix_it->next ())
112
156
{
113
- auto table_directory = prefix_directory / table_it->name ();
114
- auto current_result_info = unfreezePartitionsFromTableDirectory ([] (const String &) { return true ; }, backup_name, {disk}, table_directory, local_context);
115
- for (auto & command_result : current_result_info)
157
+ auto prefix_directory = store_path / prefix_it->name ();
158
+ for (auto table_it = disk->iterateDirectory (prefix_directory); table_it->isValid (); table_it->next ())
116
159
{
117
- command_result.command_type = " SYSTEM UNFREEZE" ;
160
+ auto table_directory = prefix_directory / table_it->name ();
161
+ auto current_result_info = unfreezePartitionsFromTableDirectory (
162
+ [](const String &) { return true ; }, backup_name, {disk}, table_directory);
163
+ for (auto & command_result : current_result_info)
164
+ {
165
+ command_result.command_type = " SYSTEM UNFREEZE" ;
166
+ }
167
+ result_info.insert (
168
+ result_info.end (),
169
+ std::make_move_iterator (current_result_info.begin ()),
170
+ std::make_move_iterator (current_result_info.end ()));
118
171
}
119
- result_info.insert (
120
- result_info.end (),
121
- std::make_move_iterator (current_result_info.begin ()),
122
- std::make_move_iterator (current_result_info.end ()));
123
172
}
124
173
}
125
174
if (disk->exists (backup_path))
126
175
{
176
+ // / After unfreezing we need to clear revision.txt file and empty directories
127
177
disk->removeRecursive (backup_path);
128
178
}
129
179
}
@@ -136,18 +186,15 @@ BlockIO Unfreezer::unfreeze(const String & backup_name, ContextPtr local_context
136
186
return result;
137
187
}
138
188
139
- bool Unfreezer::removeFreezedPart (DiskPtr disk, const String & path, const String & part_name, ContextPtr local_context)
189
+ bool Unfreezer::removeFreezedPart (DiskPtr disk, const String & path, const String & part_name, ContextPtr local_context, zkutil::ZooKeeperPtr zookeeper )
140
190
{
141
191
if (disk->supportZeroCopyReplication ())
142
192
{
143
193
FreezeMetaData meta;
144
194
if (meta.load (disk, path))
145
195
{
146
- if (meta.is_replicated )
147
- {
148
- FreezeMetaData::clean (disk, path);
149
- return StorageReplicatedMergeTree::removeSharedDetachedPart (disk, path, part_name, meta.table_shared_id , meta.zookeeper_name , meta.replica_name , " " , local_context);
150
- }
196
+ FreezeMetaData::clean (disk, path);
197
+ return StorageReplicatedMergeTree::removeSharedDetachedPart (disk, path, part_name, meta.table_shared_id , meta.zookeeper_name , meta.replica_name , " " , local_context, zookeeper);
151
198
}
152
199
}
153
200
@@ -156,7 +203,7 @@ bool Unfreezer::removeFreezedPart(DiskPtr disk, const String & path, const Strin
156
203
return false ;
157
204
}
158
205
159
- PartitionCommandsResultInfo Unfreezer::unfreezePartitionsFromTableDirectory (MergeTreeData::MatcherFn matcher, const String & backup_name, const Disks & disks, const fs::path & table_directory, ContextPtr local_context )
206
+ PartitionCommandsResultInfo Unfreezer::unfreezePartitionsFromTableDirectory (MergeTreeData::MatcherFn matcher, const String & backup_name, const Disks & disks, const fs::path & table_directory)
160
207
{
161
208
PartitionCommandsResultInfo result;
162
209
@@ -180,7 +227,7 @@ PartitionCommandsResultInfo Unfreezer::unfreezePartitionsFromTableDirectory(Merg
180
227
181
228
const auto & path = it->path ();
182
229
183
- bool keep_shared = removeFreezedPart (disk, path, partition_directory, local_context);
230
+ bool keep_shared = removeFreezedPart (disk, path, partition_directory, local_context, zookeeper );
184
231
185
232
result.push_back (PartitionCommandResultInfo{
186
233
.partition_id = partition_id,
0 commit comments