From 78e84f85f60e41802a52b6b1f279f557c0bdb711 Mon Sep 17 00:00:00 2001 From: Jonathan Melo Date: Tue, 3 Sep 2024 10:56:33 -0400 Subject: [PATCH 1/3] Only track changed values when it matters --- .../store/InMemoryBackingStore.cs | 45 ++++++++++++++++++- .../Store/InMemoryBackingStoreTests.cs | 38 ++++++++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/src/abstractions/store/InMemoryBackingStore.cs b/src/abstractions/store/InMemoryBackingStore.cs index 4d50c28..7ba778d 100644 --- a/src/abstractions/store/InMemoryBackingStore.cs +++ b/src/abstractions/store/InMemoryBackingStore.cs @@ -15,10 +15,21 @@ namespace Microsoft.Kiota.Abstractions.Store public class InMemoryBackingStore : IBackingStore { private bool isInitializationComplete = true; + private bool _returnOnlyChangedValues = false; + /// /// Determines whether the backing store should only return changed values when queried. /// - public bool ReturnOnlyChangedValues { get; set; } + public bool ReturnOnlyChangedValues + { + get => _returnOnlyChangedValues; + + set + { + _returnOnlyChangedValues = value; + ForwardReturnOnlyChangedValuesToNestedInstances(); + } + } private readonly ConcurrentDictionary> store = new(); private readonly ConcurrentDictionary> subscriptions = new(); @@ -34,7 +45,10 @@ public class InMemoryBackingStore : IBackingStore if(store.TryGetValue(key, out var result)) { - EnsureCollectionPropertyIsConsistent(key, result.Item2); + if(ReturnOnlyChangedValues) + { + EnsureCollectionPropertyIsConsistent(key, result.Item2); + } var resultObject = result.Item2; if(resultObject is Tuple collectionTuple) { @@ -128,6 +142,14 @@ public void Set(string key, T? value) /// A collection of strings containing keys changed to null public IEnumerable EnumerateKeysForValuesChangedToNull() { + if(ReturnOnlyChangedValues) // refresh the state of collection properties if they've changed in size. + { + foreach(var item in store) + { + EnsureCollectionPropertyIsConsistent(item.Key, item.Value.Item2); + } + } + foreach(var item in store) { if(item.Value.Item1 && item.Value.Item2 == null) @@ -228,5 +250,24 @@ private void EnsureCollectionPropertyIsConsistent(string key, object? storeItem) } } } + + private void ForwardReturnOnlyChangedValuesToNestedInstances() + { + foreach(var item in store) + { + if(item.Value.Item2 is Tuple collectionTuple) + { + foreach(var collectionItem in collectionTuple.Item1) + { + if(collectionItem is not IBackedModel backedModel) break; + backedModel.BackingStore.ReturnOnlyChangedValues = _returnOnlyChangedValues; + } + } + else if(item.Value.Item2 is IBackedModel backedModel) + { + backedModel.BackingStore.ReturnOnlyChangedValues = _returnOnlyChangedValues; + } + } + } } } diff --git a/tests/abstractions/Store/InMemoryBackingStoreTests.cs b/tests/abstractions/Store/InMemoryBackingStoreTests.cs index 8e5932e..2f393f3 100644 --- a/tests/abstractions/Store/InMemoryBackingStoreTests.cs +++ b/tests/abstractions/Store/InMemoryBackingStoreTests.cs @@ -487,6 +487,44 @@ public void TestsLargeArrayPerformsWell() Assert.InRange(stopWatch.ElapsedMilliseconds, 0, 1); } + [Fact] + public void TestsLargeObjectReadPerformsWell() + { + // Arrange dummy user with many child objects + var testUser = new TestEntity + { + Id = "84c747c1-d2c0-410d-ba50-fc23e0b4abbe", + Colleagues = Enumerable.Range(1, 100) + .Select(_ => new TestEntity + { + Id = Guid.NewGuid().ToString(), + BusinessPhones = new List + { + "+1 234 567 891" + }, + Colleagues = Enumerable.Range(1, 100) + .Select(_ => new TestEntity + { + Id = Guid.NewGuid().ToString(), + BusinessPhones = new List + { + "+1 234 567 891" + } + }) + .ToList() + }) + .ToList() + }; + + // Act on the data by reading a property + var stopWatch = Stopwatch.StartNew(); + _ = testUser.Colleagues[0]; + stopWatch.Stop(); + + // Assert + Assert.InRange(stopWatch.ElapsedMilliseconds, 0, 1); + } + /// /// Helper function to pull out the private `subscriptions` collection property from the InMemoryBackingStore class /// From 5172fe9fb702f4230b48f67e9c6ef276d04f15c3 Mon Sep 17 00:00:00 2001 From: Jonathan Melo Date: Tue, 3 Sep 2024 14:01:25 -0400 Subject: [PATCH 2/3] Simplify the iteration --- src/abstractions/store/InMemoryBackingStore.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/abstractions/store/InMemoryBackingStore.cs b/src/abstractions/store/InMemoryBackingStore.cs index 7ba778d..d845338 100644 --- a/src/abstractions/store/InMemoryBackingStore.cs +++ b/src/abstractions/store/InMemoryBackingStore.cs @@ -253,9 +253,9 @@ private void EnsureCollectionPropertyIsConsistent(string key, object? storeItem) private void ForwardReturnOnlyChangedValuesToNestedInstances() { - foreach(var item in store) + foreach(var item in store.Values) { - if(item.Value.Item2 is Tuple collectionTuple) + if(item.Item2 is Tuple collectionTuple) { foreach(var collectionItem in collectionTuple.Item1) { @@ -263,7 +263,7 @@ private void ForwardReturnOnlyChangedValuesToNestedInstances() backedModel.BackingStore.ReturnOnlyChangedValues = _returnOnlyChangedValues; } } - else if(item.Value.Item2 is IBackedModel backedModel) + else if(item.Item2 is IBackedModel backedModel) { backedModel.BackingStore.ReturnOnlyChangedValues = _returnOnlyChangedValues; } From 4649abd01ad9f987243ebb1cd48b806cd04aedd4 Mon Sep 17 00:00:00 2001 From: Andrew Omondi Date: Thu, 5 Sep 2024 10:27:13 +0300 Subject: [PATCH 3/3] fix: fimporves performance of backing store on reading properties. --- CHANGELOG.md | 7 +++++++ Directory.Build.props | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bd68f4..8704dbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] + +## [1.12.4] - 2024-09-05 + +### Changed + +- Improves performance of the InMemoryBackingStore when reading properties. [#347](https://github.com/microsoft/kiota-dotnet/issues/347) + ## [1.12.3] - 2024-09-03 ### Changed diff --git a/Directory.Build.props b/Directory.Build.props index 1e5ce4e..f202c97 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 1.12.3 + 1.12.4 false