Try to load the existing unlinked bundle by the content hash.

So that we don't create _File.forResolution() when we could use only
the content hash and the existing unlinked bundle. This makes loading
cached analysis results cheaper - no need to parse the unit.

TBR

R=brianwilkerson@google.com, paulberry@google.com
BUG=

Review URL: https://codereview.chromium.org/2450283003 .
This commit is contained in:
Konstantin Shcheglov 2016-10-26 13:06:03 -07:00
parent bd594d453f
commit 6be23afcf2

View file

@ -235,9 +235,8 @@ class AnalysisDriver {
bool analyzed = false; bool analyzed = false;
for (String path in _priorityFiles) { for (String path in _priorityFiles) {
if (_filesToAnalyze.remove(path)) { if (_filesToAnalyze.remove(path)) {
_File file = _fileForPath(path);
AnalysisResult result = AnalysisResult result =
_computeAnalysisResult(file, withUnit: true); _computeAnalysisResult(path, withUnit: true);
yield result; yield result;
break; break;
} }
@ -252,8 +251,7 @@ class AnalysisDriver {
// Analyze a general file. // Analyze a general file.
if (_filesToAnalyze.isNotEmpty) { if (_filesToAnalyze.isNotEmpty) {
String path = _removeFirst(_filesToAnalyze); String path = _removeFirst(_filesToAnalyze);
_File file = _fileForPath(path); AnalysisResult result = _computeAnalysisResult(path, withUnit: false);
AnalysisResult result = _computeAnalysisResult(file, withUnit: false);
yield result; yield result;
// Repeat the processing loop. // Repeat the processing loop.
_hasWork.notify(); _hasWork.notify();
@ -366,33 +364,38 @@ class AnalysisDriver {
} }
/** /**
* Compute the [AnalysisResult] for the [file]. * Return the cached or newly computed analysis result of the file with the
* given [path].
* *
* The result will have the fully resolved unit only if [withUnit] is `true`. * The result will have the fully resolved unit and will always be newly
* compute only if [withUnit] is `true`.
*/ */
AnalysisResult _computeAnalysisResult(_File file, {bool withUnit: false}) { AnalysisResult _computeAnalysisResult(String path, {bool withUnit: false}) {
// If we don't need to the fully resolved unit, check for a cached result. Source source = _sourceForPath(path);
// If we don't need the fully resolved unit, check for the cached result.
if (!withUnit) { if (!withUnit) {
AnalysisResult result = _getCachedAnalysisResult(file); _File file = new _File.forLinking(this, source);
// Prepare the key for the cached result.
String key = _getResolvedUnitKey(file);
if (key == null) {
_logger.run('Compute the dependency hash for $source', () {
_createLibraryContext(file);
key = _getResolvedUnitKey(file);
});
}
// Check for the cached result.
AnalysisResult result = _getCachedAnalysisResult(file, key);
if (result != null) { if (result != null) {
return result; return result;
} }
} }
// We need the fully resolved unit, or the result is not cached. // We need the fully resolved unit, or the result is not cached.
return _logger.run('Compute analysis result for $file', () { return _logger.run('Compute analysis result for $source', () {
_LibraryContext libraryContext = _createLibraryContext(file);
// We recomputed the dependency hash, and we might have a cached result.
if (!withUnit) {
AnalysisResult result = _getCachedAnalysisResult(file);
if (result != null) {
_logger.writeln('Return the cached analysis result.');
return result;
}
}
// Still no result, compute and store it. // Still no result, compute and store it.
_File file = new _File.forResolution(this, source);
_LibraryContext libraryContext = _createLibraryContext(file);
AnalysisContext analysisContext = _createAnalysisContext(libraryContext); AnalysisContext analysisContext = _createAnalysisContext(libraryContext);
try { try {
analysisContext.setContents(file.source, file.content); analysisContext.setContents(file.source, file.content);
@ -559,37 +562,24 @@ class AnalysisDriver {
} }
/** /**
* Return the [_File] for the given [path] in [_sourceFactory]. * If we know the result [key] for the [file], try to load the analysis
* result from the cache. Return `null` if not found.
*/ */
_File _fileForPath(String path) { AnalysisResult _getCachedAnalysisResult(_File file, String key) {
Source fileSource = _resourceProvider.getFile(path).createSource(); List<int> bytes = _byteStore.get(key);
Uri uri = _sourceFactory.restoreUri(fileSource); if (bytes != null) {
Source source = _resourceProvider.getFile(path).createSource(uri); var unit = new AnalysisDriverResolvedUnit.fromBuffer(bytes);
return new _File.forResolution(this, source); List<AnalysisError> errors = unit.errors
} .map((error) => new AnalysisError.forValues(
file.source,
/** error.offset,
* If we know the dependency signature for the [file], try to load the error.length,
* analysis result from the cache. Return `null` if not found. ErrorCode.byUniqueName(error.uniqueName),
*/ error.message,
AnalysisResult _getCachedAnalysisResult(_File file) { error.correction))
String key = _getResolvedUnitKey(file); .toList();
if (key != null) { return new AnalysisResult(
List<int> bytes = _byteStore.get(key); file.path, file.uri, null, file.contentHash, null, errors);
if (bytes != null) {
var unit = new AnalysisDriverResolvedUnit.fromBuffer(bytes);
List<AnalysisError> errors = unit.errors
.map((error) => new AnalysisError.forValues(
file.source,
error.offset,
error.length,
ErrorCode.byUniqueName(error.uniqueName),
error.message,
error.correction))
.toList();
return new AnalysisResult(
file.path, file.uri, null, file.contentHash, null, errors);
}
} }
return null; return null;
} }
@ -609,6 +599,15 @@ class AnalysisDriver {
return null; return null;
} }
/**
* Return the [Source] for the given [path] in [_sourceFactory].
*/
Source _sourceForPath(String path) {
Source fileSource = _resourceProvider.getFile(path).createSource();
Uri uri = _sourceFactory.restoreUri(fileSource);
return _resourceProvider.getFile(path).createSource(uri);
}
/** /**
* Verify the API signature for the file with the given [path], and decide * Verify the API signature for the file with the given [path], and decide
* which linked libraries should be invalidated, and files reanalyzed. * which linked libraries should be invalidated, and files reanalyzed.
@ -620,7 +619,8 @@ class AnalysisDriver {
String oldSignature = _fileApiSignatureMap[path]; String oldSignature = _fileApiSignatureMap[path];
// Compute the new API signature. // Compute the new API signature.
// _File.forResolution() also updates the content hash in the cache. // _File.forResolution() also updates the content hash in the cache.
_File newFile = _fileForPath(path); Source source = _sourceForPath(path);
_File newFile = new _File.forResolution(this, source);
String newSignature = newFile.unlinked.apiSignature; String newSignature = newFile.unlinked.apiSignature;
// If the old API signature is not null, then the file was used to // If the old API signature is not null, then the file was used to
// compute at least one dependency signature. If the new API signature // compute at least one dependency signature. If the new API signature
@ -816,22 +816,10 @@ class _File {
*/ */
final CompilationUnit unit; final CompilationUnit unit;
factory _File.forLinking(AnalysisDriver driver, Source source) { /**
// If we have enough cached information, use it. * Return the file with consistent [content] and [contentHash].
String contentHash = driver._fileContentHashMap[source.fullName]; */
if (contentHash != null) { factory _File.forContent(AnalysisDriver driver, Source source) {
String key = '$contentHash.unlinked';
List<int> bytes = driver._byteStore.get(key);
if (bytes != null) {
PackageBundle unlinked = new PackageBundle.fromBuffer(bytes);
return new _File._(driver, source, null, contentHash, unlinked, null);
}
}
// Otherwise, read the source, parse and build a new unlinked bundle.
return new _File.forResolution(driver, source);
}
factory _File.forResolution(AnalysisDriver driver, Source source) {
String path = source.fullName; String path = source.fullName;
// Read the content. // Read the content.
String content; String content;
@ -853,6 +841,37 @@ class _File {
List<int> hashBytes = md5.convert(textBytes).bytes; List<int> hashBytes = md5.convert(textBytes).bytes;
String contentHash = hex.encode(hashBytes); String contentHash = hex.encode(hashBytes);
driver._fileContentHashMap[path] = contentHash; driver._fileContentHashMap[path] = contentHash;
// Return information about the file content.
return new _File._(driver, source, content, contentHash, null, null);
}
factory _File.forLinking(AnalysisDriver driver, Source source) {
String path = source.fullName;
String contentHash = driver._fileContentHashMap[path];
// If we don't have the file content hash, compute it.
if (contentHash == null) {
_File file = new _File.forContent(driver, source);
contentHash = file.contentHash;
}
// If we have the cached unlinked bundle, use it.
{
String key = '$contentHash.unlinked';
List<int> bytes = driver._byteStore.get(key);
if (bytes != null) {
PackageBundle unlinked = new PackageBundle.fromBuffer(bytes);
driver._fileApiSignatureMap[path] = unlinked.apiSignature;
return new _File._(driver, source, null, contentHash, unlinked, null);
}
}
// Otherwise, read the source, parse and build a new unlinked bundle.
return new _File.forResolution(driver, source);
}
factory _File.forResolution(AnalysisDriver driver, Source source) {
_File file = new _File.forContent(driver, source);
String path = file.path;
String content = file.content;
String contentHash = file.contentHash;
// Parse the unit. // Parse the unit.
CompilationUnit unit = _parse(driver, source, content); CompilationUnit unit = _parse(driver, source, content);
// Prepare the unlinked bundle. // Prepare the unlinked bundle.
@ -873,7 +892,7 @@ class _File {
unlinked = new PackageBundle.fromBuffer(bytes); unlinked = new PackageBundle.fromBuffer(bytes);
driver._fileApiSignatureMap[path] = unlinked.apiSignature; driver._fileApiSignatureMap[path] = unlinked.apiSignature;
} }
// Update the current file state. // Return the full file.
return new _File._(driver, source, content, contentHash, unlinked, unit); return new _File._(driver, source, content, contentHash, unlinked, unit);
} }