Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CBL-6307: Database MMap Configuration API and tests #3333

Merged
merged 2 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Objective-C/CBLDatabase.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,9 @@ static C4DatabaseConfig2 c4DatabaseConfig2 (CBLDatabaseConfiguration *config) {

if (config.fullSync)
c4config.flags |= kC4DB_DiskSyncFull;
if (!config.mmapEnabled)
c4config.flags |= kC4DB_MmapDisabled;

#ifdef COUCHBASE_ENTERPRISE
if (config.encryptionKey)
c4config.encryptionKey = [CBLDatabase c4EncryptionKey: config.encryptionKey];
Expand Down
9 changes: 9 additions & 0 deletions Objective-C/CBLDatabaseConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic) BOOL fullSync;

/**
Enables or disables memory-mapped I/O. By default, memory-mapped I/O is enabled.
Disabling it may affect database performance. Typically, there is no need to modify this setting.

@note: Memory-mapped I/O is always disabled to prevent database corruption on macOS.
As a result, setting this configuration has no effect on the macOS platform.
*/
@property (nonatomic) BOOL mmapEnabled;

/**
Initializes the CBLDatabaseConfiguration object.
*/
Expand Down
4 changes: 3 additions & 1 deletion Objective-C/CBLDatabaseConfiguration.m
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ @implementation CBLDatabaseConfiguration {
BOOL _readonly;
}

@synthesize directory=_directory, fullSync=_fullSync;
@synthesize directory=_directory, fullSync=_fullSync, mmapEnabled=_mmapEnabled;

#ifdef COUCHBASE_ENTERPRISE
@synthesize encryptionKey=_encryptionKey;
Expand All @@ -49,12 +49,14 @@ - (instancetype) initWithConfig: (nullable CBLDatabaseConfiguration*)config
if (config) {
_directory = config.directory;
_fullSync = config.fullSync;
_mmapEnabled = config.mmapEnabled;
#ifdef COUCHBASE_ENTERPRISE
_encryptionKey = config.encryptionKey;
#endif
} else {
_directory = [CBLDatabaseConfiguration defaultDirectory];
_fullSync = kCBLDefaultDatabaseFullSync;
_mmapEnabled = kCBLDefaultDatabaseMmapEnabled;
}
}
return self;
Expand Down
5 changes: 4 additions & 1 deletion Objective-C/CBLDefaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
/** [NO] Full sync is off by default because the performance hit is seldom worth the benefit */
extern const BOOL kCBLDefaultDatabaseFullSync;

/** [NO] Memory mapped database files are disabled by default. Always disabled for macOS. */
extern const BOOL kCBLDefaultDatabaseMmapEnabled;

#pragma mark - CBLLogFileConfiguration

/** [NO] Plaintext is not used, and instead binary encoding is used in log files */
Expand Down Expand Up @@ -97,7 +100,7 @@ extern const BOOL kCBLDefaultVectorIndexIsLazy;
/** [kCBLSQ8] Vectors are encoded by using 8-bit Scalar Quantizer encoding, by default */
extern const CBLScalarQuantizerType kCBLDefaultVectorIndexEncoding;

/** [kCBLDistanceMetricEuclideanSquared] By default, vectors are compared using Euclidean metrics */
/** [kCBLDistanceMetricEuclideanSquared] By default, vectors are compared using Squared Euclidean metrics */
extern const CBLDistanceMetric kCBLDefaultVectorIndexDistanceMetric;

/** [0] By default, the value will be determined based on the number of centroids, encoding types, and the encoding parameters. */
Expand Down
2 changes: 2 additions & 0 deletions Objective-C/CBLDefaults.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

const BOOL kCBLDefaultDatabaseFullSync = NO;

const BOOL kCBLDefaultDatabaseMmapEnabled = YES;

#pragma mark - CBLLogFileConfiguration

const BOOL kCBLDefaultLogFileUsePlaintext = NO;
Expand Down
64 changes: 63 additions & 1 deletion Objective-C/Tests/DatabaseTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -2821,7 +2821,7 @@ - (void) testDBEventTrigged {
#pragma mark - Full Sync Option

/**
Test Spec for Database Full Sync Option https://github.com/couchbaselabs/couchbase-lite-api/blob/master/spec/tests/T0003-SQLite-Options.md
Test Spec v1.0.0: https://github.com/couchbaselabs/couchbase-lite-api/blob/master/spec/tests/T0003-SQLite-Options.md
*/

/**
Expand Down Expand Up @@ -2891,6 +2891,68 @@ - (void) testDBWithFullSync {
[self closeDatabase: db];
}

#pragma mark - MMap
/** Test Spec v1.0.1:
https://github.com/couchbaselabs/couchbase-lite-api/blob/master/spec/tests/T0006-MMap-Config.md
*/

/**
1. TestDefaultMMapConfig
Description
Test that the mmapEnabled default value is as expected and that it's setter and getter work.
Steps
1. Create a DatabaseConfiguration object.
2. Get and check that the value of the mmapEnabled property is true.
3. Set the mmapEnabled property to false and verify that the value is false.
4. Set the mmapEnabled property to true, and verify that the mmap value is true.
*/

- (void) testDefaultMMapConfig {
CBLDatabaseConfiguration* config = [[CBLDatabaseConfiguration alloc] init];
Assert(config.mmapEnabled);

config.mmapEnabled = false;
AssertFalse(config.mmapEnabled);

config.mmapEnabled = true;
Assert(config.mmapEnabled);
}

/**
2. TestDatabaseWithConfiguredMMap
Description
Test that a Database respects the mmapEnabled property.
Steps
1. Create a DatabaseConfiguration object and set mmapEnabled to false.
2. Create a database with the config.
3. Get the configuration object from the database and check that the mmapEnabled is false.
4. Use c4db_config2 to confirm that its config contains the kC4DB_MmapDisabled flag
5. Set the config's mmapEnabled property true
6. Create a database with the config.
7. Get the configuration object from the database and verify that mmapEnabled is true
8. Use c4db_config2 to confirm that its config doesn't contains the kC4DB_MmapDisabled flag
*/

- (void) testDatabaseWithConfiguredMMap {
NSError* err;
CBLDatabaseConfiguration* config = [[CBLDatabaseConfiguration alloc] init];

config.mmapEnabled = false;
CBLDatabase* db1 = [[CBLDatabase alloc] initWithName: @"mmap1" config: config error:&err];
CBLDatabaseConfiguration* tempConfig = [db1 config];
AssertFalse(tempConfig.mmapEnabled);
Assert(([db1 getC4DBConfig]->flags & kC4DB_MmapDisabled) == kC4DB_MmapDisabled);

config.mmapEnabled = true;
CBLDatabase* db2 = [[CBLDatabase alloc] initWithName: @"mmap2" config: config error:&err];
tempConfig = [db2 config];
Assert(tempConfig.mmapEnabled);
AssertFalse(([db2 getC4DBConfig]->flags & kC4DB_MmapDisabled) == kC4DB_MmapDisabled);

db1 = nil;
db2 = nil;
}

#pragma clang diagnostic pop

@end
11 changes: 11 additions & 0 deletions Swift/DatabaseConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ public struct DatabaseConfiguration {
/// is very safe but it is also dramatically slower.
public var fullSync: Bool = defaultFullSync

/// Enables or disables memory-mapped I/O. By default, memory-mapped I/O is enabled.
/// Disabling it may affect database performance. Typically, there is no need to modify this setting.
/// - Note: Memory-mapped I/O is always disabled to prevent database corruption on macOS.
/// As a result, setting this configuration has no effect on the macOS platform.
public var mmapEnabled: Bool = defaultMmapEnabled;

#if COUCHBASE_ENTERPRISE
/// The key to encrypt the database with.
public var encryptionKey: EncryptionKey?
Expand All @@ -53,6 +59,8 @@ public struct DatabaseConfiguration {
if let c = config {
self.directory = c.directory
self.fullSync = c.fullSync
self.mmapEnabled = c.mmapEnabled

#if COUCHBASE_ENTERPRISE
self.encryptionKey = c.encryptionKey
#endif
Expand All @@ -65,9 +73,12 @@ public struct DatabaseConfiguration {
let config = CBLDatabaseConfiguration()
config.directory = self.directory
config.fullSync = self.fullSync
config.mmapEnabled = self.mmapEnabled

#if COUCHBASE_ENTERPRISE
config.encryptionKey = self.encryptionKey?.impl
#endif

return config
}
}
5 changes: 4 additions & 1 deletion Swift/Defaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ public extension DatabaseConfiguration {
/// [false] Full sync is off by default because the performance hit is seldom worth the benefit
static let defaultFullSync: Bool = false

/// [false] Memory mapped database files are disabled by default. Always disabled for macOS.
static let defaultMmapEnabled: Bool = true

}

public extension LogFileConfiguration {
Expand Down Expand Up @@ -101,7 +104,7 @@ public extension VectorIndexConfiguration {
/// [ScalarQuantizerType.SQ8] Vectors are encoded by using 8-bit Scalar Quantizer encoding, by default
static let defaultEncoding: ScalarQuantizerType = ScalarQuantizerType.SQ8

/// [DistanceMetric.euclideanSquared] By default, vectors are compared using Euclidean metrics
/// [DistanceMetric.euclideanSquared] By default, vectors are compared using Squared Euclidean metrics
static let defaultDistanceMetric: DistanceMetric = DistanceMetric.euclideanSquared

/// [0] By default, the value will be determined based on the number of centroids, encoding types, and the encoding parameters.
Expand Down
55 changes: 52 additions & 3 deletions Swift/Tests/DatabaseTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1531,7 +1531,7 @@ class DatabaseTest: CBLTestCase {
}

// MARK: Full Sync Option
/// Test Spec for Database Full Sync Option
/// Test Spec v1.0.0:
/// https://github.com/couchbaselabs/couchbase-lite-api/blob/master/spec/tests/T0003-SQLite-Options.md

/// 1. TestSQLiteFullSyncConfig
Expand Down Expand Up @@ -1575,11 +1575,60 @@ class DatabaseTest: CBLTestCase {
var config = DatabaseConfiguration()
config.directory = self.directory
db = try Database(name: dbName, config: config)
XCTAssertFalse(DatabaseConfiguration(config: config).fullSync)
XCTAssertFalse(db.config.fullSync)

db = nil
config.fullSync = true
db = try Database(name: dbName, config: config)
XCTAssert(DatabaseConfiguration(config: config).fullSync)
XCTAssert(db.config.fullSync)
}

// MARK: MMap
/// Test Spec v1.0.1:
/// https://github.com/couchbaselabs/couchbase-lite-api/blob/master/spec/tests/T0006-MMap-Config.md

/// 1. TestDefaultMMapConfig
/// Description
/// Test that the mmapEnabled default value is as expected and that it's setter and getter work.
/// Steps
/// 1. Create a DatabaseConfiguration object.
/// 2. Get and check that the value of the mmapEnabled property is true.
/// 3. Set the mmapEnabled property to false and verify that the value is false.
/// 4. Set the mmapEnabled property to true, and verify that the mmap value is true.

func testDefaultMMapConfig() throws {
var config = DatabaseConfiguration()
XCTAssertTrue(config.mmapEnabled)

config.mmapEnabled = false;
XCTAssertFalse(config.mmapEnabled)

config.mmapEnabled = true;
XCTAssertTrue(config.mmapEnabled)
}

/// 2. TestDatabaseWithConfiguredMMap
/// Description
/// Test that a Database respects the mmapEnabled property.
/// Steps
/// 1. Create a DatabaseConfiguration object and set mmapEnabled to false.
/// 2. Create a database with the config.
/// 3. Get the configuration object from the database and check that the mmapEnabled is false.
/// 4. Use c4db_config2 to confirm that its config contains the kC4DB_MmapDisabled flag - done in Obj-C
/// 5. Set the config's mmapEnabled property true
/// 6. Create a database with the config.
/// 7. Get the configuration object from the database and verify that mmapEnabled is true
/// 8. Use c4db_config2 to confirm that its config doesn't contains the kC4DB_MmapDisabled flag - done in Obj-C

func testDatabaseWithConfiguredMMap() throws {
var config = DatabaseConfiguration()
config.mmapEnabled = false;
let db1 = try Database(name: "mmap1", config: config)
XCTAssertFalse(db1.config.mmapEnabled)

config.mmapEnabled = true;
let db2 = try Database(name: "mmap2", config: config)
XCTAssert(db2.config.mmapEnabled)
}

}
Loading