Automatically optimise the Nix store when a new path is added
Auto-optimisation is enabled by default. It can be turned off by setting auto-optimise-store to false in nix.conf.
This commit is contained in:
		
							parent
							
								
									564fb7d9fa
								
							
						
					
					
						commit
						6193105710
					
				
					 5 changed files with 45 additions and 10 deletions
				
			
		| 
						 | 
					@ -338,6 +338,19 @@ build-use-chroot = /dev /proc /bin</programlisting>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  </varlistentry>
 | 
					  </varlistentry>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  <varlistentry><term><literal>auto-optimise-store</literal></term>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <listitem><para>If set to <literal>true</literal> (the default),
 | 
				
			||||||
 | 
					    Nix automatically detects files in the store that have identical
 | 
				
			||||||
 | 
					    contents, and replaces them with hard links to a single copy.
 | 
				
			||||||
 | 
					    This saves disk space.  If set to <literal>false</literal>, you
 | 
				
			||||||
 | 
					    can still run <command>nix-store --optimise</command> to get rid
 | 
				
			||||||
 | 
					    of duplicate files.</para></listitem>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  </varlistentry>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</variablelist>
 | 
					</variablelist>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</para>
 | 
					</para>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2093,6 +2093,8 @@ void DerivationGoal::computeClosure()
 | 
				
			||||||
                if (allowed.find(*i) == allowed.end())
 | 
					                if (allowed.find(*i) == allowed.end())
 | 
				
			||||||
                    throw BuildError(format("output is not allowed to refer to path `%1%'") % *i);
 | 
					                    throw BuildError(format("output is not allowed to refer to path `%1%'") % *i);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        worker.store.optimisePath(path); // FIXME: combine with scanForReferences()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Register each output path as valid, and register the sets of
 | 
					    /* Register each output path as valid, and register the sets of
 | 
				
			||||||
| 
						 | 
					@ -2546,6 +2548,8 @@ void SubstitutionGoal::finished()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    HashResult hash = hashPath(htSHA256, storePath);
 | 
					    HashResult hash = hashPath(htSHA256, storePath);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    worker.store.optimisePath(storePath); // FIXME: combine with hashPath()
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    ValidPathInfo info2;
 | 
					    ValidPathInfo info2;
 | 
				
			||||||
    info2.path = storePath;
 | 
					    info2.path = storePath;
 | 
				
			||||||
    info2.hash = hash.first;
 | 
					    info2.hash = hash.first;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -209,6 +209,7 @@ LocalStore::LocalStore(bool reserveSpace)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Create missing state directories if they don't already exist. */
 | 
					    /* Create missing state directories if they don't already exist. */
 | 
				
			||||||
    createDirs(nixStore);
 | 
					    createDirs(nixStore);
 | 
				
			||||||
 | 
					    createDirs(linksDir = nixStore + "/.links");
 | 
				
			||||||
    Path profilesDir = nixStateDir + "/profiles";
 | 
					    Path profilesDir = nixStateDir + "/profiles";
 | 
				
			||||||
    createDirs(nixStateDir + "/profiles");
 | 
					    createDirs(nixStateDir + "/profiles");
 | 
				
			||||||
    createDirs(nixStateDir + "/temproots");
 | 
					    createDirs(nixStateDir + "/temproots");
 | 
				
			||||||
| 
						 | 
					@ -1117,6 +1118,8 @@ Path LocalStore::addToStoreFromDump(const string & dump, const string & name,
 | 
				
			||||||
            } else
 | 
					            } else
 | 
				
			||||||
                hash = hashPath(htSHA256, dstPath);
 | 
					                hash = hashPath(htSHA256, dstPath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            optimisePath(dstPath); // FIXME: combine with hashPath()
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
            ValidPathInfo info;
 | 
					            ValidPathInfo info;
 | 
				
			||||||
            info.path = dstPath;
 | 
					            info.path = dstPath;
 | 
				
			||||||
            info.hash = hash.first;
 | 
					            info.hash = hash.first;
 | 
				
			||||||
| 
						 | 
					@ -1171,6 +1174,8 @@ Path LocalStore::addTextToStore(const string & name, const string & s,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            HashResult hash = hashPath(htSHA256, dstPath);
 | 
					            HashResult hash = hashPath(htSHA256, dstPath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            optimisePath(dstPath);
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
            ValidPathInfo info;
 | 
					            ValidPathInfo info;
 | 
				
			||||||
            info.path = dstPath;
 | 
					            info.path = dstPath;
 | 
				
			||||||
            info.hash = hash.first;
 | 
					            info.hash = hash.first;
 | 
				
			||||||
| 
						 | 
					@ -1406,6 +1411,8 @@ Path LocalStore::importPath(bool requireSignature, Source & source)
 | 
				
			||||||
               here. */
 | 
					               here. */
 | 
				
			||||||
            HashResult hash = hashPath(htSHA256, dstPath);
 | 
					            HashResult hash = hashPath(htSHA256, dstPath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            optimisePath(dstPath); // FIXME: combine with hashPath()
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
            ValidPathInfo info;
 | 
					            ValidPathInfo info;
 | 
				
			||||||
            info.path = dstPath;
 | 
					            info.path = dstPath;
 | 
				
			||||||
            info.hash = hash.first;
 | 
					            info.hash = hash.first;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,6 +86,8 @@ private:
 | 
				
			||||||
    typedef std::map<Path, RunningSubstituter> RunningSubstituters;
 | 
					    typedef std::map<Path, RunningSubstituter> RunningSubstituters;
 | 
				
			||||||
    RunningSubstituters runningSubstituters;
 | 
					    RunningSubstituters runningSubstituters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Path linksDir;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Initialise the local store, upgrading the schema if
 | 
					    /* Initialise the local store, upgrading the schema if
 | 
				
			||||||
| 
						 | 
					@ -169,6 +171,9 @@ public:
 | 
				
			||||||
       files with the same contents. */
 | 
					       files with the same contents. */
 | 
				
			||||||
    void optimiseStore(OptimiseStats & stats);
 | 
					    void optimiseStore(OptimiseStats & stats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Optimise a single store path. */
 | 
				
			||||||
 | 
					    void optimisePath(const Path & path);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    /* Check the integrity of the Nix store. */
 | 
					    /* Check the integrity of the Nix store. */
 | 
				
			||||||
    void verifyStore(bool checkContents);
 | 
					    void verifyStore(bool checkContents);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -267,6 +272,8 @@ private:
 | 
				
			||||||
    Path importPath(bool requireSignature, Source & source);
 | 
					    Path importPath(bool requireSignature, Source & source);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    void checkDerivationOutputs(const Path & drvPath, const Derivation & drv);
 | 
					    void checkDerivationOutputs(const Path & drvPath, const Derivation & drv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void optimisePath_(OptimiseStats & stats, const Path & path);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,10 +49,7 @@ struct MakeImmutable
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const string linksDir = ".links";
 | 
					void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path)
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void hashAndLink(OptimiseStats & stats, const Path & path)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    struct stat st;
 | 
					    struct stat st;
 | 
				
			||||||
    if (lstat(path.c_str(), &st))
 | 
					    if (lstat(path.c_str(), &st))
 | 
				
			||||||
| 
						 | 
					@ -61,7 +58,7 @@ static void hashAndLink(OptimiseStats & stats, const Path & path)
 | 
				
			||||||
    if (S_ISDIR(st.st_mode)) {
 | 
					    if (S_ISDIR(st.st_mode)) {
 | 
				
			||||||
        Strings names = readDirectory(path);
 | 
					        Strings names = readDirectory(path);
 | 
				
			||||||
	foreach (Strings::iterator, i, names)
 | 
						foreach (Strings::iterator, i, names)
 | 
				
			||||||
	    hashAndLink(stats, path + "/" + *i);
 | 
						    optimisePath_(stats, path + "/" + *i);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
| 
						 | 
					@ -91,7 +88,7 @@ static void hashAndLink(OptimiseStats & stats, const Path & path)
 | 
				
			||||||
    printMsg(lvlDebug, format("`%1%' has hash `%2%'") % path % printHash(hash));
 | 
					    printMsg(lvlDebug, format("`%1%' has hash `%2%'") % path % printHash(hash));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Check if this is a known hash. */
 | 
					    /* Check if this is a known hash. */
 | 
				
			||||||
    Path linkPath = nixStore + "/" + linksDir + "/" + printHash32(hash);
 | 
					    Path linkPath = linksDir + "/" + printHash32(hash);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!pathExists(linkPath)) {
 | 
					    if (!pathExists(linkPath)) {
 | 
				
			||||||
        /* Nope, create a hard link in the links directory. */
 | 
					        /* Nope, create a hard link in the links directory. */
 | 
				
			||||||
| 
						 | 
					@ -177,15 +174,22 @@ static void hashAndLink(OptimiseStats & stats, const Path & path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void LocalStore::optimiseStore(OptimiseStats & stats)
 | 
					void LocalStore::optimiseStore(OptimiseStats & stats)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    createDirs(nixStore + "/" + linksDir);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    PathSet paths = queryValidPaths();
 | 
					    PathSet paths = queryValidPaths();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    foreach (PathSet::iterator, i, paths) {
 | 
					    foreach (PathSet::iterator, i, paths) {
 | 
				
			||||||
        addTempRoot(*i);
 | 
					        addTempRoot(*i);
 | 
				
			||||||
        if (!isValidPath(*i)) continue; /* path was GC'ed, probably */
 | 
					        if (!isValidPath(*i)) continue; /* path was GC'ed, probably */
 | 
				
			||||||
        startNest(nest, lvlChatty, format("hashing files in `%1%'") % *i);
 | 
					        startNest(nest, lvlChatty, format("hashing files in `%1%'") % *i);
 | 
				
			||||||
        hashAndLink(stats, *i);
 | 
					        optimisePath_(stats, *i);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void LocalStore::optimisePath(const Path & path)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (queryBoolSetting("auto-optimise-store", true)) {
 | 
				
			||||||
 | 
					        OptimiseStats stats;
 | 
				
			||||||
 | 
					        optimisePath_(stats, path);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue