#include <set>
#include "format.h"
+#include "localdb.h"
#include "store.h"
#include "sha1.h"
static const size_t LBS_METADATA_BLOCK_SIZE = 65536;
+/* Local database, which tracks objects written in this and previous
+ * invocations to help in creating incremental snapshots. */
+LocalDb *db;
+
/* Contents of the root object. This will contain a set of indirect links to
* the metadata objects. */
std::ostringstream metadata_root;
}
/* Read the contents of a file (specified by an open file descriptor) and copy
- * the data to the store. */
-void dumpfile(int fd, dictionary &file_info)
+ * the data to the store. Returns the size of the file (number of bytes
+ * dumped), or -1 on error. */
+int64_t dumpfile(int fd, dictionary &file_info)
{
struct stat stat_buf;
fstat(fd, &stat_buf);
if ((stat_buf.st_mode & S_IFMT) != S_IFREG) {
fprintf(stderr, "file is no longer a regular file!\n");
- return;
+ return -1;
}
/* The index data consists of a sequence of pointers to the data blocks
hash.process(block_buf, bytes);
- // tarstore processing
- LbsObject *o = new LbsObject;
- o->set_group("data");
- o->set_data(block_buf, bytes);
- o->write(tss);
- object_list.push_back(o->get_name());
- segment_list.insert(o->get_ref().get_segment());
- delete o;
-
+ // Either find a copy of this block in an already-existing segment, or
+ // index it so it can be re-used in the future
+ SHA1Checksum block_hash;
+ block_hash.process(block_buf, bytes);
+ string block_csum = block_hash.checksum_str();
+ ObjectReference ref = db->FindObject(block_csum, bytes);
+
+ // Store a copy of the object if one does not yet exist
+ if (ref.get_segment().size() == 0) {
+ LbsObject *o = new LbsObject;
+ o->set_group("data");
+ o->set_data(block_buf, bytes);
+ o->write(tss);
+ ref = o->get_ref();
+ db->StoreObject(ref, block_csum, bytes);
+ delete o;
+ }
+ object_list.push_back(ref.to_string());
+ segment_list.insert(ref.get_segment());
size += bytes;
}
segment_list.insert(i->get_ref().get_segment());
delete i;
}
+
+ return size;
}
void scanfile(const string& path)
struct stat stat_buf;
char *buf;
ssize_t len;
+ int64_t file_size;
list<string> refs;
// Set to true if the item is a directory and we should recursively scan
flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
- file_info["size"] = encode_int(stat_buf.st_size);
- dumpfile(fd, file_info);
+ file_size = dumpfile(fd, file_info);
+ file_info["size"] = encode_int(file_size);
close(fd);
+ if (file_size < 0)
+ return; // error occurred; do not dump file
+
+ if (file_size != stat_buf.st_size) {
+ fprintf(stderr, "Warning: Size of %s changed during reading\n",
+ path.c_str());
+ }
+
break;
case S_IFDIR:
inode_type = 'd';
tss = new TarSegmentStore(backup_dest);
+ string database_path = backup_dest + "/localdb.sqlite";
+ db = new LocalDb;
+ db->Open(database_path.c_str());
+
/* Write a backup descriptor file, which says which segments are needed and
* where to start to restore this snapshot. The filename is based on the
* current time. */
descriptor << " " << *i << "\n";
}
+ db->Close();
+
tss->sync();
delete tss;