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

Commit

Permalink
TDPuller now uses async GETs from the remote db.
Browse files Browse the repository at this point in the history
  • Loading branch information
snej committed Dec 16, 2011
1 parent 6a96cff commit 328678e
Show file tree
Hide file tree
Showing 13 changed files with 376 additions and 74 deletions.
27 changes: 27 additions & 0 deletions Source/ChangeTracker/TDRemoteRequest.h
@@ -0,0 +1,27 @@
//
// TDRemoteRequest.h
// TouchDB
//
// Created by Jens Alfke on 12/15/11.
// Copyright (c) 2011 Couchbase, Inc. All rights reserved.
//

#import <Foundation/Foundation.h>


typedef void (^TDRemoteRequestCompletionBlock)(id, NSError*);


@interface TDRemoteRequest : NSObject <NSURLConnectionDelegate>
{
@private
NSMutableURLRequest* _request;
TDRemoteRequestCompletionBlock _onCompletion;
NSURLConnection* _connection;
NSMutableData* _inputBuffer;
}

- (id) initWithMethod: (NSString*)method URL: (NSURL*)url body: (id)body
onCompletion: (TDRemoteRequestCompletionBlock)onCompletion;

@end
98 changes: 98 additions & 0 deletions Source/ChangeTracker/TDRemoteRequest.m
@@ -0,0 +1,98 @@
//
// TDRemoteRequest.m
// TouchDB
//
// Created by Jens Alfke on 12/15/11.
// Copyright (c) 2011 Couchbase, Inc. All rights reserved.
//

#import "TDRemoteRequest.h"

@implementation TDRemoteRequest


- (id) initWithMethod: (NSString*)method URL: (NSURL*)url body: (id)body
onCompletion: (TDRemoteRequestCompletionBlock)onCompletion
{
self = [super init];
if (self) {
LogTo(RemoteRequest, @"%@: %@ .%@", self, method, url);
_onCompletion = [onCompletion copy];
_request = [[NSMutableURLRequest alloc] initWithURL: url];
_request.HTTPMethod = method;
_request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
if (body) {
_request.HTTPBody = [NSJSONSerialization dataWithJSONObject: body options: 0 error: nil];
[_request addValue: @"application/json" forHTTPHeaderField: @"Content-Type"];
}

_connection = [[NSURLConnection connectionWithRequest: _request delegate: self] retain];
[_connection start];
}
return self;
}


- (void) clearConnection {
[_request release];
_request = nil;
[_connection autorelease];
_connection = nil;
[_inputBuffer release];
_inputBuffer = nil;
}


- (void)dealloc {
[self clearConnection];
[_onCompletion release];
[super dealloc];
}


- (void) respondWithResult: (id)result error: (NSError*)error {
LogTo(RemoteRequest, @"%@: Calling completion block...");
_onCompletion(result, error);
}


- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
int status = (int) ((NSHTTPURLResponse*)response).statusCode;
LogTo(RemoteRequest, @"%@: Got response, status %d", self, status);
if (status >= 300) {
[_connection cancel];
NSError* error = [NSError errorWithDomain: @"HTTP" code: status userInfo:nil];
[self connection: connection didFailWithError: error];
}
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
LogTo(RemoteRequest, @"%@: Got %lu bytes", self, (unsigned long)data.length);
if (!_inputBuffer)
_inputBuffer = [[NSMutableData alloc] initWithCapacity: MAX(data.length, 8192)];
[_inputBuffer appendData: data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
Warn(@"%@: Got error %@", self, error);
[self clearConnection];
[self respondWithResult: nil error: error];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
id result = [NSJSONSerialization JSONObjectWithData: _inputBuffer options: 0 error:nil];
if (!result) {
Warn(@"%@: %@ %@ returned unparseable data '%@'",
self, _request.HTTPMethod, _request.URL, [_inputBuffer my_UTF8ToString]);
}
[self clearConnection];
[self respondWithResult: result error: nil];
}

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
return nil;
}

@end
32 changes: 32 additions & 0 deletions Source/TDBatcher.h
@@ -0,0 +1,32 @@
//
// TDBatcher.h
// TouchDB
//
// Created by Jens Alfke on 12/15/11.
// Copyright (c) 2011 Couchbase, Inc. All rights reserved.
//

#import <Foundation/Foundation.h>


/** Utility that queues up objects until the queue fills up or a time interval elapses,
then passes all the objects at once to a client-supplied processor block. */
@interface TDBatcher : NSObject
{
NSUInteger _capacity;
NSTimeInterval _delay;
NSMutableArray* _inbox;
void (^_processor)(NSArray*);
}

- (id) initWithCapacity: (NSUInteger)capacity
delay: (NSTimeInterval)delay
processor: (void (^)(NSArray*))block;

@property (readonly) NSUInteger count;

- (void) queueObject: (id)object;

- (void) flush;

@end
69 changes: 69 additions & 0 deletions Source/TDBatcher.m
@@ -0,0 +1,69 @@
//
// TDBatcher.m
// TouchDB
//
// Created by Jens Alfke on 12/15/11.
// Copyright (c) 2011 Couchbase, Inc. All rights reserved.
//

#import "TDBatcher.h"

@implementation TDBatcher


- (id) initWithCapacity: (NSUInteger)capacity
delay: (NSTimeInterval)delay
processor: (void (^)(NSArray*))block {
self = [super init];
if (self) {
_capacity = capacity;
_delay = delay;
_processor = [block copy];
}
return self;
}


- (void)dealloc {
[_inbox release];
[_processor release];
[super dealloc];
}


- (void) processNow {
if (_inbox.count == 0)
return;
NSMutableArray* toProcess = _inbox;
_inbox = nil;
_processor(toProcess);
[toProcess release];
}


- (void) queueObject: (id)object {
if (_inbox.count >= _capacity)
[self flush];
if (!_inbox) {
_inbox = [[NSMutableArray alloc] init];
[self performSelector: @selector(processNow) withObject: nil afterDelay: _delay];
}
[_inbox addObject: object];
}


- (void) flush {
if (_inbox) {
[NSObject cancelPreviousPerformRequestsWithTarget: self
selector: @selector(processNow) object:nil];
[self processNow];
}
}


- (NSUInteger) count {
return _inbox.count;
}


@end
3 changes: 3 additions & 0 deletions Source/TDInternal.h
Expand Up @@ -10,6 +10,7 @@
#import "TDView.h"
#import "TDServer.h"
#import "TDReplicator.h"
#import "TDRemoteRequest.h"


@interface TDDatabase ()
Expand Down Expand Up @@ -46,4 +47,6 @@
- (void) processInbox: (TDRevisionList*)inbox; // override this
- (void) flushInbox; // optionally call this to flush the inbox
- (id) sendRequest: (NSString*)method path: (NSString*)relativePath body: (id)body;
- (void) sendAsyncRequest: (NSString*)method path: (NSString*)relativePath body: (id)body
onCompletion: (TDRemoteRequestCompletionBlock)onCompletion;
@end
2 changes: 2 additions & 0 deletions Source/TDPuller.h
Expand Up @@ -15,6 +15,8 @@
{
@private
TDChangeTracker* _changeTracker;
NSThread* _thread;
TDBatcher* _revsToInsert;
}

@end

0 comments on commit 328678e

Please sign in to comment.