Skip to content
Browse files

Optimize db change tracking for TouchDB

With TouchDB a database can detect changes by just observing NSNotifications from the TDDatabase,
instead of having to run a TDChangeTracker and open a URLConnection.

Change-Id: I3ae7fc2b9ad788db784bd6e2beb637023898c7eb
  • Loading branch information...
1 parent 73728e9 commit 30f6b55e8355e4b3ea056955acad3826f440aad0 @snej snej committed May 25, 2012
View
1 Couch/CouchInternal.h
@@ -39,6 +39,7 @@ typedef void (^OnDatabaseChangeBlock)(CouchDocument*, BOOL externalChange);
- (void) endDocumentOperation: (CouchResource*)resource;
- (void) onChange: (OnDatabaseChangeBlock)block; // convenience for unit tests
- (void) unretainDocumentCache;
+- (void) changeTrackerReceivedChange: (NSDictionary*)change;
@end
View
7 Couch/CouchServer.m
@@ -103,10 +103,15 @@ - (NSArray*) getDatabases {
}
+- (Class) databaseClass {
+ return [CouchDatabase class];
+}
+
+
- (CouchDatabase*) databaseNamed: (NSString*)name {
CouchDatabase* db = (CouchDatabase*) [_dbCache resourceWithRelativePath: name];
if (!db) {
- db = [[CouchDatabase alloc] initWithParent: self relativePath: name];
+ db = [[[self databaseClass] alloc] initWithParent: self relativePath: name];
if (!db)
return nil;
if (!_dbCache)
View
17 Couch/CouchTouchDBDatabase.h
@@ -0,0 +1,17 @@
+//
+// CouchTouchDBDatabase.h
+// CouchCocoa
+//
+// Created by Jens Alfke on 5/25/12.
+// Copyright (c) 2012 Couchbase, Inc. All rights reserved.
+//
+
+#import "CouchDatabase.h"
+
+@interface CouchTouchDBDatabase : CouchDatabase
+{
+ @private
+ BOOL _tracking;
+}
+
+@end
View
75 Couch/CouchTouchDBDatabase.m
@@ -0,0 +1,75 @@
+//
+// CouchTouchDBDatabase.m
+// CouchCocoa
+//
+// Created by Jens Alfke on 5/25/12.
+// Copyright (c) 2012 Couchbase, Inc. All rights reserved.
+//
+
+#import "CouchTouchDBDatabase.h"
+#import "CouchTouchDBServer.h"
+#import "CouchInternal.h"
+
+
+// Declared in TDDatabase.h and TDRevision.h; redeclare here to avoid linking against TouchDB:
+static NSString* const TDDatabaseChangeNotification = @"TDDatabaseChange";
+
+@interface TDRevision : NSObject
+@property (readonly) NSString* docID;
+@property (readonly) NSString* revID;
+@property (readonly) BOOL deleted;
+@property (copy) NSDictionary* properties;
+@property SInt64 sequence;
+@end
+
+
+@implementation CouchTouchDBDatabase
+
+
+- (BOOL) tracksChanges {
+ return _tracking;
+}
+
+- (void) setTracksChanges: (BOOL)track {
+ if (track == _tracking)
+ return;
+ _tracking = track;
+
+ if (track) {
+ [(CouchTouchDBServer*)self.parent tellTDDatabaseNamed: self.relativePath
+ to: ^(TDDatabase* tddb) {
+ [[NSNotificationCenter defaultCenter] addObserver: self
+ selector: @selector(tdDatabaseChanged:)
+ name: TDDatabaseChangeNotification
+ object: tddb];
+ }];
+ } else {
+ [[NSNotificationCenter defaultCenter] removeObserver: self
+ name: TDDatabaseChangeNotification
+ object: nil];
+ }
+}
+
+
+- (void) tdDatabaseChanged: (NSNotification*)n {
+ // Careful! This method is called on the TouchDB background thread!
+ if (!_tracking)
+ return;
+ // Adapted from -[TDRouter changeDictForRev:]
+ TDRevision* rev = [n.userInfo objectForKey: @"rev"];
+ NSArray* changes = [NSArray arrayWithObject: [NSDictionary dictionaryWithObject: rev.revID
+ forKey: @"rev"]];
+ NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithLongLong: rev.sequence], @"seq",
+ rev.docID, @"id",
+ changes, @"changes",
+ [NSNumber numberWithBool: rev.deleted], @"deleted",
+ rev.properties, @"doc", // may be nil
+ nil];
+ [self performSelectorOnMainThread: @selector(changeTrackerReceivedChange:)
+ withObject: dict
+ waitUntilDone: NO];
+}
+
+
+@end
View
6 Couch/CouchTouchDBServer.m
@@ -7,6 +7,7 @@
//
#import "CouchTouchDBServer.h"
+#import "CouchTouchDBDatabase.h"
#import "CouchInternal.h"
@@ -125,6 +126,11 @@ - (void) dealloc {
@synthesize error=_error;
+- (Class) databaseClass {
+ return [CouchTouchDBDatabase class];
+}
+
+
- (void) tellTDServer: (void (^)(TDServer*))block {
TDServer* server = _touchServer;
[_touchServer queue: ^{ block(server); }];
View
12 CouchCocoa.xcodeproj/project.pbxproj
@@ -59,6 +59,10 @@
279906D7149930DA003D4338 /* CouchSocketChangeTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = 279906D0149930DA003D4338 /* CouchSocketChangeTracker.h */; };
279906D8149930DA003D4338 /* CouchSocketChangeTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 279906D1149930DA003D4338 /* CouchSocketChangeTracker.m */; };
279906D9149930DA003D4338 /* CouchSocketChangeTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 279906D1149930DA003D4338 /* CouchSocketChangeTracker.m */; };
+ 279CA782156FE4B700871563 /* CouchTouchDBDatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = 279CA780156FE4B700871563 /* CouchTouchDBDatabase.h */; };
+ 279CA783156FE4B700871563 /* CouchTouchDBDatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = 279CA780156FE4B700871563 /* CouchTouchDBDatabase.h */; };
+ 279CA784156FE4B700871563 /* CouchTouchDBDatabase.m in Sources */ = {isa = PBXBuildFile; fileRef = 279CA781156FE4B700871563 /* CouchTouchDBDatabase.m */; };
+ 279CA785156FE4B700871563 /* CouchTouchDBDatabase.m in Sources */ = {isa = PBXBuildFile; fileRef = 279CA781156FE4B700871563 /* CouchTouchDBDatabase.m */; };
279CCBF213F9823F00C38C82 /* CouchReplication.h in Headers */ = {isa = PBXBuildFile; fileRef = 279CCBF013F9823F00C38C82 /* CouchReplication.h */; settings = {ATTRIBUTES = (Public, ); }; };
279CCBF313F9823F00C38C82 /* CouchReplication.h in Headers */ = {isa = PBXBuildFile; fileRef = 279CCBF013F9823F00C38C82 /* CouchReplication.h */; };
279CCBF413F9823F00C38C82 /* CouchReplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 279CCBF113F9823F00C38C82 /* CouchReplication.m */; };
@@ -257,6 +261,8 @@
279906CF149930DA003D4338 /* CouchConnectionChangeTracker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CouchConnectionChangeTracker.m; sourceTree = "<group>"; };
279906D0149930DA003D4338 /* CouchSocketChangeTracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CouchSocketChangeTracker.h; sourceTree = "<group>"; };
279906D1149930DA003D4338 /* CouchSocketChangeTracker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CouchSocketChangeTracker.m; sourceTree = "<group>"; };
+ 279CA780156FE4B700871563 /* CouchTouchDBDatabase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CouchTouchDBDatabase.h; sourceTree = "<group>"; };
+ 279CA781156FE4B700871563 /* CouchTouchDBDatabase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CouchTouchDBDatabase.m; sourceTree = "<group>"; };
279CCBF013F9823F00C38C82 /* CouchReplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CouchReplication.h; sourceTree = "<group>"; };
279CCBF113F9823F00C38C82 /* CouchReplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CouchReplication.m; sourceTree = "<group>"; };
27A577A613970959002776DB /* DemoQuery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoQuery.h; sourceTree = "<group>"; };
@@ -404,6 +410,8 @@
2783A0C5156D616800DC8692 /* CouchEmbeddedServer.m */,
278B22F4138F269200DDD950 /* CouchDatabase.h */,
278B22F5138F269200DDD950 /* CouchDatabase.m */,
+ 279CA780156FE4B700871563 /* CouchTouchDBDatabase.h */,
+ 279CA781156FE4B700871563 /* CouchTouchDBDatabase.m */,
278B22F7138F2AA600DDD950 /* CouchDocument.h */,
278B22F8138F2AA600DDD950 /* CouchDocument.m */,
2739BF2013BAB411004829CD /* CouchRevision.h */,
@@ -619,6 +627,7 @@
27E9C61A14A0EECC00F67966 /* CouchTouchDBServer.h in Headers */,
27AE23AE147C95D3005AAB52 /* CouchModelFactory.h in Headers */,
2783A0C6156D616800DC8692 /* CouchEmbeddedServer.h in Headers */,
+ 279CA783156FE4B700871563 /* CouchTouchDBDatabase.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -651,6 +660,7 @@
27D083B8143FBEEA0067702F /* CouchbaseCallbacks.h in Headers */,
279906D2149930DA003D4338 /* CouchConnectionChangeTracker.h in Headers */,
279906D6149930DA003D4338 /* CouchSocketChangeTracker.h in Headers */,
+ 279CA782156FE4B700871563 /* CouchTouchDBDatabase.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1003,6 +1013,7 @@
27E9C61C14A0EECC00F67966 /* CouchTouchDBServer.m in Sources */,
27AE23B0147C95D3005AAB52 /* CouchModelFactory.m in Sources */,
2783A0C7156D616800DC8692 /* CouchEmbeddedServer.m in Sources */,
+ 279CA785156FE4B700871563 /* CouchTouchDBDatabase.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1056,6 +1067,7 @@
279906D8149930DA003D4338 /* CouchSocketChangeTracker.m in Sources */,
27E9C61B14A0EECC00F67966 /* CouchTouchDBServer.m in Sources */,
27AE23AF147C95D3005AAB52 /* CouchModelFactory.m in Sources */,
+ 279CA784156FE4B700871563 /* CouchTouchDBDatabase.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

0 comments on commit 30f6b55

Please sign in to comment.
Something went wrong with that request. Please try again.