@@ -5,6 +5,7 @@ use futures::channel::mpsc;
5
5
use futures:: {
6
6
future, join, pin_mut, stream, try_join, FutureExt , SinkExt , StreamExt , TryStreamExt ,
7
7
} ;
8
+ use std:: convert:: TryInto ;
8
9
use std:: fmt:: Write ;
9
10
use std:: time:: Duration ;
10
11
use tokio:: net:: TcpStream ;
@@ -21,7 +22,6 @@ mod parse;
21
22
#[ cfg( feature = "runtime" ) ]
22
23
mod runtime;
23
24
mod types;
24
- use std:: sync:: { Arc , Mutex } ;
25
25
use std:: thread;
26
26
async fn connect_raw ( s : & str ) -> Result < ( Client , Connection < TcpStream , NoTlsStream > ) , Error > {
27
27
let socket = TcpStream :: connect ( "127.0.0.1:5433" ) . await . unwrap ( ) ;
@@ -808,70 +808,77 @@ async fn replication_start() {
808
808
809
809
client
810
810
. batch_execute (
811
- "CREATE TABLE IF NOT EXISTS foo (
811
+ "CREATE TABLE IF NOT EXISTS replication (
812
812
id SERIAL,
813
813
name TEXT
814
814
);
815
- DROP PUBLICATION IF EXISTS rust;
816
- CREATE PUBLICATION rust FOR ALL TABLES;
817
815
" ,
818
816
)
819
817
. await
820
818
. unwrap ( ) ;
821
819
let _ = r_client
822
- . simple_query ( "DROP_REPLICATION_SLOT rust_slot" )
823
- . await ;
824
- // let _ = r_client.simple_query("CREATE_REPLICATION_SLOT rust_slot LOGICAL pgoutput NOEXPORT_SNAPSHOT").await;
825
- let _ = r_client
826
- . simple_query ( "CREATE_REPLICATION_SLOT rust_slot LOGICAL wal2json NOEXPORT_SNAPSHOT" )
820
+ . simple_query (
821
+ "CREATE_REPLICATION_SLOT rust_slot TEMPORARY LOGICAL test_decoding NOEXPORT_SNAPSHOT" ,
822
+ )
827
823
. await ;
828
824
829
825
let stream = r_client
830
- //.start_replication("START_REPLICATION SLOT rust_slot LOGICAL 0/0 (proto_version '1', publication_names 'rust')")
831
- . start_replication ( "START_REPLICATION SLOT rust_slot LOGICAL 0/0 (\" pretty-print\" '1', \" format-version\" '2')" )
826
+ . start_replication (
827
+ "START_REPLICATION SLOT rust_slot LOGICAL 0/0 (\" skip-empty-xacts\" '1')" ,
828
+ )
832
829
. await
833
830
. unwrap ( ) ;
834
831
835
- let events = Arc :: new ( Mutex :: new ( vec ! [ ] ) ) ;
836
- let total_events = Arc :: new ( Mutex :: new ( 0 ) ) ;
837
- let total_events_1 = Arc :: clone ( & total_events) ;
838
- let events_1 = Arc :: clone ( & events) ;
839
- let t = tokio:: spawn ( async move {
840
- let events = stream. try_collect :: < Vec < _ > > ( ) . await . unwrap ( ) ;
841
- let mut num = total_events_1. lock ( ) . unwrap ( ) ;
842
- * num = events. len ( ) ;
843
- let mut ev = events_1. lock ( ) . unwrap ( ) ;
844
- * ev = events;
845
- } ) ;
846
-
847
832
client
848
- . query ( "INSERT INTO foo (name) VALUES ('ann')" , & [ ] )
833
+ . query ( "INSERT INTO replication (name) VALUES ('ann')" , & [ ] )
849
834
. await
850
835
. unwrap ( ) ;
851
- client
852
- . query ( "INSERT INTO foo (name) VALUES ('jim'), ('joe')" , & [ ] )
853
- . await
854
- . unwrap ( ) ;
855
- client. query ( "DROP TABLE foo" , & [ ] ) . await . unwrap ( ) ;
856
836
857
837
thread:: sleep ( time:: Duration :: from_secs ( 1 ) ) ; //give a chance to pg to send the events
858
838
let _ = r_client. stop_replication ( ) . await ;
859
- let _ = t. await ;
860
- println ! ( "events {:?}" , * events. lock( ) . unwrap( ) ) ;
861
- //assert_eq!(*total_events.lock().unwrap(), 2);
862
- for e in & * events. lock ( ) . unwrap ( ) {
839
+ let events = stream. try_collect :: < Vec < _ > > ( ) . await . unwrap ( ) ;
840
+ client. query ( "DROP TABLE replication" , & [ ] ) . await . unwrap ( ) ;
841
+
842
+ let mut total_events = 0 ;
843
+ for e in & events {
863
844
match e[ 0 ] . into ( ) {
864
845
'k' => {
865
- // let message_type = "keepalive";
866
- // println!("type: ({}), {}", message_type, e.len());
846
+ //keepalive message
847
+ let current_wal_end =
848
+ i64:: from_be_bytes ( e. slice ( 1 ..9 ) . as_ref ( ) . try_into ( ) . unwrap ( ) ) ;
849
+ let timestamp = i64:: from_be_bytes ( e. slice ( 9 ..17 ) . as_ref ( ) . try_into ( ) . unwrap ( ) ) ;
850
+ let reply: char = e[ 17 ] . into ( ) ;
851
+ println ! (
852
+ "keepalive tiemstamp: {} current_wal_end: {:X}/{:X} reply: {}" ,
853
+ timestamp,
854
+ ( current_wal_end >> 32 ) as i32 ,
855
+ current_wal_end as i32 ,
856
+ reply as i8
857
+ ) ;
867
858
}
868
859
'w' => {
869
- let message_type = "dataframe" ;
870
- let slice = e. slice ( 25 ..) ;
871
- let data = std:: str:: from_utf8 ( slice. as_ref ( ) ) . unwrap ( ) ;
872
- println ! ( "type: ({}), {}, {}" , message_type, e. len( ) , data) ;
860
+ // WAL message
861
+ let current_wal = i64:: from_be_bytes ( e. slice ( 1 ..9 ) . as_ref ( ) . try_into ( ) . unwrap ( ) ) ;
862
+ let current_wal_end =
863
+ i64:: from_be_bytes ( e. slice ( 9 ..17 ) . as_ref ( ) . try_into ( ) . unwrap ( ) ) ;
864
+ let timestamp = i64:: from_be_bytes ( e. slice ( 17 ..25 ) . as_ref ( ) . try_into ( ) . unwrap ( ) ) ;
865
+ let _data = e. slice ( 25 ..) ; //the format of these bytes depends on the logical decoder
866
+ println ! (
867
+ "WAL timestamp: {} current_wal: {:X}/{:X} current_wal_end: {:X}/{:X} {:?}" ,
868
+ timestamp,
869
+ ( current_wal >> 32 ) as i32 ,
870
+ current_wal as i32 ,
871
+ ( current_wal_end >> 32 ) as i32 ,
872
+ current_wal_end as i32 ,
873
+ _data
874
+ ) ;
875
+ total_events += 1 ;
876
+ //while in replication state, one needs to send updates from time to time like this
877
+ //let _ = r_pg_client.standby_status_update(current_wal, current_wal, current_wal).await.unwrap();
873
878
}
874
879
_ => { }
875
880
} ;
876
881
}
882
+ // in this case we receive 3 events (BEGIN,INSERT,COMMIT)
883
+ assert_eq ! ( total_events, 3 ) ;
877
884
}
0 commit comments