Skip to content

Commit

Permalink
Improve durability of schema version file writes
Browse files Browse the repository at this point in the history
- call close explicitly in writeFile to prevent the close exception
  from being ignored
- fsync after writing schema file to flush data to disk
- fsync schema file parent to flush metadata to disk

#7064
  • Loading branch information
squalus committed Sep 20, 2022
1 parent 9d860f3 commit 1b59502
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 7 deletions.
6 changes: 3 additions & 3 deletions src/libstore/local-store.cc
Expand Up @@ -158,7 +158,7 @@ void migrateCASchema(SQLite& db, Path schemaPath, AutoCloseFD& lockFd)
txn.commit();
}

writeFile(schemaPath, fmt("%d", nixCASchemaVersion));
writeFile(schemaPath, fmt("%d", nixCASchemaVersion), 0666, true);
lockFile(lockFd.get(), ltRead, true);
}
}
Expand Down Expand Up @@ -281,7 +281,7 @@ LocalStore::LocalStore(const Params & params)
else if (curSchema == 0) { /* new store */
curSchema = nixSchemaVersion;
openDB(*state, true);
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str(), 0666, true);
}

else if (curSchema < nixSchemaVersion) {
Expand Down Expand Up @@ -329,7 +329,7 @@ LocalStore::LocalStore(const Params & params)
txn.commit();
}

writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str(), 0666, true);

lockFile(globalLock.get(), ltRead, true);
}
Expand Down
38 changes: 36 additions & 2 deletions src/libutil/util.cc
Expand Up @@ -353,7 +353,7 @@ void readFile(const Path & path, Sink & sink)
}


void writeFile(const Path & path, std::string_view s, mode_t mode)
void writeFile(const Path & path, std::string_view s, mode_t mode, bool sync)
{
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
if (!fd)
Expand All @@ -364,10 +364,16 @@ void writeFile(const Path & path, std::string_view s, mode_t mode)
e.addTrace({}, "writing file '%1%'", path);
throw;
}
if (sync)
fd.fsync();
// Explicitly close to make sure exceptions are propagated.
fd.close();
if (sync)
syncParent(path);
}


void writeFile(const Path & path, Source & source, mode_t mode)
void writeFile(const Path & path, Source & source, mode_t mode, bool sync)
{
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
if (!fd)
Expand All @@ -386,6 +392,20 @@ void writeFile(const Path & path, Source & source, mode_t mode)
e.addTrace({}, "writing file '%1%'", path);
throw;
}
if (sync)
fd.fsync();
// Explicitly close to make sure exceptions are propagated.
fd.close();
if (sync)
syncParent(path);
}

void syncParent(const Path & path)
{
AutoCloseFD fd = open(dirOf(path).c_str(), O_RDONLY, 0);
if (!fd)
throw SysError("opening file '%1%'", path);
fd.fsync();
}

std::string readLine(int fd)
Expand Down Expand Up @@ -841,6 +861,20 @@ void AutoCloseFD::close()
}
}

void AutoCloseFD::fsync()
{
if (fd != -1) {
int result;
#if __APPLE__
result = ::fcntl(fd, F_FULLFSYNC);
#else
result = ::fsync(fd);
#endif
if (result == -1)
throw SysError("fsync file descriptor %1%", fd);
}
}


AutoCloseFD::operator bool() const
{
Expand Down
8 changes: 6 additions & 2 deletions src/libutil/util.hh
Expand Up @@ -115,9 +115,12 @@ std::string readFile(const Path & path);
void readFile(const Path & path, Sink & sink);

/* Write a string to a file. */
void writeFile(const Path & path, std::string_view s, mode_t mode = 0666);
void writeFile(const Path & path, std::string_view s, mode_t mode = 0666, bool sync = false);

void writeFile(const Path & path, Source & source, mode_t mode = 0666);
void writeFile(const Path & path, Source & source, mode_t mode = 0666, bool sync = false);

/* Flush a file's parent directory to disk */
void syncParent(const Path & path);

/* Read a line from a file descriptor. */
std::string readLine(int fd);
Expand Down Expand Up @@ -231,6 +234,7 @@ public:
explicit operator bool() const;
int release();
void close();
void fsync();
};


Expand Down

0 comments on commit 1b59502

Please sign in to comment.