Skip to content

Commit

Permalink
Merge pull request #368 from Le-Merle/main
Browse files Browse the repository at this point in the history
Only track changed values when it matters
  • Loading branch information
andrueastman authored Sep 5, 2024
2 parents 01bd490 + 4649abd commit 6516c93
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 3 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>
<!-- Common default project properties for ALL projects-->
<PropertyGroup>
<VersionPrefix>1.12.3</VersionPrefix>
<VersionPrefix>1.12.4</VersionPrefix>
<VersionSuffix></VersionSuffix>
<!-- This is overidden in test projects by setting to true-->
<IsTestProject>false</IsTestProject>
Expand Down
45 changes: 43 additions & 2 deletions src/abstractions/store/InMemoryBackingStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,21 @@ namespace Microsoft.Kiota.Abstractions.Store
public class InMemoryBackingStore : IBackingStore
{
private bool isInitializationComplete = true;
private bool _returnOnlyChangedValues = false;

/// <summary>
/// Determines whether the backing store should only return changed values when queried.
/// </summary>
public bool ReturnOnlyChangedValues { get; set; }
public bool ReturnOnlyChangedValues
{
get => _returnOnlyChangedValues;

set
{
_returnOnlyChangedValues = value;
ForwardReturnOnlyChangedValuesToNestedInstances();
}
}
private readonly ConcurrentDictionary<string, Tuple<bool, object?>> store = new();
private readonly ConcurrentDictionary<string, Action<string, object?, object?>> subscriptions = new();

Expand All @@ -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<ICollection, int> collectionTuple)
{
Expand Down Expand Up @@ -128,6 +142,14 @@ public void Set<T>(string key, T? value)
/// <returns>A collection of strings containing keys changed to null </returns>
public IEnumerable<string> 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)
Expand Down Expand Up @@ -228,5 +250,24 @@ private void EnsureCollectionPropertyIsConsistent(string key, object? storeItem)
}
}
}

private void ForwardReturnOnlyChangedValuesToNestedInstances()
{
foreach(var item in store.Values)
{
if(item.Item2 is Tuple<ICollection, int> collectionTuple)
{
foreach(var collectionItem in collectionTuple.Item1)
{
if(collectionItem is not IBackedModel backedModel) break;
backedModel.BackingStore.ReturnOnlyChangedValues = _returnOnlyChangedValues;
}
}
else if(item.Item2 is IBackedModel backedModel)
{
backedModel.BackingStore.ReturnOnlyChangedValues = _returnOnlyChangedValues;
}
}
}
}
}
38 changes: 38 additions & 0 deletions tests/abstractions/Store/InMemoryBackingStoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>
{
"+1 234 567 891"
},
Colleagues = Enumerable.Range(1, 100)
.Select(_ => new TestEntity
{
Id = Guid.NewGuid().ToString(),
BusinessPhones = new List<string>
{
"+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);
}

/// <summary>
/// Helper function to pull out the private `subscriptions` collection property from the InMemoryBackingStore class
/// </summary>
Expand Down

0 comments on commit 6516c93

Please sign in to comment.