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

Replaced SVN by Ext3COW as a backend for state (still some things need to happen: reverting doesn't go right in all cases yet)

This commit is contained in:
Wouter den Breejen 2007-07-25 21:52:33 +00:00
parent dc4395b737
commit 0fc5accd86
16 changed files with 269 additions and 268 deletions

View file

@ -89,7 +89,7 @@ unsigned int take_snapshot(const string & dir2) //const string & file_or_dir)
exit(1); exit(1);
} }
printf("%u\n", (unsigned int)epoch); //printf("%u\n", (unsigned int)epoch);
return epoch; return epoch;
} }

View file

@ -1809,8 +1809,12 @@ void DerivationGoal::computeClosure()
state_stateReferences, state_stateReferences,
drvPath, 0); drvPath, 0);
//Commit state //Commit state (we only include our own state in the rivisionMapping (but other build component states might have been changed !!!! TODO)
commitStatePathTxn(txn, statePath); RevisionClosure rivisionMapping;
rivisionMapping[statePath] = commitStatePathTxn(txn, statePath);
//Save the new revision
setStateRevisionsTxn(txn, statePath, rivisionMapping);
//Shared state //Shared state
Path sharedState = drv.stateOutputs.find("state")->second.sharedState; Path sharedState = drv.stateOutputs.find("state")->second.sharedState;

View file

@ -467,7 +467,6 @@ void Database::splitStatePathRevision(const Path & revisionedStatePath, Path & s
throw Error(format("Malformed revision value of path '%1%'") % revisionedStatePath); throw Error(format("Malformed revision value of path '%1%'") % revisionedStatePath);
} }
int Database::getNewRevisionNumber(const Transaction & txn, TableId table, int Database::getNewRevisionNumber(const Transaction & txn, TableId table,
const Path & statePath) const Path & statePath)
{ {
@ -491,31 +490,6 @@ int Database::getNewRevisionNumber(const Transaction & txn, TableId table,
return revision; return revision;
} }
void Database::setStateReferences(const Transaction & txn, TableId table,
const Path & statePath, const Strings & references, int revision)
{
//printMsg(lvlError, format("setStateReferences/Referrers %1%") % table);
if(revision == -1)
revision = getNewRevisionNumber(txn, table, statePath);
/*
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( queryStateReferences(txn, table, statePath, empty, revision) )
printMsg(lvlError, format("Warning: The revision '%1%' already exists for set-references/referrers of path '%2%' with db '%3%'") % revision % statePath % table);
//Create the key
string key = makeStatePathRevision(statePath, revision);
//Insert
setStrings(txn, table, key, references);
}
bool Database::lookupHighestRevivison(const Strings & keys, const Path & statePath, string & key, int lowerthan) bool Database::lookupHighestRevivison(const Strings & keys, const Path & statePath, string & key, int lowerthan)
{ {
int highestRev = -1; int highestRev = -1;
@ -548,6 +522,33 @@ bool Database::lookupHighestRevivison(const Strings & keys, const Path & statePa
return true; return true;
} }
//////////////////////////////////////////////
void Database::setStateReferences(const Transaction & txn, TableId table,
const Path & statePath, const Strings & references, int revision)
{
//printMsg(lvlError, format("setStateReferences/Referrers %1%") % table);
if(revision == -1)
revision = getNewRevisionNumber(txn, table, statePath);
/*
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( queryStateReferences(txn, table, statePath, empty, revision) )
printMsg(lvlError, format("Warning: The revision '%1%' already exists for set-references/referrers of path '%2%' with db '%3%'") % revision % statePath % table);
//Create the key
string key = makeStatePathRevision(statePath, revision);
//Insert
setStrings(txn, table, key, references);
}
bool Database::queryStateReferences(const Transaction & txn, TableId table, bool Database::queryStateReferences(const Transaction & txn, TableId table,
const Path & statePath, Strings & references, int revision) const Path & statePath, Strings & references, int revision)
{ {
@ -590,62 +591,51 @@ bool Database::queryStateReferrers(const Transaction & txn, TableId table,
return queryStateReferences(txn, table, statePath, referrers, revision); return queryStateReferences(txn, table, statePath, referrers, revision);
} }
/////////////////////////////////////////////
void Database::setStateRevisions(const Transaction & txn, TableId table,
const Path & statePath, const RevisionNumbersSet & revisions) void Database::setStateRevisions(const Transaction & txn, TableId revisions_table, TableId snapshots_table,
const Path & root_statePath, const RevisionClosure & revisions)
{ {
//get a new revision number int ts = getTimeStamp();
int root_revision = getNewRevisionNumber(txn, table, statePath);
//Sort based on statePath to RevisionNumbersClosure //Insert all ss_epochs into table ...... with the current ts.
vector<Path> sortedStatePaths; for (RevisionClosure::const_iterator i = revisions.begin(); i != revisions.end(); ++i){
for (RevisionNumbersSet::const_iterator i = revisions.begin(); i != revisions.end(); ++i) string key = makeStatePathRevision((*i).first, ts);
sortedStatePaths.push_back((*i).first); Strings data;
sort(sortedStatePaths.begin(), sortedStatePaths.end()); //the map<> takes care of the sorting on
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);
}
vector<RevisionNumbers> sorted_revisions; //Insert for each statePath a new revision record linked to the ss_epochs
for (vector<Path>::const_iterator i = sortedStatePaths.begin(); i != sortedStatePaths.end(); ++i){ for (RevisionClosure::const_iterator i = revisions.begin(); i != revisions.end(); ++i){
map<Path, unsigned int> ss_revisions = revisions.at(*i); Path statePath = (*i).first;
int revision = getNewRevisionNumber(txn, revisions_table, statePath); //get a new revision number
string key = makeStatePathRevision(statePath, revision);
//Sort the set of paths that have revisions based on //get all its requisites
vector<Path> sorted_ssp; PathSet statePaths;
for (map<Path, unsigned int>::const_iterator j = ss_revisions.begin(); j != ss_revisions.end(); ++j) storePathRequisitesTxn(txn, statePath, false, statePaths, false, true, -1);
sorted_ssp.push_back((*j).first); statePaths.insert(statePath);
sort(sorted_ssp.begin(), sorted_ssp.end());
//Insert into sorted_ss_revs based on the sorted order //save in db
RevisionNumbers sorted_ss_revs; Strings data;
for (vector<Path>::const_iterator j = sorted_ssp.begin(); j != sorted_ssp.end(); ++j) for (PathSet::const_iterator j = statePaths.begin(); j != statePaths.end(); ++j)
sorted_ss_revs.push_back(ss_revisions.at(*j)); data.push_back(makeStatePathRevision(*j, ts));
setStrings(txn, revisions_table, key, data);
//Insert ...... }
sorted_revisions.push_back(sorted_ss_revs);
}
//Debugging
//for (vector<Path>::const_iterator i = sortedStatePaths.begin(); i != sortedStatePaths.end(); ++i)
// printMsg(lvlError, format("Insert: %1% into %2%") % revisions.at(*i) % *i);
//Convert the vector<RevisionNumbers> into Strings
Strings data;
for (vector<RevisionNumbers>::const_iterator i = sorted_revisions.begin(); i != sorted_revisions.end(); ++i)
data.push_back(packRevisionNumbers(*i));
//Create the key
string key = makeStatePathRevision(statePath, root_revision);
//Insert
setStrings(txn, table, key, data);
} }
bool Database::queryStateRevisions(const Transaction & txn, TableId table, const PathSet statePath_deps, bool Database::queryStateRevisions(const Transaction & txn, TableId revisions_table, TableId snapshots_table,
const Path & statePath, RevisionNumbersSet & revisions, int root_revision) const Path & statePath, RevisionClosure & revisions, int root_revision)
{ {
Strings keys;
enumTable(txn, table, keys); //get all revisions
string key; string key;
if(root_revision == -1){ if(root_revision == -1){
Strings keys;
enumTable(txn, revisions_table, keys); //get all revisions
bool foundsomething = lookupHighestRevivison(keys, statePath, key); bool foundsomething = lookupHighestRevivison(keys, statePath, key);
if(!foundsomething) if(!foundsomething)
return false; return false;
@ -653,65 +643,66 @@ bool Database::queryStateRevisions(const Transaction & txn, TableId table, const
else else
key = makeStatePathRevision(statePath, root_revision); key = makeStatePathRevision(statePath, root_revision);
Strings data; //Get references pointingg to snapshots_table from revisions_table with root_revision
bool notempty = queryStrings(txn, table, key, data); //now that we have the key, we can query the revisions Strings references;
bool notempty = queryStrings(txn, revisions_table, key, references);
//Check if(!notempty)
if(statePath_deps.size() != data.size()) throw Error(format("Root revision '%1%' not found of statePath '%2%'") % int2String(root_revision) % statePath);
throw Error(format("The number of statepath references doenst equal the number of revisions for '%1%'") % statePath);
//sort all state references recursively //
vector<Path> sortedStatePaths; for (Strings::iterator i = references.begin(); i != references.end(); ++i){
for (PathSet::iterator i = statePath_deps.begin(); i != statePath_deps.end(); ++i)
sortedStatePaths.push_back(*i);
sort(sortedStatePaths.begin(), sortedStatePaths.end());
//Convert the Strings into int's and match them to the sorted statePaths Path getStatePath;
for (vector<Path>::const_iterator i = sortedStatePaths.begin(); i != sortedStatePaths.end(); ++i){ int getTimestamp;
splitStatePathRevision(*i, getStatePath, getTimestamp);
RevisionNumbers ss_revisions = unpackRevisionNumbers(data.front());
data.pop_front();
//query state versioined directorys/files //query state versioined directorys/files
vector<Path> sortedPaths; vector<Path> sortedPaths;
Derivation drv = derivationFromPath(queryStatePathDrvTxn(txn, statePath)); Derivation drv = derivationFromPath(queryStatePathDrvTxn(txn, getStatePath));
DerivationStateOutputs stateOutputs = drv.stateOutputs; DerivationStateOutputs stateOutputs = drv.stateOutputs;
DerivationStateOutputDirs stateOutputDirs = drv.stateOutputDirs; DerivationStateOutputDirs stateOutputDirs = drv.stateOutputDirs;
for (DerivationStateOutputDirs::const_iterator j = stateOutputDirs.begin(); j != stateOutputDirs.end(); ++j){ for (DerivationStateOutputDirs::const_iterator j = stateOutputDirs.begin(); j != stateOutputDirs.end(); ++j){
string thisdir = (j->second).path; string thisdir = (j->second).path;
string fullstatedir = statePath + "/" + thisdir; string fullstatedir = getStatePath + "/" + thisdir;
if(thisdir == "/") //exception for the root dir if(thisdir == "/") //exception for the root dir
fullstatedir = statePath + "/"; fullstatedir = statePath + "/";
sortedPaths.push_back(fullstatedir); sortedPaths.push_back(fullstatedir);
} }
sort(sortedPaths.begin(), sortedPaths.end()); //sort sort(sortedPaths.begin(), sortedPaths.end()); //sort
//link Strings snapshots_s;
map<Path, unsigned int> revisions_ss; Snapshots snapshots;
for (vector<Path>::const_iterator j = sortedPaths.begin(); j != sortedPaths.end(); ++j){ queryStrings(txn, snapshots_table, *i, snapshots_s);
revisions_ss[*j] = ss_revisions.front(); int counter=0;
ss_revisions.pop_front(); 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[*i] = revisions_ss; revisions[getStatePath] = snapshots;
} }
if(!notempty)
throw Error(format("Root revision '%1%' not found of statePath '%2%'") % int2String(root_revision) % statePath);
return notempty; return notempty;
} }
//TODO include comments into revisions? //TODO include comments into revisions?
bool Database::queryAvailableStateRevisions(const Transaction & txn, TableId table, bool Database::queryAvailableStateRevisions(const Transaction & txn, TableId revisions_table,
const Path & statePath, RevisionNumbers & revisions) const Path & statePath, RevisionNumbers & revisions)
{ {
Strings keys; Strings keys;
enumTable(txn, table, keys); //get all revisions enumTable(txn, revisions_table, keys); //get all revisions
for (Strings::const_iterator i = keys.begin(); i != keys.end(); ++i) { 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 if((*i).substr(0, statePath.length()) != statePath || (*i).length() == statePath.length()) //dont check the new-revision key or other keys
continue; continue;
Path getStatePath; Path getStatePath;

View file

@ -115,15 +115,15 @@ public:
const Path & statePath, Strings & referrers, int revision = -1); const Path & statePath, Strings & referrers, int revision = -1);
/* Set the revision number of the statePath and the revision numbers of all state paths in the references closure */ /* 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 table, void setStateRevisions(const Transaction & txn, TableId revisions_table, TableId snapshots_table,
const Path & statePath, const RevisionNumbersSet & revisions); const Path & statePath, const RevisionClosure & revisions);
/* Returns all the revision numbers of the state references closure of the given state path */ /* Returns all the revision numbers of the state references closure of the given state path */
bool queryStateRevisions(const Transaction & txn, TableId table, const PathSet statePath_deps, bool queryStateRevisions(const Transaction & txn, TableId revisions_table, TableId snapshots_table,
const Path & statePath, RevisionNumbersSet & revisions, int root_revision = -1); const Path & statePath, RevisionClosure & revisions, int root_revision = -1);
/* Returns all available revision numbers of the given state path */ /* Returns all available revision numbers of the given state path */
bool queryAvailableStateRevisions(const Transaction & txn, TableId table, bool queryAvailableStateRevisions(const Transaction & txn, TableId revisions_table,
const Path & statePath, RevisionNumbers & revisions); const Path & statePath, RevisionNumbers & revisions);

View file

@ -124,13 +124,20 @@ static TableId dbStateCounters = 0;
*/ */
static TableId dbStateInfo = 0; static TableId dbStateInfo = 0;
/* dbStateRevisions :: StatePath -> RevisionNumbers /* dbStateRevisions :: StatePath -> [StatePath]
This table lists the statepaths + recursive (indirect) references and the revision numbers of their repositorys This table lists the ...............
*/ */
static TableId dbStateRevisions = 0; static TableId dbStateRevisions = 0;
/* dbStateSnapshots :: StatePath -> RevisionNumbers
This table lists the ...............
*/
static TableId dbStateSnapshots = 0;
/* dbSharedState :: Path -> Path /* dbSharedState :: Path -> Path
* *
* Lists all paths that are shared with other paths * Lists all paths that are shared with other paths
@ -211,6 +218,7 @@ LocalStore::LocalStore(bool reserveSpace)
dbStateComponentReferrers = nixDB.openTable("referrers_s_c", true); dbStateComponentReferrers = nixDB.openTable("referrers_s_c", true);
dbStateStateReferrers = nixDB.openTable("referrers_s_s", true); dbStateStateReferrers = nixDB.openTable("referrers_s_s", true);
dbStateRevisions = nixDB.openTable("staterevisions"); dbStateRevisions = nixDB.openTable("staterevisions");
dbStateSnapshots = nixDB.openTable("stateSnapshots");
dbSharedState = nixDB.openTable("sharedState"); dbSharedState = nixDB.openTable("sharedState");
dbSolidStateReferences = nixDB.openTable("references_solid_c_s"); /* The contents of this table is included in references_c_s */ dbSolidStateReferences = nixDB.openTable("references_solid_c_s"); /* The contents of this table is included in references_c_s */
@ -1661,26 +1669,22 @@ void queryAllValidPaths(const Transaction & txn, PathSet & allComponentPaths, Pa
} }
void setStateRevisionsTxn(const Transaction & txn, const Path & statePath, const RevisionNumbersSet & revisions) void setStateRevisionsTxn(const Transaction & txn, const Path & statePath, const RevisionClosure & revisions)
{ {
nixDB.setStateRevisions(txn, dbStateRevisions, statePath, revisions); nixDB.setStateRevisions(txn, dbStateRevisions, dbStateSnapshots, statePath, revisions);
} }
void LocalStore::setStateRevisions(const Path & statePath, const RevisionNumbersSet & revisions) void LocalStore::setStateRevisions(const Path & statePath, const RevisionClosure & revisions)
{ {
nix::setStateRevisionsTxn(noTxn, statePath, revisions); nix::setStateRevisionsTxn(noTxn, statePath, revisions);
} }
bool queryStateRevisionsTxn(const Transaction & txn, const Path & statePath, RevisionNumbersSet & revisions, const int revision) bool queryStateRevisionsTxn(const Transaction & txn, const Path & statePath, RevisionClosure & revisions, const int revision)
{ {
PathSet statePaths; return nixDB.queryStateRevisions(txn, dbStateRevisions, dbStateSnapshots, statePath, revisions, revision);
storePathRequisites(statePath, false, statePaths, false, true, revision); //Get all current state dependencies
statePaths.insert(statePath); //also insert the root statePath
return nixDB.queryStateRevisions(txn, dbStateRevisions, statePaths, statePath, revisions, revision);
} }
bool LocalStore::queryStateRevisions(const Path & statePath, RevisionNumbersSet & revisions, const int revision) bool LocalStore::queryStateRevisions(const Path & statePath, RevisionClosure & revisions, const int revision)
{ {
return nix::queryStateRevisionsTxn(noTxn, statePath, revisions, revision); return nix::queryStateRevisionsTxn(noTxn, statePath, revisions, revision);
} }

View file

@ -100,9 +100,9 @@ public:
void storePathRequisites(const Path & storeOrstatePath, const bool includeOutputs, PathSet & paths, const bool & withComponents, const bool & withState, const int revision); void storePathRequisites(const Path & storeOrstatePath, const bool includeOutputs, PathSet & paths, const bool & withComponents, const bool & withState, const int revision);
void setStateRevisions(const Path & statePath, const RevisionNumbersSet & revisions); void setStateRevisions(const Path & statePath, const RevisionClosure & revisions);
bool queryStateRevisions(const Path & statePath, RevisionNumbersSet & revisions, const int revision); bool queryStateRevisions(const Path & statePath, RevisionClosure & revisions, const int revision);
bool queryAvailableStateRevisions(const Path & statePath, RevisionNumbers & revisions); bool queryAvailableStateRevisions(const Path & statePath, RevisionNumbers & revisions);
@ -233,7 +233,7 @@ void queryStateReferrersTxn(const Transaction & txn, const Path & storePath, Pat
Path queryStatePathDrvTxn(const Transaction & txn, const Path & statePath); Path queryStatePathDrvTxn(const Transaction & txn, const Path & statePath);
void storePathRequisitesTxn(const Transaction & txn, const Path & storeOrstatePath, const bool includeOutputs, PathSet & paths, const bool & withComponents, const bool & withState, const int revision); void storePathRequisitesTxn(const Transaction & txn, const Path & storeOrstatePath, const bool includeOutputs, PathSet & paths, const bool & withComponents, const bool & withState, const int revision);
void setStateRevisionsTxn(const Transaction & txn, const Path & statePath, const RevisionNumbersSet & revisions); void setStateRevisionsTxn(const Transaction & txn, const Path & statePath, const RevisionClosure & revisions);
bool isValidPathTxn(const Transaction & txn, const Path & path); bool isValidPathTxn(const Transaction & txn, const Path & path);
bool isValidStatePathTxn(const Transaction & txn, const Path & path); bool isValidStatePathTxn(const Transaction & txn, const Path & path);

View file

@ -469,13 +469,13 @@ void RemoteStore::storePathRequisites(const Path & storeOrstatePath, const bool
} }
//TODO //TODO
void RemoteStore::setStateRevisions(const Path & statePath, const RevisionNumbersSet & revisions) void RemoteStore::setStateRevisions(const Path & statePath, const RevisionClosure & revisions)
{ {
} }
//TODO //TODO
bool RemoteStore::queryStateRevisions(const Path & statePath, RevisionNumbersSet & revisions, const int revision) bool RemoteStore::queryStateRevisions(const Path & statePath, RevisionClosure & revisions, const int revision)
{ {
return false; return false;
} }

View file

@ -88,9 +88,9 @@ public:
void storePathRequisites(const Path & storeOrstatePath, const bool includeOutputs, PathSet & paths, const bool & withComponents, const bool & withState, const int revision); void storePathRequisites(const Path & storeOrstatePath, const bool includeOutputs, PathSet & paths, const bool & withComponents, const bool & withState, const int revision);
void setStateRevisions(const Path & statePath, const RevisionNumbersSet & revisions); void setStateRevisions(const Path & statePath, const RevisionClosure & revisions);
bool queryStateRevisions(const Path & statePath, RevisionNumbersSet & revisions, const int revision); bool queryStateRevisions(const Path & statePath, RevisionClosure & revisions, const int revision);
bool queryAvailableStateRevisions(const Path & statePath, RevisionNumbers & revisions); bool queryAvailableStateRevisions(const Path & statePath, RevisionNumbers & revisions);

View file

@ -151,29 +151,6 @@ void checkStatePath(const Derivation & drv)
Error(format("The statepath from the Derivation does not match the recalculated statepath, are u trying to spoof the statepath?")); Error(format("The statepath from the Derivation does not match the recalculated statepath, are u trying to spoof the statepath?"));
} }
Path getStateReposPath(const string & type, const Path statePath)
{
//This is a little trick: we could use the same hash as the statepath, but we change it so the repository also gets a unique scannable hash
Hash hash = hashString(htSHA256, statePath);
//Extract suffix and stateIdentifier from statePath
int pos = statePath.find_first_of("-");
string suffix = statePath.substr(pos, statePath.length());
/* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */
string s = type + ":sha256:" + printHash(hash) + ":"
+ nixStoreState + ":" + suffix;
checkStoreName(suffix);
Path path = nixStoreStateRepos + "/"
+ printHash32(compressHash(hashString(htSHA256, s), 20))
+ suffix + "/";
return path;
}
Path makeFixedOutputPath(bool recursive, Path makeFixedOutputPath(bool recursive,
string hashAlgo, Hash hash, string name) string hashAlgo, Hash hash, string name)
{ {

View file

@ -220,10 +220,10 @@ public:
virtual void storePathRequisites(const Path & storeOrstatePath, const bool includeOutputs, PathSet & paths, const bool & withComponents, const bool & withState, const int revision) = 0; virtual void storePathRequisites(const Path & storeOrstatePath, const bool includeOutputs, PathSet & paths, const bool & withComponents, const bool & withState, const int revision) = 0;
/* TODO */ /* TODO */
virtual void setStateRevisions(const Path & statePath, const RevisionNumbersSet & revisions) = 0; virtual void setStateRevisions(const Path & statePath, const RevisionClosure & revisions) = 0;
/* TODO */ /* TODO */
virtual bool queryStateRevisions(const Path & statePath, RevisionNumbersSet & revisions, const int revision) = 0; virtual bool queryStateRevisions(const Path & statePath, RevisionClosure & revisions, const int revision) = 0;
/* TODO */ /* TODO */
virtual bool queryAvailableStateRevisions(const Path & statePath, RevisionNumbers & revisions) = 0; virtual bool queryAvailableStateRevisions(const Path & statePath, RevisionNumbers & revisions) = 0;
@ -265,9 +265,6 @@ Path makeStatePath(const string & componentHash, const string & suffix, const st
/* TODO ... */ /* TODO ... */
void checkStatePath(const Derivation & drv); void checkStatePath(const Derivation & drv);
/* Calculates a unique store state repos path */
Path getStateReposPath(const string & type, const Path statePath);
/* This is the preparatory part of addToStore() and addToStoreFixed(); /* This is the preparatory part of addToStore() and addToStoreFixed();
it computes the store path to which srcPath is to be copied. it computes the store path to which srcPath is to be copied.
Returns the store path and the cryptographic hash of the Returns the store path and the cryptographic hash of the

View file

@ -57,10 +57,7 @@ void createStateDirs(const DerivationStateOutputDirs & stateOutputDirs, const De
Path fullstatedir = stateDir + "/" + thisdir; Path fullstatedir = stateDir + "/" + thisdir;
Strings p_args; ensureDirExists(fullstatedir);
p_args.push_back("-p");
p_args.push_back(fullstatedir);
runProgram_AndPrintOutput("mkdir", true, p_args, "mkdir");
if(d.type == "interval"){ if(d.type == "interval"){
intervalPaths.insert(fullstatedir); intervalPaths.insert(fullstatedir);
@ -72,10 +69,8 @@ void createStateDirs(const DerivationStateOutputDirs & stateOutputDirs, const De
store->setStatePathsInterval(intervalPaths, empty, true); store->setStatePathsInterval(intervalPaths, empty, true);
} }
void commitStatePathTxn(const Transaction & txn, const Path & statePath) Snapshots commitStatePathTxn(const Transaction & txn, const Path & statePath)
{ {
//TODO: include code from: updateRevisionsRecursivelyTxn(txn, root_statePath);
if(!isValidStatePathTxn(txn, statePath)) if(!isValidStatePathTxn(txn, statePath))
throw Error(format("path `%1%' is not a valid state path") % statePath); throw Error(format("path `%1%' is not a valid state path") % statePath);
@ -100,6 +95,8 @@ void commitStatePathTxn(const Transaction & txn, const Path & statePath)
} }
vector<int> intervals = store->getStatePathsInterval(intervalPaths); //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! txn vector<int> intervals = store->getStatePathsInterval(intervalPaths); //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! txn
Snapshots revisions_list;
int intervalAt=0; int intervalAt=0;
for (DerivationStateOutputDirs::const_iterator i = stateOutputDirs.begin(); i != stateOutputDirs.end(); ++i){ for (DerivationStateOutputDirs::const_iterator i = stateOutputDirs.begin(); i != stateOutputDirs.end(); ++i){
DerivationStateOutputDir d = i->second; DerivationStateOutputDir d = i->second;
@ -122,92 +119,31 @@ void commitStatePathTxn(const Transaction & txn, const Path & statePath)
intervals[intervalAt] = interval_counter + 1; intervals[intervalAt] = interval_counter + 1;
intervalAt++; intervalAt++;
if(interval_counter % interval != 0){ return; } if(interval_counter % interval != 0){ continue; }
} }
else if(d.type == "full"){ } else if(d.type == "full"){ }
else if(d.type == "manual"){ return; } //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! else if(d.type == "manual"){ continue; } //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
else else
throw Error(format("Type '%1%' is not handled in nix-state") % d.type); throw Error(format("Type '%1%' is not handled in nix-state") % d.type);
//We got here so we need to commit //We got here so we need to commit
unsigned int epoch_time; unsigned int revision_number;
if(pathExists(fullstatedir) || FileExist(fullstatedir)){ if(pathExists(fullstatedir) || FileExist(fullstatedir)){
epoch_time = take_snapshot(fullstatedir); revision_number = take_snapshot(fullstatedir);
printMsg(lvlError, format("Snapshotted '%1%' with id '%2%'") % fullstatedir % epoch_time); printMsg(lvlError, format("Snapshotted '%1%' with id '%2%'") % fullstatedir % revision_number);
} }
else else
{ revision_number = 0; //deleted, so we assign 0 to indicate that
//TODO !!!!!!!!!!!!!!
}
//Put in database !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! revisions_list[fullstatedir] = revision_number;
//TODO
} }
return revisions_list;
//Update the intervals again //Update the intervals again
//setStatePathsIntervalTxn(txn, intervalPaths, intervals); //TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!! uncomment //setStatePathsIntervalTxn(txn, intervalPaths, intervals); //TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!! uncomment
} }
/*
* This function takes all state requisites (references) and revision numbers and stores them ...
*/
/*
void updateRevisionsRecursivelyTxn(const Transaction & txn, const Path & statePath)
{
//Save all revisions for the call to
RevisionNumbersSet rivisionMapping;
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);
//Sort
vector<Path> sortedStatePaths;
for (PathSet::iterator i = statePaths.begin(); i != statePaths.end(); ++i)
sortedStatePaths.push_back(*i);
sort(sortedStatePaths.begin(), sortedStatePaths.end());
//call scanForAllReferences again on all newly found statePaths
for (vector<Path>::const_iterator i = sortedStatePaths.begin(); i != sortedStatePaths.end(); ++i)
rivisionMapping[*i] = readRevisionNumber(*i);
//Store the revision numbers in the database for this statePath with revision number
setStateRevisionsTxn(txn, statePath, rivisionMapping);
}
int readRevisionNumber(Path statePath)
{
string svnbin = nixSVNPath + "/svn";
RevisionNumbers revisions;
string repos = getStateReposPath("stateOutput:staterepospath", statePath); //this is a copy from store-state.cc
//TODO Check if the .svn exists, it might be deleted, then we dont have to remember the state revision (set -1)
Strings p_args;
p_args.push_back(svnbin);
p_args.push_back("file://" + repos);
string output = runProgram(nixLibexecDir + "/nix/nix-readrevisions.sh", true, p_args); //run
int pos = output.find("\n",0); //remove trailing \n
output.erase(pos,1);
int revision;
bool succeed = string2Int(output, revision);
if(!succeed)
throw Error(format("Cannot read revision number of path '%1%'") % repos);
return revision;
}
*/
// string s = "/media/ext3cow/cca/";
// unsigned int i = take_snapshot(s);
// printMsg(lvlError, format("SS: '%1%'") % i);
} }

View file

@ -11,7 +11,7 @@ namespace nix {
void createStateDirs(const DerivationStateOutputDirs & stateOutputDirs, const DerivationStateOutputs & stateOutputs); void createStateDirs(const DerivationStateOutputDirs & stateOutputDirs, const DerivationStateOutputs & stateOutputs);
/* TODO */ /* TODO */
void commitStatePathTxn(const Transaction & txn, const Path & statePath); Snapshots commitStatePathTxn(const Transaction & txn, const Path & statePath);
/* TODO */ /* TODO */
//void updateRevisionsRecursivelyTxn(const Transaction & txn, const Path & statePath); //void updateRevisionsRecursivelyTxn(const Transaction & txn, const Path & statePath);

View file

@ -59,8 +59,9 @@ typedef list<Path> Paths;
typedef set<Path> PathSet; typedef set<Path> PathSet;
//state types //state types
typedef list<int> RevisionNumbers; //the Strings (list) of StateReferences and this list are connected by position typedef list<int> RevisionNumbers; //the Strings (list) of StateReferences and this list are connected by position
typedef map<Path, map<Path, unsigned int> > RevisionNumbersSet; //We include to the paths to sort on typedef map<Path, unsigned int> Snapshots; //Automatically sorted on Path :)
typedef map<Path, Snapshots > RevisionClosure;
typedef map<int, Strings> StateReferences; typedef map<int, Strings> StateReferences;

View file

@ -1039,6 +1039,20 @@ bool string2Int(const string & s, int & n)
return str && str.get() == EOF; return str && str.get() == EOF;
} }
string unsignedInt2String(unsigned int n)
{
std::ostringstream str;
str << n;
return str.str();
}
bool string2UnsignedInt(const string & s, unsigned int & n)
{
std::istringstream str(s);
str >> n;
return str && str.get() == EOF;
}
string bool2string(const bool b) string bool2string(const bool b)
{ {
if(b == true) if(b == true)
@ -1126,11 +1140,11 @@ void executeShellCommand(const string & command)
} }
} }
string time_t2string(const time_t & t) int getTimeStamp()
{ {
int i = t; const time_t now = time(0);
string s = int2String(i); int i = now;
return s; return i;
} }
//TODO Does this work on windows? //TODO Does this work on windows?
@ -1218,5 +1232,12 @@ void pathSets_difference(const PathSet & oldpaths, const PathSet & newpaths, Pat
} }
} }
void ensureDirExists(const Path & path)
{
Strings p_args;
p_args.push_back("-p");
p_args.push_back(path);
runProgram_AndPrintOutput("mkdir", true, p_args, "mkdir"); //TODO ensurePath
}
} }

View file

@ -280,6 +280,10 @@ bool statusOk(int status);
string int2String(int n); string int2String(int n);
bool string2Int(const string & s, int & n); bool string2Int(const string & s, int & n);
/* */
bool string2UnsignedInt(const string & s, unsigned int & n);
string unsignedInt2String(unsigned int n);
/* Parse a bool to a string and back */ /* Parse a bool to a string and back */
string bool2string(const bool b); string bool2string(const bool b);
bool string2bool(const string & s); bool string2bool(const string & s);
@ -297,8 +301,7 @@ void executeShellCommand(const string & command);
// //
void runProgram_AndPrintOutput(Path program, bool searchPath, const Strings & args, const string outputPrefix); void runProgram_AndPrintOutput(Path program, bool searchPath, const Strings & args, const string outputPrefix);
//Convert time_t to a string int getTimeStamp();
string time_t2string(const time_t & t);
bool FileExist(const string FileName); bool FileExist(const string FileName);
@ -312,9 +315,8 @@ PathSet pathSets_union(const PathSet & paths1, const PathSet & paths2);
/* TODO */ /* TODO */
void pathSets_difference(const PathSet & oldpaths, const PathSet & newpaths, PathSet & addedpaths, PathSet & removedpaths); void pathSets_difference(const PathSet & oldpaths, const PathSet & newpaths, PathSet & addedpaths, PathSet & removedpaths);
string packRevisionNumbers(const RevisionNumbers & revs);
RevisionNumbers unpackRevisionNumbers(const string & packed); void ensureDirExists(const Path & path);
} }

View file

@ -1,5 +1,6 @@
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
#include <sys/time.h>
#include "globals.hh" #include "globals.hh"
#include "misc.hh" #include "misc.hh"
@ -158,7 +159,7 @@ static void opShowStatePath(Strings opFlags, Strings opArgs)
} }
//Prints the root path that contains the repoisitorys of the state of a component - indetiefier combination //Prints the root path that contains the repoisitorys of the state of a component - indetiefier combination
static void opShowStateReposPath(Strings opFlags, Strings opArgs) static void opShowStatePathAtRevision(Strings opFlags, Strings opArgs)
{ {
Path componentPath; Path componentPath;
Path statePath; Path statePath;
@ -171,10 +172,9 @@ static void opShowStateReposPath(Strings opFlags, Strings opArgs)
if(!isStateComponent) if(!isStateComponent)
throw UsageError(format("This path '%1%' is not a state-component path") % componentPath); throw UsageError(format("This path '%1%' is not a state-component path") % componentPath);
//Get the a repository for this state location //TODO
string repos = getStateReposPath("stateOutput:staterepospath", statePath); //this is a copy from store-state.cc
printMsg(lvlError, format("%1%") % repos); //printMsg(lvlError, format("%1%") % repos);
} }
@ -236,6 +236,7 @@ static void revertToRevision(Strings opFlags, Strings opArgs)
bool isStateComponent; bool isStateComponent;
string program_args; string program_args;
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);
DerivationStateOutputDirs stateOutputDirs = drv.stateOutputDirs;
bool recursive = true; //TODO !!!!!!!!!!!!!!!!! bool recursive = true; //TODO !!!!!!!!!!!!!!!!!
@ -246,15 +247,71 @@ static void revertToRevision(Strings opFlags, Strings opArgs)
statePaths.insert(derivationPath); //Insert direct state path statePaths.insert(derivationPath); //Insert direct state path
//Get the revisions recursively to also roll them back //Get the revisions recursively to also roll them back
RevisionNumbersSet getRivisions; RevisionClosure getRivisions;
bool b = store->queryStateRevisions(statePath, getRivisions, revision_arg); bool b = store->queryStateRevisions(statePath, getRivisions, revision_arg);
//Revert each statePath in the list //Revert each statePath in the list
for (RevisionNumbersSet::iterator i = getRivisions.begin(); i != getRivisions.end(); ++i){ for (RevisionClosure::iterator i = getRivisions.begin(); i != getRivisions.end(); ++i){
Path statePath = (*i).first; Path statePath = (*i).first;
map<Path, unsigned int> revisioned_paths = (*i).second; Snapshots revisioned_paths = (*i).second;
//TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //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 -R";
if(revertPathOrFile.substr(revertPathOrFile.length() -1 , revertPathOrFile.length()) == "/"){ //is dir
cpcommand += " " + (revertPathOrFile.substr(0, revertPathOrFile.length() -1) + "@" + unsignedInt2String(epoch) + "/*");
//clean all contents of the folder first (so were sure the path is clean)
if(pathExists(revertPathOrFile))
deletePath(revertPathOrFile);
//If path was not deleted in the previous version, we need to make sure it exists or cp will fail
if(epoch == 0)
continue;
else
ensureDirExists(revertPathOrFile);
}
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;
}
}
printMsg(lvlError, format("Reverting '%1%'") % revertPathOrFile);
cpcommand += " " + revertPathOrFile;
p_args.push_back(cpcommand);
//for (Strings::iterator h = p_args.begin(); h != p_args.end(); ++h)
// printMsg(lvlError, format("SH ARGS '%1%'") % *h);
runProgram_AndPrintOutput("sh", true, p_args, "sh-cp"); //TODO does this work on windows?
}
printMsg(lvlError, format("Reverted state of '%1%' to revision '%2%'") % statePath % revision_arg);
} }
} }
@ -357,7 +414,8 @@ void scanAndUpdateAllReferencesRecusivelyTxn(const Transaction & txn, const Path
//TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //TODO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
int revision = 0; int revision = 0;
//Get last revision number from DB !!!!!!!!!! //Get last revision number from DB !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//TODO first snapshot all paths....?
//Scan, update, call recursively //Scan, update, call recursively
PathSet newFoundComponentReferences; PathSet newFoundComponentReferences;
@ -408,7 +466,7 @@ static void opRunComponent(Strings opFlags, Strings opArgs)
//******************* Run **************************** //******************* Run ****************************
if(!only_commit) if(!only_commit)
executeShellCommand(root_componentPath + root_binary + " " + root_program_args); //more efficient way needed ??? executeShellCommand(root_componentPath + root_binary + " " + root_program_args);
//******************* With everything in place, we call the commit script on all statePaths (in)directly referenced ********************** //******************* With everything in place, we call the commit script on all statePaths (in)directly referenced **********************
@ -419,16 +477,20 @@ static void opRunComponent(Strings opFlags, Strings opArgs)
scanAndUpdateAllReferencesRecusivelyTxn(txn, root_statePath); scanAndUpdateAllReferencesRecusivelyTxn(txn, root_statePath);
//Commit all statePaths //Commit all statePaths
RevisionClosure rivisionMapping;
for (PathSet::iterator i = statePaths.begin(); i != statePaths.end(); ++i) //TODO first commit own state path? for (PathSet::iterator i = statePaths.begin(); i != statePaths.end(); ++i) //TODO first commit own state path?
commitStatePathTxn(txn, *i); rivisionMapping[*i] = commitStatePathTxn(txn, *i);
//Save new revisions
setStateRevisionsTxn(txn, root_statePath, rivisionMapping);
//Commit transaction //Commit transaction
//txn.commit(); //txn.commit();
//Debugging //Debugging
RevisionNumbersSet getRivisions; RevisionClosure getRivisions;
bool b = store->queryStateRevisions(root_statePath, getRivisions, -1); bool b = store->queryStateRevisions(root_statePath, getRivisions, -1);
for (RevisionNumbersSet::iterator i = getRivisions.begin(); i != getRivisions.end(); ++i){ for (RevisionClosure::iterator i = getRivisions.begin(); i != getRivisions.end(); ++i){
//printMsg(lvlError, format("State %1% has revision %2%") % (*i).first % int2String((*i).second)); //printMsg(lvlError, format("State %1% has revision %2%") % (*i).first % int2String((*i).second));
} }
@ -537,11 +599,20 @@ void run(Strings args)
for (Strings::iterator i = strings2.begin(); i != strings2.end(); ++i) for (Strings::iterator i = strings2.begin(); i != strings2.end(); ++i)
printMsg(lvlError, format("UN '%1%'") % *i); printMsg(lvlError, format("UN '%1%'") % *i);
*/
//updateRevisionNumbers("/nix/state/xf582zrz6xl677llr07rvskgsi3dli1d-hellohardcodedstateworld-dep1-1.0-test"); //updateRevisionNumbers("/nix/state/xf582zrz6xl677llr07rvskgsi3dli1d-hellohardcodedstateworld-dep1-1.0-test");
//return; //return;
//printMsg(lvlError, format("NOW: '%1%'") % getTimeStamp());
//auto sort
map<string, string> test;
test["q"] = "324";
test["c"] = "3241";
test["a"] = "a";
for (map<string, string>::const_iterator j = test.begin(); j != test.end(); ++j)
printMsg(lvlError, format("KEY: '%1%'") % (*j).first);
*/
/* test */ /* test */
for (Strings::iterator i = args.begin(); i != args.end(); ) { for (Strings::iterator i = args.begin(); i != args.end(); ) {
@ -557,8 +628,6 @@ void run(Strings args)
} }
else if (arg == "--showstatepath") else if (arg == "--showstatepath")
op = opShowStatePath; op = opShowStatePath;
else if (arg == "--showstatereposrootpath")
op = opShowStateReposPath;
else if (arg == "--showderivations") else if (arg == "--showderivations")
op = opShowDerivations; op = opShowDerivations;
else if (arg == "--showrevisions") else if (arg == "--showrevisions")
@ -571,11 +640,10 @@ void run(Strings args)
} }
/* /*
--commit
--run-without-commit --run-without-commit
--show-revision-path=....
--showrevisions --showrevisions
--revert-to-revision= --revert-to-revision=