@@ -3,6 +3,7 @@ use std::ops::Range;
3
3
use std:: path:: { Path , PathBuf } ;
4
4
use std:: sync:: Arc ;
5
5
6
+ use anyhow:: Context ;
6
7
use async_trait:: async_trait;
7
8
use slog:: { debug, Logger } ;
8
9
use tokio:: { runtime:: Handle , task} ;
@@ -51,6 +52,7 @@ pub trait TransactionStore: Send + Sync {
51
52
}
52
53
53
54
/// Import and store [CardanoTransaction].
55
+ #[ derive( Clone ) ]
54
56
pub struct CardanoTransactionsImporter {
55
57
block_scanner : Arc < dyn BlockScanner > ,
56
58
transaction_store : Arc < dyn TransactionStore > ,
@@ -174,31 +176,29 @@ impl CardanoTransactionsImporter {
174
176
. store_block_range_roots ( block_ranges_with_merkle_root)
175
177
. await
176
178
}
177
-
178
- async fn import_transactions_and_block_ranges (
179
- & self ,
180
- up_to_beacon : BlockNumber ,
181
- ) -> StdResult < ( ) > {
182
- self . import_transactions ( up_to_beacon) . await ?;
183
- self . import_block_ranges ( up_to_beacon) . await
184
- }
185
179
}
186
180
187
181
#[ async_trait]
188
182
impl TransactionsImporter for CardanoTransactionsImporter {
189
183
async fn import ( & self , up_to_beacon : BlockNumber ) -> StdResult < ( ) > {
190
- task:: block_in_place ( move || {
184
+ let importer = self . clone ( ) ;
185
+ task:: spawn_blocking ( move || {
191
186
Handle :: current ( ) . block_on ( async move {
192
- self . import_transactions_and_block_ranges ( up_to_beacon)
193
- . await
187
+ importer. import_transactions ( up_to_beacon) . await ?;
188
+ importer. import_block_ranges ( up_to_beacon) . await ?;
189
+ Ok ( ( ) )
194
190
} )
195
191
} )
192
+ . await
193
+ . with_context ( || "TransactionsImporter - worker thread crashed" ) ?
196
194
}
197
195
}
198
196
199
197
#[ cfg( test) ]
200
198
mod tests {
201
- use mithril_persistence:: sqlite:: SqliteConnectionPool ;
199
+ use std:: sync:: atomic:: AtomicUsize ;
200
+ use std:: time:: Duration ;
201
+
202
202
use mockall:: mock;
203
203
204
204
use mithril_common:: cardano_block_scanner:: {
@@ -207,6 +207,7 @@ mod tests {
207
207
use mithril_common:: crypto_helper:: MKTree ;
208
208
use mithril_common:: entities:: { BlockNumber , BlockRangesSequence } ;
209
209
use mithril_persistence:: database:: repository:: CardanoTransactionRepository ;
210
+ use mithril_persistence:: sqlite:: SqliteConnectionPool ;
210
211
211
212
use crate :: database:: test_helper:: cardano_tx_db_connection;
212
213
use crate :: test_tools:: TestLogger ;
@@ -717,7 +718,7 @@ mod tests {
717
718
) ;
718
719
}
719
720
720
- #[ tokio:: test( flavor = "multi_thread" ) ]
721
+ #[ tokio:: test]
721
722
async fn importing_twice_starting_with_nothing_in_a_real_db_should_yield_transactions_in_same_order (
722
723
) {
723
724
let blocks = vec ! [
@@ -754,7 +755,7 @@ mod tests {
754
755
assert_eq ! ( cold_imported_transactions, warm_imported_transactions) ;
755
756
}
756
757
757
- #[ tokio:: test( flavor = "multi_thread" ) ]
758
+ #[ tokio:: test]
758
759
async fn when_rollbackward_should_remove_transactions ( ) {
759
760
let connection = cardano_tx_db_connection ( ) . unwrap ( ) ;
760
761
let repository = Arc :: new ( CardanoTransactionRepository :: new ( Arc :: new (
@@ -797,7 +798,7 @@ mod tests {
797
798
assert_eq ! ( expected_remaining_transactions, stored_transactions) ;
798
799
}
799
800
800
- #[ tokio:: test( flavor = "multi_thread" ) ]
801
+ #[ tokio:: test]
801
802
async fn when_rollbackward_should_remove_block_ranges ( ) {
802
803
let connection = cardano_tx_db_connection ( ) . unwrap ( ) ;
803
804
let repository = Arc :: new ( CardanoTransactionRepository :: new ( Arc :: new (
@@ -869,4 +870,92 @@ mod tests {
869
870
. collect:: <Vec <_>>( )
870
871
) ;
871
872
}
873
+
874
+ #[ tokio:: test]
875
+ async fn test_import_is_non_blocking ( ) {
876
+ static COUNTER : AtomicUsize = AtomicUsize :: new ( 0 ) ;
877
+ static MAX_COUNTER : usize = 25 ;
878
+ static WAIT_TIME : u64 = 50 ;
879
+
880
+ // Use a local set to ensure the counter task is not dispatched on a different thread
881
+ let local = task:: LocalSet :: new ( ) ;
882
+ local
883
+ . run_until ( async {
884
+ let importer = CardanoTransactionsImporter :: new_for_test (
885
+ Arc :: new ( DumbBlockScanner :: new ( ) ) ,
886
+ Arc :: new ( BlockingRepository {
887
+ wait_time : Duration :: from_millis ( WAIT_TIME ) ,
888
+ } ) ,
889
+ ) ;
890
+
891
+ let importer_future = importer. import ( 100 ) ;
892
+ let counter_task = task:: spawn_local ( async {
893
+ while COUNTER . load ( std:: sync:: atomic:: Ordering :: SeqCst ) < MAX_COUNTER {
894
+ tokio:: time:: sleep ( Duration :: from_millis ( 1 ) ) . await ;
895
+ COUNTER . fetch_add ( 1 , std:: sync:: atomic:: Ordering :: SeqCst ) ;
896
+ }
897
+ } ) ;
898
+ importer_future. await . unwrap ( ) ;
899
+
900
+ counter_task. abort ( ) ;
901
+ } )
902
+ . await ;
903
+
904
+ assert_eq ! (
905
+ MAX_COUNTER ,
906
+ COUNTER . load( std:: sync:: atomic:: Ordering :: SeqCst )
907
+ ) ;
908
+
909
+ struct BlockingRepository {
910
+ wait_time : Duration ,
911
+ }
912
+
913
+ impl BlockingRepository {
914
+ fn block_thread ( & self ) {
915
+ std:: thread:: sleep ( self . wait_time ) ;
916
+ }
917
+ }
918
+
919
+ #[ async_trait]
920
+ impl TransactionStore for BlockingRepository {
921
+ async fn get_highest_beacon ( & self ) -> StdResult < Option < ChainPoint > > {
922
+ self . block_thread ( ) ;
923
+ Ok ( None )
924
+ }
925
+
926
+ async fn get_highest_block_range ( & self ) -> StdResult < Option < BlockRange > > {
927
+ self . block_thread ( ) ;
928
+ Ok ( None )
929
+ }
930
+
931
+ async fn store_transactions ( & self , _: Vec < CardanoTransaction > ) -> StdResult < ( ) > {
932
+ self . block_thread ( ) ;
933
+ Ok ( ( ) )
934
+ }
935
+
936
+ async fn get_transactions_in_range (
937
+ & self ,
938
+ _: Range < BlockNumber > ,
939
+ ) -> StdResult < Vec < CardanoTransaction > > {
940
+ self . block_thread ( ) ;
941
+ Ok ( vec ! [ ] )
942
+ }
943
+
944
+ async fn store_block_range_roots (
945
+ & self ,
946
+ _: Vec < ( BlockRange , MKTreeNode ) > ,
947
+ ) -> StdResult < ( ) > {
948
+ self . block_thread ( ) ;
949
+ Ok ( ( ) )
950
+ }
951
+
952
+ async fn remove_rolled_back_transactions_and_block_range (
953
+ & self ,
954
+ _: SlotNumber ,
955
+ ) -> StdResult < ( ) > {
956
+ self . block_thread ( ) ;
957
+ Ok ( ( ) )
958
+ }
959
+ }
960
+ }
872
961
}
0 commit comments