Permalink
Browse files

Share map/reduce/filter/validate fns with background dbs

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...
1 parent 0f8fce1 commit daab43d76d4057391aace055c1e7fd50bac5b460 @snej snej committed Mar 20, 2013
@@ -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 */; };
@@ -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>"; };
@@ -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 */,
@@ -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;
};
@@ -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;
};
@@ -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;
};
View
@@ -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"
@@ -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
@@ -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);
}
View
@@ -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"
@@ -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);
}
@@ -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];
}
View
@@ -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"
@@ -38,6 +39,7 @@ @implementation CBLManager
CBL_Server* _server;
NSURL* _internalURL;
NSMutableArray* _replications;
+ CBL_Shared *_shared;
}
@@ -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;
}
@@ -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;
}
@@ -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];
}
View
@@ -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;
}
View
@@ -8,6 +8,7 @@
#import "CouchbaseLitePrivate.h"
#import "CBLView+Internal.h"
+#import "CBL_Shared.h"
#import "CBLInternal.h"
#import "CBLCollateJSON.h"
#import "CBLCanonicalJSON.h"
@@ -38,7 +39,7 @@ - (instancetype) initWithDatabase: (CBLDatabase*)db name: (NSString*)name {
}
-@synthesize name=_name, mapBlock=_mapBlock, reduceBlock=_reduceBlock;
+@synthesize name=_name;
- (CBLDatabase*) database {
@@ -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;
@@ -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"
@@ -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];
@@ -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]];
@@ -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;
@@ -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
@@ -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? */
@@ -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;
Oops, something went wrong.

0 comments on commit daab43d

Please sign in to comment.