write dirstate file atomically

Summary:
Write the dirstate data using the new folly::writeFileAtomic() function.
This ensures that the dirstate file will always contain full, valid contents,
even if we crash or run out of disk space partway through writing out the data.

This diff also includes a couple other minor tweaks:
- Update Dirstate to store the DirstatePersistence object directly inline,
  rather than allocating it separately on the heap.
- Update the DirstatePersistenceTest code to prefix temporary directories with
  "eden_test".  This just makes it easier to tell if the tests fail to clean up
  after themselves for any reason.

Reviewed By: bolinfest

Differential Revision: D4254027

fbshipit-source-id: 6b6601b65aeacdee998a6c4260e972d5fb2426ac
This commit is contained in:
Adam Simpkins 2016-12-01 17:49:33 -08:00 committed by Facebook Github Bot
parent aaa3332644
commit 87c2d46ce3
4 changed files with 16 additions and 17 deletions

View File

@ -8,10 +8,12 @@
*
*/
#include "Dirstate.h"
#include <folly/Format.h>
#include <folly/io/Cursor.h>
#include <folly/io/IOBuf.h>
#include "eden/fs/config/ClientConfig.h"
#include "eden/fs/inodes/DirstatePersistence.h"
#include "eden/fs/inodes/EdenMount.h"
#include "eden/fs/inodes/EdenMounts.h"
#include "eden/fs/inodes/FileInode.h"
@ -123,10 +125,10 @@ void processRemovedFile(
Dirstate::Dirstate(EdenMount* mount)
: mountPoint_(mount->getMountPoint()),
objectStore_(mount->getObjectStore()) {
auto dirstateStoragePath = mount->getConfig()->getDirstateStoragePath();
persistence_ = std::make_unique<DirstatePersistence>(dirstateStoragePath);
*(userDirectives_.wlock()) = persistence_->load();
objectStore_(mount->getObjectStore()),
persistence_(mount->getConfig()->getDirstateStoragePath()) {
auto loadedData = persistence_.load();
userDirectives_.wlock()->swap(loadedData);
}
Dirstate::~Dirstate() {}
@ -449,12 +451,12 @@ void Dirstate::add(RelativePathPiece path) {
break;
case overlay::UserStatusDirective::Remove:
userDirectives->erase(path.copy());
persistence_->save(*userDirectives);
persistence_.save(*userDirectives);
break;
}
} else {
(*userDirectives)[path.copy()] = overlay::UserStatusDirective::Add;
persistence_->save(*userDirectives);
persistence_.save(*userDirectives);
}
}
}
@ -593,7 +595,7 @@ void Dirstate::remove(RelativePathPiece path, bool force) {
}
}
(*userDirectives)[path.copy()] = overlay::UserStatusDirective::Remove;
persistence_->save(*userDirectives);
persistence_.save(*userDirectives);
} else {
switch (result->second) {
case overlay::UserStatusDirective::Remove:
@ -607,7 +609,7 @@ void Dirstate::remove(RelativePathPiece path, bool force) {
path.stringPiece()));
} else {
userDirectives->erase(path.copy());
persistence_->save(*userDirectives);
persistence_.save(*userDirectives);
}
break;
}

View File

@ -164,7 +164,7 @@ class Dirstate {
fusell::MountPoint* mountPoint_;
ObjectStore* objectStore_;
std::unique_ptr<DirstatePersistence> persistence_;
DirstatePersistence persistence_;
/**
* Manifest of files in the working copy whose status is not CLEAN. These are
* also referred to as "nonnormal" files.

View File

@ -8,6 +8,7 @@
*
*/
#include "DirstatePersistence.h"
#include <folly/FileUtil.h>
#include <thrift/lib/cpp2/protocol/Serializer.h>
@ -26,12 +27,8 @@ void DirstatePersistence::save(
}
dirstateData.directives = directives;
auto serializedData = CompactSerializer::serialize<std::string>(dirstateData);
auto wrote = folly::writeFile(serializedData, storageFile_.c_str());
if (!wrote) {
throw std::runtime_error(folly::to<std::string>(
"Failed to persist Dirstate to file ", storageFile_));
}
folly::writeFileAtomic(storageFile_.stringPiece(), serializedData, 0644);
}
std::unordered_map<RelativePath, overlay::UserStatusDirective>

View File

@ -19,7 +19,7 @@ using apache::thrift::CompactSerializer;
using folly::test::TemporaryFile;
TEST(DirstatePersistence, saveAndReadDirectivesBackOut) {
TemporaryFile storageFile;
TemporaryFile storageFile("eden_test");
AbsolutePath storageFilePath(storageFile.path().c_str());
DirstatePersistence persistence(storageFilePath);
@ -35,7 +35,7 @@ TEST(DirstatePersistence, saveAndReadDirectivesBackOut) {
}
TEST(DirstatePersistence, loadFromFileWithWellFormattedData) {
TemporaryFile storageFile;
TemporaryFile storageFile("eden_test");
overlay::DirstateData dirstateData;
dirstateData.directives = {
@ -59,7 +59,7 @@ TEST(DirstatePersistence, loadFromFileWithWellFormattedData) {
TEST(DirstatePersistence, attemptLoadFromNonExistentFile) {
AbsolutePath storageFilePath;
{
TemporaryFile storageFile;
TemporaryFile storageFile("eden_test");
storageFilePath = AbsolutePath(storageFile.path().c_str());
}
DirstatePersistence persistence(storageFilePath);