* Make dbRefs a mapping from Hash to [Path].
This commit is contained in:
parent
609a224848
commit
5895c160c4
|
@ -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
|
||||
|
|
57
src/db.cc
57
src/db.cc
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>)",
|
||||
|
|
|
@ -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;
|
||||
|
|
93
src/store.cc
93
src/store.cc
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
15
src/test.cc
15
src/test.cc
|
@ -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";
|
||||
|
|
17
src/util.cc
17
src/util.cc
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue