Flag "volatile" files when creating a snapshot.
authorMichael Vrable <mvrable@cs.ucsd.edu>
Mon, 3 Dec 2007 19:10:48 +0000 (11:10 -0800)
committerMichael Vrable <mvrable@turin.ucsd.edu>
Mon, 3 Dec 2007 19:10:48 +0000 (11:10 -0800)
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
scandir.cc

index a3323a1..f972b75 100644 (file)
@@ -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"]))
index 818a460..03d8414 100644 (file)
@@ -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;