mirror of
https://github.com/NixOS/nix.git
synced 2025-11-26 04:00:59 +01:00
Fixed sharing issue. Created unshare method.
This commit is contained in:
parent
315cd18337
commit
51cff21c92
18 changed files with 593 additions and 456 deletions
|
|
@ -1829,18 +1829,11 @@ void DerivationGoal::computeClosure()
|
||||||
//Shared state
|
//Shared state
|
||||||
Path sharedState = drv.stateOutputs.find("state")->second.sharedState;
|
Path sharedState = drv.stateOutputs.find("state")->second.sharedState;
|
||||||
if(sharedState != ""){
|
if(sharedState != ""){
|
||||||
//Remove state path
|
shareStateTxn(txn, sharedState, statePath, false);
|
||||||
deletePathWrapped(statePath);
|
|
||||||
symlinkPath(sharedState, statePath);
|
|
||||||
|
|
||||||
//Set in database
|
|
||||||
setSharedStateTxn(txn, sharedState, statePath);
|
|
||||||
}
|
}
|
||||||
//If not shared: create the dir and set the rights
|
//If not shared: create the dir and set the rights
|
||||||
else{
|
else{
|
||||||
ensureDirExists(statePath);
|
ensureStateDir(statePath, queryCallingUsername(), "nixbld", "700");
|
||||||
setChown(statePath, queryCallingUsername(), "nixbld");
|
|
||||||
setChmod(statePath, "700");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2598,7 +2591,7 @@ void LocalStore::buildDerivations(const PathSet & drvPaths)
|
||||||
Worker worker;
|
Worker worker;
|
||||||
Goals goals;
|
Goals goals;
|
||||||
for (PathSet::const_iterator i = drvPaths.begin(); i != drvPaths.end(); ++i){
|
for (PathSet::const_iterator i = drvPaths.begin(); i != drvPaths.end(); ++i){
|
||||||
//printMsg(lvlError, format("BUILD: '%1%'") % *i);
|
printMsg(lvlError, format("BUILD: '%1%'") % *i);
|
||||||
goals.insert(worker.makeDerivationGoal(*i));
|
goals.insert(worker.makeDerivationGoal(*i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -447,331 +447,6 @@ void Database::enumTable(const Transaction & txn, TableId table,
|
||||||
} catch (DbException e) { rethrow(e); }
|
} catch (DbException e) { rethrow(e); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* State specific db functions */
|
|
||||||
|
|
||||||
Path Database::mergeToDBKey(const Path & statePath, const unsigned int intvalue)
|
|
||||||
{
|
|
||||||
string prefix = "-KEY-";
|
|
||||||
return statePath + prefix + unsignedInt2String(intvalue);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Database::splitDBKey(const Path & revisionedStatePath, Path & statePath, unsigned int & intvalue)
|
|
||||||
{
|
|
||||||
string prefix = "-KEY-";
|
|
||||||
|
|
||||||
int pos = revisionedStatePath.find_last_of(prefix);
|
|
||||||
statePath = revisionedStatePath.substr(0, pos - prefix.length() + 1);
|
|
||||||
//printMsg(lvlError, format("'%2%' - '%1%'") % revisionedStatePath.substr(pos+1, revisionedStatePath.length()) % int2String(pos));
|
|
||||||
bool succeed = string2UnsignedInt(revisionedStatePath.substr(pos+1, revisionedStatePath.length()), intvalue);
|
|
||||||
if(!succeed)
|
|
||||||
throw Error(format("Malformed revision value of path '%1%'") % revisionedStatePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int Database::getNewRevisionNumber(const Transaction & txn, TableId table,
|
|
||||||
const Path & statePath)
|
|
||||||
{
|
|
||||||
//query
|
|
||||||
string data;
|
|
||||||
bool notEmpty = queryString(txn, table, statePath, data);
|
|
||||||
|
|
||||||
if(!notEmpty){
|
|
||||||
setString(txn, table, statePath, int2String(1));
|
|
||||||
return 1; //we begin counting from 1 since 0 is a special value representing the last revision
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int revision;
|
|
||||||
bool succeed = string2UnsignedInt(data, revision);
|
|
||||||
if(!succeed)
|
|
||||||
throw Error(format("Malformed revision counter value of path '%1%'") % statePath);
|
|
||||||
|
|
||||||
revision++;
|
|
||||||
setString(txn, table, statePath, unsignedInt2String(revision));
|
|
||||||
|
|
||||||
return revision;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Database::lookupHighestRevivison(const Strings & keys, const Path & statePath, string & key, unsigned int lowerthan)
|
|
||||||
{
|
|
||||||
unsigned int highestRev = 0;
|
|
||||||
|
|
||||||
//Lookup which key we need
|
|
||||||
for (Strings::const_iterator i = keys.begin(); i != keys.end(); ++i) {
|
|
||||||
|
|
||||||
if((*i).substr(0, statePath.length()) != statePath || (*i).length() == statePath.length()) //dont check the new-revision key or other keys
|
|
||||||
continue;
|
|
||||||
|
|
||||||
//printMsg(lvlError, format("'%1%' - '%2%'") % *i % statePath);
|
|
||||||
Path getStatePath;
|
|
||||||
unsigned int getRevision;
|
|
||||||
splitDBKey(*i, getStatePath, getRevision);
|
|
||||||
if(getRevision > highestRev){
|
|
||||||
|
|
||||||
if(lowerthan != 0){
|
|
||||||
if(getRevision <= lowerthan) //if we have an uppper limit, see to it that we downt go over it
|
|
||||||
highestRev = getRevision;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
highestRev = getRevision;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(highestRev == 0) //no records found
|
|
||||||
return false;
|
|
||||||
|
|
||||||
key = mergeToDBKey(statePath, highestRev); //final key that matches revision + statePath
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Database::revisionToTimeStamp(const Transaction & txn, TableId revisions_table, const Path & statePath, const int revision, unsigned int & timestamp)
|
|
||||||
{
|
|
||||||
string key = mergeToDBKey(statePath, revision);
|
|
||||||
Strings references;
|
|
||||||
bool notempty = queryStrings(txn, revisions_table, key, references);
|
|
||||||
|
|
||||||
if(notempty){
|
|
||||||
Path empty;
|
|
||||||
splitDBKey(*(references.begin()), empty, timestamp); //extract the timestamp
|
|
||||||
//printMsg(lvlError, format("PRINT '%1%'") % timestamp);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Database::setStateReferences(const Transaction & txn, TableId references_table, TableId revisions_table,
|
|
||||||
const Path & statePath, const Strings & references, const unsigned int revision, const unsigned int timestamp)
|
|
||||||
{
|
|
||||||
//printMsg(lvlError, format("setStateReferences '%1%' for '%2%'") % references_table % statePath);
|
|
||||||
|
|
||||||
//Find the timestamp if we need
|
|
||||||
unsigned int timestamp2 = timestamp;
|
|
||||||
if(revision == 0 && timestamp == 0)
|
|
||||||
timestamp2 = getTimeStamp();
|
|
||||||
else if(revision != 0 && timestamp == 0){
|
|
||||||
bool found = revisionToTimeStamp(txn, revisions_table, statePath, revision, timestamp2);
|
|
||||||
if(!found)
|
|
||||||
throw Error(format("Revision '%1%' cannot be matched to a timestamp...") % revision);
|
|
||||||
}
|
|
||||||
|
|
||||||
//for (Strings::const_iterator i = references.begin(); i != references.end(); ++i)
|
|
||||||
// printMsg(lvlError, format("setStateReferences::: '%1%'") % *i);
|
|
||||||
|
|
||||||
//Warning if it already exists
|
|
||||||
Strings empty;
|
|
||||||
if( queryStrings(txn, references_table, mergeToDBKey(statePath, timestamp2), empty) )
|
|
||||||
printMsg(lvlError, format("Warning: The timestamp '%1%' (now: '%5%') / revision '%4%' already exists for set-references of path '%2%' with db '%3%'")
|
|
||||||
% timestamp2 % statePath % references_table % revision % getTimeStamp());
|
|
||||||
|
|
||||||
//Create the key
|
|
||||||
string key = mergeToDBKey(statePath, timestamp2);
|
|
||||||
|
|
||||||
//printMsg(lvlError, format("Set references '%1%'") % key);
|
|
||||||
//for (Strings::const_iterator i = references.begin(); i != references.end(); ++i)
|
|
||||||
// printMsg(lvlError, format("reference '%1%'") % *i);
|
|
||||||
|
|
||||||
//Insert
|
|
||||||
setStrings(txn, references_table, key, references, false); //The false makes sure also empty references are set
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Database::queryStateReferences(const Transaction & txn, TableId references_table, TableId revisions_table,
|
|
||||||
const Path & statePath, Strings & references, const unsigned int revision, const unsigned int timestamp)
|
|
||||||
{
|
|
||||||
//printMsg(lvlError, format("queryStateReferences '%1%' with revision '%2%'") % references_table % revision);
|
|
||||||
|
|
||||||
//Convert revision to timestamp number useing the revisions_table
|
|
||||||
unsigned int timestamp2 = timestamp;
|
|
||||||
if(timestamp == 0 && revision != 0){
|
|
||||||
bool found = revisionToTimeStamp(txn, revisions_table, statePath, revision, timestamp2);
|
|
||||||
if(!found) //we are asked for references of some revision, but there are no references registered yet, so we return false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Strings keys;
|
|
||||||
enumTable(txn, references_table, keys);
|
|
||||||
|
|
||||||
//Mabye we need the latest timestamp?
|
|
||||||
string key = "";
|
|
||||||
if(timestamp2 == 0){
|
|
||||||
bool foundsomething = lookupHighestRevivison(keys, statePath, key);
|
|
||||||
if(!foundsomething)
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
return queryStrings(txn, references_table, key, references);
|
|
||||||
}
|
|
||||||
|
|
||||||
//If a specific key is given: check if this timestamp exists key in the table
|
|
||||||
key = mergeToDBKey(statePath, timestamp2);
|
|
||||||
bool found = false;
|
|
||||||
for (Strings::const_iterator i = keys.begin(); i != keys.end(); ++i) {
|
|
||||||
if(key == *i){
|
|
||||||
found = true;
|
|
||||||
key = mergeToDBKey(statePath, timestamp2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//If it doesn't exist in the table then find the highest key lower than it
|
|
||||||
if(!found){
|
|
||||||
bool foundsomething = lookupHighestRevivison(keys, statePath, key, 0);
|
|
||||||
if(!foundsomething)
|
|
||||||
return false;
|
|
||||||
//printMsg(lvlError, format("Warning: References for timestamp '%1%' not was not found, so taking the highest rev-key possible for statePath '%2%'") % timestamp2 % statePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return queryStrings(txn, references_table, key, references); //now that we have the key, we can query the references
|
|
||||||
}
|
|
||||||
|
|
||||||
void Database::setStateRevisions(const Transaction & txn, TableId revisions_table, TableId revisions_comments,
|
|
||||||
TableId snapshots_table, const RevisionClosure & revisions, const Path & rootStatePath, const string & comment)
|
|
||||||
{
|
|
||||||
if( !isStatePath(rootStatePath) ) //weak check on statePath
|
|
||||||
throw Error(format("StatePath '%1%' is not a statepath") % rootStatePath);
|
|
||||||
|
|
||||||
unsigned int timestamp = getTimeStamp();
|
|
||||||
|
|
||||||
//Insert all ss_epochs into snapshots_table with the current ts.
|
|
||||||
for (RevisionClosure::const_iterator i = revisions.begin(); i != revisions.end(); ++i){
|
|
||||||
string key = mergeToDBKey((*i).first, timestamp);
|
|
||||||
Strings data;
|
|
||||||
//the map<> takes care of the sorting on the Path
|
|
||||||
for (Snapshots::const_iterator j = (*i).second.begin(); j != (*i).second.end(); ++j)
|
|
||||||
data.push_back(int2String((*j).second));
|
|
||||||
setStrings(txn, snapshots_table, key, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Insert for each statePath a new revision record linked to the ss_epochs
|
|
||||||
for (RevisionClosure::const_iterator i = revisions.begin(); i != revisions.end(); ++i){
|
|
||||||
Path statePath = (*i).first;
|
|
||||||
|
|
||||||
unsigned int revision = getNewRevisionNumber(txn, revisions_table, statePath); //get a new revision number
|
|
||||||
|
|
||||||
string key = mergeToDBKey(statePath, revision);
|
|
||||||
|
|
||||||
//get all its requisites
|
|
||||||
PathSet statePath_references;
|
|
||||||
storePathRequisitesTxn(txn, statePath, false, statePath_references, false, true, 0);
|
|
||||||
statePath_references.insert(statePath);
|
|
||||||
|
|
||||||
//save in db
|
|
||||||
Strings data;
|
|
||||||
for (PathSet::const_iterator j = statePath_references.begin(); j != statePath_references.end(); ++j)
|
|
||||||
data.push_back(mergeToDBKey(*j, timestamp));
|
|
||||||
|
|
||||||
setStrings(txn, revisions_table, key, data, false); //The false makes sure also empty revisions are set
|
|
||||||
|
|
||||||
//save the date and comments
|
|
||||||
Strings metadata;
|
|
||||||
metadata.push_back(unsignedInt2String(timestamp));
|
|
||||||
|
|
||||||
//get all paths that point to the same state (using shareing) and check if one of them equals the rootStatePath
|
|
||||||
PathSet sharedWith = getSharedWithPathSetRecTxn(txn, statePath);
|
|
||||||
if(statePath == rootStatePath || sharedWith.find(rootStatePath) != sharedWith.end())
|
|
||||||
metadata.push_back(comment);
|
|
||||||
else
|
|
||||||
metadata.push_back("Part of the snashot closure for " + rootStatePath);
|
|
||||||
setStrings(txn, revisions_comments, key, metadata);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Database::queryStateRevisions(const Transaction & txn, TableId revisions_table, TableId snapshots_table,
|
|
||||||
const Path & statePath, RevisionClosure & revisions, RevisionClosureTS & timestamps, const unsigned int root_revision)
|
|
||||||
{
|
|
||||||
string key;
|
|
||||||
|
|
||||||
if(root_revision == 0){
|
|
||||||
Strings keys;
|
|
||||||
enumTable(txn, revisions_table, keys); //get all revisions
|
|
||||||
bool foundsomething = lookupHighestRevivison(keys, statePath, key);
|
|
||||||
if(!foundsomething)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
key = mergeToDBKey(statePath, root_revision);
|
|
||||||
|
|
||||||
//Get references pointing to snapshots_table from revisions_table with root_revision
|
|
||||||
Strings statePaths;
|
|
||||||
bool notempty = queryStrings(txn, revisions_table, key, statePaths);
|
|
||||||
|
|
||||||
if(!notempty)
|
|
||||||
throw Error(format("Root revision '%1%' not found of statePath '%2%'") % unsignedInt2String(root_revision) % statePath);
|
|
||||||
|
|
||||||
//For each statePath add the revisions
|
|
||||||
for (Strings::iterator i = statePaths.begin(); i != statePaths.end(); ++i){
|
|
||||||
|
|
||||||
Path getStatePath;
|
|
||||||
unsigned int getTimestamp;
|
|
||||||
splitDBKey(*i, getStatePath, getTimestamp);
|
|
||||||
|
|
||||||
//query state versioined directorys/files
|
|
||||||
vector<Path> sortedPaths;
|
|
||||||
Derivation drv = derivationFromPathTxn(txn, queryStatePathDrvTxn(txn, getStatePath));
|
|
||||||
DerivationStateOutputs stateOutputs = drv.stateOutputs;
|
|
||||||
DerivationStateOutputDirs stateOutputDirs = drv.stateOutputDirs;
|
|
||||||
for (DerivationStateOutputDirs::const_iterator j = stateOutputDirs.begin(); j != stateOutputDirs.end(); ++j){
|
|
||||||
string thisdir = (j->second).path;
|
|
||||||
string fullstatedir = getStatePath + "/" + thisdir;
|
|
||||||
if(thisdir == "/") //exception for the root dir
|
|
||||||
fullstatedir = statePath + "/";
|
|
||||||
sortedPaths.push_back(fullstatedir);
|
|
||||||
}
|
|
||||||
sort(sortedPaths.begin(), sortedPaths.end()); //sort
|
|
||||||
|
|
||||||
Strings snapshots_s;
|
|
||||||
Snapshots snapshots;
|
|
||||||
queryStrings(txn, snapshots_table, *i, snapshots_s);
|
|
||||||
int counter=0;
|
|
||||||
for (Strings::iterator j = snapshots_s.begin(); j != snapshots_s.end(); ++j){
|
|
||||||
|
|
||||||
unsigned int revision;
|
|
||||||
bool succeed = string2UnsignedInt(*j, revision);
|
|
||||||
if(!succeed)
|
|
||||||
throw Error(format("Malformed epoch (snapshot timestamp) value of path '%1%'") % statePath);
|
|
||||||
|
|
||||||
snapshots[sortedPaths.at(counter)] = revision;
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
revisions[getStatePath] = snapshots;
|
|
||||||
timestamps[getStatePath] = getTimestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return notempty;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO include comments into revisions?
|
|
||||||
bool Database::queryAvailableStateRevisions(const Transaction & txn, TableId revisions_table, TableId revisions_comments,
|
|
||||||
const Path & statePath, RevisionInfos & revisions)
|
|
||||||
{
|
|
||||||
Strings keys;
|
|
||||||
enumTable(txn, revisions_table, keys); //get all revisions
|
|
||||||
|
|
||||||
for (Strings::const_iterator i = keys.begin(); i != keys.end(); ++i) {
|
|
||||||
|
|
||||||
if((*i).substr(0, statePath.length()) != statePath || (*i).length() == statePath.length()) //dont check the new-revision key or other keys
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Path getStatePath;
|
|
||||||
unsigned int getRevision;
|
|
||||||
splitDBKey(*i, getStatePath, getRevision);
|
|
||||||
|
|
||||||
//save the date and comments
|
|
||||||
RevisionInfo rev;
|
|
||||||
Strings metadata;
|
|
||||||
queryStrings(txn, revisions_comments, *i, metadata);
|
|
||||||
unsigned int ts;
|
|
||||||
bool succeed = string2UnsignedInt(*(metadata.begin()), ts);
|
|
||||||
if(!succeed)
|
|
||||||
throw Error(format("Malformed timestamp in the revisions-comments table of path '%1%'") % *i);
|
|
||||||
rev.timestamp = ts;
|
|
||||||
metadata.pop_front();
|
|
||||||
rev.comment = *(metadata.begin());
|
|
||||||
revisions[getRevision] = rev;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(revisions.empty())
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,11 +60,7 @@ private:
|
||||||
|
|
||||||
void open2(const string & path, bool removeOldEnv);
|
void open2(const string & path, bool removeOldEnv);
|
||||||
|
|
||||||
/* TODO */
|
|
||||||
bool lookupHighestRevivison(const Strings & keys, const Path & statePath, string & key, unsigned int lowerthan = 0);
|
|
||||||
|
|
||||||
/* TODO */
|
|
||||||
unsigned int getNewRevisionNumber(const Transaction & txn, TableId table, const Path & statePath);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Database();
|
Database();
|
||||||
|
|
@ -96,37 +92,6 @@ public:
|
||||||
void enumTable(const Transaction & txn, TableId table,
|
void enumTable(const Transaction & txn, TableId table,
|
||||||
Strings & keys, const string & keyPrefix = "");
|
Strings & keys, const string & keyPrefix = "");
|
||||||
|
|
||||||
/* TODO */
|
|
||||||
Path mergeToDBKey(const Path & statePath, const unsigned int intvalue);
|
|
||||||
|
|
||||||
/* TODO */
|
|
||||||
void splitDBKey(const Path & revisionedStatePath, Path & statePath, unsigned int & intvalue);
|
|
||||||
|
|
||||||
/* TODO */
|
|
||||||
bool revisionToTimeStamp(const Transaction & txn, TableId revisions_table, const Path & statePath, const int revision, unsigned int & timestamp);
|
|
||||||
|
|
||||||
/* Set the stateReferences for a specific revision (and older until the next higher revision number in the table) */
|
|
||||||
void setStateReferences(const Transaction & txn, TableId references_table, TableId revisions_table,
|
|
||||||
const Path & statePath, const Strings & references, const unsigned int revision = 0, const unsigned int timestamp = 0);
|
|
||||||
|
|
||||||
/* Returns the references for a specific revision (and older until the next higher revision number in the table) */
|
|
||||||
bool queryStateReferences(const Transaction & txn, TableId references_table, TableId revisions_table,
|
|
||||||
const Path & statePath, Strings & references, const unsigned int revision = 0, const unsigned int timestamp = 0);
|
|
||||||
|
|
||||||
/* Set the revision number of the statePath and the revision numbers of all state paths in the references closure */
|
|
||||||
void setStateRevisions(const Transaction & txn, TableId revisions_table, TableId revisions_comments,
|
|
||||||
TableId snapshots_table, const RevisionClosure & revisions, const Path & rootStatePath, const string & comment);
|
|
||||||
|
|
||||||
/* Returns all the revision numbers of the state references closure of the given state path */
|
|
||||||
bool queryStateRevisions(const Transaction & txn, TableId revisions_table, TableId snapshots_table,
|
|
||||||
const Path & statePath, RevisionClosure & revisions, RevisionClosureTS & timestamps, const unsigned int root_revision = 0);
|
|
||||||
|
|
||||||
/* Returns all available revision numbers of the given state path */
|
|
||||||
bool queryAvailableStateRevisions(const Transaction & txn, TableId revisions_table, TableId revisions_comments,
|
|
||||||
const Path & statePath, RevisionInfos & revisions);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -477,7 +477,6 @@ void setReferences(const Transaction & txn, const Path & store_or_statePath,
|
||||||
|
|
||||||
nixDB.setStrings(txn, dbComponentComponentReferences, store_or_statePath, Paths(references.begin(), references.end()));
|
nixDB.setStrings(txn, dbComponentComponentReferences, store_or_statePath, Paths(references.begin(), references.end()));
|
||||||
nixDB.setStrings(txn, dbComponentStateReferences, store_or_statePath, Paths(stateReferences.begin(), stateReferences.end()));
|
nixDB.setStrings(txn, dbComponentStateReferences, store_or_statePath, Paths(stateReferences.begin(), stateReferences.end()));
|
||||||
|
|
||||||
}
|
}
|
||||||
else if(isRealisableStatePath(txn, store_or_statePath))
|
else if(isRealisableStatePath(txn, store_or_statePath))
|
||||||
{
|
{
|
||||||
|
|
@ -489,15 +488,15 @@ void setReferences(const Transaction & txn, const Path & store_or_statePath,
|
||||||
//query the references of revision (0 is query the latest references)
|
//query the references of revision (0 is query the latest references)
|
||||||
Paths oldStateReferences_s_c;
|
Paths oldStateReferences_s_c;
|
||||||
Paths oldStateReferences_s_s;
|
Paths oldStateReferences_s_s;
|
||||||
nixDB.queryStateReferences(txn, dbStateComponentReferences, dbStateRevisions, store_or_statePath, oldStateReferences_s_c, revision);
|
queryStateReferences(nixDB, txn, dbStateComponentReferences, dbStateRevisions, store_or_statePath, oldStateReferences_s_c, revision);
|
||||||
nixDB.queryStateReferences(txn, dbStateStateReferences, dbStateRevisions, store_or_statePath, oldStateReferences_s_s, revision);
|
queryStateReferences(nixDB, txn, dbStateStateReferences, dbStateRevisions, store_or_statePath, oldStateReferences_s_s, revision);
|
||||||
|
|
||||||
PathSet oldReferences = PathSet(oldStateReferences_s_c.begin(), oldStateReferences_s_c.end());
|
PathSet oldReferences = PathSet(oldStateReferences_s_c.begin(), oldStateReferences_s_c.end());
|
||||||
PathSet oldStateReferences = PathSet(oldStateReferences_s_s.begin(), oldStateReferences_s_s.end());
|
PathSet oldStateReferences = PathSet(oldStateReferences_s_s.begin(), oldStateReferences_s_s.end());
|
||||||
|
|
||||||
//set the references of revision (0 insert as a new timestamp)
|
//set the references of revision (0 insert as a new timestamp)
|
||||||
nixDB.setStateReferences(txn, dbStateComponentReferences, dbStateRevisions, store_or_statePath, Paths(references.begin(), references.end()), revision);
|
setStateReferences(nixDB, txn, dbStateComponentReferences, dbStateRevisions, store_or_statePath, Paths(references.begin(), references.end()), revision);
|
||||||
nixDB.setStateReferences(txn, dbStateStateReferences, dbStateRevisions, store_or_statePath, Paths(stateReferences.begin(), stateReferences.end()), revision);
|
setStateReferences(nixDB, txn, dbStateStateReferences, dbStateRevisions, store_or_statePath, Paths(stateReferences.begin(), stateReferences.end()), revision);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw Error(format("Path '%1%' is not a valid component or state path") % store_or_statePath);
|
throw Error(format("Path '%1%' is not a valid component or state path") % store_or_statePath);
|
||||||
|
|
@ -522,7 +521,7 @@ void queryXReferencesTxn(const Transaction & txn, const Path & store_or_statePat
|
||||||
nixDB.queryStrings(txn, table1, store_or_statePath, references2);
|
nixDB.queryStrings(txn, table1, store_or_statePath, references2);
|
||||||
else if(isRealisableStatePath(txn, store_or_statePath)){
|
else if(isRealisableStatePath(txn, store_or_statePath)){
|
||||||
Path statePath_ns = toNonSharedPathTxn(txn, store_or_statePath); //Lookup its where it points to if its shared
|
Path statePath_ns = toNonSharedPathTxn(txn, store_or_statePath); //Lookup its where it points to if its shared
|
||||||
nixDB.queryStateReferences(txn, table2, dbStateRevisions, statePath_ns, references2, revision, timestamp);
|
queryStateReferences(nixDB, txn, table2, dbStateRevisions, statePath_ns, references2, revision, timestamp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw Error(format("Path '%1%' is not a valid component or state path") % store_or_statePath);
|
throw Error(format("Path '%1%' is not a valid component or state path") % store_or_statePath);
|
||||||
|
|
@ -593,7 +592,7 @@ static PathSet getXReferrers(const Transaction & txn, const Path & store_or_stat
|
||||||
//Now in references of ALL referrers, (possibly lookup their latest TS based on revision)
|
//Now in references of ALL referrers, (possibly lookup their latest TS based on revision)
|
||||||
unsigned int timestamp;
|
unsigned int timestamp;
|
||||||
if(revision != 0){
|
if(revision != 0){
|
||||||
bool succeed = nixDB.revisionToTimeStamp(txn, dbStateRevisions, path, revision, timestamp);
|
bool succeed = revisionToTimeStamp(nixDB, txn, dbStateRevisions, path, revision, timestamp);
|
||||||
if(!succeed)
|
if(!succeed)
|
||||||
throw Error(format("Getreferrers cannot find timestamp for revision: '%1%'") % revision);
|
throw Error(format("Getreferrers cannot find timestamp for revision: '%1%'") % revision);
|
||||||
}
|
}
|
||||||
|
|
@ -604,7 +603,7 @@ static PathSet getXReferrers(const Transaction & txn, const Path & store_or_stat
|
||||||
for (Strings::const_iterator i = keys.begin(); i != keys.end(); ++i){
|
for (Strings::const_iterator i = keys.begin(); i != keys.end(); ++i){
|
||||||
Path getStatePath;
|
Path getStatePath;
|
||||||
unsigned int getRevision;
|
unsigned int getRevision;
|
||||||
nixDB.splitDBKey(*i, getStatePath, getRevision);
|
splitDBKey(*i, getStatePath, getRevision);
|
||||||
|
|
||||||
if(latest[getStatePath] == 0) //either it is unset
|
if(latest[getStatePath] == 0) //either it is unset
|
||||||
latest[getStatePath] = getRevision;
|
latest[getStatePath] = getRevision;
|
||||||
|
|
@ -623,7 +622,7 @@ static PathSet getXReferrers(const Transaction & txn, const Path & store_or_stat
|
||||||
//printMsg(lvlError, format("AAAAA '%1%'") % (*i).first);
|
//printMsg(lvlError, format("AAAAA '%1%'") % (*i).first);
|
||||||
|
|
||||||
Strings references;
|
Strings references;
|
||||||
nixDB.queryStrings(txn, table, nixDB.mergeToDBKey((*i).first, (*i).second), references);
|
nixDB.queryStrings(txn, table, mergeToDBKey((*i).first, (*i).second), references);
|
||||||
for (Strings::iterator j = references.begin(); j != references.end(); ++j){
|
for (Strings::iterator j = references.begin(); j != references.end(); ++j){
|
||||||
//printMsg(lvlError, format("TEST: '%1%' has ref '%2%' check with '%3%'") % (*i).first % *j % path);
|
//printMsg(lvlError, format("TEST: '%1%' has ref '%2%' check with '%3%'") % (*i).first % *j % path);
|
||||||
if(*j == path)
|
if(*j == path)
|
||||||
|
|
@ -1665,7 +1664,7 @@ void queryAllValidPathsTxn(const Transaction & txn, PathSet & allComponentPaths,
|
||||||
|
|
||||||
void setStateRevisionsTxn(const Transaction & txn, const RevisionClosure & revisions, const Path & rootStatePath, const string & comment)
|
void setStateRevisionsTxn(const Transaction & txn, const RevisionClosure & revisions, const Path & rootStatePath, const string & comment)
|
||||||
{
|
{
|
||||||
nixDB.setStateRevisions(txn, dbStateRevisions, dbStateRevisionsComments, dbStateSnapshots, revisions, rootStatePath, comment);
|
setStateRevisions(nixDB, txn, dbStateRevisions, dbStateRevisionsComments, dbStateSnapshots, revisions, rootStatePath, comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalStore::setStateRevisions(const RevisionClosure & revisions, const Path & rootStatePath, const string & comment)
|
void LocalStore::setStateRevisions(const RevisionClosure & revisions, const Path & rootStatePath, const string & comment)
|
||||||
|
|
@ -1675,7 +1674,7 @@ void LocalStore::setStateRevisions(const RevisionClosure & revisions, const Path
|
||||||
|
|
||||||
bool queryStateRevisionsTxn(const Transaction & txn, const Path & statePath, RevisionClosure & revisions, RevisionClosureTS & timestamps, const unsigned int revision)
|
bool queryStateRevisionsTxn(const Transaction & txn, const Path & statePath, RevisionClosure & revisions, RevisionClosureTS & timestamps, const unsigned int revision)
|
||||||
{
|
{
|
||||||
return nixDB.queryStateRevisions(txn, dbStateRevisions, dbStateSnapshots, statePath, revisions, timestamps, revision);
|
return queryStateRevisions(nixDB, txn, dbStateRevisions, dbStateSnapshots, statePath, revisions, timestamps, revision);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LocalStore::queryStateRevisions(const Path & statePath, RevisionClosure & revisions, RevisionClosureTS & timestamps, const unsigned int revision)
|
bool LocalStore::queryStateRevisions(const Path & statePath, RevisionClosure & revisions, RevisionClosureTS & timestamps, const unsigned int revision)
|
||||||
|
|
@ -1685,7 +1684,7 @@ bool LocalStore::queryStateRevisions(const Path & statePath, RevisionClosure & r
|
||||||
|
|
||||||
bool queryAvailableStateRevisionsTxn(const Transaction & txn, const Path & statePath, RevisionInfos & revisions)
|
bool queryAvailableStateRevisionsTxn(const Transaction & txn, const Path & statePath, RevisionInfos & revisions)
|
||||||
{
|
{
|
||||||
return nixDB.queryAvailableStateRevisions(txn, dbStateRevisions, dbStateRevisionsComments, statePath, revisions);
|
return queryAvailableStateRevisions(nixDB, txn, dbStateRevisions, dbStateRevisionsComments, statePath, revisions);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LocalStore::queryAvailableStateRevisions(const Path & statePath, RevisionInfos & revisions)
|
bool LocalStore::queryAvailableStateRevisions(const Path & statePath, RevisionInfos & revisions)
|
||||||
|
|
@ -1727,25 +1726,97 @@ bool querySolidStateReferencesTxn(const Transaction & txn, const Path & statePat
|
||||||
return notempty;
|
return notempty;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSharedStateTxn(const Transaction & txn, const Path & fromExisting, const Path & toNew)
|
void unShareStateTxn(const Transaction & txn, const Path & path, const bool copyFromOld)
|
||||||
{
|
{
|
||||||
//TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! LEGALITY CHECK IF THE PATH MAY BE SHARED !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
//Check if is statePath
|
||||||
//TODO
|
if(!isValidStatePathTxn(txn, path))
|
||||||
|
throw Error(format("Path `%1%' is not a valid state path") % path);
|
||||||
|
|
||||||
//Remove earlier entries
|
//Check if path was shared...
|
||||||
nixDB.delPair(txn, dbSharedState, toNew);
|
Path sharedWithOldPath;
|
||||||
|
if(!querySharedStateTxn(txn, path, sharedWithOldPath))
|
||||||
|
throw Error(format("Path `%1%' is not a shared so cannot be unshared") % path);
|
||||||
|
|
||||||
//Set new entry
|
//Remove Symlink
|
||||||
nixDB.setString(txn, dbSharedState, toNew, fromExisting);
|
removeSymlink(path);
|
||||||
|
|
||||||
|
//Touch dir with correct rights
|
||||||
|
Derivation drv = derivationFromPathTxn(txn, queryStatePathDrvTxn(txn, path));
|
||||||
|
ensureStateDir(path, drv.stateOutputs.find("state")->second.username, "nixbld", "700");
|
||||||
|
|
||||||
|
//Copy if necessary (TODO first snapshot?)
|
||||||
|
if(copyFromOld){
|
||||||
|
copyContents(sharedWithOldPath, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalStore::setSharedState(const Path & fromExisting, const Path & toNew)
|
//Remove earlier entries (unshare)
|
||||||
|
nixDB.delPair(txn, dbSharedState, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalStore::unShareState(const Path & path, const bool copyFromOld)
|
||||||
{
|
{
|
||||||
Transaction txn(nixDB);
|
Transaction txn(nixDB);
|
||||||
setSharedStateTxn(txn, fromExisting, toNew);
|
unShareStateTxn(txn, path, copyFromOld);
|
||||||
txn.commit();
|
txn.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FROM (NEW) --> TO (EXISTING) */
|
||||||
|
void shareStateTxn(const Transaction & txn, const Path & from, const Path & to, const bool snapshot)
|
||||||
|
{
|
||||||
|
//Check if is statePath
|
||||||
|
if(! (isValidStatePathTxn(txn, from) && isValidStatePathTxn(txn, to)))
|
||||||
|
throw Error(format("Path `%1%' or `%2%' is not a valid state path") % from % to);
|
||||||
|
|
||||||
|
//Cant share with yourself
|
||||||
|
if(from == to)
|
||||||
|
throw Error(format("You cannot share with yourself `%1%'") % from);
|
||||||
|
|
||||||
|
//Check for infinite recursion
|
||||||
|
//we do querySharedStateTxn until there the current path is not a shared path anymore
|
||||||
|
Path sharedPath;
|
||||||
|
Path returnedPath = to;
|
||||||
|
while(querySharedStateTxn(txn, returnedPath, sharedPath)){
|
||||||
|
if(sharedPath == from)
|
||||||
|
throw Error(format("You cannot create an infinite sharing loop !! `%1%' is already shared with `%2%'") % sharedPath % from);
|
||||||
|
returnedPath = sharedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if the user has the right to share this path
|
||||||
|
Derivation from_drv = derivationFromPathTxn(txn, queryStatePathDrvTxn(txn, from));
|
||||||
|
Derivation to_drv = derivationFromPathTxn(txn, queryStatePathDrvTxn(txn, to));
|
||||||
|
//TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
|
||||||
|
//Snapshot if necessary
|
||||||
|
if(snapshot){
|
||||||
|
//Commit state (we only include our own state in the rivisionMapping)
|
||||||
|
RevisionClosure rivisionMapping;
|
||||||
|
rivisionMapping[from] = commitStatePathTxn(txn, from);
|
||||||
|
|
||||||
|
//Save the new revision
|
||||||
|
setStateRevisionsTxn(txn, rivisionMapping, from, ("Before sharing revision with '" + to)+"'");
|
||||||
|
}
|
||||||
|
|
||||||
|
//If from was shared: unshare
|
||||||
|
Path empty;
|
||||||
|
if(querySharedStateTxn(txn, from, empty))
|
||||||
|
unShareStateTxn(txn, from, false);
|
||||||
|
|
||||||
|
//Remove state path and link
|
||||||
|
deletePathWrapped(from);
|
||||||
|
symlinkPath(to, from); //a link named 'from' pointing to existing dir 'to'
|
||||||
|
|
||||||
|
//Set new entry
|
||||||
|
nixDB.setString(txn, dbSharedState, from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalStore::shareState(const Path & from, const Path & to, const bool snapshot)
|
||||||
|
{
|
||||||
|
Transaction txn(nixDB);
|
||||||
|
shareStateTxn(txn, from, to, snapshot);
|
||||||
|
txn.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool querySharedStateTxn(const Transaction & txn, const Path & statePath, Path & shared_with)
|
bool querySharedStateTxn(const Transaction & txn, const Path & statePath, Path & shared_with)
|
||||||
{
|
{
|
||||||
|
|
@ -1758,8 +1829,10 @@ Path toNonSharedPathTxn(const Transaction & txn, const Path & statePath)
|
||||||
Path sharedPath;
|
Path sharedPath;
|
||||||
Path returnedPath = statePath;
|
Path returnedPath = statePath;
|
||||||
|
|
||||||
while(querySharedStateTxn(txn, returnedPath, sharedPath))
|
while(querySharedStateTxn(txn, returnedPath, sharedPath)){
|
||||||
|
//printMsg(lvlError, format("querySharedStateTxn '%1%' '%2%'") % returnedPath % sharedPath);
|
||||||
returnedPath = sharedPath;
|
returnedPath = sharedPath;
|
||||||
|
}
|
||||||
|
|
||||||
return returnedPath;
|
return returnedPath;
|
||||||
}
|
}
|
||||||
|
|
@ -1782,12 +1855,12 @@ PathSet LocalStore::toNonSharedPathSet(const PathSet & statePaths)
|
||||||
|
|
||||||
void setStateComponentReferencesTxn(const Transaction & txn, const Path & statePath, const Strings & references, const unsigned int revision, const unsigned int timestamp)
|
void setStateComponentReferencesTxn(const Transaction & txn, const Path & statePath, const Strings & references, const unsigned int revision, const unsigned int timestamp)
|
||||||
{
|
{
|
||||||
nixDB.setStateReferences(txn, dbStateComponentReferences, dbStateRevisions, statePath, references, revision, timestamp);
|
setStateReferences(nixDB, txn, dbStateComponentReferences, dbStateRevisions, statePath, references, revision, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setStateStateReferencesTxn(const Transaction & txn, const Path & statePath, const Strings & references, const unsigned int revision, const unsigned int timestamp)
|
void setStateStateReferencesTxn(const Transaction & txn, const Path & statePath, const Strings & references, const unsigned int revision, const unsigned int timestamp)
|
||||||
{
|
{
|
||||||
nixDB.setStateReferences(txn, dbStateStateReferences, dbStateRevisions, statePath, references, revision, timestamp);
|
setStateReferences(nixDB, txn, dbStateStateReferences, dbStateRevisions, statePath, references, revision, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Lookups which statePaths directy share (point to) statePath
|
//Lookups which statePaths directy share (point to) statePath
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,9 @@ public:
|
||||||
|
|
||||||
void revertToRevision(const Path & statePath, const unsigned int revision_arg, const bool recursive);
|
void revertToRevision(const Path & statePath, const unsigned int revision_arg, const bool recursive);
|
||||||
|
|
||||||
void setSharedState(const Path & fromExisting, const Path & toNew);
|
void shareState(const Path & from, const Path & to, const bool snapshot);
|
||||||
|
|
||||||
|
void unShareState(const Path & path, const bool copyFromOld);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -217,13 +219,14 @@ bool isStateDrvPathTxn(const Transaction & txn, const Path & drvPath);
|
||||||
|
|
||||||
bool isStateDrv(const Derivation & drv);
|
bool isStateDrv(const Derivation & drv);
|
||||||
|
|
||||||
//TODO can this ?????
|
|
||||||
|
//TODO CHECK IF THESE DONT BELONG HERE, REFACTOR CODE, EG MOVE FUNCTIONS AROUND
|
||||||
|
|
||||||
void queryAllValidPathsTxn(const Transaction & txn, PathSet & allComponentPaths, PathSet & allStatePaths);
|
void queryAllValidPathsTxn(const Transaction & txn, PathSet & allComponentPaths, PathSet & allStatePaths);
|
||||||
bool isValidStatePathTxn(const Transaction & txn, const Path & path);
|
bool isValidStatePathTxn(const Transaction & txn, const Path & path);
|
||||||
|
|
||||||
void queryXReferencesTxn(const Transaction & txn, const Path & path, PathSet & references, const bool component_or_state, const unsigned int revision, const unsigned int timestamp = 0);
|
void queryXReferencesTxn(const Transaction & txn, const Path & path, PathSet & references, const bool component_or_state, const unsigned int revision, const unsigned int timestamp = 0);
|
||||||
|
|
||||||
//TODO THESE DONT BELONG HERE, REFACTOR CODE, EG MOVE FUNCTIONS AROUND
|
|
||||||
void setStateComponentReferencesTxn(const Transaction & txn, const Path & statePath, const Strings & references, const unsigned int revision, const unsigned int timestamp);
|
void setStateComponentReferencesTxn(const Transaction & txn, const Path & statePath, const Strings & references, const unsigned int revision, const unsigned int timestamp);
|
||||||
void setStateStateReferencesTxn(const Transaction & txn, const Path & statePath, const Strings & references, const unsigned int revision, const unsigned int timestamp);
|
void setStateStateReferencesTxn(const Transaction & txn, const Path & statePath, const Strings & references, const unsigned int revision, const unsigned int timestamp);
|
||||||
|
|
||||||
|
|
@ -240,7 +243,9 @@ bool isValidStatePathTxn(const Transaction & txn, const Path & path);
|
||||||
void setSolidStateReferencesTxn(const Transaction & txn, const Path & statePath, const PathSet & paths);
|
void setSolidStateReferencesTxn(const Transaction & txn, const Path & statePath, const PathSet & paths);
|
||||||
bool querySolidStateReferencesTxn(const Transaction & txn, const Path & statePath, PathSet & paths);
|
bool querySolidStateReferencesTxn(const Transaction & txn, const Path & statePath, PathSet & paths);
|
||||||
|
|
||||||
void setSharedStateTxn(const Transaction & txn, const Path & fromExisting, const Path & toNew);
|
void shareStateTxn(const Transaction & txn, const Path & from, const Path & to, const bool snapshot);
|
||||||
|
void unShareStateTxn(const Transaction & txn, const Path & path, const bool copyFromOld);
|
||||||
|
|
||||||
PathSet toNonSharedPathSetTxn(const Transaction & txn, const PathSet & statePaths);
|
PathSet toNonSharedPathSetTxn(const Transaction & txn, const PathSet & statePaths);
|
||||||
Path toNonSharedPathTxn(const Transaction & txn, const Path & statePath);
|
Path toNonSharedPathTxn(const Transaction & txn, const Path & statePath);
|
||||||
|
|
||||||
|
|
@ -254,6 +259,7 @@ IntVector getStatePathsIntervalTxn(const Transaction & txn, const PathSet & stat
|
||||||
|
|
||||||
bool queryStateRevisionsTxn(const Transaction & txn, const Path & statePath, RevisionClosure & revisions, RevisionClosureTS & timestamps, const unsigned int revision);
|
bool queryStateRevisionsTxn(const Transaction & txn, const Path & statePath, RevisionClosure & revisions, RevisionClosureTS & timestamps, const unsigned int revision);
|
||||||
void setStatePathsIntervalTxn(const Transaction & txn, const PathSet & statePath, const IntVector & intervals, bool allZero = false);
|
void setStatePathsIntervalTxn(const Transaction & txn, const PathSet & statePath, const IntVector & intervals, bool allZero = false);
|
||||||
|
bool querySharedStateTxn(const Transaction & txn, const Path & statePath, Path & shared_with);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ void computeFSClosureTxn(const Transaction & txn, const Path & path, PathSet & p
|
||||||
if(!withComponents && !withState)
|
if(!withComponents && !withState)
|
||||||
throw Error(format("Useless call to computeFSClosure, at leat withComponents or withState must be true"));
|
throw Error(format("Useless call to computeFSClosure, at leat withComponents or withState must be true"));
|
||||||
|
|
||||||
//TODO MAYBE EDIT: HOW CAN THESE PATHS ALREADY BE VALID SOMETIMES ..... ?????????????????????
|
//TODO HOW CAN THESE PATHS ALREADY BE VALID SOMETIMES ..... ?????????????????????
|
||||||
for (PathSet::iterator i = allPaths.begin(); i != allPaths.end(); ++i)
|
for (PathSet::iterator i = allPaths.begin(); i != allPaths.end(); ++i)
|
||||||
if ( !isValidPathTxn(txn, *i) && !isValidStatePathTxn(txn, *i) )
|
if ( !isValidPathTxn(txn, *i) && !isValidStatePathTxn(txn, *i) )
|
||||||
throw Error(format("Not a state or store path: ") % *i);
|
throw Error(format("Not a state or store path: ") % *i);
|
||||||
|
|
@ -70,7 +70,8 @@ void computeFSClosureTxn(const Transaction & txn, const Path & path, PathSet & p
|
||||||
|
|
||||||
void computeFSClosureRecTxn(const Transaction & txn, const Path & path, PathSet & paths, const int revision, const bool & flipDirection)
|
void computeFSClosureRecTxn(const Transaction & txn, const Path & path, PathSet & paths, const int revision, const bool & flipDirection)
|
||||||
{
|
{
|
||||||
if (paths.find(path) != paths.end()) return; //takes care of double entries
|
if (paths.find(path) != paths.end()) //takes care of double entries
|
||||||
|
return;
|
||||||
|
|
||||||
paths.insert(path);
|
paths.insert(path);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -523,11 +523,21 @@ void RemoteStore::revertToRevision(const Path & statePath, const unsigned int re
|
||||||
readInt(from);
|
readInt(from);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteStore::setSharedState(const Path & fromExisting, const Path & toNew)
|
void RemoteStore::shareState(const Path & from_arg, const Path & to_arg, const bool snapshot)
|
||||||
{
|
{
|
||||||
writeInt(wopSetSharedState, to);
|
writeInt(wopShareState, to);
|
||||||
writeString(fromExisting, to);
|
writeString(from_arg, to);
|
||||||
writeString(toNew, to);
|
writeString(to_arg, to);
|
||||||
|
writeInt(snapshot ? 1 : 0, to);
|
||||||
|
processStderr();
|
||||||
|
readInt(from);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteStore::unShareState(const Path & path, const bool copyFromOld)
|
||||||
|
{
|
||||||
|
writeInt(wopUnShareState, to);
|
||||||
|
writeString(path, to);
|
||||||
|
writeInt(copyFromOld ? 1 : 0, to);
|
||||||
processStderr();
|
processStderr();
|
||||||
readInt(from);
|
readInt(from);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,9 @@ public:
|
||||||
|
|
||||||
void revertToRevision(const Path & statePath, const unsigned int revision_arg, const bool recursive);
|
void revertToRevision(const Path & statePath, const unsigned int revision_arg, const bool recursive);
|
||||||
|
|
||||||
void setSharedState(const Path & fromExisting, const Path & toNew);
|
void shareState(const Path & from, const Path & to, const bool snapshot);
|
||||||
|
|
||||||
|
void unShareState(const Path & path, const bool copyFromOld);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AutoCloseFD fdSocket;
|
AutoCloseFD fdSocket;
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ void checkStatePath(const Derivation & drv)
|
||||||
|
|
||||||
|
|
||||||
//TODO Name check
|
//TODO Name check
|
||||||
|
//if( user != callinguser
|
||||||
|
|
||||||
|
|
||||||
Path calculatedPath = makeStatePath(componentHash, suffix, stateIdentifier); //TODO INCLUDE USER !!!!!!!!!!!!
|
Path calculatedPath = makeStatePath(componentHash, suffix, stateIdentifier); //TODO INCLUDE USER !!!!!!!!!!!!
|
||||||
|
|
|
||||||
|
|
@ -244,7 +244,10 @@ public:
|
||||||
virtual void revertToRevision(const Path & statePath, const unsigned int revision_arg, const bool recursive) = 0;
|
virtual void revertToRevision(const Path & statePath, const unsigned int revision_arg, const bool recursive) = 0;
|
||||||
|
|
||||||
/* TODO */
|
/* TODO */
|
||||||
virtual void setSharedState(const Path & fromExisting, const Path & toNew) = 0;
|
virtual void shareState(const Path & from, const Path & to, const bool snapshot) = 0;
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
virtual void unShareState(const Path & path, const bool copyFromOld) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
#include "snapshot.hh"
|
#include "snapshot.hh"
|
||||||
#include "references.hh"
|
#include "references.hh"
|
||||||
|
|
||||||
|
//for nixDB
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -113,7 +115,7 @@ void revertToRevisionTxn(const Transaction & txn, const Path & statePath, const
|
||||||
unsigned int timestamp = getTimestamps[statePath];
|
unsigned int timestamp = getTimestamps[statePath];
|
||||||
|
|
||||||
//get its derivation-state-items
|
//get its derivation-state-items
|
||||||
Derivation statePath_drv = derivationFromPathTxn(txn, queryStatePathDrvTxn(noTxn, statePath));
|
Derivation statePath_drv = derivationFromPathTxn(txn, queryStatePathDrvTxn(txn, statePath));
|
||||||
DerivationStateOutputDirs stateOutputDirs = statePath_drv.stateOutputDirs;
|
DerivationStateOutputDirs stateOutputDirs = statePath_drv.stateOutputDirs;
|
||||||
|
|
||||||
//TODO Sort snapshots??? eg first restore root, then the subdirs??
|
//TODO Sort snapshots??? eg first restore root, then the subdirs??
|
||||||
|
|
@ -377,4 +379,333 @@ void scanAndUpdateAllReferencesRecusivelyTxn(const Transaction & txn, const Path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ******************************************************************* DB FUNCTIONS
|
||||||
|
|
||||||
|
/* State specific db functions */
|
||||||
|
|
||||||
|
Path mergeToDBKey(const Path & statePath, const unsigned int intvalue)
|
||||||
|
{
|
||||||
|
string prefix = "-KEY-";
|
||||||
|
return statePath + prefix + unsignedInt2String(intvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void splitDBKey(const Path & revisionedStatePath, Path & statePath, unsigned int & intvalue)
|
||||||
|
{
|
||||||
|
string prefix = "-KEY-";
|
||||||
|
|
||||||
|
int pos = revisionedStatePath.find_last_of(prefix);
|
||||||
|
statePath = revisionedStatePath.substr(0, pos - prefix.length() + 1);
|
||||||
|
//printMsg(lvlError, format("'%2%' - '%1%'") % revisionedStatePath.substr(pos+1, revisionedStatePath.length()) % int2String(pos));
|
||||||
|
bool succeed = string2UnsignedInt(revisionedStatePath.substr(pos+1, revisionedStatePath.length()), intvalue);
|
||||||
|
if(!succeed)
|
||||||
|
throw Error(format("Malformed revision value of path '%1%'") % revisionedStatePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int getNewRevisionNumber(Database & nixDB, const Transaction & txn, TableId table,
|
||||||
|
const Path & statePath)
|
||||||
|
{
|
||||||
|
//query
|
||||||
|
string data;
|
||||||
|
bool notEmpty = nixDB.queryString(txn, table, statePath, data);
|
||||||
|
|
||||||
|
if(!notEmpty){
|
||||||
|
nixDB.setString(txn, table, statePath, int2String(1));
|
||||||
|
return 1; //we begin counting from 1 since 0 is a special value representing the last revision
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int revision;
|
||||||
|
bool succeed = string2UnsignedInt(data, revision);
|
||||||
|
if(!succeed)
|
||||||
|
throw Error(format("Malformed revision counter value of path '%1%'") % statePath);
|
||||||
|
|
||||||
|
revision++;
|
||||||
|
nixDB.setString(txn, table, statePath, unsignedInt2String(revision));
|
||||||
|
|
||||||
|
return revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lookupHighestRevivison(const Strings & keys, const Path & statePath, string & key, unsigned int lowerthan)
|
||||||
|
{
|
||||||
|
unsigned int highestRev = 0;
|
||||||
|
|
||||||
|
//Lookup which key we need
|
||||||
|
for (Strings::const_iterator i = keys.begin(); i != keys.end(); ++i) {
|
||||||
|
|
||||||
|
if((*i).substr(0, statePath.length()) != statePath || (*i).length() == statePath.length()) //dont check the new-revision key or other keys
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//printMsg(lvlError, format("'%1%' - '%2%'") % *i % statePath);
|
||||||
|
Path getStatePath;
|
||||||
|
unsigned int getRevision;
|
||||||
|
splitDBKey(*i, getStatePath, getRevision);
|
||||||
|
if(getRevision > highestRev){
|
||||||
|
|
||||||
|
if(lowerthan != 0){
|
||||||
|
if(getRevision <= lowerthan) //if we have an uppper limit, see to it that we downt go over it
|
||||||
|
highestRev = getRevision;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
highestRev = getRevision;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(highestRev == 0) //no records found
|
||||||
|
return false;
|
||||||
|
|
||||||
|
key = mergeToDBKey(statePath, highestRev); //final key that matches revision + statePath
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool revisionToTimeStamp(Database & nixDB, const Transaction & txn, TableId revisions_table, const Path & statePath, const int revision, unsigned int & timestamp)
|
||||||
|
{
|
||||||
|
string key = mergeToDBKey(statePath, revision);
|
||||||
|
Strings references;
|
||||||
|
bool notempty = nixDB.queryStrings(txn, revisions_table, key, references);
|
||||||
|
|
||||||
|
if(notempty){
|
||||||
|
Path empty;
|
||||||
|
splitDBKey(*(references.begin()), empty, timestamp); //extract the timestamp
|
||||||
|
//printMsg(lvlError, format("PRINT '%1%'") % timestamp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setStateReferences(Database & nixDB, const Transaction & txn, TableId references_table, TableId revisions_table,
|
||||||
|
const Path & statePath, const Strings & references, const unsigned int revision, const unsigned int timestamp)
|
||||||
|
{
|
||||||
|
//printMsg(lvlError, format("setStateReferences '%1%' for '%2%'") % references_table % statePath);
|
||||||
|
|
||||||
|
//Find the timestamp if we need
|
||||||
|
unsigned int timestamp2 = timestamp;
|
||||||
|
if(revision == 0 && timestamp == 0)
|
||||||
|
timestamp2 = getTimeStamp();
|
||||||
|
else if(revision != 0 && timestamp == 0){
|
||||||
|
bool found = revisionToTimeStamp(nixDB, txn, revisions_table, statePath, revision, timestamp2);
|
||||||
|
if(!found)
|
||||||
|
throw Error(format("Revision '%1%' cannot be matched to a timestamp...") % revision);
|
||||||
|
}
|
||||||
|
|
||||||
|
//for (Strings::const_iterator i = references.begin(); i != references.end(); ++i)
|
||||||
|
// printMsg(lvlError, format("setStateReferences::: '%1%'") % *i);
|
||||||
|
|
||||||
|
//Warning if it already exists
|
||||||
|
Strings empty;
|
||||||
|
if( nixDB.queryStrings(txn, references_table, mergeToDBKey(statePath, timestamp2), empty) )
|
||||||
|
printMsg(lvlError, format("Warning: The timestamp '%1%' (now: '%5%') / revision '%4%' already exists for set-references of path '%2%' with db '%3%'")
|
||||||
|
% timestamp2 % statePath % references_table % revision % getTimeStamp());
|
||||||
|
|
||||||
|
//Create the key
|
||||||
|
string key = mergeToDBKey(statePath, timestamp2);
|
||||||
|
|
||||||
|
//printMsg(lvlError, format("Set references '%1%'") % key);
|
||||||
|
//for (Strings::const_iterator i = references.begin(); i != references.end(); ++i)
|
||||||
|
// printMsg(lvlError, format("reference '%1%'") % *i);
|
||||||
|
|
||||||
|
//Insert
|
||||||
|
nixDB.setStrings(txn, references_table, key, references, false); //The false makes sure also empty references are set
|
||||||
|
}
|
||||||
|
|
||||||
|
bool queryStateReferences(Database & nixDB, const Transaction & txn, TableId references_table, TableId revisions_table,
|
||||||
|
const Path & statePath, Strings & references, const unsigned int revision, const unsigned int timestamp)
|
||||||
|
{
|
||||||
|
//printMsg(lvlError, format("queryStateReferences '%1%' with revision '%2%'") % references_table % revision);
|
||||||
|
|
||||||
|
//Convert revision to timestamp number useing the revisions_table
|
||||||
|
unsigned int timestamp2 = timestamp;
|
||||||
|
if(timestamp == 0 && revision != 0){
|
||||||
|
bool found = revisionToTimeStamp(nixDB, txn, revisions_table, statePath, revision, timestamp2);
|
||||||
|
if(!found) //we are asked for references of some revision, but there are no references registered yet, so we return false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Strings keys;
|
||||||
|
nixDB.enumTable(txn, references_table, keys);
|
||||||
|
|
||||||
|
//Mabye we need the latest timestamp?
|
||||||
|
string key = "";
|
||||||
|
if(timestamp2 == 0){
|
||||||
|
bool foundsomething = lookupHighestRevivison(keys, statePath, key);
|
||||||
|
if(!foundsomething)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return nixDB.queryStrings(txn, references_table, key, references);
|
||||||
|
}
|
||||||
|
|
||||||
|
//If a specific key is given: check if this timestamp exists key in the table
|
||||||
|
key = mergeToDBKey(statePath, timestamp2);
|
||||||
|
bool found = false;
|
||||||
|
for (Strings::const_iterator i = keys.begin(); i != keys.end(); ++i) {
|
||||||
|
if(key == *i){
|
||||||
|
found = true;
|
||||||
|
key = mergeToDBKey(statePath, timestamp2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//If it doesn't exist in the table then find the highest key lower than it
|
||||||
|
if(!found){
|
||||||
|
bool foundsomething = lookupHighestRevivison(keys, statePath, key, 0);
|
||||||
|
if(!foundsomething)
|
||||||
|
return false;
|
||||||
|
//printMsg(lvlError, format("Warning: References for timestamp '%1%' not was not found, so taking the highest rev-key possible for statePath '%2%'") % timestamp2 % statePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nixDB.queryStrings(txn, references_table, key, references); //now that we have the key, we can query the references
|
||||||
|
}
|
||||||
|
|
||||||
|
void setStateRevisions(Database & nixDB, const Transaction & txn, TableId revisions_table, TableId revisions_comments,
|
||||||
|
TableId snapshots_table, const RevisionClosure & revisions, const Path & rootStatePath, const string & comment)
|
||||||
|
{
|
||||||
|
if( !isStatePath(rootStatePath) ) //weak check on statePath
|
||||||
|
throw Error(format("StatePath '%1%' is not a statepath") % rootStatePath);
|
||||||
|
|
||||||
|
unsigned int timestamp = getTimeStamp();
|
||||||
|
|
||||||
|
//Insert all ss_epochs into snapshots_table with the current ts.
|
||||||
|
for (RevisionClosure::const_iterator i = revisions.begin(); i != revisions.end(); ++i){
|
||||||
|
string key = mergeToDBKey((*i).first, timestamp);
|
||||||
|
Strings data;
|
||||||
|
//the map<> takes care of the sorting on the Path
|
||||||
|
for (Snapshots::const_iterator j = (*i).second.begin(); j != (*i).second.end(); ++j)
|
||||||
|
data.push_back(int2String((*j).second));
|
||||||
|
nixDB.setStrings(txn, snapshots_table, key, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Insert for each statePath a new revision record linked to the ss_epochs
|
||||||
|
for (RevisionClosure::const_iterator i = revisions.begin(); i != revisions.end(); ++i){
|
||||||
|
Path statePath = (*i).first;
|
||||||
|
|
||||||
|
unsigned int revision = getNewRevisionNumber(nixDB, txn, revisions_table, statePath); //get a new revision number
|
||||||
|
|
||||||
|
string key = mergeToDBKey(statePath, revision);
|
||||||
|
|
||||||
|
//get all its requisites
|
||||||
|
PathSet statePath_references;
|
||||||
|
storePathRequisitesTxn(txn, statePath, false, statePath_references, false, true, 0);
|
||||||
|
statePath_references.insert(statePath);
|
||||||
|
|
||||||
|
//save in db
|
||||||
|
Strings data;
|
||||||
|
for (PathSet::const_iterator j = statePath_references.begin(); j != statePath_references.end(); ++j)
|
||||||
|
data.push_back(mergeToDBKey(*j, timestamp));
|
||||||
|
|
||||||
|
nixDB.setStrings(txn, revisions_table, key, data, false); //The false makes sure also empty revisions are set
|
||||||
|
|
||||||
|
//save the date and comments
|
||||||
|
Strings metadata;
|
||||||
|
metadata.push_back(unsignedInt2String(timestamp));
|
||||||
|
|
||||||
|
//get all paths that point to the same state (using shareing) and check if one of them equals the rootStatePath
|
||||||
|
PathSet sharedWith = getSharedWithPathSetRecTxn(txn, statePath);
|
||||||
|
if(statePath == rootStatePath || sharedWith.find(rootStatePath) != sharedWith.end())
|
||||||
|
metadata.push_back(comment);
|
||||||
|
else
|
||||||
|
metadata.push_back("Part of the snashot closure for " + rootStatePath);
|
||||||
|
nixDB.setStrings(txn, revisions_comments, key, metadata);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool queryStateRevisions(Database & nixDB, const Transaction & txn, TableId revisions_table, TableId snapshots_table,
|
||||||
|
const Path & statePath, RevisionClosure & revisions, RevisionClosureTS & timestamps, const unsigned int root_revision)
|
||||||
|
{
|
||||||
|
string key;
|
||||||
|
|
||||||
|
if(root_revision == 0){
|
||||||
|
Strings keys;
|
||||||
|
nixDB.enumTable(txn, revisions_table, keys); //get all revisions
|
||||||
|
bool foundsomething = lookupHighestRevivison(keys, statePath, key);
|
||||||
|
if(!foundsomething)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
key = mergeToDBKey(statePath, root_revision);
|
||||||
|
|
||||||
|
//Get references pointing to snapshots_table from revisions_table with root_revision
|
||||||
|
Strings statePaths;
|
||||||
|
bool notempty = nixDB.queryStrings(txn, revisions_table, key, statePaths);
|
||||||
|
|
||||||
|
if(!notempty)
|
||||||
|
throw Error(format("Root revision '%1%' not found of statePath '%2%'") % unsignedInt2String(root_revision) % statePath);
|
||||||
|
|
||||||
|
//For each statePath add the revisions
|
||||||
|
for (Strings::iterator i = statePaths.begin(); i != statePaths.end(); ++i){
|
||||||
|
|
||||||
|
Path getStatePath;
|
||||||
|
unsigned int getTimestamp;
|
||||||
|
splitDBKey(*i, getStatePath, getTimestamp);
|
||||||
|
|
||||||
|
//query state versioined directorys/files
|
||||||
|
vector<Path> sortedPaths;
|
||||||
|
Derivation drv = derivationFromPathTxn(txn, queryStatePathDrvTxn(txn, getStatePath));
|
||||||
|
DerivationStateOutputs stateOutputs = drv.stateOutputs;
|
||||||
|
DerivationStateOutputDirs stateOutputDirs = drv.stateOutputDirs;
|
||||||
|
for (DerivationStateOutputDirs::const_iterator j = stateOutputDirs.begin(); j != stateOutputDirs.end(); ++j){
|
||||||
|
string thisdir = (j->second).path;
|
||||||
|
string fullstatedir = getStatePath + "/" + thisdir;
|
||||||
|
if(thisdir == "/") //exception for the root dir
|
||||||
|
fullstatedir = statePath + "/";
|
||||||
|
sortedPaths.push_back(fullstatedir);
|
||||||
|
}
|
||||||
|
sort(sortedPaths.begin(), sortedPaths.end()); //sort
|
||||||
|
|
||||||
|
Strings snapshots_s;
|
||||||
|
Snapshots snapshots;
|
||||||
|
nixDB.queryStrings(txn, snapshots_table, *i, snapshots_s);
|
||||||
|
int counter=0;
|
||||||
|
for (Strings::iterator j = snapshots_s.begin(); j != snapshots_s.end(); ++j){
|
||||||
|
|
||||||
|
unsigned int revision;
|
||||||
|
bool succeed = string2UnsignedInt(*j, revision);
|
||||||
|
if(!succeed)
|
||||||
|
throw Error(format("Malformed epoch (snapshot timestamp) value of path '%1%'") % statePath);
|
||||||
|
|
||||||
|
snapshots[sortedPaths.at(counter)] = revision;
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
revisions[getStatePath] = snapshots;
|
||||||
|
timestamps[getStatePath] = getTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return notempty;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO include comments into revisions?
|
||||||
|
bool queryAvailableStateRevisions(Database & nixDB, const Transaction & txn, TableId revisions_table, TableId revisions_comments,
|
||||||
|
const Path & statePath, RevisionInfos & revisions)
|
||||||
|
{
|
||||||
|
Strings keys;
|
||||||
|
nixDB.enumTable(txn, revisions_table, keys); //get all revisions
|
||||||
|
|
||||||
|
for (Strings::const_iterator i = keys.begin(); i != keys.end(); ++i) {
|
||||||
|
|
||||||
|
if((*i).substr(0, statePath.length()) != statePath || (*i).length() == statePath.length()) //dont check the new-revision key or other keys
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Path getStatePath;
|
||||||
|
unsigned int getRevision;
|
||||||
|
splitDBKey(*i, getStatePath, getRevision);
|
||||||
|
|
||||||
|
//save the date and comments
|
||||||
|
RevisionInfo rev;
|
||||||
|
Strings metadata;
|
||||||
|
nixDB.queryStrings(txn, revisions_comments, *i, metadata);
|
||||||
|
unsigned int ts;
|
||||||
|
bool succeed = string2UnsignedInt(*(metadata.begin()), ts);
|
||||||
|
if(!succeed)
|
||||||
|
throw Error(format("Malformed timestamp in the revisions-comments table of path '%1%'") % *i);
|
||||||
|
rev.timestamp = ts;
|
||||||
|
metadata.pop_front();
|
||||||
|
rev.comment = *(metadata.begin());
|
||||||
|
revisions[getRevision] = rev;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(revisions.empty())
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,46 @@ void scanAndUpdateAllReferencesRecusivelyTxn(const Transaction & txn, const Path
|
||||||
|
|
||||||
void revertToRevisionTxn(const Transaction & txn, const Path & statePath, const int revision_arg, const bool recursive);
|
void revertToRevisionTxn(const Transaction & txn, const Path & statePath, const int revision_arg, const bool recursive);
|
||||||
|
|
||||||
|
|
||||||
|
// **************************************** *******************************************
|
||||||
|
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
bool lookupHighestRevivison(const Strings & keys, const Path & statePath, string & key, unsigned int lowerthan = 0);
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
unsigned int getNewRevisionNumber(Database & nixDB, const Transaction & txn, TableId table, const Path & statePath);
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
Path mergeToDBKey(const Path & statePath, const unsigned int intvalue);
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
void splitDBKey(const Path & revisionedStatePath, Path & statePath, unsigned int & intvalue);
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
bool revisionToTimeStamp(Database & nixDB, const Transaction & txn, TableId revisions_table, const Path & statePath, const int revision, unsigned int & timestamp);
|
||||||
|
|
||||||
|
/* Set the stateReferences for a specific revision (and older until the next higher revision number in the table) */
|
||||||
|
void setStateReferences(Database & nixDB, const Transaction & txn, TableId references_table, TableId revisions_table,
|
||||||
|
const Path & statePath, const Strings & references, const unsigned int revision = 0, const unsigned int timestamp = 0);
|
||||||
|
|
||||||
|
/* Returns the references for a specific revision (and older until the next higher revision number in the table) */
|
||||||
|
bool queryStateReferences(Database & nixDB, const Transaction & txn, TableId references_table, TableId revisions_table,
|
||||||
|
const Path & statePath, Strings & references, const unsigned int revision = 0, const unsigned int timestamp = 0);
|
||||||
|
|
||||||
|
/* Set the revision number of the statePath and the revision numbers of all state paths in the references closure */
|
||||||
|
void setStateRevisions(Database & nixDB, const Transaction & txn, TableId revisions_table, TableId revisions_comments,
|
||||||
|
TableId snapshots_table, const RevisionClosure & revisions, const Path & rootStatePath, const string & comment);
|
||||||
|
|
||||||
|
/* Returns all the revision numbers of the state references closure of the given state path */
|
||||||
|
bool queryStateRevisions(Database & nixDB, const Transaction & txn, TableId revisions_table, TableId snapshots_table,
|
||||||
|
const Path & statePath, RevisionClosure & revisions, RevisionClosureTS & timestamps, const unsigned int root_revision = 0);
|
||||||
|
|
||||||
|
/* Returns all available revision numbers of the given state path */
|
||||||
|
bool queryAvailableStateRevisions(Database & nixDB, const Transaction & txn, TableId revisions_table, TableId revisions_comments,
|
||||||
|
const Path & statePath, RevisionInfos & revisions);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !__STORESTATE_H */
|
#endif /* !__STORESTATE_H */
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,8 @@ typedef enum {
|
||||||
wopScanAndUpdateAllReferences,
|
wopScanAndUpdateAllReferences,
|
||||||
wopToNonSharedPathSet,
|
wopToNonSharedPathSet,
|
||||||
wopRevertToRevision,
|
wopRevertToRevision,
|
||||||
wopSetSharedState,
|
wopShareState,
|
||||||
|
wopUnShareState,
|
||||||
} WorkerOp;
|
} WorkerOp;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1281,24 +1281,45 @@ string padd(const string & s, char c , unsigned int size, bool front)
|
||||||
return ss;
|
return ss;
|
||||||
}
|
}
|
||||||
|
|
||||||
void symlinkPath(const Path & fromExisting, const Path & toNew)
|
void symlinkPath(const Path & existingDir, const Path & newLinkName)
|
||||||
{
|
{
|
||||||
//Symlink link to the share path
|
//Symlink link to the share path
|
||||||
//Usage: ln [OPTION]... [-T] TARGET LINK_NAME (1st form)
|
//Usage: ln [OPTION]... [-T] TARGET LINK_NAME (1st form)
|
||||||
Strings p_args;
|
Strings p_args;
|
||||||
p_args.push_back("-sf");
|
p_args.push_back("-sf");
|
||||||
p_args.push_back(fromExisting);
|
p_args.push_back(existingDir);
|
||||||
p_args.push_back(toNew);
|
p_args.push_back(newLinkName);
|
||||||
runProgram_AndPrintOutput("ln", true, p_args, "ln");
|
runProgram_AndPrintOutput("ln", true, p_args, "ln");
|
||||||
|
|
||||||
//printMsg(lvlError, format("ln -sf %1% %2%") % fromExisting % toNew);
|
//printMsg(lvlError, format("ln -sf %1% %2%") % existingDir % newLinkName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeSymlink(const string & path)
|
||||||
|
{
|
||||||
|
if(path[path.length() - 1] != '/')
|
||||||
|
throw Error(format("We dont want to remove the enitre directory, only the symlink, but a / is given for `%1%'") % path);
|
||||||
|
deletePath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ensureStateDir(const Path & statePath, const string & user, const string & group, const string & chmod)
|
||||||
|
{
|
||||||
|
ensureDirExists(statePath);
|
||||||
|
setChown(statePath, user, group);
|
||||||
|
setChmod(statePath, chmod);
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyContents(const Path & from, const Path & to)
|
void copyContents(const Path & from, const Path & to)
|
||||||
{
|
{
|
||||||
|
//Copy all files + dirs recursively
|
||||||
Strings p_args;
|
Strings p_args;
|
||||||
p_args.push_back("-R");
|
p_args.push_back("-R");
|
||||||
p_args.push_back(from + "/"); //the / makes sure it copys the contents of the dir, not just the symlink
|
p_args.push_back(from + "/*");
|
||||||
|
p_args.push_back(to);
|
||||||
|
runProgram_AndPrintOutput("cp", true, p_args, "cp");
|
||||||
|
|
||||||
|
//Also copy the hidden files (but not the ../ dir)
|
||||||
|
p_args.clear();
|
||||||
|
p_args.push_back(from + "/.[a-zA-Z0-9]*");
|
||||||
p_args.push_back(to);
|
p_args.push_back(to);
|
||||||
runProgram_AndPrintOutput("cp", true, p_args, "cp");
|
runProgram_AndPrintOutput("cp", true, p_args, "cp");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -330,7 +330,11 @@ void setChmod(const Path & pathOrFile, const string & chmod);
|
||||||
string padd(const string & s, char c , unsigned int size, bool front = false);
|
string padd(const string & s, char c , unsigned int size, bool front = false);
|
||||||
|
|
||||||
/* Symlinks one path to the other */
|
/* Symlinks one path to the other */
|
||||||
void symlinkPath(const Path & fromExisting, const Path & toNew);
|
void symlinkPath(const Path & existingDir, const Path & newLinkName);
|
||||||
|
|
||||||
|
void removeSymlink(const string & path);
|
||||||
|
|
||||||
|
void ensureStateDir(const Path & statePath, const string & user, const string & group, const string & chmod);
|
||||||
|
|
||||||
/* Copy all files and folders recursively (also the hidden ones) from the dir from/... to the dir to/... */
|
/* Copy all files and folders recursively (also the hidden ones) from the dir from/... to the dir to/... */
|
||||||
void copyContents(const Path & from, const Path & to);
|
void copyContents(const Path & from, const Path & to);
|
||||||
|
|
|
||||||
|
|
@ -609,26 +609,21 @@ static void installDerivations(Globals & globals,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
printMsg(lvlError, format("DONE!!!!!!!!"));
|
|
||||||
|
|
||||||
createUserEnv(globals.state, allElems,
|
createUserEnv(globals.state, allElems,
|
||||||
profile, globals.keepDerivations);
|
profile, globals.keepDerivations);
|
||||||
|
|
||||||
printMsg(lvlError, format("DONE!!!!!!!!"));
|
|
||||||
|
|
||||||
//After all components have been built succesfully, share their state paths with the old ones
|
//After all components have been built succesfully, share their state paths with the old ones
|
||||||
for (StringPairs::iterator i = toBeShared.begin(); i != toBeShared.end(); ++i){
|
for (StringPairs::iterator i = toBeShared.begin(); i != toBeShared.end(); ++i){
|
||||||
|
|
||||||
printMsg(lvlError, format("Sharing state from old <-- new component '%1%' <-- '%2%'") % i->first % i->second);
|
printMsg(lvlError, format("Sharing state from old <-- new component '%1%' <-- '%2%'") % i->first % i->second);
|
||||||
|
|
||||||
deletePath(i->second); //Remove contents of current new state path
|
//Share from new --> to existing
|
||||||
symlinkPath(i->first, i->second); //Share new statepath to the old statepath
|
store->shareState(i->second, i->first, false);
|
||||||
|
|
||||||
//Set in database
|
|
||||||
store->setSharedState(i->first, i->second);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//**********************
|
||||||
|
|
||||||
//Let the stateDirs in /nix/state point to the solidStateDependencies
|
//Let the stateDirs in /nix/state point to the solidStateDependencies
|
||||||
for (StringPairs::iterator i = externalStates.begin(); i != externalStates.end(); ++i){
|
for (StringPairs::iterator i = externalStates.begin(); i != externalStates.end(); ++i){
|
||||||
|
|
||||||
|
|
@ -668,6 +663,8 @@ static void installDerivations(Globals & globals,
|
||||||
symlinkPath(statePath, externalState);
|
symlinkPath(statePath, externalState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//**********************
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,7 @@ static void queryAvailableStateRevisions(Strings opFlags, Strings opArgs)
|
||||||
Derivation drv = getDerivation_andCheckArgs(opFlags, opArgs, componentPath, statePath, binary, derivationPath, isStateComponent, program_args);
|
Derivation drv = getDerivation_andCheckArgs(opFlags, opArgs, componentPath, statePath, binary, derivationPath, isStateComponent, program_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Unshare if neccacary
|
//Lookup unshared path if neccacary
|
||||||
PathSet nonSharedPaths;
|
PathSet nonSharedPaths;
|
||||||
nonSharedPaths.insert(statePath);
|
nonSharedPaths.insert(statePath);
|
||||||
Path nonSharedStatePath = *((store->toNonSharedPathSet(nonSharedPaths)).begin()); //TODO CHECK IF THIS WORKS !!!!!!!!
|
Path nonSharedStatePath = *((store->toNonSharedPathSet(nonSharedPaths)).begin()); //TODO CHECK IF THIS WORKS !!!!!!!!
|
||||||
|
|
@ -506,10 +506,14 @@ void run(Strings args)
|
||||||
for (PathSet::const_iterator j = comparePaths_result.begin(); j != comparePaths_result.end(); ++j)
|
for (PathSet::const_iterator j = comparePaths_result.begin(); j != comparePaths_result.end(); ++j)
|
||||||
printMsg(lvlError, format("RES '%1%'") % *j);
|
printMsg(lvlError, format("RES '%1%'") % *j);
|
||||||
|
|
||||||
|
deletePath("/nix/state/b");
|
||||||
|
copyContents("/nix/state/a", "/nix/state/b");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* test */
|
/* test */
|
||||||
|
|
||||||
for (Strings::iterator i = args.begin(); i != args.end(); ) {
|
for (Strings::iterator i = args.begin(); i != args.end(); ) {
|
||||||
|
|
|
||||||
|
|
@ -591,11 +591,22 @@ static void performOp(Source & from, Sink & to, unsigned int op)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case wopSetSharedState: {
|
case wopShareState: {
|
||||||
Path fromExisting = readString(from);
|
Path from_arg = readString(from);
|
||||||
Path toNew = readString(from);
|
Path to_arg = readString(from);
|
||||||
|
bool snapshot = readInt(from) == 1;
|
||||||
startWork();
|
startWork();
|
||||||
store->setSharedState(fromExisting, toNew);
|
store->shareState(from_arg, to_arg, snapshot);
|
||||||
|
stopWork();
|
||||||
|
writeInt(1, to);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case wopUnShareState: {
|
||||||
|
Path path = readString(from);
|
||||||
|
bool copyFromOld = readInt(from) == 1;
|
||||||
|
startWork();
|
||||||
|
store->unShareState(path, copyFromOld);
|
||||||
stopWork();
|
stopWork();
|
||||||
writeInt(1, to);
|
writeInt(1, to);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue