6
6
//! immutable nature.
7
7
8
8
use crate :: utils;
9
- use rusqlite:: Connection ;
9
+ use rusqlite:: { params , Connection } ;
10
10
use std:: {
11
11
env,
12
- process:: Command ,
13
12
sync:: { Arc , Mutex } ,
14
13
} ;
15
14
@@ -44,24 +43,16 @@ impl Ledger {
44
43
let path = Ledger :: get_database_path ( path) ;
45
44
let _ = utils:: initialize_logger ( ) ;
46
45
47
- // Check if database has another connections.
48
- let is_open = {
49
- let ret = Command :: new ( "lsof" )
50
- . args ( [ & path] )
51
- . output ( )
52
- . expect ( "failed to execute process" ) ;
53
-
54
- !ret. stdout . is_empty ( )
55
- } ;
56
-
57
46
let database = Connection :: open ( path. clone ( ) ) . unwrap ( ) ;
58
47
59
48
// If database has another connections, skip clearing.
60
- if !is_open {
49
+ if Ledger :: get_database_connection_count ( & database ) == 0 {
61
50
tracing:: trace!( "Creating new database at path {path}" ) ;
51
+
62
52
Ledger :: drop_tables ( & database) . unwrap ( ) ;
63
53
Ledger :: create_tables ( & database) . unwrap ( ) ;
64
54
}
55
+ Ledger :: increment_connection_count ( & database) ;
65
56
66
57
tracing:: trace!( "Database connection to {path} is established" ) ;
67
58
@@ -95,13 +86,51 @@ impl Ledger {
95
86
}
96
87
}
97
88
89
+ /// Returns current connection count to the database. If not zero
90
+ fn get_database_connection_count ( database : & Connection ) -> i64 {
91
+ let count = database. query_row ( "SELECT count FROM connection_info" , params ! [ ] , |row| {
92
+ Ok ( row. get :: < _ , i64 > ( 0 ) . unwrap ( ) )
93
+ } ) ;
94
+
95
+ let count = match count {
96
+ Ok ( count) => count,
97
+ Err ( _) => 0 ,
98
+ } ;
99
+ tracing:: trace!( "Current connection count: {count}" ) ;
100
+
101
+ count
102
+ }
103
+
104
+ /// Increments connection count.
105
+ fn increment_connection_count ( database : & Connection ) {
106
+ let count = Self :: get_database_connection_count ( database) + 1 ;
107
+ tracing:: trace!( "Incrementing connection count to {count}..." ) ;
108
+
109
+ database
110
+ . execute ( "UPDATE connection_info SET count = ?1" , params ! [ count] )
111
+ . unwrap ( ) ;
112
+ }
113
+
114
+ /// Decrements connection count.
115
+ fn decrement_connection_count ( & self ) {
116
+ let count = Self :: get_database_connection_count ( & self . database . lock ( ) . unwrap ( ) ) - 1 ;
117
+ tracing:: trace!( "Decrementing connection count to {count}..." ) ;
118
+
119
+ self . database
120
+ . lock ( )
121
+ . unwrap ( )
122
+ . execute ( "UPDATE connection_info SET count = ?1" , params ! [ count] )
123
+ . unwrap ( ) ;
124
+ }
125
+
98
126
fn get_database_path ( path : & str ) -> String {
99
127
env:: temp_dir ( ) . to_str ( ) . unwrap ( ) . to_owned ( ) + "/bitcoin_mock_rpc_" + path
100
128
}
101
129
102
130
fn drop_tables ( database : & Connection ) -> Result < ( ) , rusqlite:: Error > {
103
131
database. execute_batch (
104
132
"
133
+ DROP TABLE IF EXISTS connection_info;
105
134
DROP TABLE IF EXISTS blocks;
106
135
DROP TABLE IF EXISTS mempool;
107
136
DROP TABLE IF EXISTS transactions;
@@ -117,6 +146,14 @@ impl Ledger {
117
146
fn create_tables ( database : & Connection ) -> Result < ( ) , rusqlite:: Error > {
118
147
database. execute_batch (
119
148
"
149
+ CREATE TABLE connection_info
150
+ (
151
+ count INTEGER NOT NULL
152
+
153
+ CONSTRAINT count PRIMARY KEY
154
+ );
155
+ INSERT INTO connection_info (count) VALUES (0);
156
+
120
157
CREATE TABLE blocks
121
158
(
122
159
height INTEGER NOT NULL,
@@ -155,6 +192,12 @@ impl Ledger {
155
192
}
156
193
}
157
194
195
+ impl Drop for Ledger {
196
+ fn drop ( & mut self ) {
197
+ self . decrement_connection_count ( ) ;
198
+ }
199
+ }
200
+
158
201
#[ cfg( test) ]
159
202
mod tests {
160
203
use super :: * ;
@@ -163,4 +206,11 @@ mod tests {
163
206
fn new ( ) {
164
207
let _should_not_panic = Ledger :: new ( "ledger_new" ) ;
165
208
}
209
+
210
+ #[ test]
211
+ fn concurrent_connections ( ) {
212
+ let _ledger = Ledger :: new ( "concurrent_connections" ) ;
213
+
214
+ let _ledger2 = Ledger :: new ( "concurrent_connections" ) ;
215
+ }
166
216
}
0 commit comments