Partial commit of statcache support.
[cumulus.git] / statcache.cc
1 /* LBS: An LFS-inspired filesystem backup system Copyright (C) 2007  Michael
2  * Vrable
3  *
4  * To speed backups, we maintain a "stat cache" containing selected information
5  * about all regular files, including modification times and the list of blocks
6  * that comprised the file in the last backup.  If the file has not changed
7  * according to a stat() call, we may re-use the information contained in the
8  * stat cache instead of re-reading the entire file.  It is always safe to
9  * discard information from the stat cache; this will only cause a file to be
10  * re-read to determine that it contains the same data as before.
11  *
12  * The stat cache is stored in a file called "statcache" in the local backup
13  * directory.  During a backup, a new statcache file is written out with a
14  * suffix based on the current time; at the end of a successful backup this
15  * file is renamed over the original statcache file.
16  *
17  * The information in the statcache file is stored in sorted order as we
18  * traverse the filesystem, so that we can read and write it in a purely
19  * streaming manner.  (This is why we don't include the information in the
20  * SQLite local database; doing so is likely less efficient.)
21  */
22
23 #include <assert.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include <fstream>
28 #include <iostream>
29 #include <string>
30
31 #include "format.h"
32 #include "statcache.h"
33
34 using std::list;
35 using std::string;
36 using std::ifstream;
37 using std::ofstream;
38
39 void StatCache::Open(const char *path, const char *snapshot_name)
40 {
41     oldpath = path;
42     oldpath += "/statcache";
43     newpath = oldpath + "." + snapshot_name;
44
45     oldcache = NULL;
46     newcache = new ofstream(newpath.c_str());
47 }
48
49 void StatCache::Close()
50 {
51     if (oldcache != NULL)
52         delete oldcache;
53
54     delete newcache;
55
56     if (rename(newpath.c_str(), oldpath.c_str()) < 0) {
57         fprintf(stderr, "Error renaming statcache from %s to %s: %m\n",
58                 newpath.c_str(), oldpath.c_str());
59     }
60 }
61
62 /* Save stat information about a regular file for future invocations. */
63 void StatCache::Save(const string &path, struct stat *stat_buf,
64                      const string &checksum, const list<string> &blocks)
65 {
66     *newcache << uri_encode(path) << "\n";
67     *newcache << "mtime: " << encode_int(stat_buf->st_mtime) << "\n"
68               << "ctime: " << encode_int(stat_buf->st_ctime) << "\n"
69               << "inode: " << encode_int(stat_buf->st_ino) << "\n"
70               << "checksum: " << checksum << "\n";
71
72     *newcache << "blocks:";
73     for (list<string>::const_iterator i = blocks.begin();
74          i != blocks.end(); ++i) {
75         *newcache << " " << *i << "\n";
76     }
77
78     *newcache << "\n";
79 }