Skip to content

Commit

Permalink
Share map/reduce/filter/validate fns with background dbs
Browse files Browse the repository at this point in the history
When a CBLManager runs a background-thread manager, the CBLDatabases in the background manager
need to have access to the callback blocks defined in the main manager, or they won't work right.
Created a CBL_Shared object to hold this shared state. Fixes #26.
  • Loading branch information
snej committed Mar 20, 2013
1 parent 0f8fce1 commit daab43d
Show file tree
Hide file tree
Showing 16 changed files with 267 additions and 75 deletions.
10 changes: 10 additions & 0 deletions CouchbaseLite.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@
2711CE0314C759BD00505D55 /* CBLDatabase+Replication.h in Headers */ = {isa = PBXBuildFile; fileRef = 2711CE0214C759BD00505D55 /* CBLDatabase+Replication.h */; settings = {ATTRIBUTES = (Private, ); }; };
2711CE0414C759BD00505D55 /* CBLDatabase+Replication.h in Headers */ = {isa = PBXBuildFile; fileRef = 2711CE0214C759BD00505D55 /* CBLDatabase+Replication.h */; settings = {ATTRIBUTES = (Public, ); }; };
2711CE1414C75B6E00505D55 /* CBLDatabase+LocalDocs.h in Headers */ = {isa = PBXBuildFile; fileRef = 2773ADC514BD1EB80027A292 /* CBLDatabase+LocalDocs.h */; settings = {ATTRIBUTES = (Public, ); }; };
271C2AD416FA176300B8C9DB /* CBL_Shared.h in Headers */ = {isa = PBXBuildFile; fileRef = 271C2AD216FA176300B8C9DB /* CBL_Shared.h */; };
271C2AD516FA176300B8C9DB /* CBL_Shared.m in Sources */ = {isa = PBXBuildFile; fileRef = 271C2AD316FA176300B8C9DB /* CBL_Shared.m */; };
271C2AD616FA176300B8C9DB /* CBL_Shared.m in Sources */ = {isa = PBXBuildFile; fileRef = 271C2AD316FA176300B8C9DB /* CBL_Shared.m */; };
272B85141523691700A90CB2 /* CBLJSON.h in Headers */ = {isa = PBXBuildFile; fileRef = 272B85121523691700A90CB2 /* CBLJSON.h */; settings = {ATTRIBUTES = (Public, ); }; };
272B85151523691700A90CB2 /* CBLJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 272B85131523691700A90CB2 /* CBLJSON.m */; };
272B85161523691700A90CB2 /* CBLJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 272B85131523691700A90CB2 /* CBLJSON.m */; };
Expand Down Expand Up @@ -590,6 +593,8 @@
2711CDFF14C7595900505D55 /* CBLDatabase+Insertion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CBLDatabase+Insertion.h"; sourceTree = "<group>"; };
2711CE0214C759BD00505D55 /* CBLDatabase+Replication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CBLDatabase+Replication.h"; sourceTree = "<group>"; };
2714CF511496AE5B00E03341 /* Entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Entitlements.plist; sourceTree = "<group>"; };
271C2AD216FA176300B8C9DB /* CBL_Shared.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CBL_Shared.h; sourceTree = "<group>"; };
271C2AD316FA176300B8C9DB /* CBL_Shared.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CBL_Shared.m; sourceTree = "<group>"; };
272B85121523691700A90CB2 /* CBLJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CBLJSON.h; sourceTree = "<group>"; };
272B85131523691700A90CB2 /* CBLJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CBLJSON.m; sourceTree = "<group>"; };
274C3917149E6B0900A5E89B /* EmptyAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EmptyAppDelegate.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1050,6 +1055,8 @@
2751D4E2151BAE7000F7FD57 /* CBLManager+Internal.h */,
279EB2CC149140DE00E74185 /* CBLView+Internal.h */,
279EB2CD149140DE00E74185 /* CBLView+Internal.m */,
271C2AD216FA176300B8C9DB /* CBL_Shared.h */,
271C2AD316FA176300B8C9DB /* CBL_Shared.m */,
27F074A911CD5D7A00E9A2AB /* CBL_Body.h */,
27F074AA11CD5D7A00E9A2AB /* CBL_Body.m */,
270B3E3714898DF200E0A926 /* CBL_Revision.h */,
Expand Down Expand Up @@ -1668,6 +1675,7 @@
275A29021649A11900B0D8EE /* CouchbaseLitePrivate.h in Headers */,
2776A59116A0C3A6006FF199 /* CBLBrowserIDAuthorizer.h in Headers */,
2776A63016A9BCBC006FF199 /* CBL_DatabaseChange.h in Headers */,
271C2AD416FA176300B8C9DB /* CBL_Shared.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -2159,6 +2167,7 @@
27B15517164A118100DF5E2C /* CBL_Database_Tests.m in Sources */,
2776A59316A0C3A6006FF199 /* CBLBrowserIDAuthorizer.m in Sources */,
2776A63116A9BCBC006FF199 /* CBL_DatabaseChange.m in Sources */,
271C2AD516FA176300B8C9DB /* CBL_Shared.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -2280,6 +2289,7 @@
27846FBE15D475DF0030122F /* MYStreamUtils.m in Sources */,
2776A59616A0C3B1006FF199 /* CBLBrowserIDAuthorizer.m in Sources */,
2776A63216A9BCBC006FF199 /* CBL_DatabaseChange.m in Sources */,
271C2AD616FA176300B8C9DB /* CBL_Shared.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
42 changes: 41 additions & 1 deletion Source/API/APITests.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.

#import "CouchbaseLite.h"
#import "CouchbaseLitePrivate.h"
#import "CBLInternal.h"
#import "Test.h"


Expand Down Expand Up @@ -547,6 +548,44 @@ static void createDocuments(CBLDatabase* db, unsigned n) {
}


// Make sure that a database's map/reduce functions are shared with the shadow database instance
// running in the background server.
TestCase(API_SharedMapBlocks) {
CBLManager* mgr = [CBLManager createEmptyAtTemporaryPath: @"API_SharedMapBlocks"];
CBLDatabase* db = [mgr createDatabaseNamed: @"db" error: nil];
[db defineFilter: @"phil" asBlock: ^BOOL(CBLRevision *revision, NSDictionary *params) {
return YES;
}];
[db defineValidation: @"val" asBlock: VALIDATIONBLOCK({
return YES;
})];
CBLView* view = [db viewNamed: @"view"];
BOOL ok = [view setMapBlock:^(NSDictionary *doc, CBLMapEmitBlock emit) {
// nothing
} reduceBlock:^id(NSArray *keys, NSArray *values, BOOL rereduce) {
return nil;
} version: @"1"];
CAssert(ok, @"Couldn't set map/reduce");

CBLMapBlock map = view.mapBlock;
CBLReduceBlock reduce = view.reduceBlock;
CBLFilterBlock filter = [db filterNamed: @"phil"];
CBLValidationBlock validation = [db validationNamed: @"val"];

id result = [mgr.backgroundServer waitForDatabaseNamed: @"db" to: ^id(CBLDatabase *serverDb) {
CAssert(serverDb != nil);
CBLView* serverView = [serverDb viewNamed: @"view"];
CAssert(serverView != nil);
CAssertEq([serverDb filterNamed: @"phil"], filter);
CAssertEq([serverDb validationNamed: @"val"], validation);
CAssertEq(serverView.mapBlock, map);
CAssertEq(serverView.reduceBlock, reduce);
return @"ok";
}];
CAssertEqual(result, @"ok");
}


#if 0
#pragma mark - Custom Path Maps

Expand Down Expand Up @@ -640,6 +679,7 @@ - (void) test_GetDocument_using_a_custom_path_map {
RequireTestCase(API_CreateView);
RequireTestCase(API_Validation);
RequireTestCase(API_ViewWithLinkedDocs);
RequireTestCase(API_SharedMapBlocks);
// RequireTestCase(API_ViewOptions);
}

Expand Down
24 changes: 10 additions & 14 deletions Source/API/CBLDatabase.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#import "CBLDatabase.h"
#import "CBLDatabase+Insertion.h"
#import "CBL_DatabaseChange.h"
#import "CBL_Shared.h"
#import "CBLInternal.h"
#import "CBLModelFactory.h"
#import "CBLCache.h"
Expand Down Expand Up @@ -134,11 +135,12 @@ - (BOOL) deleteDatabase: (NSError**)outError {
if (_isOpen) {
if (![self close])
return NO;
} else if (!self.exists) {
return YES;
}
[_manager _forgetDatabase: self];
[[NSNotificationCenter defaultCenter] removeObserver: self];
if (!self.exists) {
return YES;
}
return CBLRemoveFileIfExists(_path, outError)
&& CBLRemoveFileIfExists(self.attachmentStorePath, outError);
}
Expand Down Expand Up @@ -246,28 +248,22 @@ - (CBLQuery*) slowQueryWithMap: (CBLMapBlock)mapBlock {


- (void) defineValidation: (NSString*)validationName asBlock: (CBLValidationBlock)validationBlock {
if (validationBlock) {
if (!_validations)
_validations = [[NSMutableDictionary alloc] init];
[_validations setValue: [validationBlock copy] forKey: validationName];
} else {
[_validations removeObjectForKey: validationName];
}
[self.shared setValue: [validationBlock copy]
forType: @"validation" name: validationName inDatabaseNamed: _name];
}

- (CBLValidationBlock) validationNamed: (NSString*)validationName {
return _validations[validationName];
return [self.shared valueForType: @"validation" name: validationName inDatabaseNamed: _name];
}


- (void) defineFilter: (NSString*)filterName asBlock: (CBLFilterBlock)filterBlock {
if (!_filters)
_filters = [[NSMutableDictionary alloc] init];
[_filters setValue: [filterBlock copy] forKey: filterName];
[self.shared setValue: [filterBlock copy]
forType: @"filter" name: filterName inDatabaseNamed: _name];
}

- (CBLFilterBlock) filterNamed: (NSString*)filterName {
return _filters[filterName];
return [self.shared valueForType: @"filter" name: filterName inDatabaseNamed: _name];
}


Expand Down
37 changes: 27 additions & 10 deletions Source/API/CBLManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#import "CBL_URLProtocol.h"
#import "CBLBrowserIDAuthorizer.h"
#import "CBLOAuth1Authorizer.h"
#import "CBL_Shared.h"
#import "CBLInternal.h"
#import "CBLMisc.h"
#import "CBLStatus.h"
Expand All @@ -38,6 +39,7 @@ @implementation CBLManager
CBL_Server* _server;
NSURL* _internalURL;
NSMutableArray* _replications;
CBL_Shared *_shared;
}


Expand Down Expand Up @@ -142,7 +144,16 @@ + (instancetype) createEmptyAtTemporaryPath: (NSString*)name {
- (id) copyWithZone: (NSZone*)zone {
CBLManagerOptions options = _options;
options.noReplicator = true; // Don't want to run multiple replicator tasks
return [[[self class] alloc] initWithDirectory: self.directory options: &options error: NULL];
NSError* error;
CBLManager* mgr = [[[self class] alloc] initWithDirectory: self.directory
options: &options
error: &error];
if (!mgr) {
Warn(@"Couldn't copy CBLManager: %@", error);
return nil;
}
mgr->_shared = self.shared;
return mgr;
}


Expand Down Expand Up @@ -174,16 +185,20 @@ - (NSString*) description {
}


- (CBL_Shared*) shared {
if (!_shared)
_shared = [[CBL_Shared alloc] init];
return _shared;
}


- (CBL_Server*) backgroundServer {
if (!_server) {
CBLManagerOptions tdOptions = {
.readOnly = _options.readOnly,
.noReplicator = true
};
_server = [[CBL_Server alloc] initWithDirectory: self.directory
options: &tdOptions
error: nil];
LogTo(CBLDatabase, @"%@ created %@", self, _server);
CBLManager* newManager = [self copy];
if (newManager) {
_server = [[CBL_Server alloc] initWithManager: newManager];
LogTo(CBLDatabase, @"%@ created %@", self, _server);
}
}
return _server;
}
Expand Down Expand Up @@ -365,7 +380,9 @@ - (CBLDatabase*) _databaseNamed: (NSString*)name


- (void) _forgetDatabase: (CBLDatabase*)db {
[_databases removeObjectForKey: db.name];
NSString* name = db.name;
[_databases removeObjectForKey: name];
[_shared forgetDatabaseNamed: name];
}


Expand Down
2 changes: 0 additions & 2 deletions Source/API/CBLView.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ typedef id (^CBLReduceBlock)(NSArray* keys, NSArray* values, BOOL rereduce);
CBLDatabase* __weak _db;
NSString* _name;
int _viewID;
CBLMapBlock _mapBlock;
CBLReduceBlock _reduceBlock;
uint8_t _collation;
uint8_t /*CBLContentOptions*/ _mapContentOptions;
}
Expand Down
19 changes: 16 additions & 3 deletions Source/API/CBLView.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#import "CouchbaseLitePrivate.h"
#import "CBLView+Internal.h"
#import "CBL_Shared.h"
#import "CBLInternal.h"
#import "CBLCollateJSON.h"
#import "CBLCanonicalJSON.h"
Expand Down Expand Up @@ -38,7 +39,7 @@ - (instancetype) initWithDatabase: (CBLDatabase*)db name: (NSString*)name {
}


@synthesize name=_name, mapBlock=_mapBlock, reduceBlock=_reduceBlock;
@synthesize name=_name;


- (CBLDatabase*) database {
Expand All @@ -58,15 +59,27 @@ - (SequenceNumber) lastSequenceIndexed {
}


- (CBLMapBlock) mapBlock {
return [_db.shared valueForType: @"map" name: _name inDatabaseNamed: _db.name];
}

- (CBLReduceBlock) reduceBlock {
return [_db.shared valueForType: @"reduce" name: _name inDatabaseNamed: _db.name];
}


- (BOOL) setMapBlock: (CBLMapBlock)mapBlock
reduceBlock: (CBLReduceBlock)reduceBlock
version: (NSString *)version
{
Assert(mapBlock);
Assert(version);
_mapBlock = mapBlock; // copied implicitly in ARC
_reduceBlock = reduceBlock; // copied implicitly in ARC

[_db.shared setValue: [mapBlock copy]
forType: @"map" name: _name inDatabaseNamed: _db.name];
[_db.shared setValue: [reduceBlock copy]
forType: @"reduce" name: _name inDatabaseNamed: _db.name];

if (![_db open: nil])
return NO;

Expand Down
10 changes: 6 additions & 4 deletions Source/CBLDatabase+Insertion.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#import "CBLCanonicalJSON.h"
#import "CBL_Attachment.h"
#import "CBL_DatabaseChange.h"
#import "CBL_Shared.h"
#import "CBLInternal.h"
#import "CBLMisc.h"
#import "Test.h"
Expand Down Expand Up @@ -309,7 +310,7 @@ - (CBL_Revision*) putRevision: (CBL_Revision*)rev
return nil;
}

if (_validations.count > 0) {
if ([self.shared hasValuesOfType: @"validation" inDatabaseNamed: _name]) {
// Fetch the previous revision and validate the new one against it:
CBL_Revision* prevRev = [[CBL_Revision alloc] initWithDocID: docID revID: prevRevID
deleted: NO];
Expand Down Expand Up @@ -504,7 +505,7 @@ - (CBLStatus) forceInsert: (CBL_Revision*)rev
}

// Validate against the latest common ancestor:
if (_validations.count > 0) {
if (([self.shared hasValuesOfType: @"validation" inDatabaseNamed: _name])) {
CBL_Revision* oldRev = nil;
for (NSUInteger i = 1; i<historyCount; ++i) {
oldRev = [localRevs revWithDocID: docID revID: history[i]];
Expand Down Expand Up @@ -740,14 +741,15 @@ - (CBLStatus) purgeRevisions: (NSDictionary*)docsToRevs


- (CBLStatus) validateRevision: (CBL_Revision*)newRev previousRevision: (CBL_Revision*)oldRev {
if (_validations.count == 0)
NSDictionary* validations = [self.shared valuesOfType: @"validation" inDatabaseNamed: _name];
if (validations.count == 0)
return kCBLStatusOK;
CBLRevision* publicRev = [[CBLRevision alloc] initWithDatabase: self revision: newRev];
CBLValidationContext* context = [[CBLValidationContext alloc] initWithDatabase: self
revision: oldRev
newRevision: newRev];
CBLStatus status = kCBLStatusOK;
for (NSString* validationName in _validations) {
for (NSString* validationName in validations) {
CBLValidationBlock validation = [self validationNamed: validationName];
if (!validation(publicRev, context)) {
status = context.errorType;
Expand Down
8 changes: 5 additions & 3 deletions Source/CBLDatabase+Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#import "CBL_Revision.h"
#import "CBLStatus.h"
#import "CBLDatabase.h"
@class FMDatabase, CBLView, CBL_BlobStore, CBLDocument, CBLCache, CBLDatabase, CBL_DatabaseChange;
@class FMDatabase, CBLView, CBL_BlobStore, CBLDocument, CBLCache, CBLDatabase, CBL_DatabaseChange, CBL_Shared;
struct CBLQueryOptions; // declared in CBLView+Internal.h


Expand Down Expand Up @@ -68,12 +68,13 @@ extern const CBLChangesOptions kDefaultCBLChangesOptions;
int _transactionLevel;
NSThread* _thread;
NSMutableDictionary* _views;
NSMutableDictionary* _validations;
NSMutableDictionary* _filters;
CBL_BlobStore* _attachments;
NSMutableDictionary* _pendingAttachmentsByDigest;
NSMutableArray* _activeReplicators;
NSMutableArray* _changesToNotify;
#if DEBUG
CBL_Shared* _debug_shared;
#endif
}

/** Should the database file be opened in read-only mode? */
Expand Down Expand Up @@ -105,6 +106,7 @@ extern const CBLChangesOptions kDefaultCBLChangesOptions;

@property (nonatomic, readonly) FMDatabase* fmdb;
@property (nonatomic, readonly) CBL_BlobStore* attachmentStore;
@property (nonatomic, readonly) CBL_Shared* shared;

@property (nonatomic, readonly) BOOL exists;
@property (nonatomic, readonly) UInt64 totalDataSize;
Expand Down
Loading

0 comments on commit daab43d

Please sign in to comment.