2
2
using System . Buffers . Binary ;
3
3
using NexusMods . EventSourcing . Abstractions ;
4
4
using NexusMods . EventSourcing . Abstractions . Serialization ;
5
+ using NexusMods . Hashing . xxHash64 ;
5
6
using Reloaded . Memory . Extensions ;
6
7
7
8
namespace NexusMods . EventSourcing . TestModel ;
8
9
9
10
public class InMemoryEventStore < TSerializer > : AEventStore
10
11
where TSerializer : IEventSerializer
11
12
{
12
- private TransactionId _tx = TransactionId . From ( 0 ) ;
13
- private readonly Dictionary < EntityId , IList < ( TransactionId TxId , byte [ ] Data ) > > _events = new ( ) ;
13
+ private readonly List < byte [ ] > _events = new ( ) ;
14
+ private readonly Dictionary < ( IAttribute , Hash ) , SortedSet < TransactionId > > _indexes = new ( ) ;
14
15
private readonly Dictionary < EntityId , SortedDictionary < TransactionId , byte [ ] > > _snapshots = new ( ) ;
15
16
private TSerializer _serializer ;
16
17
@@ -19,43 +20,61 @@ public InMemoryEventStore(TSerializer serializer, ISerializationRegistry seriali
19
20
_serializer = serializer ;
20
21
}
21
22
22
- public override TransactionId Add < T > ( T entity )
23
+ public override TransactionId Add < T > ( T entity , ( IIndexableAttribute , IAccumulator ) [ ] indexed )
23
24
{
24
25
lock ( this )
25
26
{
26
- _tx = _tx . Next ( ) ;
27
+ // Create the new txId
28
+ var txId = TransactionId . From ( ( ulong ) _events . Count ) ;
29
+
27
30
var data = _serializer . Serialize ( entity ) ;
28
- var logger = new ModifiedEntitiesIngester ( ) ;
29
- entity . Apply ( logger ) ;
30
- foreach ( var id in logger . Entities )
31
+ _events . Add ( data . ToArray ( ) ) ;
32
+
33
+ foreach ( var ( attr , accumulator ) in indexed )
31
34
{
32
- if ( ! _events . TryGetValue ( id , out var value ) )
35
+ // Hash the accumulator to condense it down into a single ulong
36
+ var hash = HashAccumulator ( attr , accumulator ) ;
37
+
38
+ if ( _indexes . TryGetValue ( ( attr , hash ) , out var found ) )
33
39
{
34
- value = new List < ( TransactionId , byte [ ] ) > ( ) ;
35
- _events . Add ( id , value ) ;
40
+ found . Add ( txId ) ;
41
+ }
42
+ else
43
+ {
44
+ var newSet = new SortedSet < TransactionId > { txId } ;
45
+ _indexes . Add ( ( attr , hash ) , newSet ) ;
36
46
}
37
-
38
- value . Add ( ( _tx , data . ToArray ( ) ) ) ;
39
47
}
40
-
41
- return _tx ;
48
+ return txId ;
42
49
}
43
50
}
44
51
52
+ private static Hash HashAccumulator ( IIndexableAttribute attr , IAccumulator accumulator )
53
+ {
54
+ Span < byte > span = stackalloc byte [ attr . SpanSize ( ) ] ;
55
+ attr . WriteTo ( span , accumulator ) ;
56
+ var hash = span . XxHash64 ( ) ;
57
+ return hash ;
58
+ }
45
59
46
- public override void EventsForEntity < TIngester > ( EntityId entityId , TIngester ingester , TransactionId fromId , TransactionId toId )
60
+ public override void EventsForIndex < TIngester , TVal > ( IIndexableAttribute < TVal > attr , TVal value , TIngester ingester , TransactionId fromTx ,
61
+ TransactionId toTx )
47
62
{
48
- if ( ! _events . TryGetValue ( entityId , out var events ) )
63
+ Span < byte > valueSpan = stackalloc byte [ attr . SpanSize ( ) ] ;
64
+ attr . WriteTo ( valueSpan , value ) ;
65
+ var hash = valueSpan . XxHash64 ( ) ;
66
+
67
+ if ( ! _indexes . TryGetValue ( ( attr , hash ) , out var found ) )
49
68
return ;
50
69
51
- foreach ( var data in events )
70
+ foreach ( var txId in found )
52
71
{
53
- if ( data . TxId < fromId ) continue ;
54
- if ( data . TxId > toId ) break ;
72
+ if ( txId > toTx || txId < fromTx ) continue ;
55
73
56
- var @event = _serializer . Deserialize ( data . Data ) ! ;
57
- if ( ! ingester . Ingest ( data . TxId , @event ) ) break ;
74
+ var eventItem = _serializer . Deserialize ( _events [ ( int ) txId . Value ] ) ;
75
+ ingester . Ingest ( txId , eventItem ) ;
58
76
}
77
+
59
78
}
60
79
61
80
public override TransactionId GetSnapshot ( TransactionId asOf , EntityId entityId , out IAccumulator loadedDefinition ,
0 commit comments