1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-26 20:20:58 +01:00

Added / Removed state functions to the Store API

This commit is contained in:
Wouter den Breejen 2007-08-27 13:09:24 +00:00
parent 53a6b9aaa5
commit bdcce95a39
25 changed files with 624 additions and 383 deletions

View file

@ -1079,7 +1079,7 @@ static string makeValidityRegistration(const PathSet & paths,
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) {
s += *i + "\n";
Path deriver = showDerivers ? queryDeriver(noTxn, *i) : "";
Path deriver = showDerivers ? store->queryDeriver(*i) : "";
s += deriver + "\n";
PathSet references;
@ -1400,7 +1400,7 @@ void DerivationGoal::startBuilder()
checkStatePath(drv);
if(drv.stateOutputs.find("state")->second.getCreateDirsBeforeInstall())
createStateDirs(drv.stateOutputDirs, drv.stateOutputs);
createStateDirsTxn(noTxn, drv.stateOutputDirs, drv.stateOutputs);
}
/* For convenience, set an environment pointing to the top build
@ -1640,7 +1640,7 @@ void DerivationGoal::computeClosure()
//We create state dirs only when state is enabled and when the dirs need to be created after the installation
if(drv.stateOutputs.size() != 0)
if(!drv.stateOutputs.find("state")->second.getCreateDirsBeforeInstall())
createStateDirs(drv.stateOutputDirs, drv.stateOutputs);
createStateDirsTxn(noTxn, drv.stateOutputDirs, drv.stateOutputs);
/*
for (PathSet::iterator i = allPaths.begin(); i != allPaths.end(); ++i)

View file

@ -478,7 +478,7 @@ void LocalStore::collectGarbage(GCAction action, const PathSet & pathsToDelete,
/* Note that the deriver need not be valid (e.g., if we
previously ran the collector with `gcKeepDerivations'
turned off). */
Path deriver = queryDeriver(noTxn, *i);
Path deriver = store->queryDeriver(*i);
if (deriver != "" && store->isValidPath(deriver))
computeFSClosure(deriver, livePaths, true, false, -1); //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!! WE (MAY) ALSO NEED TO KEEP STATE
}

View file

@ -3,7 +3,7 @@
#include <map>
#include <algorithm>
#include <pwd.h>
namespace nix {
@ -27,8 +27,9 @@ unsigned int maxBuildJobs = 1;
bool readOnlyMode = false;
string thisSystem = "unset";
unsigned int maxSilentTime = 0;
static bool settingsRead = false;
uid_t callingUID = 0;
bool debugWorker = true;
static std::map<string, Strings> settings;
@ -115,5 +116,32 @@ unsigned int queryIntSetting(const string & name, unsigned int def)
return n;
}
uid_t queryCallingUID()
{
/* A root user will not even bother calling the daemon, so there is no way to check
* If the uid is not yet set...
*/
return callingUID;
}
void setCallingUID(uid_t uid, bool reset)
{
if(callingUID != 0 && !reset)
throw Error(format("The UID of the caller aleady set! at this point"));
callingUID = uid;
}
string queryCallingUsername()
{
uid_t uid = queryCallingUID();
passwd *pwd = getpwuid(uid);
char *pw_name = pwd->pw_name;
return (string)pw_name;
}
}

View file

@ -80,7 +80,16 @@ bool queryBoolSetting(const string & name, bool def);
unsigned int queryIntSetting(const string & name, unsigned int def);
/* TODO PRIVATE: UID of the user that calls the nix-worker daemon */
extern uid_t callingUID;
/* get/set the UID of the user that calls the nix-worker daemon */
uid_t queryCallingUID();
void setCallingUID(uid_t uid, bool reset = false);
/* get the username based on the UID of the user that calls the nix-worker daemon */
string queryCallingUsername();
extern bool debugWorker;
}

View file

@ -256,11 +256,11 @@ LocalStore::LocalStore(bool reserveSpace)
throw Error(format("`%1%' is corrupt") % schemaFN);
}
if (curSchema > nixSchemaVersion)
if (curSchema > nixSchemaVersion && curSchema != 4) //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MAJOR HACK, I SHOULD MERGE WITH THE TRUNK
throw Error(format("current Nix store schema is version %1%, but I only support %2%")
% curSchema % nixSchemaVersion);
if (curSchema < nixSchemaVersion) {
if (curSchema < nixSchemaVersion && curSchema != 4) { //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MAJOR HACK, I SHOULD MERGE WITH THE TRUNK
if (curSchema <= 1)
upgradeStore07();
if (curSchema == 2)
@ -809,7 +809,7 @@ bool LocalStore::isStateDrv(const Derivation & drv)
return nix::isStateDrvTxn(noTxn, drv);
}
Path queryDeriver(const Transaction & txn, const Path & storePath)
static Path queryDeriver(const Transaction & txn, const Path & storePath)
{
if (!isRealisablePath(txn, storePath))
throw Error(format("path `%1%' is not valid") % storePath);
@ -827,6 +827,11 @@ Path queryDeriver(const Transaction & txn, const Path & storePath)
return "";
}
Path LocalStore::queryDeriver(const Path & path)
{
return nix::queryDeriver(noTxn, path);
}
//A '*' as argument stands for all identifiers or all users
PathSet queryDerivers(const Transaction & txn, const Path & storePath, const string & identifier, const string & user)
{
@ -859,6 +864,11 @@ PathSet queryDerivers(const Transaction & txn, const Path & storePath, const str
return filtereddata;
}
PathSet LocalStore::queryDerivers(const Path & storePath, const string & identifier, const string & user)
{
return nix::queryDerivers(noTxn, storePath, identifier, user);
}
//Wrapper around converting the drvPath to the statePath
/*
PathSet queryDeriversStatePath(const Transaction & txn, const Path & storePath, const string & identifier, const string & user)
@ -1158,10 +1168,11 @@ Path LocalStore::addToStore(const Path & _srcPath, bool fixed,
registerValidPath(txn, dstPath, h, PathSet(), PathSet(), "", -1); //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!! CHECK (probabyly ok?)
txn.commit();
}
outputLock.setDeletion(true);
}
return dstPath;
}
@ -1256,7 +1267,7 @@ void LocalStore::exportPath(const Path & path, bool sign,
nix::queryXReferencesTxn(txn, path, references, true, -1); //TODO we can only now export the final revision //TODO also export the state references ???
writeStringSet(references, hashAndWriteSink);
Path deriver = queryDeriver(txn, path);
Path deriver = nix::queryDeriver(txn, path);
writeString(deriver, hashAndWriteSink);
if (sign) {
@ -1423,8 +1434,7 @@ void deleteFromStore(const Path & _path, unsigned long long & bytesFreed)
throw PathInUse(format("cannot delete path `%1%' because it is in use by path `%2%'") % path % *i);
invalidatePath(txn, path);
//TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//Also delete/invalidate stateReferrers?????
//TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Also delete/invalidate stateReferrers?????
}
txn.commit();
@ -1563,13 +1573,11 @@ void verifyStore(bool checkContents)
txn.commit();
}
void setStatePathsInterval(const PathSet & statePaths, const vector<int> & intervals, bool allZero)
void setStatePathsIntervalTxn(const Transaction & txn, const PathSet & statePaths, const vector<int> & intervals, bool allZero)
{
if(!allZero && statePaths.size() != intervals.size()){
throw Error("the number of statepaths and intervals must be equal");
}
Transaction txn(nixDB);
int n=0;
for (PathSet::iterator i = statePaths.begin(); i != statePaths.end(); ++i)
@ -1583,13 +1591,13 @@ void setStatePathsInterval(const PathSet & statePaths, const vector<int> & inter
nixDB.setString(txn, dbStateCounters, *i, int2String(interval));
n++;
}
txn.commit();
}
void LocalStore::setStatePathsInterval(const PathSet & statePaths, const vector<int> & intervals, bool allZero)
{
nix::setStatePathsInterval(statePaths, intervals, allZero);
Transaction txn(nixDB);
nix::setStatePathsIntervalTxn(txn, statePaths, intervals, allZero);
txn.commit();
}
vector<int> getStatePathsIntervalTxn(const Transaction & txn, const PathSet & statePaths)
@ -1664,7 +1672,7 @@ void LocalStore::storePathRequisites(const Path & storeOrstatePath, const bool i
nix::storePathRequisites(storeOrstatePath, includeOutputs, paths, withComponents, withState, revision);
}
void queryAllValidPaths(const Transaction & txn, PathSet & allComponentPaths, PathSet & allStatePaths)
void queryAllValidPathsTxn(const Transaction & txn, PathSet & allComponentPaths, PathSet & allStatePaths)
{
Paths allComponentPaths2;
Paths allStatePaths2;
@ -1711,9 +1719,24 @@ bool LocalStore::queryAvailableStateRevisions(const Path & statePath, RevisionIn
return nix::queryAvailableStateRevisionsTxn(noTxn, statePath, revisions);
}
void LocalStore::commitStatePath(const Path & statePath)
Snapshots LocalStore::commitStatePath(const Path & statePath)
{
nix::commitStatePathTxn(noTxn, statePath);
Transaction txn(nixDB);
Snapshots ss = nix::commitStatePathTxn(txn, statePath);
txn.commit();
return ss;
}
void LocalStore::scanAndUpdateAllReferences(const Path & statePath, const bool recursive)
{
Transaction txn(nixDB);
if(recursive)
nix::scanAndUpdateAllReferencesRecusivelyTxn(txn, statePath);
else{
PathSet empty;
nix::scanAndUpdateAllReferencesTxn(txn, statePath, empty, empty);
}
txn.commit();
}
void setSolidStateReferencesTxn(const Transaction & txn, const Path & statePath, const PathSet & paths)
@ -1767,6 +1790,11 @@ PathSet toNonSharedPathSetTxn(const Transaction & txn, const PathSet & statePath
return real_statePaths;
}
PathSet LocalStore::toNonSharedPathSet(const PathSet & statePaths)
{
return toNonSharedPathSetTxn(noTxn, statePaths);
}
void setStateComponentReferencesTxn(const Transaction & txn, const Path & statePath, const Strings & references, int revision, int timestamp)
{
nixDB.setStateReferences(txn, dbStateComponentReferences, dbStateRevisions, statePath, references, revision, timestamp);
@ -1819,6 +1847,15 @@ PathSet getSharedWithPathSetRecTxn(const Transaction & txn, const Path & statePa
return getSharedWithPathSetRecTxn_private(txn, statePath_ns, empty);
}
void LocalStore::revertToRevision(Path & componentPath, Path & derivationPath, Path & statePath, int revision_arg, bool recursive)
{
Transaction txn(nixDB);
revertToRevisionTxn(txn, componentPath, derivationPath, statePath, revision_arg, recursive);
txn.commit();
}
/* Upgrade from schema 1 (Nix <= 0.7) to schema 2 (Nix >= 0.8). */
static void upgradeStore07()
{

View file

@ -87,6 +87,8 @@ public:
void collectGarbage(GCAction action, const PathSet & pathsToDelete,
bool ignoreLiveness, PathSet & result, unsigned long long & bytesFreed);
/////////////////////////////
void setStatePathsInterval(const PathSet & statePath, const vector<int> & intervals, bool allZero = false);
@ -106,7 +108,17 @@ public:
bool queryAvailableStateRevisions(const Path & statePath, RevisionInfos & revisions);
void commitStatePath(const Path & statePath);
Snapshots commitStatePath(const Path & statePath);
Path queryDeriver(const Path & path); //should these be in here ????
PathSet queryDerivers(const Path & storePath, const string & identifier, const string & user); //should these be in here ????
void scanAndUpdateAllReferences(const Path & statePath, const bool recursive);
PathSet toNonSharedPathSet(const PathSet & statePaths);
void revertToRevision(Path & componentPath, Path & derivationPath, Path & statePath, int revision_arg, bool recursive);
};
@ -174,16 +186,9 @@ void setReferences(const Transaction & txn, const Path & store_or_statePath,
void setDeriver(const Transaction & txn, const Path & path,
const Path & deriver);
/* Query the deriver of a store path. Return the empty string if no
deriver has been set. */
Path queryDeriver(const Transaction & txn, const Path & path);
/* Query the derivers of a state-store path. */
PathSet queryDerivers(const Transaction & txn, const Path & storePath, const string & identifier, const string & user);
/* Query the derivers of a state path. (are there more then 1 for a statepath?) */
//PathSet queryDeriversStatePath(const Transaction & txn, const Path & storePath, const string & identifier, const string & user);
/* Delete a value from the nixStore directory. */
void deleteFromStore(const Path & path, unsigned long long & bytesFreed);
@ -217,7 +222,7 @@ bool isStateDrvPathTxn(const Transaction & txn, const Path & drvPath);
bool isStateDrvTxn(const Transaction & txn, const Derivation & drv);
//TODO can this ?????
void queryAllValidPaths(const Transaction & txn, PathSet & allComponentPaths, PathSet & allStatePaths);
void queryAllValidPathsTxn(const Transaction & txn, PathSet & allComponentPaths, PathSet & allStatePaths);
bool isValidStatePathTxn(const Transaction & txn, const Path & path);
void queryXReferencesTxn(const Transaction & txn, const Path & path, PathSet & references, const bool component_or_state, const int revision, int timestamp = -1);
@ -245,6 +250,10 @@ Path toNonSharedPathTxn(const Transaction & txn, const Path & statePath);
PathSet getSharedWithPathSetRecTxn(const Transaction & txn, const Path & statePath);
void ensurePathTxn(const Transaction & txn, const Path & path);
vector<int> getStatePathsIntervalTxn(const Transaction & txn, const PathSet & statePaths);
bool queryStateRevisionsTxn(const Transaction & txn, const Path & statePath, RevisionClosure & revisions, RevisionClosureTS & timestamps, const int revision);
void setStatePathsIntervalTxn(const Transaction & txn, const PathSet & statePath, const vector<int> & intervals, bool allZero = false);
}

View file

@ -39,6 +39,7 @@ RemoteStore::RemoteStore()
{
string remoteMode = getEnv("NIX_REMOTE");
debug(format("Client remoteMode: '%1%'") % remoteMode);
if (remoteMode == "slave")
/* Fork off a setuid worker to do the privileged work. */
forkSlave();
@ -280,7 +281,9 @@ Path RemoteStore::addToStore(const Path & _srcPath, bool fixed,
writeString(hashAlgo, to);
dumpPath(srcPath, to, filter);
processStderr();
Path path = readStorePath(from);
printMsg(lvlInfo, format("REMOTESTORE: ADD TO STORE REMOTE 1"));
Path path = readStorePath(from);
printMsg(lvlInfo, format("REMOTESTORE: ADD TO STORE REMOTE 2"));
return path;
}
@ -294,8 +297,7 @@ Path RemoteStore::addTextToStore(const string & suffix, const string & s,
writeStringSet(references, to);
processStderr();
Path path = readStorePath(from);
return path;
return readStorePath(from);
}
@ -318,7 +320,7 @@ Path RemoteStore::importPath(bool requireSignature, Source & source)
processStderr(0, &source);
Path path = readStorePath(from);
return path;
return readStorePath(from);
}
@ -487,7 +489,42 @@ bool RemoteStore::queryAvailableStateRevisions(const Path & statePath, RevisionI
}
//TODO
void RemoteStore::commitStatePath(const Path & statePath)
Snapshots RemoteStore::commitStatePath(const Path & statePath)
{
Snapshots ss;
return ss;
}
void RemoteStore::scanAndUpdateAllReferences(const Path & statePath, const bool recursive)
{
}
Path RemoteStore::queryDeriver(const Path & path)
{
writeInt(wopQueryDeriver, to);
writeString(path, to);
processStderr();
return readStorePath(from);
}
PathSet RemoteStore::queryDerivers(const Path & storePath, const string & identifier, const string & user)
{
writeInt(wopQueryDerivers, to);
writeString(storePath, to);
writeString(identifier, to);
writeString(user, to);
processStderr();
return readStorePaths(from); //TODO is this ok ??
}
PathSet RemoteStore::toNonSharedPathSet(const PathSet & statePaths)
{
PathSet p;
return p;
}
void RemoteStore::revertToRevision(Path & componentPath, Path & derivationPath, Path & statePath, int revision_arg, bool recursive)
{
}

View file

@ -94,7 +94,17 @@ public:
bool queryAvailableStateRevisions(const Path & statePath, RevisionInfos & revisions);
void commitStatePath(const Path & statePath);
Snapshots commitStatePath(const Path & statePath);
Path queryDeriver(const Path & path);
PathSet queryDerivers(const Path & storePath, const string & identifier, const string & user);
void scanAndUpdateAllReferences(const Path & statePath, const bool recursive);
PathSet toNonSharedPathSet(const PathSet & statePaths);
void revertToRevision(Path & componentPath, Path & derivationPath, Path & statePath, int revision_arg, bool recursive);
private:
AutoCloseFD fdSocket;

View file

@ -122,7 +122,7 @@ Path makeStatePath(const string & componentHash, const string & suffix, const st
string suffix_stateIdentifier = stateIdentifier;
suffix_stateIdentifier = "-" + suffix_stateIdentifier;
string username = getCallingUserName(); //Can and Should NOT be faked
string username = queryCallingUsername(); //Should NOT be fake-able
/* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */
string s = ":sha256:" + componentHash + ":"

View file

@ -59,7 +59,7 @@ public:
/* Checks whether a path is valid. */
virtual bool isValidPath(const Path & path) = 0;
/* TODO */
/* Checks whether a state-path is valid. */
virtual bool isValidStatePath(const Path & path) = 0;
/* TODO */
@ -207,7 +207,7 @@ public:
/* TODO */
virtual vector<int> getStatePathsInterval(const PathSet & statePaths) = 0;
/* TODO */
/* Checks whether a path is a component path that has a statePath. */
virtual bool isStateComponent(const Path & path) = 0;
/* TODO */
@ -229,7 +229,19 @@ public:
virtual bool queryAvailableStateRevisions(const Path & statePath, RevisionInfos & revisions) = 0;
/* TODO */
virtual void commitStatePath(const Path & statePath) = 0;
virtual Snapshots commitStatePath(const Path & statePath) = 0;
/* Query the deriver of a store path. Return the empty string if
no deriver has been set. */
virtual Path queryDeriver(const Path & path) = 0;
virtual PathSet queryDerivers(const Path & storePath, const string & identifier, const string & user) = 0;
virtual void scanAndUpdateAllReferences(const Path & statePath, const bool recursive) = 0;
virtual PathSet toNonSharedPathSet(const PathSet & statePaths) = 0;
virtual void revertToRevision(Path & componentPath, Path & derivationPath, Path & statePath, int revision_arg, bool recursive) = 0;
};

View file

@ -15,10 +15,11 @@
#include "misc.hh"
#include "archive.hh"
#include "snapshot.hh"
#include "references.hh"
namespace nix {
/*
void updatedStateDerivation(Path storePath)
{
//We dont remove the old .svn folders
@ -26,8 +27,9 @@ void updatedStateDerivation(Path storePath)
printMsg(lvlTalkative, format("Resetting state drv settings"));
}
*/
void createStateDirs(const DerivationStateOutputDirs & stateOutputDirs, const DerivationStateOutputs & stateOutputs)
void createStateDirsTxn(const Transaction & txn, const DerivationStateOutputDirs & stateOutputDirs, const DerivationStateOutputs & stateOutputs)
{
Path statePath = stateOutputs.find("state")->second.statepath;
string stateDir = statePath;
@ -64,9 +66,138 @@ void createStateDirs(const DerivationStateOutputDirs & stateOutputDirs, const De
//Initialize the counters for the statePaths that have an interval to 0
vector<int> empty;
store->setStatePathsInterval(intervalPaths, empty, true);
setStatePathsIntervalTxn(txn, intervalPaths, empty, true);
}
/*
* Input: store (or statePath?)
* Returns all the drv's of the statePaths (in)directly referenced.
*/
//TODO TXN
PathSet getAllStateDerivationsRecursivelyTxn(const Transaction & txn, const Path & storePath, const int revision)
{
//Get recursively all state paths
PathSet statePaths;
storePathRequisitesTxn(noTxn, storePath, false, statePaths, false, true, revision);
//Find the matching drv with the statePath
PathSet derivations;
for (PathSet::iterator i = statePaths.begin(); i != statePaths.end(); ++i)
derivations.insert(queryStatePathDrvTxn(txn,*i));
return derivations;
}
void revertToRevisionTxn(const Transaction & txn, Path & componentPath, Path & derivationPath, Path & statePath, int revision_arg, bool recursive)
{
PathSet statePaths;
if(recursive)
PathSet statePaths = getAllStateDerivationsRecursivelyTxn(txn, componentPath, revision_arg); //get dependecies (if neccecary | recusively) of all state components that need to be updated
else
statePaths.insert(derivationPath); //Insert direct state path
//get a new timestamp for the references update
int newTimestamp = getTimeStamp();
//Get the revisions recursively to also roll them back
RevisionClosure getRivisions;
RevisionClosureTS getTimestamps;
queryStateRevisionsTxn(txn, statePath, getRivisions, getTimestamps, revision_arg);
//Revert each statePath in the list
for (RevisionClosure::iterator i = getRivisions.begin(); i != getRivisions.end(); ++i){
Path statePath = (*i).first;
Snapshots revisioned_paths = (*i).second;
int timestamp = getTimestamps[statePath];
//get its derivation-state-items
Derivation statePath_drv = derivationFromPathTxn(txn, queryStatePathDrvTxn(noTxn, statePath));
DerivationStateOutputDirs stateOutputDirs = statePath_drv.stateOutputDirs;
//TODO Sort snapshots??? eg first restore root, then the subdirs??
for (Snapshots::iterator j = revisioned_paths.begin(); j != revisioned_paths.end(); ++j){
Path revertPathOrFile = (*j).first;
unsigned int epoch = (*j).second;
//printMsg(lvlError, format("MAYBE '%1%'") % revertPathOrFile);
//Look up the type from the drv with for the current snapshotted path
Path statePath_postfix = revertPathOrFile.substr(nixStoreState.length() + 1, revertPathOrFile.length() - nixStoreState.length());
statePath_postfix = statePath_postfix.substr(statePath_postfix.find_first_of("/") + 1, statePath_postfix.length());
if(statePath_postfix == "")
statePath_postfix = "/";
string type = stateOutputDirs.at(statePath_postfix).type;
if(type == "none")
continue;
//Now that were still here, we need to copy the state from the previous version back
Strings p_args;
p_args.push_back("-c"); //we use the shell to execute the cp command becuase the shell expands the '*'
string cpcommand = "cp";
if(revertPathOrFile.substr(revertPathOrFile.length() -1 , revertPathOrFile.length()) == "/"){ //is dir
string revert_to_path = revertPathOrFile.substr(0, revertPathOrFile.length() -1) + "@" + unsignedInt2String(epoch);
cpcommand += " -R " + revert_to_path + "/*";
//clean all contents of the folder first (so were sure the path is clean)
if(pathExists(revertPathOrFile))
deletePath(revertPathOrFile);
if(epoch == 0) //Path was deleted so were done
continue;
else //If path was not deleted in the previous version, we need to make sure it exists or cp will fail
ensureDirExists(revertPathOrFile);
//If the the dir has not contents then a cp ..../* will error since * cannot be expanded. So in this case were done and dont have to revert.
Strings p2_args;
p2_args.push_back("-A");
p2_args.push_back(revert_to_path + "/");
string output = runProgram("ls", true, p2_args);
if(output == "")
continue;
}
else{ //is file
cpcommand += " " + (revertPathOrFile + "@" + unsignedInt2String(epoch));
if(epoch == 0){
//delete file
if(FileExist(revertPathOrFile))
deletePath(revertPathOrFile); //we only delete if the cp doesnt overwrite it below
continue;
}
}
//Revert
printMsg(lvlError, format("Reverting '%1%@%2%'") % revertPathOrFile % unsignedInt2String(epoch));
printMsg(lvlError, format("Command: '%1%'") % cpcommand);
cpcommand += " " + revertPathOrFile;
p_args.push_back(cpcommand);
runProgram_AndPrintOutput("sh", true, p_args, "sh-cp");
}
//*** Now also revert state references to the specific revision (the revision is already converted to a timestamp here)
//Query the references of the old revision (already converted to a timestamp)
PathSet state_references;
queryXReferencesTxn(txn, statePath, state_references, true, -1, timestamp);
PathSet state_stateReferences;
queryXReferencesTxn(txn, statePath, state_stateReferences, false, -1, timestamp);
//Now set these old references as the new references at the new (just created) Timestamp
setStateComponentReferencesTxn(txn, statePath, Strings(state_references.begin(), state_references.end()), -1, newTimestamp);
setStateStateReferencesTxn(txn, statePath, Strings(state_stateReferences.begin(), state_stateReferences.end()), -1, newTimestamp);
printMsg(lvlError, format("Reverted state of '%1%' to revision '%2%'") % statePath % revision_arg);
}
}
//TODO maybe add user ID ?
Snapshots commitStatePathTxn(const Transaction & txn, const Path & statePath)
{
if(!isValidStatePathTxn(txn, statePath))
@ -91,7 +222,7 @@ Snapshots commitStatePathTxn(const Transaction & txn, const Path & statePath)
intervalPaths.insert(fullstatedir);
}
}
vector<int> intervals = store->getStatePathsInterval(intervalPaths); //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! txn
vector<int> intervals = getStatePathsIntervalTxn(txn, intervalPaths);
Snapshots revisions_list;
@ -142,4 +273,109 @@ Snapshots commitStatePathTxn(const Transaction & txn, const Path & statePath)
//setStatePathsIntervalTxn(txn, intervalPaths, intervals); //TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!! uncomment
}
//TODO include this call in the validate function
//TODO ONLY CALL THIS FUNCTION ON A NON-SHARED STATE PATH!!!!!!!!!!!
void scanAndUpdateAllReferencesTxn(const Transaction & txn, const Path & statePath
, PathSet & newFoundComponentReferences, PathSet & newFoundStateReferences) //only for recursion
{
//Check if is a state Path
if(! isValidStatePathTxn(txn, statePath))
throw Error(format("This path '%1%' is not a state path") % statePath);
//printMsg(lvlError, format("scanAndUpdateAllReferencesTxn: '%1%' - %2%") % statePath % revision);
//TODO check if path is not a shared path !
//TODO
//get all possible state and component references
PathSet allComponentPaths;
PathSet allStatePaths;
queryAllValidPathsTxn(txn, allComponentPaths, allStatePaths);
//Remove derivation paths
PathSet allComponentPaths2; //without derivations
for (PathSet::iterator i = allComponentPaths.begin(); i != allComponentPaths.end(); ++i){
string path = *i;
if(path.substr(path.length() - 4,path.length()) != drvExtension) //TODO HACK: we should have a typed table or a seperate table .... drvExtension == ".drv"
allComponentPaths2.insert(path);
}
//TODO maybe only scan in the changeset (patch) for new references? (this will be difficult and depending on the underlying versioning system)
//Scan in for (new) component and state references
PathSet state_references = scanForReferences(statePath, allComponentPaths2);
PathSet state_stateReferences = scanForStateReferences(statePath, allStatePaths);
//Retrieve old references
PathSet old_references;
PathSet old_state_references;
queryXReferencesTxn(txn, statePath, old_references, true, -1); //get the latsest references
queryXReferencesTxn(txn, statePath, old_state_references, false, -1);
//Check for added and removed paths
PathSet diff_references_removed;
PathSet diff_references_added;
pathSets_difference(state_references, old_references, diff_references_removed, diff_references_added);
PathSet diff_state_references_removed;
PathSet diff_state_references_added;
pathSets_difference(state_stateReferences, old_state_references, diff_state_references_removed, diff_state_references_added);
//Set PathSet's for the caller of this function
newFoundComponentReferences = diff_references_added;
newFoundStateReferences = diff_state_references_added;
//Print error, but we could also throw an error.
if(diff_references_added.size() != 0)
for (PathSet::iterator i = diff_references_added.begin(); i != diff_references_added.end(); ++i)
printMsg(lvlError, format("Added component reference found!: '%1%' in state path '%2%'") % (*i) % statePath);
if(diff_references_removed.size() != 0)
for (PathSet::iterator i = diff_references_removed.begin(); i != diff_references_removed.end(); ++i)
printMsg(lvlError, format("Removed component reference found!: '%1%' in state path '%2%'") % (*i) % statePath);
if(diff_state_references_added.size() != 0)
for (PathSet::iterator i = diff_state_references_added.begin(); i != diff_state_references_added.end(); ++i)
printMsg(lvlError, format("Added state reference found!: '%1%' in state path '%2%'") % (*i) % statePath);
if(diff_state_references_removed.size() != 0)
for (PathSet::iterator i = diff_state_references_removed.begin(); i != diff_state_references_removed.end(); ++i)
printMsg(lvlError, format("Removed state reference found!: '%1%' in state path '%2%'") % (*i) % statePath);
//We always set the referernces so we know they were scanned (maybe the same) at a certain time
printMsg(lvlError, format("Updating new references for statepath: '%1%'") % statePath);
Path drvPath = queryStatePathDrvTxn(txn, statePath);
registerValidPath(txn,
statePath,
Hash(), //emtpy hash
state_references,
state_stateReferences,
drvPath,
-1); //Set at a new timestamp
}
void scanAndUpdateAllReferencesRecusivelyTxn(const Transaction & txn, const Path & statePath)
{
if(! isValidStatePathTxn(txn, statePath))
throw Error(format("This path '%1%' is not a state path") % statePath);
//get all state current state references recursively
PathSet statePaths;
storePathRequisitesTxn(txn, statePath, false, statePaths, false, true, -1); //Get all current state dependencies
//Add own statePath (may already be in there, but its a set, so no doubles)
statePaths.insert(statePath);
//We dont need to sort since the db does that
//call scanForAllReferences again on all statePaths
for (PathSet::iterator i = statePaths.begin(); i != statePaths.end(); ++i){
//Scan, update, call recursively
PathSet newFoundComponentReferences;
PathSet newFoundStateReferences;
scanAndUpdateAllReferencesTxn(txn, *i, newFoundComponentReferences, newFoundStateReferences);
//Call the function recursively again on all newly found references //TODO test if this works
PathSet allNewReferences = pathSets_union(newFoundComponentReferences, newFoundStateReferences);
for (PathSet::iterator j = allNewReferences.begin(); j != allNewReferences.end(); ++j)
scanAndUpdateAllReferencesRecusivelyTxn(txn, *j);
}
}
}

View file

@ -8,7 +8,7 @@
namespace nix {
/* Create a state directory. */
void createStateDirs(const DerivationStateOutputDirs & stateOutputDirs, const DerivationStateOutputs & stateOutputs);
void createStateDirsTxn(const Transaction & txn, const DerivationStateOutputDirs & stateOutputDirs, const DerivationStateOutputs & stateOutputs);
/* TODO */
Snapshots commitStatePathTxn(const Transaction & txn, const Path & statePath);
@ -19,6 +19,14 @@ Snapshots commitStatePathTxn(const Transaction & txn, const Path & statePath);
/* TODO */
//int readRevisionNumber(Path statePath);
void scanAndUpdateAllReferencesTxn(const Transaction & txn, const Path & statePath
, PathSet & newFoundComponentReferences, PathSet & newFoundStateReferences);
void scanAndUpdateAllReferencesRecusivelyTxn(const Transaction & txn, const Path & statePath);
void revertToRevisionTxn(const Transaction & txn, Path & componentPath, Path & derivationPath, Path & statePath, int revision_arg, bool recursive);
}
#endif /* !__STORESTATE_H */

View file

@ -33,6 +33,8 @@ typedef enum {
wopCollectGarbage,
wopExportPath,
wopImportPath,
wopQueryDeriver,
wopQueryDerivers,
} WorkerOp;