Skip to content

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
  • 7 commits
  • 6 files changed
  • 0 commit comments
  • 1 contributor
Commits on Jun 04, 2012
@snej snej Implemented linked documents for views
Support for linked documents: http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views#Linked_documents
Emitting a _id key from a map function will cause include_docs to include the doc with that ID instead.
Note: This is not the most efficient way to implement this.
Fixes #92.
45f592f
Commits on Jun 05, 2012
@snej snej Fixed off-by-1000 error in replicator 'heartbeat' property
Forgot to convert milliseconds to seconds, so 'heartbeat' wouldn't have had any effect.
6906a9d
@snej snej Change tracker will retry connection if closed by proxy
The AWS Elastic Load Balancer seems to close connections after a brief idle time (45 sec?).
This breaks the _changes feed. The header of the JSON gets sent but no changes, so it's unparseable.
This patch adds code to detect this case and retry after adjusting the heartbeat interval to less than the elapsed idle time.
6043f1c
@snej snej Bump version to 0.79 (beta candidate!) fced3bb
Commits on Jun 06, 2012
@snej snej Improved: Change tracker will retry connection if closed by proxy
Tweak the heuristic added in 6043f1c by looking at total connection time, not idle time.
92a6edb
@snej snej Merge remote-tracking branch 'origin/master' into syncpoint 40c3f16
@snej snej Update version to 0.791 26b0ba1
View
1 Source/ChangeTracker/TDConnectionChangeTracker.h
@@ -17,6 +17,7 @@
NSURLConnection* _connection;
NSMutableData* _inputBuffer;
unsigned _retryCount;
+ CFAbsoluteTime _startTime;
}
@end
View
28 Source/ChangeTracker/TDConnectionChangeTracker.m
@@ -40,6 +40,7 @@ - (BOOL) start {
}];
_connection = [[NSURLConnection connectionWithRequest: request delegate: self] retain];
+ _startTime = CFAbsoluteTimeGetCurrent();
LogTo(ChangeTracker, @"%@: Started... <%@>", self, request.URL);
return YES;
}
@@ -105,16 +106,33 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// Now parse the entire response as a JSON document:
NSData* input = [_inputBuffer retain];
LogTo(ChangeTracker, @"%@: Got entire body, %u bytes", self, (unsigned)input.length);
+ BOOL restart = NO;
NSInteger numChanges = [self receivedPollResponse: input];
- if (numChanges < 0)
- [self setUpstreamError: @"Unparseable server response"];
+ if (numChanges < 0) {
+ // Oops, unparseable response:
+ if (_mode == kLongPoll && [input isEqualToData: [@"{\"results\":[\n"
+ dataUsingEncoding: NSUTF8StringEncoding]]) {
+ // Looks like the connection got closed by a proxy (like AWS' load balancer) before
+ // the server had an actual change to send.
+ NSTimeInterval elapsed = CFAbsoluteTimeGetCurrent() - _startTime;
+ Warn(@"%@: Longpoll connection closed (by proxy?) after %.1f sec", self, elapsed);
+ if (elapsed >= 30.0 && elapsed < _heartbeat) {
+ self.heartbeat = elapsed * 0.75;
+ restart = YES;
+ }
+ }
+ if (!restart)
+ [self setUpstreamError: @"Unparseable server response"];
+ } else {
+ // Poll again if there was no error, and either we're in longpoll mode or it looks like we
+ // ran out of changes due to a _limit rather than because we hit the end.
+ restart = (numChanges > 0 && (_mode == kLongPoll || numChanges == (NSInteger)_limit));
+ }
[input release];
[self clearConnection];
- // Poll again if there was no error, and either we're in longpoll mode or it looks like we
- // ran out of changes due to a _limit rather than because we hit the end.
- if (numChanges > 0 && (_mode == kLongPoll || numChanges == (NSInteger)_limit))
+ if (restart)
[self start]; // Next poll...
else
[self stopped];
View
2 Source/TDPuller.m
@@ -114,7 +114,7 @@ - (void) startChangeTracker {
_changeTracker.filterParameters = _filterParameters;
unsigned heartbeat = $castIf(NSNumber, [_options objectForKey: @"heartbeat"]).unsignedIntValue;
if (heartbeat >= 15000)
- _changeTracker.heartbeat = heartbeat;
+ _changeTracker.heartbeat = heartbeat / 1000.0;
NSMutableDictionary* headers = $mdict({@"User-Agent", [TDRemoteRequest userAgentHeader]});
[headers addEntriesFromDictionary: _requestHeaders];
View
22 Source/TDView.m
@@ -481,13 +481,23 @@ - (NSArray*) queryWithOptions: (const TDQueryOptions*)options
} else {
// Regular query:
NSString* docID = [r stringForColumnIndex: 2];
- NSDictionary* docContents = nil;
+ id docContents = nil;
if (options->includeDocs) {
- docContents = [_db documentPropertiesFromJSON: [r dataNoCopyForColumnIndex: 4]
- docID: docID
- revID: [r stringForColumnIndex: 3]
- sequence: [r longLongIntForColumnIndex:5]
- options: options->content];
+ NSString* linkedID = [value objectForKey: @"_id"];
+ if (linkedID) {
+ // Linked document: http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views#Linked_documents
+ NSString* linkedRev = [value objectForKey: @"_rev"]; // usually nil
+ TDRevision* linked = [_db getDocumentWithID: linkedID
+ revisionID: linkedRev
+ options: options->content];
+ docContents = linked ? linked.properties : $null;
+ } else {
+ docContents = [_db documentPropertiesFromJSON: [r dataNoCopyForColumnIndex: 4]
+ docID: docID
+ revID: [r stringForColumnIndex: 3]
+ sequence: [r longLongIntForColumnIndex:5]
+ options: options->content];
+ }
}
[rows addObject: $dict({@"id", docID},
{@"key", key},
View
47 Source/TDView_Tests.m
@@ -604,4 +604,51 @@
}
+TestCase(TDView_LinkedDocs) {
+ RequireTestCase(TDView_Query);
+ TDDatabase *db = createDB();
+ NSArray* revs = putDocs(db);
+
+ NSDictionary* docs[5];
+ int i = 0;
+ for (TDRevision* rev in revs) {
+ docs[i++] = [db getDocumentWithID: rev.docID revisionID: rev.revID options: 0].properties;
+ }
+
+ TDView* view = [db viewNamed: @"linkview"];
+ [view setMapBlock: ^(NSDictionary* doc, TDMapEmitBlock emit) {
+ NSString* key = [doc objectForKey: @"key"];
+ NSDictionary* value = nil;
+ int linkedID = [[doc objectForKey: @"_id"] intValue] - 11111;
+ if (linkedID > 0)
+ value = $dict({@"_id", $sprintf(@"%d", linkedID)});
+ emit(key, value);
+ } reduceBlock: NULL version: @"1"];
+
+ CAssertEq([view updateIndex], kTDStatusOK);
+
+ // Query all rows:
+ TDQueryOptions options = kDefaultTDQueryOptions;
+ options.includeDocs = YES;
+ TDStatus status;
+ NSArray* rows = [view queryWithOptions: &options status: &status];
+ NSArray* expectedRows = $array($dict({@"id", @"55555"}, {@"key", @"five"},
+ {@"value", $dict({@"_id", @"44444"})},
+ {@"doc", docs[1]}),
+ $dict({@"id", @"44444"}, {@"key", @"four"},
+ {@"value", $dict({@"_id", @"33333"})},
+ {@"doc", docs[3]}),
+ $dict({@"id", @"11111"}, {@"key", @"one"},
+ {@"doc", docs[2]}),
+ $dict({@"id", @"33333"}, {@"key", @"three"},
+ {@"value", $dict({@"_id", @"22222"})},
+ {@"doc", docs[0]}),
+ $dict({@"id", @"22222"}, {@"key", @"two"},
+ {@"value", $dict({@"_id", @"11111"})},
+ {@"doc", docs[2]}));
+ CAssertEqual(rows, expectedRows);
+
+}
+
+
#endif
View
4 TouchDB.xcodeproj/project.pbxproj
@@ -2062,7 +2062,7 @@
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
- CURRENT_PROJECT_VERSION = 0.79;
+ CURRENT_PROJECT_VERSION = 0.791;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
@@ -2083,7 +2083,7 @@
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
- CURRENT_PROJECT_VERSION = 0.79;
+ CURRENT_PROJECT_VERSION = 0.791;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;

No commit comments for this range

Something went wrong with that request. Please try again.