From 2f5d9b51edebfd70f0e427dfb27ecb496bf53fe0 Mon Sep 17 00:00:00 2001 From: Michael Vrable Date: Mon, 3 Dec 2007 11:10:48 -0800 Subject: [PATCH] Flag "volatile" files when creating a snapshot. If a file has changed very near to the time it was backed up (right now 30 seconds, though this could probably be decreased to only a few seconds), mark the file as "volatile" and do not use the stat information to skip that file on the next backup. This is to avoid a race condition where a file's stat information is saved, the file is dumped, and then the file is modified again. If this happens within the same second as the earlier modifications, then mtime and ctime will not be updated (since they already refer to the current second), and on a subsequent backup the file would not be stored since it appears to be unchanged. However, if the file's mtime and ctime are in the past, then this can't happen, so use this as a test for when it is safe to skip apparently unchanged files. The volatile flag only needs to go in the statcache, not the main metadata log, but for the moment it is going in both. --- metadata.cc | 9 +++++---- scandir.cc | 7 +++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/metadata.cc b/metadata.cc index a3323a1..f972b75 100644 --- a/metadata.cc +++ b/metadata.cc @@ -198,12 +198,13 @@ bool MetadataWriter::find(const string& path) } /* Does a file appear to be unchanged from the previous time it was backed up, - * based on stat information? - * - * TODO: Notice files that were modified as they were being backed up the last - * time. */ + * based on stat information? */ bool MetadataWriter::is_unchanged(const struct stat *stat_buf) { + if (old_metadata.find("volatile") != old_metadata.end() + && parse_int(old_metadata["volatile"]) != 0) + return false; + if (old_metadata.find("ctime") == old_metadata.end()) return false; if (stat_buf->st_ctime != parse_int(old_metadata["ctime"])) diff --git a/scandir.cc b/scandir.cc index 818a460..03d8414 100644 --- a/scandir.cc +++ b/scandir.cc @@ -248,6 +248,7 @@ void dump_inode(const string& path, // Path within snapshot ssize_t len; printf("%s\n", path.c_str()); + metawriter->find(path); file_info["name"] = uri_encode(path); file_info["mode"] = encode_int(stat_buf.st_mode & 07777, 8); @@ -256,6 +257,11 @@ void dump_inode(const string& path, // Path within snapshot file_info["user"] = encode_int(stat_buf.st_uid); file_info["group"] = encode_int(stat_buf.st_gid); + time_t now = time(NULL); + if (now - stat_buf.st_ctime < 30 || now - stat_buf.st_mtime < 30) + if ((stat_buf.st_mode & S_IFMT) != S_IFDIR) + file_info["volatile"] = "1"; + struct passwd *pwd = getpwuid(stat_buf.st_uid); if (pwd != NULL) { file_info["user"] += " (" + uri_encode(pwd->pw_name) + ")"; @@ -320,6 +326,7 @@ void dump_inode(const string& path, // Path within snapshot if (file_size != stat_buf.st_size) { fprintf(stderr, "Warning: Size of %s changed during reading\n", path.c_str()); + file_info["volatile"] = "1"; } break; -- 2.20.1