Improve durability of schema version file writes
- 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 https://github.com/NixOS/nix/issues/7064
This commit is contained in:
parent
9d860f3467
commit
1b595026e1
|
@ -158,7 +158,7 @@ void migrateCASchema(SQLite& db, Path schemaPath, AutoCloseFD& lockFd)
|
||||||
txn.commit();
|
txn.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
writeFile(schemaPath, fmt("%d", nixCASchemaVersion));
|
writeFile(schemaPath, fmt("%d", nixCASchemaVersion), 0666, true);
|
||||||
lockFile(lockFd.get(), ltRead, true);
|
lockFile(lockFd.get(), ltRead, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -281,7 +281,7 @@ LocalStore::LocalStore(const Params & params)
|
||||||
else if (curSchema == 0) { /* new store */
|
else if (curSchema == 0) { /* new store */
|
||||||
curSchema = nixSchemaVersion;
|
curSchema = nixSchemaVersion;
|
||||||
openDB(*state, true);
|
openDB(*state, true);
|
||||||
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
|
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str(), 0666, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (curSchema < nixSchemaVersion) {
|
else if (curSchema < nixSchemaVersion) {
|
||||||
|
@ -329,7 +329,7 @@ LocalStore::LocalStore(const Params & params)
|
||||||
txn.commit();
|
txn.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
|
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str(), 0666, true);
|
||||||
|
|
||||||
lockFile(globalLock.get(), ltRead, true);
|
lockFile(globalLock.get(), ltRead, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
|
||||||
if (!fd)
|
if (!fd)
|
||||||
|
@ -364,10 +364,16 @@ void writeFile(const Path & path, std::string_view s, mode_t mode)
|
||||||
e.addTrace({}, "writing file '%1%'", path);
|
e.addTrace({}, "writing file '%1%'", path);
|
||||||
throw;
|
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);
|
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
|
||||||
if (!fd)
|
if (!fd)
|
||||||
|
@ -386,6 +392,20 @@ void writeFile(const Path & path, Source & source, mode_t mode)
|
||||||
e.addTrace({}, "writing file '%1%'", path);
|
e.addTrace({}, "writing file '%1%'", path);
|
||||||
throw;
|
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)
|
std::string readLine(int fd)
|
||||||
|
@ -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
|
AutoCloseFD::operator bool() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -115,9 +115,12 @@ std::string readFile(const Path & path);
|
||||||
void readFile(const Path & path, Sink & sink);
|
void readFile(const Path & path, Sink & sink);
|
||||||
|
|
||||||
/* Write a string to a file. */
|
/* 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. */
|
/* Read a line from a file descriptor. */
|
||||||
std::string readLine(int fd);
|
std::string readLine(int fd);
|
||||||
|
@ -231,6 +234,7 @@ public:
|
||||||
explicit operator bool() const;
|
explicit operator bool() const;
|
||||||
int release();
|
int release();
|
||||||
void close();
|
void close();
|
||||||
|
void fsync();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue