Skip to content

Commit e0634e7

Browse files
committed
Fix memory leak issues around Collection, Scope & QueryIndex
1 parent 3624f13 commit e0634e7

File tree

5 files changed

+52
-24
lines changed

5 files changed

+52
-24
lines changed

src/collection.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,16 @@ impl Collection {
6363
}
6464
}
6565

66+
/// References the object without taking ownership and increasing it's reference counter
67+
pub(crate) const fn wrap(cbl_ref: *mut CBLCollection) -> Self {
68+
Self { cbl_ref }
69+
}
70+
6671
////////
6772

6873
/// Returns the scope of the collection.
6974
pub fn scope(&self) -> Scope {
70-
unsafe { Scope::retain(CBLCollection_Scope(self.get_ref())) }
75+
unsafe { Scope::wrap(CBLCollection_Scope(self.get_ref())) }
7176
}
7277

7378
/// Returns the collection name.
@@ -90,7 +95,7 @@ impl Collection {
9095

9196
/// Returns the collection's database.
9297
pub fn database(&self) -> Database {
93-
unsafe { Database::wrap(CBLCollection_Database(self.get_ref())) }
98+
unsafe { Database::retain(CBLCollection_Database(self.get_ref())) }
9499
}
95100

96101
/// Returns the number of documents in the collection.

src/database.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ impl Database {
418418
if scope.is_null() {
419419
None
420420
} else {
421-
Some(Scope::retain(scope))
421+
Some(Scope::wrap(scope))
422422
}
423423
})
424424
}
@@ -445,7 +445,7 @@ impl Database {
445445
if collection.is_null() {
446446
None
447447
} else {
448-
Some(Collection::retain(collection))
448+
Some(Collection::wrap(collection))
449449
}
450450
})
451451
}
@@ -474,7 +474,7 @@ impl Database {
474474
)
475475
};
476476

477-
check_error(&error).map(|()| Collection::retain(collection))
477+
check_error(&error).map(|()| Collection::wrap(collection))
478478
}
479479

480480
/// Delete an existing collection.
@@ -499,7 +499,7 @@ impl Database {
499499
let mut error = CBLError::default();
500500
let scope = unsafe { CBLDatabase_DefaultScope(self.get_ref(), &mut error) };
501501

502-
check_error(&error).map(|()| Scope::retain(scope))
502+
check_error(&error).map(|()| Scope::wrap(scope))
503503
}
504504

505505
/// Returns the default collection.
@@ -511,7 +511,7 @@ impl Database {
511511
if collection.is_null() {
512512
None
513513
} else {
514-
Some(Collection::retain(collection))
514+
Some(Collection::wrap(collection))
515515
}
516516
})
517517
}
@@ -526,7 +526,7 @@ impl Database {
526526
if collection.is_null() {
527527
Err(Error::cbl_error(CouchbaseLiteError::NotFound))
528528
} else {
529-
Ok(Collection::retain(collection))
529+
Ok(Collection::wrap(collection))
530530
}
531531
}
532532

src/index.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
slice::{from_str, from_c_str, Slice},
1111
QueryLanguage, Array,
1212
collection::Collection,
13-
check_error, retain, CouchbaseLiteError,
13+
check_error, release, retain, CouchbaseLiteError,
1414
};
1515
use std::ffi::CString;
1616

@@ -149,12 +149,18 @@ impl QueryIndex {
149149
//////// CONSTRUCTORS:
150150

151151
/// Takes ownership of the object and increase it's reference counter.
152+
#[allow(dead_code)]
152153
pub(crate) fn retain(cbl_ref: *mut CBLQueryIndex) -> Self {
153154
Self {
154155
cbl_ref: unsafe { retain(cbl_ref) },
155156
}
156157
}
157158

159+
/// References the object without taking ownership and increasing it's reference counter
160+
pub(crate) const fn wrap(cbl_ref: *mut CBLQueryIndex) -> Self {
161+
Self { cbl_ref }
162+
}
163+
158164
////////
159165

160166
/// Returns the index's name.
@@ -172,6 +178,12 @@ impl QueryIndex {
172178
}
173179
}
174180

181+
impl Drop for QueryIndex {
182+
fn drop(&mut self) {
183+
unsafe { release(self.get_ref()) }
184+
}
185+
}
186+
175187
impl Database {
176188
/// Creates a value index.
177189
/// Indexes are persistent.
@@ -280,7 +292,7 @@ impl Collection {
280292
let slice = from_str(name);
281293
let index = unsafe { CBLCollection_GetIndex(self.get_ref(), slice.get_ref(), &mut err) };
282294
if !err {
283-
return Ok(QueryIndex::retain(index));
295+
return Ok(QueryIndex::wrap(index));
284296
}
285297
failure(err)
286298
}

src/scope.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,20 @@ pub struct Scope {
1919
impl Scope {
2020
pub const DEFAULT_NAME: &str = "_default";
2121

22+
//////// CONSTRUCTORS:
23+
24+
/// Takes ownership of the object and increase it's reference counter.
2225
pub(crate) fn retain(cbl_ref: *mut CBLScope) -> Self {
2326
Self {
2427
cbl_ref: unsafe { retain(cbl_ref) },
2528
}
2629
}
2730

31+
/// References the object without taking ownership and increasing it's reference counter
32+
pub(crate) const fn wrap(cbl_ref: *mut CBLScope) -> Self {
33+
Self { cbl_ref }
34+
}
35+
2836
/** Returns the name of the scope. */
2937
pub fn name(&self) -> String {
3038
unsafe {
@@ -36,7 +44,7 @@ impl Scope {
3644

3745
/** Returns the scope's database */
3846
pub fn database(&self) -> Database {
39-
unsafe { Database::wrap(CBLScope_Database(self.get_ref())) }
47+
unsafe { Database::retain(CBLScope_Database(self.get_ref())) }
4048
}
4149

4250
/** Returns the names of all collections in the scope. */
@@ -63,7 +71,7 @@ impl Scope {
6371
if collection.is_null() {
6472
None
6573
} else {
66-
Some(Collection::retain(collection))
74+
Some(Collection::wrap(collection))
6775
}
6876
})
6977
}

tests/utils.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,21 @@ where
4444
init_logging();
4545

4646
let start_inst_count = instance_count();
47-
let tmp_dir = TempDir::new("cbl_rust").expect("create temp dir");
48-
let cfg = DatabaseConfiguration {
49-
directory: tmp_dir.path(),
50-
#[cfg(feature = "enterprise")]
51-
encryption_key: None,
52-
};
53-
let mut db = Database::open(DB_NAME, Some(cfg)).expect("open db");
54-
assert!(Database::exists(DB_NAME, tmp_dir.path()));
55-
56-
f(&mut db);
57-
58-
db.delete().unwrap();
47+
48+
{
49+
let tmp_dir = TempDir::new("cbl_rust").expect("create temp dir");
50+
let cfg = DatabaseConfiguration {
51+
directory: tmp_dir.path(),
52+
#[cfg(feature = "enterprise")]
53+
encryption_key: None,
54+
};
55+
let mut db = Database::open(DB_NAME, Some(cfg)).expect("open db");
56+
assert!(Database::exists(DB_NAME, tmp_dir.path()));
57+
58+
f(&mut db);
59+
60+
db.delete().unwrap();
61+
}
5962

6063
if LEAK_CHECK.is_some() {
6164
info!("Checking if Couchbase Lite objects were leaked by this test");

0 commit comments

Comments
 (0)