Skip to content
This repository has been archived by the owner on Mar 9, 2022. It is now read-only.

Commit

Permalink
Merge remote-tracking branch 'origin/master' into syncpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
snej committed Jun 6, 2012
2 parents 2244603 + 92a6edb commit 40c3f16
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 12 deletions.
1 change: 1 addition & 0 deletions Source/ChangeTracker/TDConnectionChangeTracker.h
Expand Up @@ -17,6 +17,7 @@
NSURLConnection* _connection;
NSMutableData* _inputBuffer;
unsigned _retryCount;
CFAbsoluteTime _startTime;
}

@end
28 changes: 23 additions & 5 deletions Source/ChangeTracker/TDConnectionChangeTracker.m
Expand Up @@ -40,6 +40,7 @@ - (BOOL) start {
}];

_connection = [[NSURLConnection connectionWithRequest: request delegate: self] retain];
_startTime = CFAbsoluteTimeGetCurrent();
LogTo(ChangeTracker, @"%@: Started... <%@>", self, request.URL);
return YES;
}
Expand Down Expand Up @@ -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];
Expand Down
2 changes: 1 addition & 1 deletion Source/TDPuller.m
Expand Up @@ -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];
Expand Down
22 changes: 16 additions & 6 deletions Source/TDView.m
Expand Up @@ -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},
Expand Down
47 changes: 47 additions & 0 deletions Source/TDView_Tests.m
Expand Up @@ -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

0 comments on commit 40c3f16

Please sign in to comment.