* Make dbRefs a mapping from Hash to [Path].

This commit is contained in:
Eelco Dolstra 2003-07-07 09:25:26 +00:00
parent 609a224848
commit 5895c160c4
11 changed files with 172 additions and 49 deletions

View file

@ -14,7 +14,7 @@ fix_LDADD = libnix.a -ldb_cxx-4 -lATerm
TESTS = test
test_SOURCES = test.cc
test_SOURCES = test.cc shared.cc
test_LDADD = libnix.a -ldb_cxx-4 -lATerm
noinst_LIBRARIES = libnix.a

View file

@ -73,6 +73,40 @@ bool queryDB(const string & filename, const string & dbname,
}
bool queryListDB(const string & filename, const string & dbname,
const string & key, Strings & data)
{
string d;
if (!queryDB(filename, dbname, key, d))
return false;
string::iterator it = d.begin();
while (it != d.end()) {
if (it + 4 > d.end())
throw Error(format("short db entry: `%1%'") % d);
unsigned int len;
len = (unsigned char) *it++;
len |= ((unsigned char) *it++) << 8;
len |= ((unsigned char) *it++) << 16;
len |= ((unsigned char) *it++) << 24;
if (it + len > d.end())
throw Error(format("short db entry: `%1%'") % d);
string s;
while (len--) s += *it++;
data.push_back(s);
}
return true;
}
void setDB(const string & filename, const string & dbname,
const string & key, const string & data)
{
@ -85,6 +119,29 @@ void setDB(const string & filename, const string & dbname,
}
void setListDB(const string & filename, const string & dbname,
const string & key, const Strings & data)
{
string d;
for (Strings::const_iterator it = data.begin();
it != data.end(); it++)
{
string s = *it;
unsigned int len = s.size();
d += len & 0xff;
d += (len >> 8) & 0xff;
d += (len >> 16) & 0xff;
d += (len >> 24) & 0xff;
d += s;
}
setDB(filename, dbname, key, d);
}
void delDB(const string & filename, const string & dbname,
const string & key)
{

View file

@ -4,6 +4,8 @@
#include <string>
#include <list>
#include "util.hh"
using namespace std;
typedef pair<string, string> DBPair;
@ -14,9 +16,15 @@ void createDB(const string & filename, const string & dbname);
bool queryDB(const string & filename, const string & dbname,
const string & key, string & data);
bool queryListDB(const string & filename, const string & dbname,
const string & key, Strings & data);
void setDB(const string & filename, const string & dbname,
const string & key, const string & data);
void setListDB(const string & filename, const string & dbname,
const string & key, const Strings & data);
void delDB(const string & filename, const string & dbname,
const string & key);

View file

@ -29,7 +29,7 @@ static bool isFState(Expr e, string & path)
}
else if (ATmatch(e, "Include(<str>)", &s1))
{
string fn = queryFromStore(parseHash(s1));
string fn = queryPathByHash(parseHash(s1));
return isFState(evalFile(fn), path);
}
else return false;

View file

@ -167,7 +167,7 @@ struct RStatus
static ATerm termFromHash(const Hash & hash)
{
string path = queryFromStore(hash);
string path = queryPathByHash(hash);
ATerm t = ATreadFromNamedFile(path.c_str());
if (!t) throw Error(format("cannot read aterm %1%") % path);
return t;
@ -183,7 +183,7 @@ Hash writeTerm(ATerm t)
string path2 = nixStore + "/" + (string) hash + ".nix";
if (rename(path.c_str(), path2.c_str()) == -1)
throw SysError(format("renaming %1% to %2%") % path % path2);
setDB(nixDB, dbRefs, hash, path2);
registerPath(path2, hash);
return hash;
}
@ -259,7 +259,7 @@ static FState realise(RStatus & status, FState fs)
}
/* Do we know a path with that hash? If so, copy it. */
string path2 = queryFromStore(hash);
string path2 = queryPathByHash(hash);
copyPath(path2, path);
return nf;
@ -318,7 +318,7 @@ static FState realise(RStatus & status, FState fs)
/* Register targetHash -> targetPath. !!! this should be in
values.cc. */
setDB(nixDB, dbRefs, outHash, outPath);
registerPath(outPath, outHash);
/* Register the normal form of fs. */
FState nf = ATmake("Path(<str>, Hash(<str>), <term>)",

View file

@ -54,6 +54,9 @@ int main(int argc, char * * argv)
"Try `%2% --help' for more information.\n")
% e.what() % programId;
return 1;
} catch (Error & e) {
cerr << format("error: %1%\n") % e.msg();
return 1;
} catch (exception & e) {
cerr << format("error: %1%\n") % e.what();
return 1;

View file

@ -83,25 +83,89 @@ void copyPath(string src, string dst)
}
Hash registerPath(const string & _path, Hash hash)
{
string path(canonPath(_path));
if (hash == Hash()) hash = hashPath(path);
Strings paths;
queryListDB(nixDB, dbRefs, hash, paths); /* non-existence = ok */
for (Strings::iterator it = paths.begin();
it != paths.end(); it++)
if (*it == path) goto exists;
paths.push_back(path);
setListDB(nixDB, dbRefs, hash, paths);
exists:
return hash;
}
bool isInPrefix(const string & path, const string & _prefix)
{
string prefix = canonPath(_prefix + "/");
return string(path, 0, prefix.size()) == prefix;
}
static string queryPathByHashPrefix(Hash hash, const string & prefix)
{
Strings paths;
if (!queryListDB(nixDB, dbRefs, hash, paths))
throw Error(format("no paths known with hash `%1%'") % (string) hash);
/* Arbitrarily pick the first one that exists and still hash the
right hash. */
for (Strings::iterator it = paths.begin();
it != paths.end(); it++)
{
debug(*it);
string path = *it;
try {
debug(path);
debug(prefix);
if (isInPrefix(path, prefix) && hashPath(path) == hash)
return path;
} catch (Error & e) {
debug(format("checking hash: %1%") % e.msg());
/* try next one */
}
}
throw Error(format("all paths with hash `%1%' are stale") % (string) hash);
}
string queryPathByHash(Hash hash)
{
return queryPathByHashPrefix(hash, "/");
}
void addToStore(string srcPath, string & dstPath, Hash & hash)
{
srcPath = absPath(srcPath);
hash = hashPath(srcPath);
string path;
if (queryDB(nixDB, dbRefs, hash, path)) {
debug((string) hash + " already known");
dstPath = path;
try {
dstPath = queryPathByHashPrefix(hash, nixStore);
return;
} catch (...) {
}
string baseName = baseNameOf(srcPath);
dstPath = nixStore + "/" + (string) hash + "-" + baseName;
copyPath(srcPath, dstPath);
setDB(nixDB, dbRefs, hash, dstPath);
registerPath(dstPath, hash);
}
@ -113,20 +177,3 @@ void deleteFromStore(const string & path)
deletePath(path);
// delDB(nixDB, dbRefs, hash);
}
string queryFromStore(Hash hash)
{
string fn, url;
if (queryDB(nixDB, dbRefs, hash, fn)) {
/* Verify that the file hasn't changed. !!! race !!! slow */
if (hashPath(fn) != hash)
throw Error("file " + fn + " is stale");
return fn;
}
throw Error(format("don't know a path with hash `%1%'") % (string) hash);
}

View file

@ -10,6 +10,12 @@ using namespace std;
void copyPath(string src, string dst);
/* Register a path keyed on its hash. */
Hash registerPath(const string & path, Hash hash = Hash());
/* Query a path (any path) through its hash. */
string queryPathByHash(Hash hash);
/* Copy a file to the nixStore directory and register it in dbRefs.
Return the hash code of the value. */
void addToStore(string srcPath, string & dstPath, Hash & hash);
@ -17,8 +23,5 @@ void addToStore(string srcPath, string & dstPath, Hash & hash);
/* Delete a value from the nixStore directory. */
void deleteFromStore(const string & path);
/* !!! */
string queryFromStore(Hash hash);
#endif /* !__VALUES_H */

View file

@ -191,15 +191,10 @@ void runTests()
}
int main(int argc, char * * argv)
void run(Strings args)
{
ATerm bottomOfStack;
ATinit(argc, argv, &bottomOfStack);
try {
runTests();
} catch (exception & e) {
cerr << "error: " << e.what() << endl;
return 1;
}
runTests();
}
string programId = "test";

View file

@ -33,13 +33,18 @@ string absPath(string path, string dir)
dir = buf;
}
path = dir + "/" + path;
/* !!! canonicalise */
char resolved[PATH_MAX];
if (!realpath(path.c_str(), resolved))
throw SysError(format("cannot canonicalise path %1%") % path);
path = resolved;
}
return path;
return canonPath(path);
}
string canonPath(const string & path)
{
char resolved[PATH_MAX];
if (!realpath(path.c_str(), resolved))
throw SysError(format("cannot canonicalise path `%1%'") % path);
/* !!! check that this removes trailing slashes */
return resolved;
}

View file

@ -21,6 +21,7 @@ public:
Error(const format & f);
~Error() throw () { };
const char * what() const throw () { return err.c_str(); }
const string & msg() const throw () { return err; }
};
class SysError : public Error
@ -44,9 +45,13 @@ extern string thisSystem;
/* Return an absolutized path, resolving paths relative to the
specified directory, or the current directory otherwise. */
specified directory, or the current directory otherwise. The path
is also canonicalised. */
string absPath(string path, string dir = "");
/* Canonicalise a path (as in realpath(3)). */
string canonPath(const string & path);
/* Return the directory part of the given path, i.e., everything
before the final `/'. */
string dirOf(string path);