Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance: Adds headers optimization #1781

Merged
merged 30 commits into from
Aug 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
dab3214
Rewriting the headers
kirankumarkolli Jun 12, 2020
5099bd9
Making headers INameValueCollection
kirankumarkolli Jun 12, 2020
d4cfdc4
Rewriting the headers
kirankumarkolli Jun 12, 2020
cb8fb1b
Making headers INameValueCollection
kirankumarkolli Jun 12, 2020
2d4cc2b
Clean build
kirankumarkolli Jun 18, 2020
12a0d1a
Pull from origin
kirankumarkolli Jun 18, 2020
6da58db
Merge branch 'master' into users/kirankk/headers_revisit
kirankumarkolli Jul 11, 2020
1344ac1
One small refactoring
kirankumarkolli Jul 11, 2020
6629272
Merge branch 'master' into users/kirankk/headers_revisit
kirankumarkolli Jul 20, 2020
0bc993b
Merge remote-tracking branch 'origin/master' into users/kirankk/heade…
Jul 29, 2020
5d4ea8b
Merge remote-tracking branch 'origin/master' into users/jawilley/perf…
Aug 12, 2020
6c52f2d
Merge to latest
Aug 12, 2020
e7e327d
Switch header to use DictionaryNameValueCollection. Fixed null ref ex…
Aug 12, 2020
bc14d88
Merge remote-tracking branch 'origin/master' into users/jawilley/perf…
Aug 13, 2020
143232f
Revert back to CosmosMessageHeadersInternal
Aug 13, 2020
5cc9d4c
Merge remote-tracking branch 'origin/master' into users/jawilley/perf…
Aug 14, 2020
5556d96
Implemented missing methods
Aug 14, 2020
34c8be4
Removed unused code
Aug 14, 2020
1e62e99
Update contract changes
Aug 17, 2020
b6852fc
Fixed retry after logic
Aug 17, 2020
c46df34
Fixed substatus code
Aug 17, 2020
00320b0
Fix null ref exception
Aug 17, 2020
5b61b44
Fixed invariant culture
Aug 17, 2020
64d9a3b
Fix header checks. Add with null now works as remove
Aug 17, 2020
4de6a24
Merge branch 'master' into users/jawilley/perf/headers
j82w Aug 18, 2020
c61230c
Merge remote-tracking branch 'origin/master' into users/jawilley/perf…
Aug 25, 2020
7ce6a64
Merge remote-tracking branch 'origin/master' into users/jawilley/perf…
Aug 26, 2020
b29c4e1
Use static readonly instead of const
Aug 26, 2020
a523f5a
Merge branch 'users/jawilley/perf/headers' of https://github.com/Azur…
Aug 26, 2020
1905b12
Merge branch 'master' into users/jawilley/perf/headers
j82w Aug 26, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 0 additions & 29 deletions Microsoft.Azure.Cosmos/src/Headers/CosmosCustomHeader.cs

This file was deleted.

This file was deleted.

163 changes: 33 additions & 130 deletions Microsoft.Azure.Cosmos/src/Headers/CosmosMessageHeadersInternal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,41 +18,24 @@ namespace Microsoft.Azure.Cosmos
/// </summary>
internal class CosmosMessageHeadersInternal : INameValueCollection
{
private readonly Lazy<Dictionary<string, string>> headers = new Lazy<Dictionary<string, string>>(CosmosMessageHeadersInternal.CreateDictionary);
private static readonly int HeadersDefaultCapacity = 16;
private readonly Dictionary<string, string> headers;

private readonly Dictionary<string, CosmosCustomHeader> knownHeaders;

public CosmosMessageHeadersInternal(Dictionary<string, CosmosCustomHeader> knownHeaders)
public CosmosMessageHeadersInternal()
: this(HeadersDefaultCapacity)
{
this.knownHeaders = knownHeaders;
}

public void Add(string headerName, string value)
public CosmosMessageHeadersInternal(int capacity)
{
if (headerName == null || value == null)
{
throw new ArgumentNullException($"{nameof(headerName)}: {headerName ?? "null"}; {nameof(value)}: {value ?? "null"}");
}

CosmosCustomHeader knownHeader;
if (this.knownHeaders.TryGetValue(headerName, out knownHeader))
{
knownHeader.Set(value);
return;
}

this.headers.Value.Add(headerName, value);
this.headers = new Dictionary<string, string>(
capacity,
StringComparer.OrdinalIgnoreCase);
}

public void Add(string headerName, IEnumerable<string> values)
public void Add(string headerName, string value)
{
if (headerName == null || values == null)
{
string value = values == null ? "null" : string.Join(";", values);
throw new ArgumentNullException($"{nameof(headerName)}: {headerName ?? "null" }; {nameof(values)}: {value}");
}

this.Add(headerName, string.Join(",", values));
this.Set(headerName, value);
}

public bool TryGetValue(string headerName, out string value)
Expand All @@ -62,15 +45,7 @@ public bool TryGetValue(string headerName, out string value)
throw new ArgumentNullException(nameof(headerName));
}

CosmosCustomHeader knownHeader;
if (this.knownHeaders.TryGetValue(headerName, out knownHeader))
{
value = knownHeader.Get();
return true;
}

value = null;
return this.headers.IsValueCreated && this.headers.Value.TryGetValue(headerName, out value);
return this.headers.TryGetValue(headerName, out value);
}

public void Remove(string headerName)
Expand All @@ -80,14 +55,7 @@ public void Remove(string headerName)
throw new ArgumentNullException(nameof(headerName));
}

CosmosCustomHeader knownHeader;
if (this.knownHeaders.TryGetValue(headerName, out knownHeader))
{
knownHeader.Set(null);
return;
}

this.headers.Value.Remove(headerName);
this.headers.Remove(headerName);
}

public string this[string headerName]
Expand All @@ -112,18 +80,15 @@ public void Set(string key, string value)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
throw new ArgumentNullException($"{nameof(key)}; {nameof(value)}: {value ?? "null"}");
}

CosmosCustomHeader knownHeader;
if (this.knownHeaders.TryGetValue(key, out knownHeader))
if (value == null)
{
knownHeader.Set(value);
return;
this.headers.Remove(key);
}

this.headers.Value.Remove(key);
this.headers.Value.Add(key, value);
this.headers[key] = value;
}

public string Get(string key)
Expand All @@ -138,30 +103,31 @@ public string Get(string key)

public void Clear()
{
foreach (KeyValuePair<string, CosmosCustomHeader> knownHeader in this.knownHeaders)
{
knownHeader.Value.Set(null);
}

if (this.headers.IsValueCreated)
{
this.headers.Value.Clear();
}
this.headers.Clear();
}

public int Count()
{
return this.CountHeaders() + this.CountKnownHeaders();
return this.headers.Count;
}

public INameValueCollection Clone()
{
return new DictionaryNameValueCollection(this);
CosmosMessageHeadersInternal headersClone = new CosmosMessageHeadersInternal(this.headers.Count);
foreach (KeyValuePair<string, string> header in this.headers)
{
headersClone.Add(header.Key, header.Value);
}

return headersClone;
}

public void Add(INameValueCollection collection)
{
throw new NotImplementedException();
foreach (string key in collection.Keys())
{
this.Add(key, collection[key]);
}
}

public string[] GetValues(string key)
Expand All @@ -182,55 +148,25 @@ public string[] GetValues(string key)

public string[] AllKeys()
{
return this.knownHeaders.Where(header => !string.IsNullOrEmpty(header.Value.Get()))
.Select(header => header.Key)
.Concat(this.headers.Value.Keys).ToArray();
return this.headers.Keys.ToArray();
}

public IEnumerable<string> Keys()
{
foreach (KeyValuePair<string, CosmosCustomHeader> knownHeader in this.knownHeaders.Where(header => !string.IsNullOrEmpty(header.Value.Get())))
{
yield return knownHeader.Key;
}

foreach (string key in this.headers.Value.Keys)
foreach (string key in this.headers.Keys)
{
yield return key;
}
}

public NameValueCollection ToNameValueCollection()
{
throw new NotImplementedException();
throw new NotImplementedException(nameof(this.ToNameValueCollection));
}

public IEnumerator<string> GetEnumerator()
{
using (Dictionary<string, CosmosCustomHeader>.Enumerator customHeaderIterator = this.knownHeaders.GetEnumerator())
{
while (customHeaderIterator.MoveNext())
{
string customValue = customHeaderIterator.Current.Value.Get();
if (!string.IsNullOrEmpty(customValue))
{
yield return customHeaderIterator.Current.Key;
}
}
}

if (!this.headers.IsValueCreated)
{
yield break;
}

using (IEnumerator<string> headerIterator = this.headers.Value.Select(x => x.Key).GetEnumerator())
{
while (headerIterator.MoveNext())
{
yield return headerIterator.Current;
}
}
return this.headers.Select(x => x.Key).GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
Expand All @@ -254,38 +190,5 @@ public T GetHeaderValue<T>(string key)

return (T)(object)value;
}

internal static KeyValuePair<string, PropertyInfo>[] GetHeaderAttributes<T>()
{
IEnumerable<PropertyInfo> knownHeaderProperties = typeof(T)
.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(p => p.GetCustomAttributes(typeof(CosmosKnownHeaderAttribute), false).Any());

return knownHeaderProperties.Select(
knownProperty =>
new KeyValuePair<string, PropertyInfo>(
((CosmosKnownHeaderAttribute)knownProperty.GetCustomAttributes(typeof(CosmosKnownHeaderAttribute), false).First()).HeaderName,
knownProperty)).ToArray();
}

private static Dictionary<string, string> CreateDictionary()
{
return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}

private int CountHeaders()
{
if (!this.headers.IsValueCreated)
{
return 0;
}

return this.headers.Value.Count;
}

private int CountKnownHeaders()
{
return this.knownHeaders.Where(customHeader => !string.IsNullOrEmpty(customHeader.Value.Get())).Count();
}
}
}
Loading