Index: clangd/index/BackgroundIndexStorage.cpp =================================================================== --- clangd/index/BackgroundIndexStorage.cpp +++ clangd/index/BackgroundIndexStorage.cpp @@ -9,6 +9,8 @@ #include "Logger.h" #include "index/Background.h" +#include "llvm/ADT/ScopeExit.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -33,6 +35,29 @@ return ShardRootSS.str(); } +template +llvm::Error writeAtomically(llvm::StringRef OutPath, WriterFunction &&Writer) { + // Write to a temporary file first. + llvm::Twine TempPath(OutPath, ".tmp."); + TempPath.concat(std::to_string(rand())); + std::error_code EC; + llvm::raw_fd_ostream OS(TempPath.str(), EC); + if (EC) + return llvm::errorCodeToError(EC); + // Make sure temp file is destroyed at exit. + auto _ = + llvm::make_scope_exit([TempPath] { llvm::sys::fs::remove(TempPath); }); + Writer(OS); + OS.close(); + if (OS.has_error()) + return llvm::errorCodeToError(OS.error()); + // Then move to real location. + EC = llvm::sys::fs::rename(TempPath, OutPath); + if (EC) + return llvm::errorCodeToError(EC); + return llvm::ErrorSuccess(); +} + // Uses disk as a storage for index shards. Creates a directory called // ".clangd-index/" under the path provided during construction. class DiskBackedIndexStorage : public BackgroundIndexStorage { @@ -70,14 +95,9 @@ llvm::Error storeShard(llvm::StringRef ShardIdentifier, IndexFileOut Shard) const override { - auto ShardPath = getShardPathFromFilePath(DiskShardRoot, ShardIdentifier); - std::error_code EC; - llvm::raw_fd_ostream OS(ShardPath, EC); - if (EC) - return llvm::errorCodeToError(EC); - OS << Shard; - OS.close(); - return llvm::errorCodeToError(OS.error()); + return writeAtomically( + getShardPathFromFilePath(DiskShardRoot, ShardIdentifier), + [&Shard](llvm::raw_ostream &OS) { OS << Shard; }); } };