@@ -37,6 +37,7 @@ namespace ErrorCodes
37
37
extern const int BACKUP_ENTRY_ALREADY_EXISTS;
38
38
extern const int BACKUP_ENTRY_NOT_FOUND;
39
39
extern const int BACKUP_IS_EMPTY;
40
+ extern const int FAILED_TO_SYNC_BACKUP_OR_RESTORE;
40
41
extern const int LOGICAL_ERROR;
41
42
}
42
43
@@ -146,9 +147,9 @@ BackupImpl::BackupImpl(
146
147
const std::optional<BackupInfo> & base_backup_info_,
147
148
std::shared_ptr<IBackupWriter> writer_,
148
149
const ContextPtr & context_,
149
- const std::optional<UUID> & backup_uuid_,
150
150
bool is_internal_backup_,
151
- const std::shared_ptr<IBackupCoordination> & coordination_)
151
+ const std::shared_ptr<IBackupCoordination> & coordination_,
152
+ const std::optional<UUID> & backup_uuid_)
152
153
: backup_name(backup_name_)
153
154
, archive_params(archive_params_)
154
155
, use_archives(!archive_params.archive_name.empty())
@@ -177,42 +178,28 @@ BackupImpl::~BackupImpl()
177
178
}
178
179
}
179
180
180
-
181
181
void BackupImpl::open (const ContextPtr & context)
182
182
{
183
183
std::lock_guard lock{mutex};
184
184
185
- String file_name_to_check_existence;
186
- if (use_archives)
187
- file_name_to_check_existence = archive_params.archive_name ;
188
- else
189
- file_name_to_check_existence = " .backup" ;
190
- bool backup_exists = (open_mode == OpenMode::WRITE) ? writer->fileExists (file_name_to_check_existence) : reader->fileExists (file_name_to_check_existence);
191
-
192
- if (open_mode == OpenMode::WRITE)
193
- {
194
- if (backup_exists)
195
- throw Exception (ErrorCodes::BACKUP_ALREADY_EXISTS, " Backup {} already exists" , backup_name);
196
- }
197
- else
198
- {
199
- if (!backup_exists)
200
- throw Exception (ErrorCodes::BACKUP_NOT_FOUND, " Backup {} not found" , backup_name);
201
- }
202
-
203
185
if (open_mode == OpenMode::WRITE)
204
186
{
205
187
timestamp = std::time (nullptr );
206
188
if (!uuid)
207
189
uuid = UUIDHelpers::generateV4 ();
190
+ lock_file_name = use_archives ? (archive_params.archive_name + " .lock" ) : " .lock" ;
208
191
writing_finalized = false ;
192
+
193
+ // / Check that we can write a backup there and create the lock file to own this destination.
194
+ checkBackupDoesntExist ();
195
+ if (!is_internal_backup)
196
+ createLockFile ();
197
+ checkLockFile (true );
209
198
}
210
199
211
200
if (open_mode == OpenMode::READ)
212
201
readBackupMetadata ();
213
202
214
- assert (uuid); // / Backup's UUID must be loaded or generated at this point.
215
-
216
203
if (base_backup_info)
217
204
{
218
205
BackupFactory::CreateParams params;
@@ -253,6 +240,8 @@ time_t BackupImpl::getTimestamp() const
253
240
254
241
void BackupImpl::writeBackupMetadata ()
255
242
{
243
+ assert (!is_internal_backup);
244
+
256
245
Poco::AutoPtr<Poco::Util::XMLConfiguration> config{new Poco::Util::XMLConfiguration ()};
257
246
config->setUInt (" version" , CURRENT_BACKUP_VERSION);
258
247
config->setString (" timestamp" , toString (LocalDateTime{timestamp}));
@@ -308,6 +297,8 @@ void BackupImpl::writeBackupMetadata()
308
297
config->save (stream);
309
298
String str = stream.str ();
310
299
300
+ checkLockFile (true );
301
+
311
302
std::unique_ptr<WriteBuffer> out;
312
303
if (use_archives)
313
304
out = getArchiveWriter (" " )->writeFile (" .backup" );
@@ -321,9 +312,17 @@ void BackupImpl::readBackupMetadata()
321
312
{
322
313
std::unique_ptr<ReadBuffer> in;
323
314
if (use_archives)
315
+ {
316
+ if (!reader->fileExists (archive_params.archive_name ))
317
+ throw Exception (ErrorCodes::BACKUP_NOT_FOUND, " Backup {} not found" , backup_name);
324
318
in = getArchiveReader (" " )->readFile (" .backup" );
319
+ }
325
320
else
321
+ {
322
+ if (!reader->fileExists (" .backup" ))
323
+ throw Exception (ErrorCodes::BACKUP_NOT_FOUND, " Backup {} not found" , backup_name);
326
324
in = reader->readFile (" .backup" );
325
+ }
327
326
328
327
String str;
329
328
readStringUntilEOF (str, *in);
@@ -387,6 +386,59 @@ void BackupImpl::readBackupMetadata()
387
386
}
388
387
}
389
388
389
+ void BackupImpl::checkBackupDoesntExist () const
390
+ {
391
+ String file_name_to_check_existence;
392
+ if (use_archives)
393
+ file_name_to_check_existence = archive_params.archive_name ;
394
+ else
395
+ file_name_to_check_existence = " .backup" ;
396
+
397
+ if (writer->fileExists (file_name_to_check_existence))
398
+ throw Exception (ErrorCodes::BACKUP_ALREADY_EXISTS, " Backup {} already exists" , backup_name);
399
+
400
+ // / Check that no other backup (excluding internal backups) is writing to the same destination.
401
+ if (!is_internal_backup)
402
+ {
403
+ assert (!lock_file_name.empty ());
404
+ if (writer->fileExists (lock_file_name))
405
+ throw Exception (ErrorCodes::BACKUP_ALREADY_EXISTS, " Backup {} is being written already" , backup_name);
406
+ }
407
+ }
408
+
409
+ void BackupImpl::createLockFile ()
410
+ {
411
+ // / Internal backup must not create the lock file (it should be created by the initiator).
412
+ assert (!is_internal_backup);
413
+
414
+ assert (uuid);
415
+ auto out = writer->writeFile (lock_file_name);
416
+ writeUUIDText (*uuid, *out);
417
+ }
418
+
419
+ bool BackupImpl::checkLockFile (bool throw_if_failed) const
420
+ {
421
+ if (!lock_file_name.empty () && uuid && writer->fileContentsEqual (lock_file_name, toString (*uuid)))
422
+ return true ;
423
+
424
+ if (throw_if_failed)
425
+ {
426
+ if (!writer->fileExists (lock_file_name))
427
+ throw Exception (ErrorCodes::FAILED_TO_SYNC_BACKUP_OR_RESTORE, " Lock file {} suddenly disappeared while writing backup {}" , lock_file_name, backup_name);
428
+ throw Exception (ErrorCodes::BACKUP_ALREADY_EXISTS, " A concurrent backup writing to the same destination {} detected" , backup_name);
429
+ }
430
+ return false ;
431
+ }
432
+
433
+ void BackupImpl::removeLockFile ()
434
+ {
435
+ if (is_internal_backup)
436
+ return ; // / Internal backup must not remove the lock file (it's still used by the initiator).
437
+
438
+ if (checkLockFile (false ))
439
+ writer->removeFiles ({lock_file_name});
440
+ }
441
+
390
442
Strings BackupImpl::listFiles (const String & directory, bool recursive) const
391
443
{
392
444
std::lock_guard lock{mutex};
@@ -648,6 +700,9 @@ void BackupImpl::writeFile(const String & file_name, BackupEntryPtr entry)
648
700
read_buffer = entry->getReadBuffer ();
649
701
read_buffer->seek (copy_pos, SEEK_SET);
650
702
703
+ if (!num_files_written)
704
+ checkLockFile (true );
705
+
651
706
// / Copy the entry's data after `copy_pos`.
652
707
std::unique_ptr<WriteBuffer> out;
653
708
if (use_archives)
@@ -675,6 +730,7 @@ void BackupImpl::writeFile(const String & file_name, BackupEntryPtr entry)
675
730
676
731
copyData (*read_buffer, *out);
677
732
out->finalize ();
733
+ ++num_files_written;
678
734
}
679
735
680
736
@@ -694,6 +750,7 @@ void BackupImpl::finalizeWriting()
694
750
{
695
751
LOG_TRACE (log , " Finalizing backup {}" , backup_name);
696
752
writeBackupMetadata ();
753
+ removeLockFile ();
697
754
LOG_TRACE (log , " Finalized backup {}" , backup_name);
698
755
}
699
756
@@ -741,6 +798,9 @@ std::shared_ptr<IArchiveWriter> BackupImpl::getArchiveWriter(const String & suff
741
798
742
799
void BackupImpl::removeAllFilesAfterFailure ()
743
800
{
801
+ if (is_internal_backup)
802
+ return ; // / Let the initiator remove unnecessary files.
803
+
744
804
try
745
805
{
746
806
LOG_INFO (log , " Removing all files of backup {} after failure" , backup_name);
@@ -762,7 +822,11 @@ void BackupImpl::removeAllFilesAfterFailure()
762
822
files_to_remove.push_back (file_info.data_file_name );
763
823
}
764
824
765
- writer->removeFilesAfterFailure (files_to_remove);
825
+ if (!checkLockFile (false ))
826
+ return ;
827
+
828
+ writer->removeFiles (files_to_remove);
829
+ removeLockFile ();
766
830
}
767
831
catch (...)
768
832
{
0 commit comments