@@ -27,6 +27,7 @@ use super::StateGroupEntry;
2727/// specific room.
2828///
2929/// Returns with the state_group map and the id of the last group that was used
30+ /// Or None if there are no state groups within the range given
3031///
3132/// # Arguments
3233///
@@ -36,6 +37,8 @@ use super::StateGroupEntry;
3637/// * `min_state_group` - If specified, then only fetch the entries for state
3738/// groups greater than (but not equal) to this number. It
3839/// also requires groups_to_compress to be specified
40+ /// * `max_state_group` - If specified, then only fetch the entries for state
41+ /// groups lower than or equal to this number.
3942/// * 'groups_to_compress' - The number of groups to get from the database before stopping
4043
4144pub fn get_data_from_db (
@@ -44,7 +47,7 @@ pub fn get_data_from_db(
4447 min_state_group : Option < i64 > ,
4548 groups_to_compress : Option < i64 > ,
4649 max_state_group : Option < i64 > ,
47- ) -> ( BTreeMap < i64 , StateGroupEntry > , i64 ) {
50+ ) -> Option < ( BTreeMap < i64 , StateGroupEntry > , i64 ) > {
4851 // connect to the database
4952 let mut builder = SslConnector :: builder ( SslMethod :: tls ( ) ) . unwrap ( ) ;
5053 builder. set_verify ( SslVerifyMode :: NONE ) ;
@@ -53,16 +56,27 @@ pub fn get_data_from_db(
5356 let mut client = Client :: connect ( db_url, connector)
5457 . unwrap_or_else ( |e| panic ! ( "Error connecting to the database: {}" , e) ) ;
5558
56- let state_group_map: BTreeMap < i64 , StateGroupEntry > = BTreeMap :: new ( ) ;
59+ // Search for the group id of the groups_to_compress'th group after min_state_group
60+ // If this is saved, then the compressor can continue by having min_state_group being
61+ // set to this maximum. If no such group can be found then return None.
5762
58- load_map_from_db (
63+ let max_group_found = find_max_group (
5964 & mut client,
6065 room_id,
6166 min_state_group,
6267 groups_to_compress,
6368 max_state_group,
69+ ) ?;
70+
71+ let state_group_map: BTreeMap < i64 , StateGroupEntry > = BTreeMap :: new ( ) ;
72+
73+ Some ( load_map_from_db (
74+ & mut client,
75+ room_id,
76+ min_state_group,
77+ max_group_found,
6478 state_group_map,
65- )
79+ ) )
6680}
6781
6882/// Fetch the entries in state_groups_state (and their prev groups) for a
@@ -71,6 +85,7 @@ pub fn get_data_from_db(
7185/// of each of the levels (as they were at the end of the last run of the compressor)
7286///
7387/// Returns with the state_group map and the id of the last group that was used
88+ /// Or None if there are no state groups within the range given
7489///
7590/// # Arguments
7691///
@@ -81,8 +96,6 @@ pub fn get_data_from_db(
8196/// groups greater than (but not equal) to this number. It
8297/// also requires groups_to_compress to be specified
8398/// * 'groups_to_compress' - The number of groups to get from the database before stopping
84- /// * `max_state_group` - If specified, then only fetch the entries for state
85- /// groups lower than or equal to this number.
8699/// * 'level_info' - The maximum size, current length and current head for each
87100/// level (as it was when the compressor last finished for this
88101/// room)
@@ -92,7 +105,7 @@ pub fn reload_data_from_db(
92105 min_state_group : Option < i64 > ,
93106 groups_to_compress : Option < i64 > ,
94107 level_info : & [ Level ] ,
95- ) -> ( BTreeMap < i64 , StateGroupEntry > , i64 ) {
108+ ) -> Option < ( BTreeMap < i64 , StateGroupEntry > , i64 ) > {
96109 // connect to the database
97110 let mut builder = SslConnector :: builder ( SslMethod :: tls ( ) ) . unwrap ( ) ;
98111 builder. set_verify ( SslVerifyMode :: NONE ) ;
@@ -101,20 +114,30 @@ pub fn reload_data_from_db(
101114 let mut client = Client :: connect ( db_url, connector)
102115 . unwrap_or_else ( |e| panic ! ( "Error connecting to the database: {}" , e) ) ;
103116
117+ // Search for the group id of the groups_to_compress'th group after min_state_group
118+ // If this is saved, then the compressor can continue by having min_state_group being
119+ // set to this maximum.If no such group can be found then return None.
120+ let max_group_found = find_max_group (
121+ & mut client,
122+ room_id,
123+ min_state_group,
124+ groups_to_compress,
125+ // max state group not used when saving and loading
126+ None ,
127+ ) ?;
128+
104129 // load just the state_groups at the head of each level
105130 // this doesn't load their predecessors as that will be done at the end of
106131 // load_map_from_db()
107132 let state_group_map: BTreeMap < i64 , StateGroupEntry > = load_level_heads ( & mut client, level_info) ;
108133
109- load_map_from_db (
134+ Some ( load_map_from_db (
110135 & mut client,
111136 room_id,
112137 min_state_group,
113- groups_to_compress,
114- // max state group not used when saving and loading
115- None ,
138+ max_group_found,
116139 state_group_map,
117- )
140+ ) )
118141}
119142
120143/// Finds the state_groups that are at the head of each compressor level
@@ -181,28 +204,16 @@ fn load_level_heads(client: &mut Client, level_info: &[Level]) -> BTreeMap<i64,
181204/// * `min_state_group` - If specified, then only fetch the entries for state
182205/// groups greater than (but not equal) to this number. It
183206/// also requires groups_to_compress to be specified
184- /// * 'groups_to_compress ' - The number of groups to get from the database before stopping
207+ /// * 'max_group_found ' - The last group to get from the database before stopping
185208/// * 'state_group_map' - The map to populate with the entries from the database
186209
187210fn load_map_from_db (
188211 client : & mut Client ,
189212 room_id : & str ,
190213 min_state_group : Option < i64 > ,
191- groups_to_compress : Option < i64 > ,
192- max_state_group : Option < i64 > ,
214+ max_group_found : i64 ,
193215 mut state_group_map : BTreeMap < i64 , StateGroupEntry > ,
194216) -> ( BTreeMap < i64 , StateGroupEntry > , i64 ) {
195- // Search for the group id of the groups_to_compress'th group after min_state_group
196- // If this is saved, then the compressor can continue by having min_state_group being
197- // set to this maximum
198- let max_group_found = find_max_group (
199- client,
200- room_id,
201- min_state_group,
202- groups_to_compress,
203- max_state_group,
204- ) ;
205-
206217 state_group_map. append ( & mut get_initial_data_from_db (
207218 client,
208219 room_id,
@@ -261,7 +272,8 @@ fn load_map_from_db(
261272/// Returns the group ID of the last group to be compressed
262273///
263274/// This can be saved so that future runs of the compressor only
264- /// continue from after this point
275+ /// continue from after this point. If no groups can be found in
276+ /// the range specified it returns None.
265277///
266278/// # Arguments
267279///
@@ -276,7 +288,7 @@ fn find_max_group(
276288 min_state_group : Option < i64 > ,
277289 groups_to_compress : Option < i64 > ,
278290 max_state_group : Option < i64 > ,
279- ) -> i64 {
291+ ) -> Option < i64 > {
280292 // Get list of state_id's in a certain room
281293 let mut query_chunk_of_ids = "SELECT id FROM state_groups WHERE room_id = $1" . to_string ( ) ;
282294 let params: Vec < & ( dyn ToSql + Sync ) > ;
@@ -285,22 +297,33 @@ fn find_max_group(
285297 query_chunk_of_ids = format ! ( "{} AND id <= {}" , query_chunk_of_ids, max)
286298 }
287299
288- // Adds additional constraint if a groups_to_compress has been specified
300+ // Adds additional constraint if a groups_to_compress or min_state_group have been specified
301+ // Note a min state group is only used if groups_to_compress also is
289302 if min_state_group. is_some ( ) && groups_to_compress. is_some ( ) {
290303 params = vec ! [ & room_id, & min_state_group, & groups_to_compress] ;
291304 query_chunk_of_ids = format ! ( r"{} AND id > $2 LIMIT $3" , query_chunk_of_ids) ;
305+ } else if groups_to_compress. is_some ( ) {
306+ params = vec ! [ & room_id, & groups_to_compress] ;
307+ query_chunk_of_ids = format ! ( r"{} LIMIT $2" , query_chunk_of_ids) ;
292308 } else {
293309 params = vec ! [ & room_id] ;
294- query_chunk_of_ids = format ! ( r"{} ORDER BY id DESC LIMIT 1" , query_chunk_of_ids) ;
295310 }
296311
297312 let sql_query = format ! (
298313 "SELECT id FROM ({}) AS ids ORDER BY ids.id DESC LIMIT 1" ,
299314 query_chunk_of_ids
300315 ) ;
301- let final_row = client. query ( sql_query. as_str ( ) , & params) . unwrap ( ) ;
302316
303- final_row. last ( ) . unwrap ( ) . get ( 0 )
317+ // This vector should have length 0 or 1
318+ let rows = client
319+ . query ( sql_query. as_str ( ) , & params)
320+ . expect ( "Something went wrong while querying the database" ) ;
321+
322+ // If no row can be found then return None
323+ let final_row = rows. last ( ) ?;
324+
325+ // Else return the id of the group found
326+ Some ( final_row. get :: < _ , i64 > ( 0 ) )
304327}
305328
306329/// Fetch the entries in state_groups_state and immediate predecessors for
@@ -330,22 +353,18 @@ fn get_initial_data_from_db(
330353 FROM state_groups AS m
331354 LEFT JOIN state_groups_state AS s ON (m.id = s.state_group)
332355 LEFT JOIN state_group_edges AS e ON (m.id = e.state_group)
333- WHERE m.room_id = $1
356+ WHERE m.room_id = $1 AND m.id <= $2
334357 "# ;
335358
336359 // Adds additional constraint if minimum state_group has been specified.
337- // note that the maximum group only affects queries if there is also a minimum
338- // otherwise it is assumed that ALL groups should be fetched
339360 let mut rows = if let Some ( min) = min_state_group {
340- let params: Vec < & dyn ToSql > = vec ! [ & room_id, & min, & max_group_found] ;
341- client. query_raw (
342- format ! ( r"{} AND m.id > $2 AND m.id <= $3" , sql) . as_str ( ) ,
343- params,
344- )
361+ let params: Vec < & dyn ToSql > = vec ! [ & room_id, & max_group_found, & min] ;
362+ client. query_raw ( format ! ( r"{} AND m.id > $3" , sql) . as_str ( ) , params)
345363 } else {
346- client. query_raw ( sql, & [ room_id] )
364+ let params: Vec < & dyn ToSql > = vec ! [ & room_id, & max_group_found] ;
365+ client. query_raw ( sql, params)
347366 }
348- . unwrap ( ) ;
367+ . expect ( "Something went wrong while querying the database" ) ;
349368
350369 // Copy the data from the database into a map
351370 let mut state_group_map: BTreeMap < i64 , StateGroupEntry > = BTreeMap :: new ( ) ;
@@ -481,13 +500,16 @@ fn test_pg_escape() {
481500 assert_eq ! ( & s[ start_pos - 1 ..start_pos] , "$" ) ;
482501}
483502
503+ /// Send changes to the database
504+ ///
484505/// Note that currently ignores config.transactions and wraps every state
485506/// group in it's own transaction (i.e. as if config.transactions was true)
486507///
487508/// # Arguments
488509///
489- /// * `config` - A Config struct that contains information
490- /// about the run (e.g. room_id and database url)
510+ /// * `db_url` - The URL of a Postgres database. This should be of the
511+ /// form: "postgresql://user:pass@domain:port/database"
512+ /// * `room_id` - The ID of the room in the database
491513/// * `old_map` - The state group data originally in the database
492514/// * `new_map` - The state group data generated by the compressor to
493515/// replace replace the old contents
0 commit comments