2
2
3
3
use std:: collections:: BTreeMap ;
4
4
use std:: collections:: BTreeSet ;
5
- use std:: time:: Instant ;
5
+ use std:: time:: { Duration , Instant } ;
6
6
7
7
use anyhow:: { Context as _, Result , ensure} ;
8
8
use deltachat_contact_tools:: EmailAddress ;
@@ -21,7 +21,7 @@ use crate::login_param::ConfiguredLoginParam;
21
21
use crate :: message:: MsgId ;
22
22
use crate :: provider:: get_provider_by_domain;
23
23
use crate :: sql:: Sql ;
24
- use crate :: tools:: inc_and_check;
24
+ use crate :: tools:: { Time , inc_and_check, time_elapsed } ;
25
25
26
26
const DBVERSION : i32 = 68 ;
27
27
const VERSION_CFG : & str = "dbversion" ;
@@ -1245,6 +1245,10 @@ CREATE INDEX gossip_timestamp_index ON gossip_timestamp (chat_id, fingerprint);
1245
1245
"key-contacts migration took {:?} in total." ,
1246
1246
start. elapsed( )
1247
1247
) ;
1248
+ // Schedule `msgs_to_key_contacts()`.
1249
+ context
1250
+ . set_config_internal ( Config :: LastHousekeeping , None )
1251
+ . await ?;
1248
1252
}
1249
1253
1250
1254
let new_version = sql
@@ -1830,62 +1834,110 @@ fn migrate_key_contacts(
1830
1834
}
1831
1835
1832
1836
// ======================= Step 5: =======================
1833
- // Rewrite `from_id` in messages
1837
+ // Prepare for rewriting `from_id`, `to_id ` in messages
1834
1838
{
1835
- let start = Instant :: now ( ) ;
1836
-
1837
- let mut encrypted_msgs_stmt = transaction
1838
- . prepare (
1839
- "SELECT id, from_id, to_id
1840
- FROM msgs
1841
- WHERE chat_id>9
1842
- AND (param GLOB '*\n c=1*' OR param GLOB 'c=1*')
1843
- ORDER BY id DESC LIMIT 10000" ,
1839
+ let mut contacts_map = autocrypt_key_contacts_with_reset_peerstate;
1840
+ for ( old, new) in autocrypt_key_contacts {
1841
+ contacts_map. insert ( old, new) ;
1842
+ }
1843
+ transaction
1844
+ . execute (
1845
+ "CREATE TABLE key_contacts_map (
1846
+ old_id INTEGER PRIMARY KEY NOT NULL,
1847
+ new_id INTEGER NOT NULL
1848
+ ) STRICT" ,
1849
+ ( ) ,
1844
1850
)
1845
1851
. context ( "Step 32" ) ?;
1846
- let mut rewrite_msg_stmt = transaction
1847
- . prepare ( "UPDATE msgs SET from_id=?, to_id=? WHERE id=?" )
1848
- . context ( "Step 32.1" ) ?;
1849
-
1850
- struct LoadedMsg {
1851
- id : u32 ,
1852
- from_id : u32 ,
1853
- to_id : u32 ,
1852
+ {
1853
+ let mut stmt = transaction
1854
+ . prepare ( "INSERT INTO key_contacts_map (old_id, new_id) VALUES (?, ?)" )
1855
+ . context ( "Step 33" ) ?;
1856
+ for ids in contacts_map {
1857
+ stmt. execute ( ids) . context ( "Step 34" ) ?;
1858
+ }
1854
1859
}
1860
+ transaction
1861
+ . execute (
1862
+ "INSERT INTO config (keyname, value) VALUES (
1863
+ 'first_key_contacts_msg_id',
1864
+ IFNULL((SELECT MAX(id)+1 FROM msgs), 0)
1865
+ )" ,
1866
+ ( ) ,
1867
+ )
1868
+ . context ( "Step 35" ) ?;
1869
+ }
1855
1870
1856
- let encrypted_msgs = encrypted_msgs_stmt
1857
- . query_map ( ( ) , |row| {
1858
- let id: u32 = row. get ( 0 ) ?;
1859
- let from_id: u32 = row. get ( 1 ) ?;
1860
- let to_id: u32 = row. get ( 2 ) ?;
1861
- Ok ( LoadedMsg { id, from_id, to_id } )
1862
- } )
1863
- . context ( "Step 33" ) ?;
1864
-
1865
- for msg in encrypted_msgs {
1866
- let msg = msg. context ( "Step 34" ) ?;
1867
-
1868
- let new_from_id = * autocrypt_key_contacts
1869
- . get ( & msg. from_id )
1870
- . or_else ( || autocrypt_key_contacts_with_reset_peerstate. get ( & msg. from_id ) )
1871
- . unwrap_or ( & msg. from_id ) ;
1872
-
1873
- let new_to_id = * autocrypt_key_contacts
1874
- . get ( & msg. to_id )
1875
- . or_else ( || autocrypt_key_contacts_with_reset_peerstate. get ( & msg. to_id ) )
1876
- . unwrap_or ( & msg. to_id ) ;
1871
+ Ok ( ( ) )
1872
+ }
1877
1873
1878
- rewrite_msg_stmt
1879
- . execute ( ( new_from_id, new_to_id, msg. id ) )
1880
- . context ( "Step 35" ) ?;
1874
+ /// Rewrite `from_id`, `to_id` in >= 1000 messages starting from the newest ones, to key-contacts.
1875
+ pub ( crate ) async fn msgs_to_key_contacts ( context : & Context ) -> Result < ( ) > {
1876
+ let sql = & context. sql ;
1877
+ if sql
1878
+ . get_raw_config_int64 ( "first_key_contacts_msg_id" )
1879
+ . await ?
1880
+ <= Some ( 0 )
1881
+ {
1882
+ return Ok ( ( ) ) ;
1883
+ }
1884
+ let trans_fn = |t : & mut rusqlite:: Transaction | {
1885
+ let mut first_key_contacts_msg_id: u64 = t
1886
+ . query_one (
1887
+ "SELECT CAST(value AS INTEGER) FROM config WHERE keyname='first_key_contacts_msg_id'" ,
1888
+ ( ) ,
1889
+ |row| row. get ( 0 ) ,
1890
+ )
1891
+ . context ( "Get first_key_contacts_msg_id" ) ?;
1892
+ let mut stmt = t
1893
+ . prepare (
1894
+ "UPDATE msgs SET
1895
+ from_id=IFNULL(
1896
+ (SELECT new_id FROM key_contacts_map WHERE old_id=msgs.from_id),
1897
+ from_id
1898
+ ),
1899
+ to_id=IFNULL(
1900
+ (SELECT new_id FROM key_contacts_map WHERE old_id=msgs.to_id),
1901
+ to_id
1902
+ )
1903
+ WHERE id>=? AND id<?
1904
+ AND chat_id>9
1905
+ AND (param GLOB '*\n c=1*' OR param GLOB 'c=1*')" ,
1906
+ )
1907
+ . context ( "Prepare stmt" ) ?;
1908
+ let msgs_to_migrate = 1000 ;
1909
+ let mut msgs_migrated: u64 = 0 ;
1910
+ while first_key_contacts_msg_id > 0 && msgs_migrated < msgs_to_migrate {
1911
+ let start_msg_id = first_key_contacts_msg_id. saturating_sub ( msgs_to_migrate) ;
1912
+ let cnt: u64 = stmt
1913
+ . execute ( ( start_msg_id, first_key_contacts_msg_id) )
1914
+ . context ( "UPDATE msgs" ) ?
1915
+ . try_into ( ) ?;
1916
+ msgs_migrated += cnt;
1917
+ first_key_contacts_msg_id = start_msg_id;
1918
+ }
1919
+ t. execute (
1920
+ "UPDATE config SET value=? WHERE keyname='first_key_contacts_msg_id'" ,
1921
+ ( first_key_contacts_msg_id, ) ,
1922
+ )
1923
+ . context ( "Update first_key_contacts_msg_id" ) ?;
1924
+ Ok ( ( msgs_migrated, first_key_contacts_msg_id) )
1925
+ } ;
1926
+ let start = Time :: now ( ) ;
1927
+ let mut msgs_migrated = 0 ;
1928
+ loop {
1929
+ let ( n, first_key_contacts_msg_id) = sql. transaction ( trans_fn) . await ?;
1930
+ msgs_migrated += n;
1931
+ if first_key_contacts_msg_id == 0 || time_elapsed ( & start) >= Duration :: from_millis ( 500 ) {
1932
+ break ;
1881
1933
}
1882
- info ! (
1883
- context,
1884
- "Rewriting msgs to key-contacts took {:?}." ,
1885
- start. elapsed( )
1886
- ) ;
1887
1934
}
1888
-
1935
+ sql. uncache_raw_config ( "first_key_contacts_msg_id" ) . await ;
1936
+ info ! (
1937
+ context,
1938
+ "Rewriting {msgs_migrated} msgs to key-contacts took {:?}." ,
1939
+ time_elapsed( & start) ,
1940
+ ) ;
1889
1941
Ok ( ( ) )
1890
1942
}
1891
1943
0 commit comments