Skip to content
This repository was archived by the owner on Jul 11, 2021. It is now read-only.

Commit 85c654e

Browse files
author
Simone Mosciatti
committed
finish implementation of Backup -> Copy (now called Copy) in async enviroment, also add tests
1 parent 0dfb720 commit 85c654e

3 files changed

Lines changed: 88 additions & 29 deletions

File tree

redisql_lib/src/redis.rs

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -435,9 +435,9 @@ pub unsafe fn string_ptr_len(
435435
str: *mut rm::ffi::RedisModuleString,
436436
) -> &'static str {
437437
let mut len = 0;
438-
let base = rm::ffi::RedisModule_StringPtrLen.unwrap()(
439-
str, &mut len,
440-
) as *mut u8;
438+
let base =
439+
rm::ffi::RedisModule_StringPtrLen.unwrap()(str, &mut len)
440+
as *mut u8;
441441
let slice = slice::from_raw_parts(base, len);
442442
str::from_utf8_unchecked(slice)
443443
}
@@ -489,9 +489,9 @@ pub enum Command {
489489
arguments: Vec<&'static str>,
490490
client: BlockedClient,
491491
},
492-
Copy {
493-
source: Arc<Mutex<sql::RawConnection>>,
494-
destination: Arc<Mutex<sql::RawConnection>>,
492+
MakeCopy {
493+
source: DBKey,
494+
destination: DBKey,
495495
client: BlockedClient,
496496
},
497497
}
@@ -545,6 +545,32 @@ pub fn do_query(
545545
}
546546
}
547547

548+
/// implements the copy of the source database into the destination one
549+
/// it also leak the two DBKeys
550+
pub fn do_copy(
551+
source: DBKey,
552+
destination: DBKey,
553+
) -> Result<QueryResult, err::RediSQLError> {
554+
let source_connection = source.loop_data.get_db();
555+
let destination_connection = destination.loop_data.get_db();
556+
557+
let backup_result = {
558+
let source_db = source_connection.lock().unwrap();
559+
let destination_db = destination_connection.lock().unwrap();
560+
match make_backup(&source_db, &destination_db) {
561+
Err(e) => Err(RediSQLError::from(e)),
562+
Ok(_) => Ok(QueryResult::OK {}),
563+
}
564+
};
565+
566+
restore_previous_statements(&destination.loop_data);
567+
568+
std::mem::forget(source);
569+
std::mem::forget(destination);
570+
571+
backup_result
572+
}
573+
548574
fn bind_statement<'a>(
549575
stmt: &'a MultiStatement,
550576
arguments: &[&str],
@@ -577,6 +603,13 @@ impl error::Error for RedisError {
577603
}
578604
}
579605

606+
/// restore_previous_statements wread the statements written in the database and add them to the
607+
/// loopdata datastructure.
608+
/// At the moment this function returns `()` no matter if there are errors or not.
609+
/// Errors are pretty unlikely, especially if nobody touched manually the metadata database, but
610+
/// still they may happens.
611+
/// I am not sure if it is a good idea or if I should upgrade the code to return an error, and
612+
/// maybe just ignore the error to keep the whole flow as it is now.
580613
fn restore_previous_statements<'a, L: 'a + LoopData>(
581614
loopdata: &L,
582615
) -> () {
@@ -726,18 +759,13 @@ pub fn listen_and_execute<'a, L: 'a + LoopData>(
726759
},
727760
);
728761
}
729-
Ok(Command::Copy {
762+
Ok(Command::MakeCopy {
730763
source,
731764
destination,
732765
client,
733766
}) => {
734-
let source = source.lock().unwrap();
735-
let destination = destination.lock().unwrap();
736-
let result = match make_backup(&source, &destination)
737-
{
738-
Err(e) => Err(RediSQLError::from(e)),
739-
Ok(_) => Ok(QueryResult::OK {}),
740-
};
767+
// The DBKeys MUST be leaked, they are leaked by do_copy
768+
let result = do_copy(source, destination);
741769
return_value(&client, result);
742770
}
743771
Ok(Command::Stop) => {
@@ -819,7 +847,7 @@ impl Drop for DBKey {
819847
pub fn create_metadata_table(
820848
db: Arc<Mutex<sql::RawConnection>>,
821849
) -> Result<(), sql::SQLite3Error> {
822-
let statement = "CREATE TABLE RediSQLMetadata(data_type TEXT, key TEXT, value TEXT);";
850+
let statement = "CREATE TABLE IF NOT EXISTS RediSQLMetadata(data_type TEXT, key TEXT, value TEXT);";
823851

824852
let stmt = MultiStatement::new(db, statement)?;
825853
stmt.execute()?;
@@ -1018,10 +1046,8 @@ pub fn get_dbkeyptr_from_name(
10181046
rm::ffi::RedisModule_KeyType.unwrap()(safe_key.key)
10191047
};
10201048
if unsafe {
1021-
rm::ffi::DBType
1022-
== rm::ffi::RedisModule_ModuleTypeGetType.unwrap()(
1023-
safe_key.key,
1024-
)
1049+
rm::ffi::DBType == rm::ffi::RedisModule_ModuleTypeGetType
1050+
.unwrap()(safe_key.key)
10251051
} {
10261052
let db_ptr = unsafe {
10271053
rm::ffi::RedisModule_ModuleTypeGetValue.unwrap()(

src/lib.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -801,12 +801,12 @@ unsafe extern "C" fn rdb_load(
801801
}
802802

803803
#[allow(non_snake_case)]
804-
extern "C" fn Backup(
804+
extern "C" fn MakeCopy(
805805
ctx: *mut r::rm::ffi::RedisModuleCtx,
806806
argv: *mut *mut r::rm::ffi::RedisModuleString,
807807
argc: ::std::os::raw::c_int,
808808
) -> i32 {
809-
debug!("Backup | Start");
809+
debug!("MakeCopy | Start");
810810
let (context, argvector) = r::create_argument(ctx, argv, argc);
811811

812812
if argvector.len() != 3 {
@@ -862,23 +862,27 @@ extern "C" fn Backup(
862862
},
863863
};
864864

865+
/*
865866
let source_connection = source_db.loop_data.get_db();
866867
let dest_connection = dest_db.loop_data.get_db();
868+
*/
869+
let ch = &source_db.tx.clone();
867870

868-
let cmd = r::Command::Copy {
869-
source: source_connection,
870-
destination: dest_connection,
871+
let cmd = r::Command::MakeCopy {
872+
source: source_db,
873+
destination: dest_db,
871874
client: blocked_client,
872875
};
873876

874-
let ch = &source_db.tx.clone();
877+
/*
875878
std::mem::forget(source_db);
876879
std::mem::forget(dest_db);
880+
*/
877881

878-
debug!("Backup | End");
882+
debug!("MakeCopy | End");
879883
match ch.send(cmd) {
880884
Ok(()) => {
881-
debug!("Backup | Successfully send command");
885+
debug!("MakeCopy | Successfully send command");
882886
r::rm::ffi::REDISMODULE_OK
883887
}
884888
Err(_) => r::rm::ffi::REDISMODULE_OK,
@@ -1031,9 +1035,9 @@ pub extern "C" fn RedisModule_OnLoad(
10311035

10321036
match register_function(
10331037
&ctx,
1034-
String::from("REDISQL.BACKUP"),
1038+
String::from("REDISQL.COPY"),
10351039
String::from("readonly"),
1036-
Backup,
1040+
MakeCopy,
10371041
) {
10381042
Ok(()) => (),
10391043
Err(e) => return e,

test/correctness/test.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,35 @@ def test_statement_after_rdb_load(self):
563563
self.assertTrue([4L, "cat:4", "4"] in result)
564564

565565

566+
class TestCopy(TestRediSQLWithExec):
567+
def test_copy_mem_from_mem(self):
568+
done = self.exec_naked("REDISQL.CREATE_DB", "DB1")
569+
self.assertEquals(done, "OK")
570+
done = self.exec_naked("REDISQL.CREATE_DB", "DB2")
571+
self.assertEquals(done, "OK")
572+
done = self.exec_naked("REDISQL.EXEC", "DB1", "CREATE TABLE foo(a INT);")
573+
self.assertEquals(done, ["DONE", 0L])
574+
575+
for i in xrange(10):
576+
done = self.exec_naked("REDISQL.EXEC", "DB1", "INSERT INTO foo VALUES({})".format(i))
577+
self.assertEquals(done, ["DONE", 1L])
578+
579+
done = self.exec_naked("REDISQL.COPY", "DB1", "DB2")
580+
result = self.exec_naked("REDISQL.QUERY", "DB2", "SELECT a FROM foo ORDER BY a")
581+
self.assertEquals(result, [[0L], [1L], [2L], [3L], [4L], [5L], [6L], [7L], [8L], [9L]])
582+
583+
def test_statements_copy_mem_from_mem(self):
584+
done = self.exec_naked("REDISQL.CREATE_DB", "DB1")
585+
self.assertEquals(done, "OK")
586+
done = self.exec_naked("REDISQL.CREATE_DB", "DB2")
587+
self.assertEquals(done, "OK")
588+
done = self.exec_naked("REDISQL.CREATE_STATEMENT", "DB1", "select1", "SELECT 1;")
589+
self.assertEquals(done, "OK")
590+
591+
done = self.exec_naked("REDISQL.COPY", "DB1", "DB2")
592+
result = self.exec_naked("REDISQL.QUERY_STATEMENT", "DB2", "select1")
593+
self.assertEquals(result, [[1L]])
594+
566595

567596
if __name__ == '__main__':
568597
unittest.main()

0 commit comments

Comments
 (0)