Replace boost::scoped_ptr with std::unique_ptr.
[cumulus.git] / metadata.cc
index a3323a1..96d21ea 100644 (file)
@@ -1,17 +1,37 @@
-/* LBS: An LFS-inspired filesystem backup system
- * Copyright (C) 2007  Michael Vrable
+/* Cumulus: Efficient Filesystem Backup to the Cloud
+ * Copyright (C) 2007-2008 The Cumulus Developers
+ * See the AUTHORS file for a list of contributors.
  *
- * Handling of metadata written to backup snapshots.  This manages the writing
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* Handling of metadata written to backup snapshots.  This manages the writing
  * of file metadata into new backup snapshots, including breaking the metadata
  * log apart across separate objects.  Eventually this should include unified
  * handling of the statcache, and re-use of metadata between snapshots.
  */
 
+#include <stdlib.h>
+#include <string.h>
+#include <sys/sysmacros.h>
 #include <string>
 #include <iostream>
 #include <map>
 
 #include "metadata.h"
+#include "localdb.h"
 #include "ref.h"
 #include "store.h"
 #include "util.h"
@@ -24,8 +44,12 @@ using std::ostringstream;
 
 static const size_t LBS_METADATA_BLOCK_SIZE = 65536;
 
+// If true, forces a full write of metadata: will not include pointers to
+// metadata in old snapshots.
+bool flag_full_metadata = false;
+
 /* TODO: Move to header file */
-void add_segment(const string& segment);
+extern LocalDb *db;
 
 /* Like strcmp, but sorts in the order that files will be visited in the
  * filesystem.  That is, we break paths apart at slashes, and compare path
@@ -73,7 +97,7 @@ static string encode_dict(const map<string, string>& dict)
     string result;
 
     if (dict.find("name") != dict.end()) {
-        result += "name: " + dict.at("name") + "\n";
+        result += "name: " + dict.find("name")->second + "\n";
     }
 
     for (map<string, string>::const_iterator i = dict.begin();
@@ -93,7 +117,7 @@ MetadataWriter::MetadataWriter(TarSegmentStore *store,
 {
     statcache_path = path;
     statcache_path += "/statcache2";
-    if (snapshot_scheme != NULL)
+    if (snapshot_scheme != NULL && strlen(snapshot_scheme) > 0)
         statcache_path = statcache_path + "-" + snapshot_scheme;
     statcache_tmp_path = statcache_path + "." + snapshot_name;
 
@@ -103,7 +127,7 @@ MetadataWriter::MetadataWriter(TarSegmentStore *store,
     if (statcache_out == NULL) {
         fprintf(stderr, "Error opening statcache %s: %m\n",
                 statcache_tmp_path.c_str());
-        throw IOException("Error opening statcache");
+        fatal("Error opening statcache");
     }
 
     old_metadata_eof = false;
@@ -198,12 +222,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"]))
@@ -268,6 +293,12 @@ void MetadataWriter::metadata_flush()
     ObjectReference indirect;
     for (list<MetadataItem>::iterator i = items.begin();
          i != items.end(); ++i) {
+        // If indirectly referencing any other metadata logs, be sure those
+        // segments are properly referenced.
+        if (i->reused) {
+            db->UseObject(i->ref);
+        }
+
         // Write out an indirect reference to any previous objects which could
         // be reused
         if (!i->reused || !indirect.merge(i->ref)) {
@@ -306,14 +337,13 @@ void MetadataWriter::metadata_flush()
     /* Write current metadata information to a new object. */
     LbsObject *meta = new LbsObject;
     meta->set_group("metadata");
-    meta->set_data(m.data(), m.size());
+    meta->set_data(m.data(), m.size(), NULL);
     meta->write(store);
-    meta->checksum();
 
     /* Write a reference to this block in the root. */
     ObjectReference ref = meta->get_ref();
     metadata_root << "@" << ref.to_string() << "\n";
-    add_segment(ref.get_segment());
+    db->UseObject(ref);
 
     delete meta;
 
@@ -342,9 +372,9 @@ void MetadataWriter::add(dictionary info)
     item.reused = false;
     item.text += encode_dict(info) + "\n";
 
-    if (info == old_metadata) {
+    if (info == old_metadata && !flag_full_metadata) {
         ObjectReference ref = ObjectReference::parse(old_metadata_loc);
-        if (!ref.is_null()) {
+        if (!ref.is_null() && db->IsAvailable(ref)) {
             item.reused = true;
             item.ref = ref;
         }
@@ -364,10 +394,9 @@ ObjectReference MetadataWriter::close()
 
     LbsObject *root = new LbsObject;
     root->set_group("metadata");
-    root->set_data(root_data.data(), root_data.size());
+    root->set_data(root_data.data(), root_data.size(), NULL);
     root->write(store);
-    root->checksum();
-    add_segment(root->get_ref().get_segment());
+    db->UseObject(root->get_ref());
 
     ObjectReference ref = root->get_ref();
     delete root;