From a88c81d93b17b3b32025b54beeafcae8228a50c8 Mon Sep 17 00:00:00 2001 From: Vlad Velicu Date: Thu, 17 Oct 2024 18:29:44 +0100 Subject: [PATCH 1/2] mmap and tests --- Objective-C/CBLDatabase.mm | 3 ++ Objective-C/CBLDatabaseConfiguration.h | 9 ++++ Objective-C/CBLDatabaseConfiguration.m | 4 +- Objective-C/CBLDefaults.h | 5 +- Objective-C/CBLDefaults.m | 2 + Objective-C/Tests/DatabaseTest.m | 64 +++++++++++++++++++++++++- Swift/DatabaseConfiguration.swift | 11 +++++ Swift/Defaults.swift | 5 +- Swift/Tests/DatabaseTest.swift | 55 ++++++++++++++++++++-- 9 files changed, 151 insertions(+), 7 deletions(-) diff --git a/Objective-C/CBLDatabase.mm b/Objective-C/CBLDatabase.mm index a0a97040f..1e4e4c833 100644 --- a/Objective-C/CBLDatabase.mm +++ b/Objective-C/CBLDatabase.mm @@ -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]; diff --git a/Objective-C/CBLDatabaseConfiguration.h b/Objective-C/CBLDatabaseConfiguration.h index b1b25804e..c86ac5ea8 100644 --- a/Objective-C/CBLDatabaseConfiguration.h +++ b/Objective-C/CBLDatabaseConfiguration.h @@ -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. */ diff --git a/Objective-C/CBLDatabaseConfiguration.m b/Objective-C/CBLDatabaseConfiguration.m index 9f0f44d5c..9c31f7df4 100644 --- a/Objective-C/CBLDatabaseConfiguration.m +++ b/Objective-C/CBLDatabaseConfiguration.m @@ -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; @@ -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; diff --git a/Objective-C/CBLDefaults.h b/Objective-C/CBLDefaults.h index eac560e00..d0c8f287e 100644 --- a/Objective-C/CBLDefaults.h +++ b/Objective-C/CBLDefaults.h @@ -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 */ @@ -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. */ diff --git a/Objective-C/CBLDefaults.m b/Objective-C/CBLDefaults.m index 5fc203610..0509747e2 100644 --- a/Objective-C/CBLDefaults.m +++ b/Objective-C/CBLDefaults.m @@ -26,6 +26,8 @@ const BOOL kCBLDefaultDatabaseFullSync = NO; +const BOOL kCBLDefaultDatabaseMmapEnabled = YES; + #pragma mark - CBLLogFileConfiguration const BOOL kCBLDefaultLogFileUsePlaintext = NO; diff --git a/Objective-C/Tests/DatabaseTest.m b/Objective-C/Tests/DatabaseTest.m index 3de019525..bf70e5bd7 100644 --- a/Objective-C/Tests/DatabaseTest.m +++ b/Objective-C/Tests/DatabaseTest.m @@ -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 */ /** @@ -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 diff --git a/Swift/DatabaseConfiguration.swift b/Swift/DatabaseConfiguration.swift index fb25a5e64..9af90dcfa 100644 --- a/Swift/DatabaseConfiguration.swift +++ b/Swift/DatabaseConfiguration.swift @@ -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? @@ -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 @@ -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 } } diff --git a/Swift/Defaults.swift b/Swift/Defaults.swift index 28e245fbd..572143e4e 100644 --- a/Swift/Defaults.swift +++ b/Swift/Defaults.swift @@ -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 { @@ -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. diff --git a/Swift/Tests/DatabaseTest.swift b/Swift/Tests/DatabaseTest.swift index f8e5fa1a9..ff158eb57 100644 --- a/Swift/Tests/DatabaseTest.swift +++ b/Swift/Tests/DatabaseTest.swift @@ -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 @@ -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) + } + } From 3939bc64bcb6a343e4558ff32414081d8381b4c0 Mon Sep 17 00:00:00 2001 From: Vlad Velicu Date: Thu, 17 Oct 2024 18:29:53 +0100 Subject: [PATCH 2/2] LiteCore 3.2.1-9 --- vendor/couchbase-lite-core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/couchbase-lite-core b/vendor/couchbase-lite-core index 55ddf2ca9..da8b267c0 160000 --- a/vendor/couchbase-lite-core +++ b/vendor/couchbase-lite-core @@ -1 +1 @@ -Subproject commit 55ddf2ca9410efadb88ed87b6370c07aeb908ef9 +Subproject commit da8b267c0ef7ae36a814dc3f5af984f112dc2151