Skip to content

Commit 33a51ce

Browse files
committed
Avoid deserialising the cache multiple times
The map in the cache hits the disk whenever it's enumerated. Added an intermediate cache, and also avoid multiple nested enumerations. See RSPL-6881 and RSRP-461359
1 parent 661772d commit 33a51ce

File tree

4 files changed

+43
-38
lines changed

4 files changed

+43
-38
lines changed

install/resharper-angularjs.nuspec

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<metadata>
44
<id>JetBrains.AngularJS</id>
55
<title>AngularJS</title>
6-
<version>1.6.1</version>
6+
<version>1.6.2</version>
77
<authors>JetBrains</authors>
88
<owners>JetBrains</owners>
99
<requireLicenseAcceptance>false</requireLicenseAcceptance>
@@ -12,6 +12,9 @@
1212
<iconUrl>https://raw.github.com/JetBrains/resharper-angularjs/master/icon.png</iconUrl>
1313
<description>Code completion and live templates for AngularJS</description>
1414
<releaseNotes>
15+
&#8226; Address performance issue with many directives.
16+
17+
From 1.6.1:
1518
&#8226; Updated to ReSharper 2016.2
1619
&#8226; Initial 1.6.0 release was incorrect, re-compiled and re-released as 1.6.1
1720

src/resharper-angularjs/Feature/Services/Caches/AngularJsCache.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
using JetBrains.ReSharper.Psi.JavaScript.Tree;
2525
using JetBrains.ReSharper.Psi.Tree;
2626
using JetBrains.Util;
27+
using JetBrains.Util.Caches;
2728

2829
namespace JetBrains.ReSharper.Plugins.AngularJS.Feature.Services.Caches
2930
{
@@ -37,6 +38,13 @@ public AngularJsCache(Lifetime lifetime, IPersistentIndexManager persistentIndex
3738
// TODO: Useful for testing. Remove for release
3839
ClearOnLoad = true;
3940
#endif
41+
// Eumerating the map is expensive, as it will hit the disk cache. Create
42+
// an in-memory cache for the enumerator. Items are automatically removed
43+
// from the cache when they're removed from the Map. Use an unlimited cache
44+
// because we use this data frequently - we enumerate the whole cache whenever
45+
// we display code completion (which would touch each item anyway)
46+
Map.UseCachingEnumerator = true;
47+
Map.Cache = new UnlimitedCache<IPsiSourceFile, AngularJsCacheItems>();
4048

4149
CacheUpdated = new SimpleSignal(lifetime, "AngularJsCache");
4250
}

src/resharper-angularjs/Properties/AssemblyInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@
2929
[assembly: AssemblyCulture("")]
3030

3131
// Use a static version value so that ReSharper Build won't rebuild referencing assemblies
32-
[assembly: AssemblyVersion("1.5.1.0")]
32+
[assembly: AssemblyVersion("1.6.2.0")]
3333

src/resharper-angularjs/Psi/Html/AngularJsHtmlElementsProvider.cs

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
using System;
1818
using System.Collections.Generic;
1919
using System.Linq;
20-
using System.Reflection;
2120
using JetBrains.DataFlow;
2221
using JetBrains.ProjectModel;
2322
using JetBrains.ReSharper.Plugins.AngularJS.Feature.Services.Caches;
@@ -41,7 +40,6 @@ public class AngularJsHtmlElementsProvider : IHtmlDeclaredElementsProvider
4140
private readonly IHtmlAttributeValueType cdataAttributeValueType;
4241
private readonly Dictionary<string, IHtmlTagDeclaredElement> tags = new Dictionary<string, IHtmlTagDeclaredElement>();
4342
private readonly Dictionary<string, IHtmlAttributeDeclaredElement> attributes = new Dictionary<string, IHtmlAttributeDeclaredElement>();
44-
private readonly MethodInfo getTagMethodInfo;
4543
private IList<AttributeInfo> commonAttributeInfos = new List<AttributeInfo>();
4644
private ISymbolTable commonAttributesSymbolTable;
4745
private ISymbolTable allAttributesSymbolTable;
@@ -62,9 +60,6 @@ public AngularJsHtmlElementsProvider(Lifetime lifetime, AngularJsCache cache, IS
6260

6361
// TODO: Is this the right value for angular attributes?
6462
cdataAttributeValueType = new HtmlAttributeValueType("CDATA");
65-
66-
// The API for HtmlDeclareElementsCache.GetTag changed between 2016.1 and 2016.1.2
67-
getTagMethodInfo = typeof(HtmlDeclaredElementsCache).GetMethod("GetTag");
6863
}
6964

7065
// Gets a symbol table that contains all common attributes, that is, all attributes that apply to any tag.
@@ -83,7 +78,8 @@ public ISymbolTable GetCommonAttributesSymbolTable()
8378
if (commonAttributesSymbolTable == null)
8479
{
8580
var psiServices = solution.GetComponent<IPsiServices>();
86-
var attributeDeclaredElements = from ai in GetCommonAttributeInfosLocked()
81+
var directives = cache.Directives;
82+
var attributeDeclaredElements = from ai in GetCommonAttributeInfosLocked(directives)
8783
select ai.AttributeDeclaredElement;
8884
commonAttributesSymbolTable = new DeclaredElementsSymbolTable<IHtmlAttributeDeclaredElement>(psiServices, attributeDeclaredElements);
8985
}
@@ -105,8 +101,10 @@ public IEnumerable<AttributeInfo> GetAttributeInfos(IPsiSourceFile sourceFile, I
105101
if (tag is IAngularJsDeclaredElement)
106102
return EmptyArray<AttributeInfo>.Instance;
107103

104+
var directives = cache.Directives.ToList();
105+
108106
// Note that this includes common attributes
109-
var attributeInfos = from d in cache.Directives
107+
var attributeInfos = from d in directives
110108
where d.IsAttribute && d.IsForTag(tag.ShortName)
111109
from n in GetPrefixedNames(d.Name)
112110
select
@@ -115,12 +113,10 @@ from n in GetPrefixedNames(d.Name)
115113
// Get any elements that have the same name as the tag, and add the parameters as attributes
116114
// Don't include any attributes that are aleady defined by other providers (this causes the
117115
// HTML description cache component to crash)
118-
var providers = solution.GetComponents<IHtmlDeclaredElementsProvider>();
119-
120-
var parameterAttributeInfos = from d in cache.Directives
116+
var parameterAttributeInfos = from d in directives
121117
where d.IsElement && d.Name == tag.ShortName
122118
from p in d.Parameters
123-
where !IsKnownCommonAttribute(p.Name, providers)
119+
where !IsKnownCommonAttribute(p.Name)
124120
from n in GetPrefixedNames(p.Name)
125121
select
126122
new AttributeInfo(GetOrCreateAttributeLocked(n, tag),
@@ -145,9 +141,10 @@ public IHtmlTagDeclaredElement GetTag(string name)
145141
{
146142
lock (lockObject)
147143
{
148-
var tagDeclaredElements = from d in cache.Directives
144+
var directives = cache.Directives.ToList();
145+
var tagDeclaredElements = from d in directives
149146
where d.IsElement && string.Equals(d.Name, name, StringComparison.InvariantCultureIgnoreCase) && !IsOverridingTag(d.Name)
150-
select GetOrCreateTagLocked(d.Name);
147+
select GetOrCreateTagLocked(d.Name, directives);
151148
return tagDeclaredElements.FirstOrDefault();
152149
}
153150
}
@@ -164,10 +161,11 @@ public ISymbolTable GetAllTagsSymbolTable()
164161
{
165162
var psiServices = solution.GetComponent<IPsiServices>();
166163

167-
var tagDeclaredElements = from d in cache.Directives
164+
var directives = cache.Directives.ToList();
165+
var tagDeclaredElements = from d in directives
168166
where d.IsElement && !IsOverridingTag(d.Name)
169167
from n in GetPrefixedNames(d.Name)
170-
select GetOrCreateTagLocked(n);
168+
select GetOrCreateTagLocked(n, directives);
171169
allTagsSymbolTable = new DeclaredElementsSymbolTable<IHtmlTagDeclaredElement>(psiServices, tagDeclaredElements);
172170
}
173171
return allTagsSymbolTable;
@@ -203,18 +201,19 @@ public ISymbolTable GetAllAttributesSymbolTable()
203201
if (allAttributesSymbolTable == null)
204202
{
205203
var psiServices = solution.GetComponent<IPsiServices>();
206-
var providers = solution.GetComponents<IHtmlDeclaredElementsProvider>();
207204

208-
var attributeDeclaredElements = from d in cache.Directives
205+
var directives = cache.Directives.ToList();
206+
207+
var attributeDeclaredElements = from d in directives
209208
where d.IsAttribute
210209
from n in GetPrefixedNames(d.Name)
211210
from t in d.Tags
212211
select GetOrCreateAttributeLocked(n, t);
213212

214-
var parameterAttributeDeclaredElements = from d in cache.Directives
213+
var parameterAttributeDeclaredElements = from d in directives
215214
where d.IsElement
216215
from p in d.Parameters
217-
where !IsKnownCommonAttribute(p.Name, providers)
216+
where !IsKnownCommonAttribute(p.Name)
218217
from n in GetPrefixedNames(p.Name)
219218
select GetOrCreateAttributeLocked(n, d.Name);
220219

@@ -279,7 +278,7 @@ private bool IsOverridingTag(string name)
279278
return allTags.Contains(name);
280279
}
281280

282-
private bool IsKnownCommonAttribute(string name, IEnumerable<IHtmlDeclaredElementsProvider> providers)
281+
private bool IsKnownCommonAttribute(string name)
283282
{
284283
// This is horrible. We can't override existing tags and attributes, but we calling the
285284
// other providers dynamically causes serious perf issues. We'll just make do with
@@ -315,7 +314,7 @@ private string[] GetPrefixedNames(string root)
315314
return new[] {root};
316315
}
317316

318-
private IHtmlTagDeclaredElement GetOrCreateTagLocked(string name)
317+
private IHtmlTagDeclaredElement GetOrCreateTagLocked(string name, IList<Directive> directives)
319318
{
320319
IHtmlTagDeclaredElement tag;
321320
if (!tags.TryGetValue(name, out tag))
@@ -330,14 +329,14 @@ private IHtmlTagDeclaredElement GetOrCreateTagLocked(string name)
330329

331330
// Stupid circular references. Populate the attributes after creating the tag, so
332331
// that the attribute can reference the tag
333-
var ownAttributeInfos = GetParameterAttributeInfosLocked(tag)
334-
.Concat(GetSpecificAttributeInfosLocked(tag)
332+
var ownAttributeInfos = GetParameterAttributeInfosLocked(tag, directives)
333+
.Concat(GetSpecificAttributeInfosLocked(tag, directives)
335334
.Distinct(ai => ai.AttributeDeclaredElement.ShortName));
336335
ownAttributes.AddRange(ownAttributeInfos);
337336

338337
// Only include common attributes if they're not already part of the own attributes
339338
var ownAttributeNames = ownAttributes.ToHashSet(a => a.AttributeDeclaredElement.ShortName);
340-
var inheritedAttributeInfos = GetCommonAttributeInfosLocked()
339+
var inheritedAttributeInfos = GetCommonAttributeInfosLocked(directives)
341340
.Where(ai => !ownAttributeNames.Contains(ai.AttributeDeclaredElement.ShortName));
342341
inheritedAttributes.AddRange(inheritedAttributeInfos);
343342

@@ -346,28 +345,28 @@ private IHtmlTagDeclaredElement GetOrCreateTagLocked(string name)
346345
return tag;
347346
}
348347

349-
private IEnumerable<AttributeInfo> GetParameterAttributeInfosLocked(IHtmlTagDeclaredElement tag)
348+
private IEnumerable<AttributeInfo> GetParameterAttributeInfosLocked(IHtmlTagDeclaredElement tag, IEnumerable<Directive> directives)
350349
{
351-
return from d in cache.Directives
350+
return from d in directives
352351
where d.IsElement && d.Name.Equals(tag.ShortName, StringComparison.InvariantCultureIgnoreCase)
353352
from p in d.Parameters
354353
from n in GetPrefixedNames(p.Name)
355354
select new AttributeInfo(GetOrCreateAttributeLocked(n, tag), DefaultAttributeValueType.IMPLIED, null);
356355
}
357356

358-
private IEnumerable<AttributeInfo> GetSpecificAttributeInfosLocked(IHtmlTagDeclaredElement tag)
357+
private IEnumerable<AttributeInfo> GetSpecificAttributeInfosLocked(IHtmlTagDeclaredElement tag, IEnumerable<Directive> directives)
359358
{
360-
return from d in cache.Directives
359+
return from d in directives
361360
where d.IsAttribute && d.IsForTagSpecific(tag.ShortName)
362361
from n in GetPrefixedNames(d.Name)
363362
select new AttributeInfo(GetOrCreateAttributeLocked(n, tag), DefaultAttributeValueType.IMPLIED, null);
364363
}
365364

366-
private IEnumerable<AttributeInfo> GetCommonAttributeInfosLocked()
365+
private IEnumerable<AttributeInfo> GetCommonAttributeInfosLocked(IEnumerable<Directive> directives)
367366
{
368367
if (commonAttributeInfos == null)
369368
{
370-
commonAttributeInfos = new List<AttributeInfo>(from d in cache.Directives
369+
commonAttributeInfos = new List<AttributeInfo>(from d in directives
371370
where d.IsAttribute && d.IsForAnyTag()
372371
from n in GetPrefixedNames(d.Name)
373372
select
@@ -406,12 +405,7 @@ private IHtmlAttributeDeclaredElement GetOrCreateAttributeLocked(string attribut
406405
// doing it piecemeal. Would definitely be nice to get more fine grained caching for that.
407406

408407
var htmlDeclaredElementsCache = solution.GetComponent<HtmlDeclaredElementsCache>();
409-
// Ugh. The API changed between 2016.1 and 2016.1.2...
410-
//tag = htmlDeclaredElementsCache.GetTag(null, tagName);
411-
if (getTagMethodInfo.GetParameters().Length == 3)
412-
tag = (IHtmlTagDeclaredElement) getTagMethodInfo.Invoke(htmlDeclaredElementsCache, new object[] {null, tagName, null});
413-
else
414-
tag = (IHtmlTagDeclaredElement) getTagMethodInfo.Invoke(htmlDeclaredElementsCache, new object[] {tagName, null});
408+
tag = htmlDeclaredElementsCache.GetTag(null, tagName);
415409
attribute = GetAttributeLocked(key);
416410
if (attribute != null)
417411
return attribute;

0 commit comments

Comments
 (0)