Skip to content

Commit

Permalink
CBL-6066: Implement Database Full-Sync Option (#3317)
Browse files Browse the repository at this point in the history
- Implemented FullSync DatabaseConfiguration property.
- Only Obj-C tests do check for c4db_config2 kC4DB_DiskSyncFull flag
- Updated LiteCore to 3.1.9-5
  • Loading branch information
velicuvlad authored Aug 1, 2024
1 parent 7128106 commit 5c10248
Show file tree
Hide file tree
Showing 14 changed files with 194 additions and 9 deletions.
8 changes: 8 additions & 0 deletions Objective-C/CBLDatabase.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,8 @@ static BOOL setupDatabaseDirectory(NSString *dir, NSError **outError)
static C4DatabaseConfig2 c4DatabaseConfig2 (CBLDatabaseConfiguration *config) {
C4DatabaseConfig2 c4config = kDBConfig;

if (config.fullSync)
c4config.flags |= kC4DB_DiskSyncFull;
#ifdef COUCHBASE_ENTERPRISE
if (config.encryptionKey)
c4config.encryptionKey = [CBLDatabase c4EncryptionKey: config.encryptionKey];
Expand Down Expand Up @@ -1150,4 +1152,10 @@ + (void) checkFileLogging: (BOOL)swift {
});
}

#pragma mark - Private for test

- (const C4DatabaseConfig2*) getC4DBConfig {
return c4db_getConfig2(_c4db);
}

@end
13 changes: 13 additions & 0 deletions Objective-C/CBLDatabaseConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic, copy) NSString* directory;

/**
As Couchbase Lite normally configures its databases, there is a very
small (though non-zero) chance that a power failure at just the wrong
time could cause the most recently committed transaction's changes to
be lost. This would cause the database to appear as it did immediately
before that transaction.
Setting this mode true ensures that an operating system crash or
power failure will not cause the loss of any data. FULL synchronous
is very safe but it is also dramatically slower.
*/
@property (nonatomic) BOOL fullSync;

/**
Initializes the CBLDatabaseConfiguration object.
*/
Expand Down
8 changes: 6 additions & 2 deletions Objective-C/CBLDatabaseConfiguration.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@

#import "CBLDatabaseConfiguration.h"
#import "CBLDatabase+Internal.h"
#import "CBLDefaults.h"

@implementation CBLDatabaseConfiguration {
BOOL _readonly;
}

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

#ifdef COUCHBASE_ENTERPRISE
@synthesize encryptionKey=_encryptionKey;
Expand All @@ -47,11 +48,14 @@ - (instancetype) initWithConfig: (nullable CBLDatabaseConfiguration*)config

if (config) {
_directory = config.directory;
_fullSync = config.fullSync;
#ifdef COUCHBASE_ENTERPRISE
_encryptionKey = config.encryptionKey;
#endif
} else
} else {
_directory = [CBLDatabaseConfiguration defaultDirectory];
_fullSync = kCBLDefaultDatabaseFullSync;
}
}
return self;
}
Expand Down
5 changes: 5 additions & 0 deletions Objective-C/CBLDefaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@

#import "CBLReplicatorTypes.h"

#pragma mark - CBLDatabaseConfiguration

/** [NO] Full sync is off by default because the performance hit is seldom worth the benefit */
extern const BOOL kCBLDefaultDatabaseFullSync;

#pragma mark - CBLLogFileConfiguration

/** [NO] Plaintext is not used, and instead binary encoding is used in log files */
Expand Down
3 changes: 3 additions & 0 deletions Objective-C/CBLDefaults.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@

#import "CBLDefaults.h"

#pragma mark - CBLDatabaseConfiguration

const BOOL kCBLDefaultDatabaseFullSync = NO;

#pragma mark - CBLLogFileConfiguration

Expand Down
1 change: 1 addition & 0 deletions Objective-C/Exports/CBL.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ _kCBLBlobContentTypeProperty
_kCBLBlobDigestProperty
_kCBLBlobLengthProperty
_kCBLBlobType
_kCBLDefaultDatabaseFullSync
_kCBLDefaultCollectionName
_kCBLDefaultFullTextIndexIgnoreAccents
_kCBLDefaultListenerDisableTls
Expand Down
1 change: 1 addition & 0 deletions Objective-C/Exports/Generated/CBL.exp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ _kCBLBlobDigestProperty
_kCBLBlobLengthProperty
_kCBLBlobType
_kCBLDefaultCollectionName
_kCBLDefaultDatabaseFullSync
_kCBLDefaultFullTextIndexIgnoreAccents
_kCBLDefaultListenerDisableTls
_kCBLDefaultListenerEnableDeltaSync
Expand Down
1 change: 1 addition & 0 deletions Objective-C/Exports/Generated/CBL_EE.exp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ _kCBLCertAttrStateOrProvince
_kCBLCertAttrSurname
_kCBLCertAttrURL
_kCBLDefaultCollectionName
_kCBLDefaultDatabaseFullSync
_kCBLDefaultFullTextIndexIgnoreAccents
_kCBLDefaultListenerDisableTls
_kCBLDefaultListenerEnableDeltaSync
Expand Down
5 changes: 4 additions & 1 deletion Objective-C/Internal/CBLDatabase+Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ NS_ASSUME_NONNULL_BEGIN

/// CBLDatabase:


@interface CBLDatabase () <CBLLockable, CBLRemovableListenerToken>

@property (readonly, nonatomic, nullable) C4Database* c4db;
Expand Down Expand Up @@ -77,6 +76,10 @@ NS_ASSUME_NONNULL_BEGIN

- (id) mutex;

#pragma mark - Private for test

- (const C4DatabaseConfig2*) getC4DBConfig;

@end

/// CBLDatabaseConfiguration:
Expand Down
79 changes: 76 additions & 3 deletions Objective-C/Tests/DatabaseTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -2591,7 +2591,7 @@ - (void) testCreateCollection {
Assert([(@[@"collection1", @"_default"]) containsObject: collections[1].name]);

// Create in Custom Scope
c = [self.db createCollectionWithName: @"collection2" scope: @"scope1" error: &error];
[self.db createCollectionWithName: @"collection2" scope: @"scope1" error: &error];

// verify
collections = [self.db collections: @"scope1" error: &error];
Expand Down Expand Up @@ -2633,8 +2633,8 @@ - (void) testCreateDuplicateCollection {
[self checkCollections: collections expCollectionNames: @[@"collection1", @"_default"]];

// Create in Custom Scope
c1 = [self.db createCollectionWithName: @"collection2" scope: @"scope1" error: &error];
c2 = [self.db createCollectionWithName: @"collection2" scope: @"scope1" error: &error];
[self.db createCollectionWithName: @"collection2" scope: @"scope1" error: &error];
[self.db createCollectionWithName: @"collection2" scope: @"scope1" error: &error];

// verify no duplicate is created.
collections = [self.db collections: @"scope1" error: &error];
Expand Down Expand Up @@ -2815,6 +2815,79 @@ - (void) testDBEventTrigged {
[token remove];
}

#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
*/

/**
1. TestSQLiteFullSyncConfig
Description
Test that the FullSync default is as expected and that it's setter and getter work.
Steps
1. Create a DatabaseConfiguration object.
2. Get and check the value of the FullSync property: it should be false.
3. Set the FullSync property true.
4. Get the config FullSync property and verify that it is true.
5. Set the FullSync property false.
6. Get the config FullSync property and verify that it is false.
*/
- (void) testSQLiteFullSyncConfig {
CBLDatabaseConfiguration* config = [[CBLDatabaseConfiguration alloc] init];
AssertFalse(config.fullSync);

config.fullSync = true;
Assert(config.fullSync);

config.fullSync = false;
AssertFalse(config.fullSync);
}

/**
2. TestDBWithFullSync
Description
Test that a Database respects the FullSync property.
Steps
1. Create a DatabaseConfiguration object and set Full Sync false.
2. Create a database with the config.
3. Get the configuration object from the Database and verify that FullSync is false.
4. Use c4db_config2 (perhaps necessary only for this test) to confirm that its config does not contain the kC4DB_DiskSyncFull flag.
5. Set the config's FullSync property true.
6. Create a database with the config.
7. Get the configuration object from the Database and verify that FullSync is true.
8. Use c4db_config2 to confirm that its config contains the kC4DB_DiskSyncFull flag.
*/
- (void) testDBWithFullSync {
NSString* dbName = @"fullsyncdb";
[CBLDatabase deleteDatabase: dbName inDirectory: self.directory error: nil];
AssertFalse([CBLDatabase databaseExists: dbName inDirectory: self.directory]);

CBLDatabaseConfiguration* config = [[CBLDatabaseConfiguration alloc] init];
config.directory = self.directory;
NSError* error;
CBLDatabase* db = [[CBLDatabase alloc] initWithName: dbName
config: config
error: &error];
AssertNil(error);
AssertNotNil(db, @"Couldn't open db: %@", error);
AssertFalse([db config].fullSync);
AssertFalse(([db getC4DBConfig]->flags & kC4DB_DiskSyncFull) == kC4DB_DiskSyncFull);

[self closeDatabase: db];

config.fullSync = true;
db = [[CBLDatabase alloc] initWithName: dbName
config: config
error: &error];
AssertNil(error);
AssertNotNil(db, @"Couldn't open db: %@", error);
Assert([db config].fullSync);
Assert(([db getC4DBConfig]->flags & kC4DB_DiskSyncFull) == kC4DB_DiskSyncFull);

[self closeDatabase: db];
}

#pragma clang diagnostic pop

@end
15 changes: 14 additions & 1 deletion Swift/DatabaseConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// DatabaseConfiguration.swift
// CouchbaseLite
//
// Copyright (c) 2017 Couchbase, Inc All rights reserved.
// Copyright (c) 2024 Couchbase, Inc All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -26,6 +26,17 @@ public struct DatabaseConfiguration {
/// Path to the directory to store the database in.
public var directory: String = CBLDatabaseConfiguration().directory

/// As Couchbase Lite normally configures its databases, There is a very
/// small (though non-zero) chance that a power failure at just the wrong
/// time could cause the most recently committed transaction's changes to
/// be lost. This would cause the database to appear as it did immediately
/// before that transaction.
///
/// Setting this mode true ensures that an operating system crash or
/// power failure will not cause the loss of any data. FULL synchronous
/// is very safe but it is also dramatically slower.
public var fullSync: Bool = defaultFullSync

#if COUCHBASE_ENTERPRISE
/// The key to encrypt the database with.
public var encryptionKey: EncryptionKey?
Expand All @@ -40,6 +51,7 @@ public struct DatabaseConfiguration {
public init(config: DatabaseConfiguration?) {
if let c = config {
self.directory = c.directory
self.fullSync = c.fullSync
#if COUCHBASE_ENTERPRISE
self.encryptionKey = c.encryptionKey
#endif
Expand All @@ -51,6 +63,7 @@ public struct DatabaseConfiguration {
func toImpl() -> CBLDatabaseConfiguration {
let config = CBLDatabaseConfiguration()
config.directory = self.directory
config.fullSync = self.fullSync
#if COUCHBASE_ENTERPRISE
config.encryptionKey = self.encryptionKey?.impl
#endif
Expand Down
7 changes: 7 additions & 0 deletions Swift/Defaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@

import Foundation

public extension DatabaseConfiguration {

/// [false] Full sync is off by default because the performance hit is seldom worth the benefit
static let defaultFullSync: Bool = kCBLDefaultDatabaseFullSync.boolValue

}

public extension LogFileConfiguration {
/// [false] Plaintext is not used, and instead binary encoding is used in log files
static let defaultUsePlainText: Bool = kCBLDefaultLogFileUsePlainText.boolValue
Expand Down
55 changes: 54 additions & 1 deletion Swift/Tests/DatabaseTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// DatabaseTest.swift
// CouchbaseLite
//
// Copyright (c) 2017 Couchbase, Inc All rights reserved.
// Copyright (c) 2024 Couchbase, Inc All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -1527,4 +1527,57 @@ class DatabaseTest: CBLTestCase {
XCTAssertNotNil(db.config.encryptionKey)
#endif
}

// 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

/// 1. TestSQLiteFullSyncConfig
/// Description:
/// Test that the FullSync default is as expected and that it's setter and getter work.
/// Steps
/// 1. Create a DatabaseConfiguration object.
/// 2. Get and check the value of the FullSync property: it should be false.
/// 3. Set the FullSync property true.
/// 4. Get the config FullSync property and verify that it is true.
/// 5. Set the FullSync property false.
/// 6. Get the config FullSync property and verify that it is false.
func testSQLiteFullSyncConfig() {
var config = DatabaseConfiguration()
XCTAssertFalse(config.fullSync)

config.fullSync = true
XCTAssert(config.fullSync)

config.fullSync = false
XCTAssertFalse(config.fullSync)
}

/// 2. TestDBWithFullSync
/// Description:
/// Test that the FullSync default is as expected and that it's setter and getter work.
/// Steps
/// 1. Create a DatabaseConfiguration object and set Full Sync false.
/// 2. Create a database with the config.
/// 3. Get the configuration object from the Database and verify that FullSync is false.
/// 4. Use c4db_config2 (perhaps necessary only for this test) to confirm that its config does not contain the kC4DB_DiskSyncFull flag. - done in Obj-C
/// 5. Set the config's FullSync property true.
/// 6. Create a database with the config.
/// 7. Get the configuration object from the Database and verify that FullSync is true.
/// 8. Use c4db_config2 to confirm that its config contains the kC4DB_DiskSyncFull flag. - done in Obj-C
func testDBWithFullSync() throws {
let dbName = "fullsyncdb"
try deleteDB(name: dbName)
XCTAssertFalse(Database.exists(withName: dbName, inDirectory: self.directory))

var config = DatabaseConfiguration()
config.directory = self.directory
db = try Database(name: dbName, config: config)
XCTAssertFalse(DatabaseConfiguration(config: config).fullSync)

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

0 comments on commit 5c10248

Please sign in to comment.