Skip to content

Commit 903b551

Browse files
Initial commit after repo reset
0 parents  commit 903b551

1 file changed

Lines changed: 146 additions & 0 deletions

File tree

README.md

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
[![license](https://img.shields.io/badge/License-MIT-purple.svg)](LICENSE)
2+
![semver](https://img.shields.io/badge/semver-1.3.0-blue)
3+
4+
# AutoIndexCache
5+
A thread-safe, lazy-loading cache for .NET applications that provides automatic indexing of the cached items.
6+
7+
```csharp
8+
using System;
9+
using AutoIndexCache;
10+
11+
public class User
12+
{
13+
public Int64 GroupId { get; set; }
14+
public Int64 Id { get; set; }
15+
public Boolean IsActive { get; set; }
16+
public String UserName { get; set; }
17+
}
18+
19+
public class Program
20+
{
21+
public static void Main(String[] args)
22+
{
23+
var cache = new AutoIndexCache();
24+
25+
cache.SetItemsLoader(() => LoadUsers());
26+
27+
// Get all users:
28+
cache.Items<User>().GetAllItems();
29+
30+
// Get the user that has the Id 1:
31+
cache.Items<User>().UniqueIndex(a => a.Id).GetItemOrDefault(1);
32+
33+
// Get all users that belong to group 1:
34+
cache.Items<User>().NonUniqueIndex(a => a.GroupId).GetItems(1);
35+
36+
// Get all active users of group 10:
37+
cache.Items<User>().NonUniqueIndex(a => (a.IsActive, a.GroupId)).GetItems((true, 10));
38+
39+
// Get all Ids of users:
40+
cache.Items<User>().UniqueIndex(a => a.Id).GetKeys();
41+
42+
// Reset the users cache (LoadUsers will be called again next time User items are requested from the cache):
43+
cache.Items<User>().Reset();
44+
}
45+
46+
private static User[] LoadUsers()
47+
{
48+
var result = new User[10_000];
49+
50+
for (var i = 1; i <= result.Length; i++)
51+
{
52+
result[i-1] = new() { Id = i, UserName = "User " + i, GroupId = i % 2 == 0 ? 2 : 1, IsActive = i % 2 == 0 };
53+
}
54+
55+
return result;
56+
}
57+
}
58+
```
59+
60+
# Performance
61+
AutoIndexCache is blazingly fast (as a cache should be).
62+
However, some overhead is still needed to make it thread-safe and for the auto indexing, so a hand crafted custom solution might be even faster.
63+
64+
# Benchmarks
65+
In the following benchmarks AutoIndexCache is compared to the [Dictionary<TKey,TValue>](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?view=net-9.0) type.
66+
You can find the source code of the bechmarks [here](https://github.com/rent-a-developer/AutoIndexCache/tree/main/AutoIndexCache.Benchmarks).
67+
68+
![image](https://github.com/user-attachments/assets/91cb0214-0cbd-4a9c-896e-e1090b6c0e19)
69+
70+
## Explanation
71+
### ..._Dicationary
72+
In these benchmarks the [Dictionary<TKey,TValue>](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?view=net-9.0) is used to index cached items.
73+
There is hardly any faster soltuion in .NET to index cached items.
74+
However, the Dictionary is completely non-thread-safe.
75+
### ..._AutoIndexCache
76+
In these benchmarks the AutoIndexCache is used.
77+
### ..._AutoIndexCacheOptimized
78+
In these bechmarks, also, the AutoIndexCache is used.
79+
However, a trick was applied to drastically improve the performance:
80+
81+
To access cached items you need to call the AutoIndexCache.Items<TItem> method.
82+
And to access indexes you need to call the ItemsList<TItem>.NonUniqueIndex<TKey> and ItemsList<TItem>.UniqueIndex<TKey> methods.
83+
These methods have some overhead, because they need to be thread-safe.
84+
85+
Instead of calling these method each time you want to access cached items or indexes, you can just call them once and store their return values in fields (so in essence, you are caching the cache :smiley:).
86+
This way the performance of the cache is improved drastically.
87+
88+
So instead of this:
89+
```csharp
90+
class Service
91+
{
92+
private readonly AutoIndexCache cache;
93+
94+
public Service(AutoIndexCache cache)
95+
{
96+
this.cache = cache;
97+
}
98+
99+
public User? GetUserById(Int64 id)
100+
{
101+
return this.cache.Items<User>().UniqueIndex(a => a.Id).GetItemOrDefault(id);
102+
}
103+
}
104+
```
105+
106+
you do this:
107+
```csharp
108+
class Service
109+
{
110+
private readonly AutoIndexCache cache;
111+
private readonly IItemList<User> users;
112+
private readonly IUniqueIndex<User, Int32> userById;
113+
114+
public Service(AutoIndexCache cache)
115+
{
116+
this.cache = cache;
117+
this.users = this.cache.Items<User>();
118+
this.userById = this.users.UniqueIndex(a => a.Id);
119+
}
120+
121+
public User? GetUserById(Int64 id)
122+
{
123+
return this.userById.GetItemOrDefault(id);
124+
}
125+
}
126+
```
127+
128+
# License
129+
This library is licensed under the [MIT license](LICENSE.md).
130+
131+
# Installation
132+
First, [install NuGet](http://docs.nuget.org/docs/start-here/installing-nuget).
133+
134+
Then download a release from the [releases page](https://github.com/rent-a-developer/AutoIndexCache/releases) and install via the NuGet Package Manager:
135+
```shell
136+
PM> Install-Package AutoIndexCache -Source PathToTheNuGetPackage
137+
```
138+
139+
# Documentation
140+
141+
The API documentation can be found [here](https://rent-a-developer.github.io/AutoIndexCache/api/AutoIndexCache.html).
142+
143+
# Contributors
144+
145+
## Main contributors
146+
- David Liebeherr (info@rent-a-developer.de)

0 commit comments

Comments
 (0)