Retry all SQLite operations
To deal with SQLITE_PROTOCOL, we also need to retry read-only operations.
This commit is contained in:
		
							parent
							
								
									ff02f5336c
								
							
						
					
					
						commit
						a737f51fd9
					
				
					 2 changed files with 168 additions and 127 deletions
				
			
		|  | @ -692,27 +692,32 @@ void LocalStore::addReference(unsigned long long referrer, unsigned long long re | |||
| 
 | ||||
| void LocalStore::registerFailedPath(const Path & path) | ||||
| { | ||||
|     retry_sqlite { | ||||
|         SQLiteStmtUse use(stmtRegisterFailedPath); | ||||
|         stmtRegisterFailedPath.bind(path); | ||||
|         stmtRegisterFailedPath.bind(time(0)); | ||||
|         if (sqlite3_step(stmtRegisterFailedPath) != SQLITE_DONE) | ||||
|             throwSQLiteError(db, format("registering failed path `%1%'") % path); | ||||
|     } end_retry_sqlite; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool LocalStore::hasPathFailed(const Path & path) | ||||
| { | ||||
|     retry_sqlite { | ||||
|         SQLiteStmtUse use(stmtHasPathFailed); | ||||
|         stmtHasPathFailed.bind(path); | ||||
|         int res = sqlite3_step(stmtHasPathFailed); | ||||
|         if (res != SQLITE_DONE && res != SQLITE_ROW) | ||||
|             throwSQLiteError(db, "querying whether path failed"); | ||||
|         return res == SQLITE_ROW; | ||||
|     } end_retry_sqlite; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| PathSet LocalStore::queryFailedPaths() | ||||
| { | ||||
|     retry_sqlite { | ||||
|         SQLiteStmtUse use(stmtQueryFailedPaths); | ||||
| 
 | ||||
|         PathSet res; | ||||
|  | @ -727,11 +732,13 @@ PathSet LocalStore::queryFailedPaths() | |||
|             throwSQLiteError(db, "error querying failed paths"); | ||||
| 
 | ||||
|         return res; | ||||
|     } end_retry_sqlite; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void LocalStore::clearFailedPaths(const PathSet & paths) | ||||
| { | ||||
|     retry_sqlite { | ||||
|         SQLiteTxn txn(db); | ||||
| 
 | ||||
|         foreach (PathSet::const_iterator, i, paths) { | ||||
|  | @ -742,6 +749,7 @@ void LocalStore::clearFailedPaths(const PathSet & paths) | |||
|         } | ||||
| 
 | ||||
|         txn.commit(); | ||||
|     } end_retry_sqlite; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -766,6 +774,8 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path) | |||
| 
 | ||||
|     assertStorePath(path); | ||||
| 
 | ||||
|     retry_sqlite { | ||||
| 
 | ||||
|         /* Get the path info. */ | ||||
|         SQLiteStmtUse use1(stmtQueryPathInfo); | ||||
| 
 | ||||
|  | @ -804,6 +814,7 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path) | |||
|             throwSQLiteError(db, format("error getting references of `%1%'") % path); | ||||
| 
 | ||||
|         return info; | ||||
|     } end_retry_sqlite; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -834,7 +845,7 @@ unsigned long long LocalStore::queryValidPathId(const Path & path) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool LocalStore::isValidPath(const Path & path) | ||||
| bool LocalStore::isValidPath_(const Path & path) | ||||
| { | ||||
|     SQLiteStmtUse use(stmtQueryPathInfo); | ||||
|     stmtQueryPathInfo.bind(path); | ||||
|  | @ -845,22 +856,32 @@ bool LocalStore::isValidPath(const Path & path) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool LocalStore::isValidPath(const Path & path) | ||||
| { | ||||
|     retry_sqlite { | ||||
|         return isValidPath_(path); | ||||
|     } end_retry_sqlite; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| PathSet LocalStore::queryValidPaths(const PathSet & paths) | ||||
| { | ||||
|     retry_sqlite { | ||||
|         PathSet res; | ||||
|         foreach (PathSet::const_iterator, i, paths) | ||||
|         if (isValidPath(*i)) res.insert(*i); | ||||
|             if (isValidPath_(*i)) res.insert(*i); | ||||
|         return res; | ||||
|     } end_retry_sqlite; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| PathSet LocalStore::queryAllValidPaths() | ||||
| { | ||||
|     retry_sqlite { | ||||
|         SQLiteStmt stmt; | ||||
|         stmt.create(db, "select path from ValidPaths"); | ||||
| 
 | ||||
|         PathSet res; | ||||
| 
 | ||||
|         int r; | ||||
|         while ((r = sqlite3_step(stmt)) == SQLITE_ROW) { | ||||
|             const char * s = (const char *) sqlite3_column_text(stmt, 0); | ||||
|  | @ -872,6 +893,7 @@ PathSet LocalStore::queryAllValidPaths() | |||
|             throwSQLiteError(db, "error getting valid paths"); | ||||
| 
 | ||||
|         return res; | ||||
|     } end_retry_sqlite; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -883,10 +905,8 @@ void LocalStore::queryReferences(const Path & path, | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| void LocalStore::queryReferrers(const Path & path, PathSet & referrers) | ||||
| void LocalStore::queryReferrers_(const Path & path, PathSet & referrers) | ||||
| { | ||||
|     assertStorePath(path); | ||||
| 
 | ||||
|     SQLiteStmtUse use(stmtQueryReferrers); | ||||
| 
 | ||||
|     stmtQueryReferrers.bind(path); | ||||
|  | @ -903,6 +923,15 @@ void LocalStore::queryReferrers(const Path & path, PathSet & referrers) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| void LocalStore::queryReferrers(const Path & path, PathSet & referrers) | ||||
| { | ||||
|     assertStorePath(path); | ||||
|     retry_sqlite { | ||||
|         queryReferrers_(path, referrers); | ||||
|     } end_retry_sqlite; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Path LocalStore::queryDeriver(const Path & path) | ||||
| { | ||||
|     return queryPathInfo(path).deriver; | ||||
|  | @ -913,6 +942,7 @@ PathSet LocalStore::queryValidDerivers(const Path & path) | |||
| { | ||||
|     assertStorePath(path); | ||||
| 
 | ||||
|     retry_sqlite { | ||||
|         SQLiteStmtUse use(stmtQueryValidDerivers); | ||||
|         stmtQueryValidDerivers.bind(path); | ||||
| 
 | ||||
|  | @ -928,11 +958,13 @@ PathSet LocalStore::queryValidDerivers(const Path & path) | |||
|             throwSQLiteError(db, format("error getting valid derivers of `%1%'") % path); | ||||
| 
 | ||||
|         return derivers; | ||||
|     } end_retry_sqlite; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| PathSet LocalStore::queryDerivationOutputs(const Path & path) | ||||
| { | ||||
|     retry_sqlite { | ||||
|         SQLiteStmtUse use(stmtQueryDerivationOutputs); | ||||
|         stmtQueryDerivationOutputs.bind(queryValidPathId(path)); | ||||
| 
 | ||||
|  | @ -948,11 +980,13 @@ PathSet LocalStore::queryDerivationOutputs(const Path & path) | |||
|             throwSQLiteError(db, format("error getting outputs of `%1%'") % path); | ||||
| 
 | ||||
|         return outputs; | ||||
|     } end_retry_sqlite; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| StringSet LocalStore::queryDerivationOutputNames(const Path & path) | ||||
| { | ||||
|     retry_sqlite { | ||||
|         SQLiteStmtUse use(stmtQueryDerivationOutputs); | ||||
|         stmtQueryDerivationOutputs.bind(queryValidPathId(path)); | ||||
| 
 | ||||
|  | @ -968,6 +1002,7 @@ StringSet LocalStore::queryDerivationOutputNames(const Path & path) | |||
|             throwSQLiteError(db, format("error getting output names of `%1%'") % path); | ||||
| 
 | ||||
|         return outputNames; | ||||
|     } end_retry_sqlite; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -977,6 +1012,7 @@ Path LocalStore::queryPathFromHashPart(const string & hashPart) | |||
| 
 | ||||
|     Path prefix = settings.nixStore + "/" + hashPart; | ||||
| 
 | ||||
|     retry_sqlite { | ||||
|         SQLiteStmtUse use(stmtQueryPathFromHashPart); | ||||
|         stmtQueryPathFromHashPart.bind(prefix); | ||||
| 
 | ||||
|  | @ -986,6 +1022,7 @@ Path LocalStore::queryPathFromHashPart(const string & hashPart) | |||
| 
 | ||||
|         const char * s = (const char *) sqlite3_column_text(stmtQueryPathFromHashPart, 0); | ||||
|         return s && prefix.compare(0, prefix.size(), s, prefix.size()) == 0 ? s : ""; | ||||
|     } end_retry_sqlite; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -1229,7 +1266,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos) | |||
| 
 | ||||
|         foreach (ValidPathInfos::const_iterator, i, infos) { | ||||
|             assert(i->hash.type == htSHA256); | ||||
|             if (isValidPath(i->path)) | ||||
|             if (isValidPath_(i->path)) | ||||
|                 updatePathInfo(*i); | ||||
|             else | ||||
|                 addValidPath(*i); | ||||
|  | @ -1643,8 +1680,8 @@ void LocalStore::invalidatePathChecked(const Path & path) | |||
|     retry_sqlite { | ||||
|         SQLiteTxn txn(db); | ||||
| 
 | ||||
|         if (isValidPath(path)) { | ||||
|             PathSet referrers; queryReferrers(path, referrers); | ||||
|         if (isValidPath_(path)) { | ||||
|             PathSet referrers; queryReferrers_(path, referrers); | ||||
|             referrers.erase(path); /* ignore self-references */ | ||||
|             if (!referrers.empty()) | ||||
|                 throw PathInUse(format("cannot delete path `%1%' because it is in use by %2%") | ||||
|  |  | |||
|  | @ -304,6 +304,10 @@ private: | |||
|     void checkDerivationOutputs(const Path & drvPath, const Derivation & drv); | ||||
| 
 | ||||
|     void optimisePath_(OptimiseStats & stats, const Path & path); | ||||
| 
 | ||||
|     // Internal versions that are not wrapped in retry_sqlite.
 | ||||
|     bool isValidPath_(const Path & path); | ||||
|     void queryReferrers_(const Path & path, PathSet & referrers); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue