22using System . Collections . Generic ;
33using System . Collections . Immutable ;
44using System . Diagnostics . CodeAnalysis ;
5- using System . Linq ;
65using Neo . Persistence ;
7- using OneOf ;
8- using None = OneOf . Types . None ;
6+ using Neo . Plugins ;
97
108namespace Neo . BlockchainToolkit . Persistence
119{
12- using TrackingMap = ImmutableSortedDictionary < byte [ ] , OneOf < byte [ ] ? , None > > ;
13-
1410 public partial class CheckpointStorageProvider : IDisposableStorageProvider
1511 {
16- public readonly static TrackingMap EMPTY_TRACKING_MAP = TrackingMap . Empty . WithComparers ( ByteArrayComparer . Default ) ;
17-
18- readonly RocksDbStorageProvider ? rocksDbProvider ;
19- readonly bool disposeRocksDbProvider ;
12+ readonly IStorageProvider ? storageProvider ;
2013 readonly IDisposable ? checkpointCleanup ;
14+ readonly Lazy < IStore > defaultStore ;
15+ ImmutableDictionary < string , IStore > stores = ImmutableDictionary < string , IStore > . Empty ;
2116
22- ImmutableDictionary < string , TrackingMap > trackingMaps = ImmutableDictionary < string , TrackingMap > . Empty ;
23- TrackingMap defaultTrackingMap = EMPTY_TRACKING_MAP ;
17+ public CheckpointStorageProvider ( RocksDbStorageProvider ? rocksDbStorageProvider , IDisposable ? checkpointCleanup = null )
18+ : this ( ( IStorageProvider ? ) rocksDbStorageProvider , checkpointCleanup )
19+ {
20+ }
2421
25- public CheckpointStorageProvider ( RocksDbStorageProvider ? rocksDbStorageProvider , bool disposeRocksDbProvider = true , IDisposable ? checkpointCleanup = null )
22+ public CheckpointStorageProvider ( IStorageProvider ? storageProvider , IDisposable ? checkpointCleanup = null )
2623 {
27- this . rocksDbProvider = rocksDbStorageProvider ;
28- this . disposeRocksDbProvider = disposeRocksDbProvider ;
24+ this . storageProvider = storageProvider ;
2925 this . checkpointCleanup = checkpointCleanup ;
26+
27+ defaultStore = new Lazy < IStore > ( ( ) => new MemoryTrackingStore ( GetStorageProviderStore ( null ) ) ) ;
3028 }
3129
3230 public void Dispose ( )
3331 {
34- if ( disposeRocksDbProvider ) rocksDbProvider ? . Dispose ( ) ;
32+ ( storageProvider as IDisposable ) ? . Dispose ( ) ;
3533 checkpointCleanup ? . Dispose ( ) ;
3634 }
3735
38- internal TrackingMap GetTrackingMap ( string ? storeName )
39- => storeName == null
40- ? defaultTrackingMap
41- : trackingMaps . TryGetValue ( storeName , out var trackingMap )
42- ? trackingMap
43- : EMPTY_TRACKING_MAP ;
44-
45- IReadOnlyStore GetReadOnlyStore ( string ? storeName )
46- => ( rocksDbProvider != null && rocksDbProvider . TryGetStore ( storeName , out var store ) )
47- ? store
48- : NullStore . Instance ;
49-
5036 public IStore GetStore ( string ? storeName )
5137 {
52- return new Store ( this , storeName ) ;
38+ if ( storeName == null ) return defaultStore . Value ;
39+ return ImmutableInterlocked . GetOrAdd ( ref stores , storeName ,
40+ key => new MemoryTrackingStore ( GetStorageProviderStore ( key ) ) ) ;
5341 }
5442
55- internal ISnapshot GetSnapshot ( string ? storeName )
43+ IReadOnlyStore GetStorageProviderStore ( string ? path )
5644 {
57- var map = GetTrackingMap ( storeName ) ;
58- return new CheckpointStorageProvider . Snapshot ( this , map , storeName ) ;
59- }
60-
61- internal byte [ ] ? TryGet ( string ? storeName , byte [ ] ? key ) => TryGet ( storeName , GetTrackingMap ( storeName ) , key ) ;
62-
63- internal byte [ ] ? TryGet ( string ? storeName , TrackingMap map , byte [ ] ? key )
64- {
65- if ( map . TryGetValue ( key ?? Array . Empty < byte > ( ) , out var mapValue ) )
45+ IReadOnlyStore ? roStore = null ;
46+ try
6647 {
67- return mapValue . Match < byte [ ] ? > ( v => v , n => null ) ;
48+ roStore = storageProvider ? . GetStore ( path ) ;
6849 }
50+ catch { }
6951
70- return GetReadOnlyStore ( storeName ) . TryGet ( key ) ;
71- }
72-
73- internal IEnumerable < ( byte [ ] Key , byte [ ] ? Value ) > Seek ( string ? storeName , byte [ ] ? key , SeekDirection direction )
74- => Seek ( storeName , GetTrackingMap ( storeName ) , key , direction ) ;
75-
76- internal IEnumerable < ( byte [ ] Key , byte [ ] ? Value ) > Seek ( string ? storeName , TrackingMap map , byte [ ] ? key , SeekDirection direction )
77- {
78- key ??= Array . Empty < byte > ( ) ;
79- var comparer = direction == SeekDirection . Forward ? ByteArrayComparer . Default : ByteArrayComparer . Reverse ;
80-
81- var memoryItems = map
82- . Where ( kvp => kvp . Value . IsT0 )
83- . Where ( kvp => key . Length == 0 || comparer . Compare ( kvp . Key , key ) >= 0 )
84- . Select ( kvp => ( kvp . Key , Value : kvp . Value . AsT0 ) ) ;
85-
86- var storeItems = GetReadOnlyStore ( storeName )
87- . Seek ( key , direction )
88- . Where < ( byte [ ] Key , byte [ ] ? Value ) > ( kvp => ! map . ContainsKey ( kvp . Key ) ) ;
89-
90- return memoryItems . Concat ( storeItems ) . OrderBy ( kvp => kvp . Key , comparer ) ;
91- }
92-
93- internal void Update ( string ? storeName , byte [ ] ? key , OneOf < byte [ ] ? , None > value )
94- {
95- var trackingMap = GetTrackingMap ( storeName ) ;
96- trackingMap = trackingMap . SetItem ( key ?? Array . Empty < byte > ( ) , value ) ;
97- UpdateTrackingMap ( storeName , trackingMap ) ;
98- }
99-
100- internal void Update ( string ? storeName , TrackingMap changes )
101- {
102- var trackingMap = GetTrackingMap ( storeName ) ;
103- foreach ( var change in changes )
104- {
105- trackingMap = trackingMap . SetItem ( change . Key , change . Value ) ;
106- }
107- UpdateTrackingMap ( storeName , trackingMap ) ;
108- }
109-
110- void UpdateTrackingMap ( string ? storeName , TrackingMap changes )
111- {
112- if ( storeName == null )
113- {
114- defaultTrackingMap = changes ;
115- }
116- else
117- {
118- trackingMaps = trackingMaps . SetItem ( storeName , changes ) ;
119- }
52+ return roStore ?? NullStore . Instance ;
12053 }
12154 }
12255}
0 commit comments