Chromium Code Reviews| Index: runtime/bin/vmservice/client/lib/src/service/cache.dart |
| diff --git a/runtime/bin/vmservice/client/lib/src/service/cache.dart b/runtime/bin/vmservice/client/lib/src/service/cache.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4729d39571e3c07f9007f006d0faca6011a80258 |
| --- /dev/null |
| +++ b/runtime/bin/vmservice/client/lib/src/service/cache.dart |
| @@ -0,0 +1,142 @@ |
| +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| +// 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. |
| + |
| +part of service; |
| + |
| +/// Abstract [ServiceObjectCache]. |
| +abstract class ServiceObjectCache<T extends ServiceObject> { |
| + final Isolate isolate; |
| + final _cache = new ObservableMap<String, T>(); |
| + |
| + ServiceObjectCache(this.isolate) { |
| + assert(isolate != null); |
| + } |
| + |
| + /// Returns true if [this] caches objects with this [id]. |
| + bool cachesId(String id); |
|
turnidge
2014/03/10 21:03:28
What do you think of blank lines between these dec
|
| + /// Returns true if [this] caches objects with service [type]. |
| + bool cachesType(String type); |
|
turnidge
2014/03/10 21:03:28
I'm not convinced that we want to have a data-driv
|
| + /// Upgrades [obj] into a [T]. |
|
turnidge
2014/03/10 21:03:28
More verbose comment about what "upgrading" means.
|
| + T upgrade(ObservableMap map); |
|
turnidge
2014/03/10 21:03:28
Could upgrade be private (_upgrade) or is it part
Cutch
2014/03/11 03:17:48
Done.
|
| + |
| + /// Returns true if [this] has [id] in its cache. |
| + bool contains(String id) { |
| + assert(cachesId(id)); |
| + return _cache[id] != null; |
| + } |
| + |
| + /// Gets [id] from the cache. Returns null if not contained. |
| + T operator[](String id) { |
| + assert(cachesId(id)); |
| + return _cache[id]; |
| + } |
| + |
| + /// Caches [so] with [id]. |
| + operator[]=(String id, T so) { |
|
turnidge
2014/03/10 21:03:28
"so" -> obj?
Cutch
2014/03/11 03:17:48
Done.
|
| + assert(cachesId(id)); |
| + assert(cachesType(so.serviceType)); |
| + _cache[id] = so; |
| + } |
| + |
| + /// Gets [id] from the cache or makes a network request for [id]. |
| + Future<T> get(String id) { |
| + assert(cachesId(id)); |
| + T cached = _cache[id]; |
| + if (cached != null) { |
| + return new Future.value(cached); |
| + } |
| + return isolate.fetch(id).then(_addToCache); |
| + } |
| + |
| + /// If [obj] is cached, return the cached object. Otherwise, upgrades [obj] |
| + /// and adds the upgraded value to the cache. |
| + T cachedOrUpgradeAndAdd(ObservableMap obj) { |
|
turnidge
2014/03/10 21:03:28
I would like a different name. Maybe something li
Cutch
2014/03/11 03:17:48
I've renamed it to putIfAbsent. This gets called b
|
| + assert(ServiceObject.isServiceMap(obj)); |
| + String id = obj['id']; |
| + var type = obj['type']; |
| + assert(cachesId(id)); |
| + assert(cachesType(type)); |
| + if (contains(id)) { |
| + return this[id]; |
| + } |
| + return _addToCache(upgrade(obj)); |
| + } |
| + |
| + T _addToCache(T so) { |
| + this[so.id] = so; |
| + return so; |
| + } |
| +} |
| + |
| +class ScriptCache extends ServiceObjectCache<Script> { |
| + ScriptCache(Isolate isolate) : super(isolate); |
| + |
| + bool cachesId(String id) => _matcher.hasMatch(id); |
| + bool cachesType(String type) => ServiceObject.unreffedType(type) == 'Script'; |
|
turnidge
2014/03/10 21:03:28
unreffedType... the double f is weird. Maybe "str
Cutch
2014/03/11 03:17:48
Done.
|
| + Script upgrade(ObservableMap obj) => new Script.fromMap(isolate, obj); |
| + static final RegExp _matcher = new RegExp(r'scripts/.+'); |
| + |
| + void _processCoverage(ServiceMap coverage) { |
| + assert(coverage.serviceType == 'CodeCoverage'); |
| + var coverageList = coverage['coverage']; |
| + assert(coverageList != null); |
| + coverageList.forEach((scriptCoverage) { |
| + _processScriptCoverage(scriptCoverage); |
| + }); |
| + } |
| + |
| + void _processScriptCoverage(ObservableMap scriptCoverage) { |
| + // Because the coverage data was upgraded into a ServiceObject, |
| + // the script can be directly accessed. |
| + Script script = scriptCoverage['script']; |
| + script._processHits(scriptCoverage['hits']); |
| + } |
| +} |
| + |
| +class CodeCache extends ServiceObjectCache<Code> { |
| + CodeCache(Isolate isolate) : super(isolate); |
| + |
| + bool cachesId(String id) => _matcher.hasMatch(id); |
| + bool cachesType(String type) => ServiceObject.unreffedType(type) == 'Code'; |
| + Code upgrade(ObservableMap obj) => new Code.fromMap(isolate, obj); |
| + |
| + static final RegExp _matcher = new RegExp(r'code/.+'); |
| + |
| + List<Code> topExclusive(int count) { |
| + var codeList = _cache.values.toList(); |
| + codeList.sort((Code a, Code b) { |
| + return b.exclusiveTicks - a.exclusiveTicks; |
| + }); |
| + if (codeList.length < count) { |
| + return codeList; |
| + } |
| + codeList.length = count; |
| + return codeList; |
| + } |
| + |
| + void _resetProfileData() { |
| + _cache.forEach((k, Code code) { |
| + code.resetProfileData(); |
| + }); |
| + } |
| + |
| + void _updateProfileData(ServiceMap profile, List<Code> codeTable) { |
| + var codes = profile['codes']; |
| + var sampleCount = profile['samples']; |
| + for (var profileCode in codes) { |
| + Code code = profileCode['code']; |
| + code.updateProfileData(profileCode, codeTable, sampleCount); |
| + } |
| + } |
| +} |
| + |
| +class ClassCache extends ServiceObjectCache<ServiceMap> { |
| + ClassCache(Isolate isolate) : super(isolate); |
| + |
| + bool cachesId(String id) => _matcher.hasMatch(id); |
| + bool cachesType(String type) => ServiceObject.unreffedType(type) == 'Class'; |
| + ServiceMap upgrade(ObservableMap obj) => new ServiceMap.fromMap(isolate, obj); |
| + |
| + static final RegExp _matcher = new RegExp(r'classes/\d+$'); |
| +} |