Skip to content

Commit f69c917

Browse files
committed
[Support] Add overload writeFileAtomically(std::function Writer)
Differential Revision: https://reviews.llvm.org/D67424 llvm-svn: 371890
1 parent c6ffefd commit f69c917

File tree

7 files changed

+145
-130
lines changed

7 files changed

+145
-130
lines changed

clang-tools-extra/clangd/index/BackgroundIndexStorage.cpp

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "llvm/ADT/StringRef.h"
1919
#include "llvm/Support/Error.h"
2020
#include "llvm/Support/FileSystem.h"
21+
#include "llvm/Support/FileUtilities.h"
2122
#include "llvm/Support/MemoryBuffer.h"
2223
#include "llvm/Support/Path.h"
2324
#include <functional>
@@ -35,34 +36,6 @@ std::string getShardPathFromFilePath(llvm::StringRef ShardRoot,
3536
return ShardRootSS.str();
3637
}
3738

38-
llvm::Error
39-
writeAtomically(llvm::StringRef OutPath,
40-
llvm::function_ref<void(llvm::raw_ostream &)> Writer) {
41-
// Write to a temporary file first.
42-
llvm::SmallString<128> TempPath;
43-
int FD;
44-
auto EC =
45-
llvm::sys::fs::createUniqueFile(OutPath + ".tmp.%%%%%%%%", FD, TempPath);
46-
if (EC)
47-
return llvm::errorCodeToError(EC);
48-
// Make sure temp file is destroyed on failure.
49-
auto RemoveOnFail =
50-
llvm::make_scope_exit([TempPath] { llvm::sys::fs::remove(TempPath); });
51-
llvm::raw_fd_ostream OS(FD, /*shouldClose=*/true);
52-
Writer(OS);
53-
OS.close();
54-
if (OS.has_error())
55-
return llvm::errorCodeToError(OS.error());
56-
// Then move to real location.
57-
EC = llvm::sys::fs::rename(TempPath, OutPath);
58-
if (EC)
59-
return llvm::errorCodeToError(EC);
60-
// If everything went well, we already moved the file to another name. So
61-
// don't delete the file, as the name might be taken by another file.
62-
RemoveOnFail.release();
63-
return llvm::ErrorSuccess();
64-
}
65-
6639
// Uses disk as a storage for index shards. Creates a directory called
6740
// ".clangd/index/" under the path provided during construction.
6841
class DiskBackedIndexStorage : public BackgroundIndexStorage {
@@ -100,9 +73,12 @@ class DiskBackedIndexStorage : public BackgroundIndexStorage {
10073

10174
llvm::Error storeShard(llvm::StringRef ShardIdentifier,
10275
IndexFileOut Shard) const override {
103-
return writeAtomically(
104-
getShardPathFromFilePath(DiskShardRoot, ShardIdentifier),
105-
[&Shard](llvm::raw_ostream &OS) { OS << Shard; });
76+
auto ShardPath = getShardPathFromFilePath(DiskShardRoot, ShardIdentifier);
77+
return llvm::writeFileAtomically(ShardPath + ".tmp.%%%%%%%%", ShardPath,
78+
[&Shard](llvm::raw_ostream &OS) {
79+
OS << Shard;
80+
return llvm::Error::success();
81+
});
10682
}
10783
};
10884

clang/lib/Frontend/ASTUnit.cpp

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
#include "llvm/Support/ErrorHandling.h"
8585
#include "llvm/Support/ErrorOr.h"
8686
#include "llvm/Support/FileSystem.h"
87+
#include "llvm/Support/FileUtilities.h"
8788
#include "llvm/Support/MemoryBuffer.h"
8889
#include "llvm/Support/Timer.h"
8990
#include "llvm/Support/VirtualFileSystem.h"
@@ -2301,26 +2302,19 @@ bool ASTUnit::Save(StringRef File) {
23012302
SmallString<128> TempPath;
23022303
TempPath = File;
23032304
TempPath += "-%%%%%%%%";
2304-
int fd;
2305-
if (llvm::sys::fs::createUniqueFile(TempPath, fd, TempPath))
2306-
return true;
2307-
23082305
// FIXME: Can we somehow regenerate the stat cache here, or do we need to
23092306
// unconditionally create a stat cache when we parse the file?
2310-
llvm::raw_fd_ostream Out(fd, /*shouldClose=*/true);
2311-
2312-
serialize(Out);
2313-
Out.close();
2314-
if (Out.has_error()) {
2315-
Out.clear_error();
2316-
return true;
2317-
}
23182307

2319-
if (llvm::sys::fs::rename(TempPath, File)) {
2320-
llvm::sys::fs::remove(TempPath);
2308+
if (llvm::Error Err = llvm::writeFileAtomically(
2309+
TempPath, File, [this](llvm::raw_ostream &Out) {
2310+
return serialize(Out) ? llvm::make_error<llvm::StringError>(
2311+
"ASTUnit serialization failed",
2312+
llvm::inconvertibleErrorCode())
2313+
: llvm::Error::success();
2314+
})) {
2315+
consumeError(std::move(Err));
23212316
return true;
23222317
}
2323-
23242318
return false;
23252319
}
23262320

clang/lib/Serialization/GlobalModuleIndex.cpp

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
1413
#include "ASTReaderInternals.h"
1514
#include "clang/Basic/FileManager.h"
1615
#include "clang/Lex/HeaderSearch.h"
@@ -21,10 +20,12 @@
2120
#include "llvm/ADT/DenseMap.h"
2221
#include "llvm/ADT/MapVector.h"
2322
#include "llvm/ADT/SmallString.h"
23+
#include "llvm/ADT/StringRef.h"
2424
#include "llvm/Bitstream/BitstreamReader.h"
2525
#include "llvm/Bitstream/BitstreamWriter.h"
2626
#include "llvm/Support/DJB.h"
2727
#include "llvm/Support/FileSystem.h"
28+
#include "llvm/Support/FileUtilities.h"
2829
#include "llvm/Support/LockFileManager.h"
2930
#include "llvm/Support/MemoryBuffer.h"
3031
#include "llvm/Support/OnDiskHashTable.h"
@@ -912,37 +913,9 @@ GlobalModuleIndex::writeIndex(FileManager &FileMgr,
912913
"failed writing index");
913914
}
914915

915-
// Write the global index file to a temporary file.
916-
llvm::SmallString<128> IndexTmpPath;
917-
int TmpFD;
918-
if (llvm::sys::fs::createUniqueFile(IndexPath + "-%%%%%%%%", TmpFD,
919-
IndexTmpPath))
920-
return llvm::createStringError(std::errc::io_error,
921-
"failed creating unique file");
922-
923-
// Open the temporary global index file for output.
924-
llvm::raw_fd_ostream Out(TmpFD, true);
925-
if (Out.has_error())
926-
return llvm::createStringError(Out.error(), "failed outputting to stream");
927-
928-
// Write the index.
929-
Out.write(OutputBuffer.data(), OutputBuffer.size());
930-
Out.close();
931-
if (Out.has_error())
932-
return llvm::createStringError(Out.error(), "failed writing to stream");
933-
934-
// Remove the old index file. It isn't relevant any more.
935-
llvm::sys::fs::remove(IndexPath);
936-
937-
// Rename the newly-written index file to the proper name.
938-
if (std::error_code Err = llvm::sys::fs::rename(IndexTmpPath, IndexPath)) {
939-
// Remove the file on failure, don't check whether removal succeeded.
940-
llvm::sys::fs::remove(IndexTmpPath);
941-
return llvm::createStringError(Err, "failed renaming file \"%s\" to \"%s\"",
942-
IndexTmpPath.c_str(), IndexPath.c_str());
943-
}
944-
945-
return llvm::Error::success();
916+
return llvm::writeFileAtomically(
917+
(IndexPath + "-%%%%%%%%").str(), IndexPath,
918+
llvm::StringRef(OutputBuffer.data(), OutputBuffer.size()));
946919
}
947920

948921
namespace {

lldb/tools/lldb-server/lldb-platform.cpp

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include "llvm/Support/FileSystem.h"
2424
#include "llvm/Support/FileUtilities.h"
25+
#include "llvm/Support/raw_ostream.h"
2526

2627
#include "Acceptor.h"
2728
#include "LLDBServerUtilities.h"
@@ -103,29 +104,34 @@ static Status save_socket_id_to_file(const std::string &socket_id,
103104

104105
llvm::SmallString<64> temp_file_path;
105106
temp_file_spec.AppendPathComponent("port-file.%%%%%%");
106-
int FD;
107-
auto err_code = llvm::sys::fs::createUniqueFile(temp_file_spec.GetPath(), FD,
108-
temp_file_path);
109-
if (err_code)
110-
return Status("Failed to create temp file: %s", err_code.message().c_str());
111-
112-
llvm::FileRemover tmp_file_remover(temp_file_path);
113-
114-
{
115-
llvm::raw_fd_ostream temp_file(FD, true);
116-
temp_file << socket_id;
117-
temp_file.close();
118-
if (temp_file.has_error())
119-
return Status("Failed to write to port file.");
120-
}
121-
122-
err_code = llvm::sys::fs::rename(temp_file_path, file_spec.GetPath());
123-
if (err_code)
124-
return Status("Failed to rename file %s to %s: %s", temp_file_path.c_str(),
125-
file_spec.GetPath().c_str(), err_code.message().c_str());
126107

127-
tmp_file_remover.releaseFile();
128-
return Status();
108+
Status status;
109+
if (auto Err =
110+
handleErrors(llvm::writeFileAtomically(
111+
temp_file_path, temp_file_spec.GetPath(), socket_id),
112+
[&status, &temp_file_path,
113+
&file_spec](const AtomicFileWriteError &E) {
114+
std::string ErrorMsgBuffer;
115+
llvm::raw_string_ostream S(ErrorMsgBuffer);
116+
E.log(S);
117+
118+
switch (E.Error) {
119+
case atomic_write_error::failed_to_create_uniq_file:
120+
status = Status("Failed to create temp file: %s",
121+
ErrorMsgBuffer.c_str());
122+
case atomic_write_error::output_stream_error:
123+
status = Status("Failed to write to port file.");
124+
case atomic_write_error::failed_to_rename_temp_file:
125+
status = Status("Failed to rename file %s to %s: %s",
126+
ErrorMsgBuffer.c_str(),
127+
file_spec.GetPath().c_str(),
128+
ErrorMsgBuffer.c_str());
129+
}
130+
})) {
131+
return Status("Failed to atomically write file %s",
132+
file_spec.GetPath().c_str());
133+
}
134+
return status;
129135
}
130136

131137
// main

llvm/include/llvm/Support/FileUtilities.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "llvm/ADT/StringRef.h"
1818
#include "llvm/Support/Errc.h"
19+
#include "llvm/Support/ErrorHandling.h"
1920
#include "llvm/Support/FileSystem.h"
2021
#include "llvm/Support/Path.h"
2122

@@ -75,10 +76,40 @@ namespace llvm {
7576
void releaseFile() { DeleteIt = false; }
7677
};
7778

79+
enum class atomic_write_error {
80+
failed_to_create_uniq_file = 0,
81+
output_stream_error,
82+
failed_to_rename_temp_file
83+
};
84+
85+
class AtomicFileWriteError : public llvm::ErrorInfo<AtomicFileWriteError> {
86+
public:
87+
AtomicFileWriteError(atomic_write_error Error) : Error(Error) {}
88+
89+
void log(raw_ostream &OS) const override;
90+
91+
const atomic_write_error Error;
92+
static char ID;
93+
94+
private:
95+
// Users are not expected to use error_code.
96+
std::error_code convertToErrorCode() const override {
97+
return llvm::inconvertibleErrorCode();
98+
}
99+
};
100+
101+
// atomic_write_error + whatever the Writer can return
102+
78103
/// Creates a unique file with name according to the given \p TempPathModel,
79104
/// writes content of \p Buffer to the file and renames it to \p FinalPath.
105+
///
106+
/// \returns \c AtomicFileWriteError in case of error.
80107
llvm::Error writeFileAtomically(StringRef TempPathModel, StringRef FinalPath,
81108
StringRef Buffer);
109+
110+
llvm::Error
111+
writeFileAtomically(StringRef TempPathModel, StringRef FinalPath,
112+
std::function<llvm::Error(llvm::raw_ostream &)> Writer);
82113
} // End llvm namespace
83114

84115
#endif

llvm/lib/LTO/ThinLTOCodeGenerator.cpp

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "llvm/Support/CachePruning.h"
4040
#include "llvm/Support/Debug.h"
4141
#include "llvm/Support/Error.h"
42+
#include "llvm/Support/FileUtilities.h"
4243
#include "llvm/Support/Path.h"
4344
#include "llvm/Support/SHA1.h"
4445
#include "llvm/Support/SmallVectorMemoryBuffer.h"
@@ -368,23 +369,26 @@ class ModuleCacheEntry {
368369
// Write to a temporary to avoid race condition
369370
SmallString<128> TempFilename;
370371
SmallString<128> CachePath(EntryPath);
371-
int TempFD;
372372
llvm::sys::path::remove_filename(CachePath);
373373
sys::path::append(TempFilename, CachePath, "Thin-%%%%%%.tmp.o");
374-
std::error_code EC =
375-
sys::fs::createUniqueFile(TempFilename, TempFD, TempFilename);
376-
if (EC) {
377-
errs() << "Error: " << EC.message() << "\n";
378-
report_fatal_error("ThinLTO: Can't get a temporary file");
379-
}
380-
{
381-
raw_fd_ostream OS(TempFD, /* ShouldClose */ true);
382-
OS << OutputBuffer.getBuffer();
374+
375+
if (auto Err = handleErrors(
376+
llvm::writeFileAtomically(TempFilename, EntryPath,
377+
OutputBuffer.getBuffer()),
378+
[](const llvm::AtomicFileWriteError &E) {
379+
std::string ErrorMsgBuffer;
380+
llvm::raw_string_ostream S(ErrorMsgBuffer);
381+
E.log(S);
382+
383+
if (E.Error ==
384+
llvm::atomic_write_error::failed_to_create_uniq_file) {
385+
errs() << "Error: " << ErrorMsgBuffer << "\n";
386+
report_fatal_error("ThinLTO: Can't get a temporary file");
387+
}
388+
})) {
389+
// FIXME
390+
consumeError(std::move(Err));
383391
}
384-
// Rename temp file to final destination; rename is atomic
385-
EC = sys::fs::rename(TempFilename, EntryPath);
386-
if (EC)
387-
sys::fs::remove(TempFilename);
388392
}
389393
};
390394

0 commit comments

Comments
 (0)