Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'dart:convert' show UTF8; | 5 import 'dart:convert' show UTF8; |
| 6 import 'dart:core' hide Resource; | 6 import 'dart:core' hide Resource; |
| 7 | 7 |
| 8 import 'package:analyzer/dart/element/element.dart'; | 8 import 'package:analyzer/dart/element/element.dart'; |
| 9 import 'package:analyzer/file_system/file_system.dart'; | 9 import 'package:analyzer/file_system/file_system.dart'; |
| 10 import 'package:analyzer/src/generated/engine.dart'; | 10 import 'package:analyzer/src/generated/engine.dart'; |
| 11 import 'package:analyzer/src/generated/source.dart'; | 11 import 'package:analyzer/src/generated/source.dart'; |
| 12 import 'package:analyzer/src/summary/format.dart'; | 12 import 'package:analyzer/src/summary/format.dart'; |
| 13 import 'package:analyzer/src/summary/idl.dart'; | 13 import 'package:analyzer/src/summary/idl.dart'; |
| 14 import 'package:analyzer/src/summary/summarize_elements.dart'; | 14 import 'package:analyzer/src/summary/summarize_elements.dart'; |
| 15 import 'package:crypto/crypto.dart'; | 15 import 'package:crypto/crypto.dart'; |
| 16 | 16 |
| 17 /** | 17 /** |
| 18 * The cache of per-library [PackageBundle]s. | 18 * Storage for cache data. |
| 19 * | |
| 20 * Note that currently this class is not intended for interactive use. | |
| 21 */ | 19 */ |
| 22 class LibraryBundleCache { | 20 abstract class CacheStorage { |
| 21 /** | |
| 22 * Return bytes for the given [key], `null` if [key] is not in the storage. | |
| 23 */ | |
| 24 List<int> get(String key); | |
| 25 | |
| 26 /** | |
| 27 * Associate the [key] with the given [bytes]. | |
| 28 * | |
| 29 * If the [key] was already in the storage, its associated value is changed. | |
| 30 * Otherwise the key-value pair is added to the storage. | |
| 31 * | |
| 32 * This method does not guarantee that data will always be accessible using | |
| 33 * [get], in some implementations association may silently fail or become | |
| 34 * inaccessible after some time. | |
| 35 */ | |
| 36 void put(String key, List<int> bytes); | |
| 37 } | |
| 38 | |
| 39 /** | |
| 40 * A [Folder] based implementation of [CacheStorage]. | |
| 41 */ | |
| 42 class FolderCacheStorage implements CacheStorage { | |
| 43 /** | |
| 44 * The folder to read and write files. | |
| 45 */ | |
| 46 final Folder folder; | |
| 47 | |
| 23 /** | 48 /** |
| 24 * To ensure that operations of writing files are atomic we create a temporary | 49 * To ensure that operations of writing files are atomic we create a temporary |
| 25 * file with this name in the [cacheFolder] and then rename it once we are | 50 * file with this name in the [folder] and then rename it once we are |
| 26 * done writing. | 51 * done writing. |
| 27 */ | 52 */ |
| 28 final String tempFileName; | 53 final String tempFileName; |
| 29 | 54 |
| 55 FolderCacheStorage(this.folder, this.tempFileName); | |
| 56 | |
| 57 @override | |
| 58 List<int> get(String key) { | |
| 59 Resource file = folder.getChild(key); | |
| 60 if (file is File) { | |
| 61 try { | |
| 62 return file.readAsBytesSync(); | |
| 63 } on FileSystemException {} | |
| 64 } | |
| 65 return null; | |
| 66 } | |
| 67 | |
| 68 @override | |
| 69 void put(String key, List<int> bytes) { | |
| 70 try { | |
|
Paul Berry
2016/03/18 20:22:42
The try/catch should only surround the call to ren
| |
| 71 String absPath = folder.getChild(key).path; | |
| 72 File tempFile = folder.getChild(tempFileName); | |
| 73 tempFile.writeAsBytesSync(bytes); | |
| 74 tempFile.renameSync(absPath); | |
| 75 } catch (e) {} | |
| 76 } | |
| 77 } | |
| 78 | |
| 79 /** | |
| 80 * Cache of information to support incremental analysis. | |
| 81 * | |
| 82 * Note that currently this class is not intended for interactive use. | |
| 83 */ | |
| 84 class IncrementalCache { | |
| 30 /** | 85 /** |
| 31 * The folder to read and write files. | 86 * The storage for the cache data. |
| 32 */ | 87 */ |
| 33 final Folder cacheFolder; | 88 final CacheStorage storage; |
| 34 | 89 |
| 35 /** | 90 /** |
| 36 * The context in which this cache is used. | 91 * The context in which this cache is used. |
| 37 */ | 92 */ |
| 38 final AnalysisContext context; | 93 final AnalysisContext context; |
| 39 | 94 |
| 40 /** | 95 /** |
| 41 * Opaque data that reflects the current configuration, such as the [context] | 96 * Opaque data that reflects the current configuration, such as the [context] |
| 42 * options, and is mixed into the hashes. | 97 * options, and is mixed into the hashes. |
| 43 */ | 98 */ |
| 44 final List<int> configSalt; | 99 final List<int> configSalt; |
| 45 | 100 |
| 46 final Map<Source, CacheSourceContent> _sourceContentMap = | 101 final Map<Source, CacheSourceContent> _sourceContentMap = |
| 47 <Source, CacheSourceContent>{}; | 102 <Source, CacheSourceContent>{}; |
| 48 final Map<Source, List<Source>> _libraryClosureMap = <Source, List<Source>>{}; | 103 final Map<Source, List<Source>> _libraryClosureMap = <Source, List<Source>>{}; |
| 49 final Map<Source, List<int>> _sourceContentHashMap = <Source, List<int>>{}; | 104 final Map<Source, List<int>> _sourceContentHashMap = <Source, List<int>>{}; |
| 50 | 105 |
| 51 LibraryBundleCache( | 106 IncrementalCache(this.storage, this.context, this.configSalt); |
| 52 this.tempFileName, this.cacheFolder, this.context, this.configSalt); | |
| 53 | 107 |
| 54 /** | 108 /** |
| 55 * Clear internal caches so that we read from file system again. | 109 * Clear internal caches so that we read from file system again. |
| 56 */ | 110 */ |
| 57 void clearInternalCaches() { | 111 void clearInternalCaches() { |
| 58 _sourceContentMap.clear(); | 112 _sourceContentMap.clear(); |
| 59 _libraryClosureMap.clear(); | 113 _libraryClosureMap.clear(); |
| 60 _sourceContentHashMap.clear(); | 114 _sourceContentHashMap.clear(); |
| 61 } | 115 } |
| 62 | 116 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 82 * Write information about the [library] into the cache. | 136 * Write information about the [library] into the cache. |
| 83 */ | 137 */ |
| 84 void putLibrary(LibraryElement library) { | 138 void putLibrary(LibraryElement library) { |
| 85 try { | 139 try { |
| 86 _writeCacheSourceContents(library); | 140 _writeCacheSourceContents(library); |
| 87 List<int> hash = _getLibraryClosureHash(library.source); | 141 List<int> hash = _getLibraryClosureHash(library.source); |
| 88 String hashStr = CryptoUtils.bytesToHex(hash); | 142 String hashStr = CryptoUtils.bytesToHex(hash); |
| 89 PackageBundleAssembler assembler = new PackageBundleAssembler(); | 143 PackageBundleAssembler assembler = new PackageBundleAssembler(); |
| 90 assembler.serializeLibraryElement(library); | 144 assembler.serializeLibraryElement(library); |
| 91 List<int> bytes = assembler.assemble().toBuffer(); | 145 List<int> bytes = assembler.assemble().toBuffer(); |
| 92 _safeWriteBytes('$hashStr.sum', bytes); | 146 storage.put('$hashStr.sum', bytes); |
| 93 } catch (e) {} | 147 } catch (e) {} |
| 94 } | 148 } |
| 95 | 149 |
| 96 /** | 150 /** |
| 97 * Read the [PackageBundle] for the library with the given [source] from | 151 * Read the [PackageBundle] for the library with the given [source] from |
| 98 * the cache. The returned bundle will correspond to the state when the set | 152 * the cache. The returned bundle will correspond to the state when the set |
| 99 * of direct and indirect dependencies is resolved in the [context]. Return | 153 * of direct and indirect dependencies is resolved in the [context]. Return |
| 100 * `null` if such bundle does not exist. | 154 * `null` if such bundle does not exist. |
| 101 */ | 155 */ |
| 102 PackageBundle readBundle(Source source) { | 156 PackageBundle readBundle(Source source) { |
| 103 try { | 157 try { |
| 104 List<int> hash = _getLibraryClosureHash(source); | 158 List<int> hash = _getLibraryClosureHash(source); |
| 105 String hashStr = CryptoUtils.bytesToHex(hash); | 159 String hashStr = CryptoUtils.bytesToHex(hash); |
| 106 List<int> bytes = _safeReadBytes('$hashStr.sum'); | 160 List<int> bytes = storage.get('$hashStr.sum'); |
| 107 if (bytes == null) { | 161 if (bytes == null) { |
| 108 return null; | 162 return null; |
| 109 } | 163 } |
| 110 return new PackageBundle.fromBuffer(bytes); | 164 return new PackageBundle.fromBuffer(bytes); |
| 111 } catch (e) { | 165 } catch (e) { |
| 112 return null; | 166 return null; |
| 113 } | 167 } |
| 114 } | 168 } |
| 115 | 169 |
| 116 /** | 170 /** |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 147 } | 201 } |
| 148 } | 202 } |
| 149 | 203 |
| 150 /** | 204 /** |
| 151 * Get the content based information about the given [source], maybe `null` | 205 * Get the content based information about the given [source], maybe `null` |
| 152 * if the information is not in the cache. | 206 * if the information is not in the cache. |
| 153 */ | 207 */ |
| 154 CacheSourceContent _getCacheSourceContent(Source source) { | 208 CacheSourceContent _getCacheSourceContent(Source source) { |
| 155 CacheSourceContent content = _sourceContentMap[source]; | 209 CacheSourceContent content = _sourceContentMap[source]; |
| 156 if (content == null) { | 210 if (content == null) { |
| 157 String fileName = _getCacheSourceContentFileName(source); | 211 String key = _getCacheSourceContentKey(source); |
| 158 List<int> bytes = _safeReadBytes(fileName); | 212 List<int> bytes = storage.get(key); |
| 159 if (bytes == null) { | 213 if (bytes == null) { |
| 160 return null; | 214 return null; |
| 161 } | 215 } |
| 162 content = new CacheSourceContent.fromBuffer(bytes); | 216 content = new CacheSourceContent.fromBuffer(bytes); |
| 163 _sourceContentMap[source] = content; | 217 _sourceContentMap[source] = content; |
| 164 } | 218 } |
| 165 return content; | 219 return content; |
| 166 } | 220 } |
| 167 | 221 |
| 168 /** | 222 /** |
| 169 * Return the name of the file with the content based [source] information. | 223 * Return the key of the content based [source] information. |
| 170 */ | 224 */ |
| 171 String _getCacheSourceContentFileName(Source source) { | 225 String _getCacheSourceContentKey(Source source) { |
| 172 List<int> hash = _getSourceContentHash(source); | 226 List<int> hash = _getSourceContentHash(source); |
| 173 String hashStr = CryptoUtils.bytesToHex(hash); | 227 String hashStr = CryptoUtils.bytesToHex(hash); |
| 174 return '$hashStr.content'; | 228 return '$hashStr.content'; |
| 175 } | 229 } |
| 176 | 230 |
| 177 /** | 231 /** |
| 178 * Return the whole source closure of the library with the given | 232 * Return the whole source closure of the library with the given |
| 179 * [librarySource]. It includes defining units and parts of the library and | 233 * [librarySource]. It includes defining units and parts of the library and |
| 180 * of all its directly or indirectly imported or exported libraries. | 234 * of all its directly or indirectly imported or exported libraries. |
| 181 */ | 235 */ |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 207 */ | 261 */ |
| 208 List<int> _getSourceContentHash(Source source) { | 262 List<int> _getSourceContentHash(Source source) { |
| 209 return _sourceContentHashMap.putIfAbsent(source, () { | 263 return _sourceContentHashMap.putIfAbsent(source, () { |
| 210 String sourceText = source.contents.data; | 264 String sourceText = source.contents.data; |
| 211 List<int> sourceBytes = UTF8.encode(sourceText); | 265 List<int> sourceBytes = UTF8.encode(sourceText); |
| 212 return (new MD5()..add(sourceBytes)).close(); | 266 return (new MD5()..add(sourceBytes)).close(); |
| 213 }); | 267 }); |
| 214 } | 268 } |
| 215 | 269 |
| 216 /** | 270 /** |
| 217 * Return bytes of the file with the given [relPath] in the cache, or `null` | |
| 218 * if the file does not exist. | |
| 219 */ | |
| 220 List<int> _safeReadBytes(String relPath) { | |
| 221 Resource file = cacheFolder.getChild(relPath); | |
| 222 if (file is File) { | |
| 223 try { | |
| 224 return file.readAsBytesSync(); | |
| 225 } on FileSystemException {} | |
| 226 } | |
| 227 return null; | |
| 228 } | |
| 229 | |
| 230 /** | |
| 231 * Atomically write the given [bytes] into the file with the given [relPath]. | |
| 232 * Silently ignores any errors. | |
| 233 */ | |
| 234 void _safeWriteBytes(String relPath, List<int> bytes) { | |
| 235 try { | |
| 236 String absPath = cacheFolder.getChild(relPath).path; | |
| 237 File tempFile = cacheFolder.getChild(tempFileName); | |
| 238 tempFile.writeAsBytesSync(bytes); | |
| 239 tempFile.renameSync(absPath); | |
| 240 } catch (e) {} | |
| 241 } | |
| 242 | |
| 243 /** | |
| 244 * Write the content based information about the given [source]. | 271 * Write the content based information about the given [source]. |
| 245 */ | 272 */ |
| 246 void _writeCacheSourceContent(Source source, CacheSourceContentBuilder b) { | 273 void _writeCacheSourceContent(Source source, CacheSourceContentBuilder b) { |
| 247 String fileName = _getCacheSourceContentFileName(source); | 274 String key = _getCacheSourceContentKey(source); |
| 248 List<int> bytes = b.toBuffer(); | 275 List<int> bytes = b.toBuffer(); |
| 249 _safeWriteBytes(fileName, bytes); | 276 storage.put(key, bytes); |
| 250 // Put into the cache to avoid reading it later. | 277 // Put into the cache to avoid reading it later. |
| 251 _sourceContentMap[source] = new CacheSourceContent.fromBuffer(bytes); | 278 _sourceContentMap[source] = new CacheSourceContent.fromBuffer(bytes); |
| 252 } | 279 } |
| 253 | 280 |
| 254 /** | 281 /** |
| 255 * Write [CacheSourceContent] for every unit of the given [library] and its | 282 * Write [CacheSourceContent] for every unit of the given [library] and its |
| 256 * direct and indirect imports/exports. | 283 * direct and indirect imports/exports. |
| 257 */ | 284 */ |
| 258 void _writeCacheSourceContents(LibraryElement library, | 285 void _writeCacheSourceContents(LibraryElement library, |
| 259 [Set<LibraryElement> writtenLibraries]) { | 286 [Set<LibraryElement> writtenLibraries]) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 298 // Write the library. | 325 // Write the library. |
| 299 _writeCacheSourceContent( | 326 _writeCacheSourceContent( |
| 300 librarySource, | 327 librarySource, |
| 301 new CacheSourceContentBuilder( | 328 new CacheSourceContentBuilder( |
| 302 kind: CacheSourceKind.library, | 329 kind: CacheSourceKind.library, |
| 303 importedUris: importUris, | 330 importedUris: importUris, |
| 304 exportedUris: exportUris, | 331 exportedUris: exportUris, |
| 305 partUris: partUris)); | 332 partUris: partUris)); |
| 306 } | 333 } |
| 307 } | 334 } |
| OLD | NEW |