Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Unified Diff: pkg/analyzer/lib/src/dart/analysis/file_byte_store.dart

Issue 2492933002: Evict from FileByteStore by the total cache size in bytes. (Closed)
Patch Set: Clean up cache in a separate isolate. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/analysis_server/lib/src/analysis_server.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer/lib/src/dart/analysis/file_byte_store.dart
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_byte_store.dart b/pkg/analyzer/lib/src/dart/analysis/file_byte_store.dart
index 49e668fe08f769ff796c77547e3b546830684fa9..02031ed7d0da4aa7003ade9e8ffc768d65af1123 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_byte_store.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_byte_store.dart
@@ -2,24 +2,35 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'package:analyzer/file_system/file_system.dart';
+import 'dart:async';
+import 'dart:io';
+import 'dart:isolate';
+
import 'package:analyzer/src/dart/analysis/byte_store.dart';
+import 'package:path/path.dart';
/**
- * [ByteStore] that stores values as [File]s.
- *
- * TODO(scheglov) Add some eviction policies.
+ * [ByteStore] that stores values as files.
*/
class FileByteStore implements ByteStore {
- final Folder folder;
+ static bool _evictSendPortShouldBePrepared = true;
+ static SendPort _evictSendPort;
+
+ final String _cachePath;
+ final String _tempName = 'temp_${pid}';
+ final int _maxSizeBytes;
- FileByteStore(this.folder);
+ int _currentSizeBytes = 0;
Paul Berry 2016/11/13 15:18:17 Rename this to something like "_bytesWrittenSinceC
scheglov 2016/11/14 16:51:47 Done.
+ bool _evictionIsolateIsRunning = false;
+
+ FileByteStore(this._cachePath, this._maxSizeBytes) {
+ _requestCacheCleanUp();
+ }
@override
List<int> get(String key) {
try {
- File file = folder.getChildAssumingFile(key);
- return file.readAsBytesSync();
+ return _getFileForKey(key).readAsBytesSync();
} catch (_) {
return null;
}
@@ -28,8 +39,104 @@ class FileByteStore implements ByteStore {
@override
void put(String key, List<int> bytes) {
try {
- File file = folder.getChildAssumingFile(key);
- file.writeAsBytesSync(bytes);
+ File tempFile = _getFileForKey(_tempName);
+ tempFile.writeAsBytesSync(bytes);
+ File file = _getFileForKey(key);
+ tempFile.renameSync(file.path);
+ // Update the current size.
+ _currentSizeBytes += bytes.length;
+ if (_currentSizeBytes > _maxSizeBytes ~/ 8) {
+ _requestCacheCleanUp();
+ }
} catch (_) {}
}
+
+ File _getFileForKey(String key) {
+ return new File(join(_cachePath, key));
+ }
+
+ /**
+ * If the cache clean up process has not been requested yet, request it.
+ */
+ Future<Null> _requestCacheCleanUp() async {
+ if (_evictSendPortShouldBePrepared) {
+ _evictSendPortShouldBePrepared = false;
+ ReceivePort response = new ReceivePort();
+ await Isolate.spawn(_cacheCleanUpFunction, response.sendPort);
+ _evictSendPort = await response.first as SendPort;
+ } else {
+ while (_evictSendPort == null) {
+ await new Future.delayed(new Duration(milliseconds: 100), () {});
+ }
+ }
+
+ if (!_evictionIsolateIsRunning) {
+ _evictionIsolateIsRunning = true;
+ try {
+ ReceivePort response = new ReceivePort();
+ _evictSendPort.send([_cachePath, _maxSizeBytes, response.sendPort]);
+ await response.first;
+ } finally {
+ _evictionIsolateIsRunning = false;
+ _currentSizeBytes = 0;
+ }
+ }
+ }
+
+ /**
+ * This function is stated in a new isolate, receives cache clean up requests
Paul Berry 2016/11/13 15:18:17 s/stated/started/
scheglov 2016/11/14 16:51:47 Done.
+ * and
+ */
+ static void _cacheCleanUpFunction(SendPort initialReplyTo) {
+ ReceivePort port = new ReceivePort();
+ initialReplyTo.send(port.sendPort);
+ port.listen((args) async {
+ if (args is List &&
+ args.length == 3 &&
+ args[0] is String &&
+ args[1] is int &&
+ args[2] is SendPort) {
Paul Berry 2016/11/13 15:18:17 It seems weird to send a list of objects to the is
scheglov 2016/11/14 16:51:47 Unfortunately this does not work. SendPort.send s
Paul Berry 2016/11/14 21:19:28 +rmacnak, is this due to a bug in the VM?
+ String cachePath = args[0] as String;
+ int maxSizeBytes = args[1] as int;
+ await _evictFromFolder(cachePath, maxSizeBytes);
+ // Let that client know that we're done.
+ SendPort replyTo = args[2] as SendPort;
+ replyTo.send(true);
+ }
+ });
+ }
+
+ static Future<Null> _evictFromFolder(
+ String cachePath, int maxSizeBytes) async {
+ // Prepare the list of files and their statistics.
+ List<File> files = <File>[];
+ Map<File, FileStat> fileStatMap = {};
+ int currentSizeBytes = 0;
+ List<FileSystemEntity> resources = new Directory(cachePath).listSync();
+ for (FileSystemEntity resource in resources) {
+ if (resource is File) {
+ try {
+ FileStat fileStat = await resource.stat();
+ files.add(resource);
+ fileStatMap[resource] = fileStat;
+ currentSizeBytes += fileStat.size;
+ } catch (_) {}
+ }
+ }
+ files.sort((a, b) {
+ return fileStatMap[a].accessed.millisecondsSinceEpoch -
+ fileStatMap[b].accessed.millisecondsSinceEpoch;
+ });
+
+ // Delete files until the current size is less than the max.
+ for (File file in files) {
+ if (currentSizeBytes < maxSizeBytes) {
+ break;
+ }
+ try {
+ await file.delete();
+ } catch (_) {}
+ currentSizeBytes -= fileStatMap[file].size;
+ }
+ }
}
« no previous file with comments | « pkg/analysis_server/lib/src/analysis_server.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698