Skip to content

Deferred Attachment Downloading

Jens Alfke edited this page Aug 6, 2015 · 11 revisions

Since document attachments can be arbitrarily large, you may want to skip downloading them during a pull replication, both to speed up the replication and to save bandwidth. Then of course you need a way to download those attachment(s) later if they're needed locally.

NOTE: Aug 2015: This feature isn't yet available in a release. It's likely to appear in version 1.2 but we're not guaranteeing it. The API is preliminary and subject to change. The implementation is not yet merged to the master branch; it's on a branch named feature/lazy_attachments.

Skipping Attachments

To skip downloading attachments, set the CBLReplication property downloadAttachments to NO before starting the replication. This will cause this replicator to skip the content of all attachments.

CBLReplication* pull = [db createPullReplication: kRemoteURL];
pull.downloadAttachments = NO;
[pull start];

The metadata of the attachments is still available via CBLAttachment objects (or the _attachments property), as usual. But if an attachment hasn't been downloaded, its content and contentURL properties, and the openContentStream method, will all return nil. To quickly check whether an attachment's content is available without reading or opening it, use the new boolean contentAvailable property.

CBLAttachment *att = [doc.currentRevision attachmentNamed: @"bigImage"];
UIImage* bigImage = nil;
if (att.contentAvailable) {
    bigImage = [UIImage imageWithData: att.content];
}
self.imageView.image = bigImage ? bigImage : kPlaceholderImage;

Deferred Downloading

If you need the content of an attachment, you request it from the pull replication by calling its -downloadAttachment:onProgress: method. The second parameter is an (optional) callback block that will inform you how much has been downloaded, when the download is complete, or whether it's failed.

[pull downloadAttachment: att 
              onProgress: ^(uint64_t bytesRead, uint64_t contentLength, NSError* error) {
    if (error) {
        [self downloadFailed: att];
    } else if (bytesRead < contentLength) {
        progressView.progress = bytesRead / (float)contentLength;
    } else {
        [self downloadFinished: att];
    }
}];

(Note: The CBLReplication doesn't have to be the exact same instance that was used to pull the document containing the attachment. Any pull replication with the same remote database URL will work.)

Issues & Limitations

  • There's not currently any way to pull some attachments automatically but not others. It's all or nothing.
  • Multiple calls to download the same attachment will issue redundant downloads, wasting network bandwidth.
  • Attachment downloading isn't as fault-tolerant as regular replication: if there's no network connectivity or the server isn't reachable, the request will immediately fail. If the request fails, it won't be retried automatically.
  • If you retry an interrupted download, it starts over from the beginning instead of where it left off.
  • There's no way yet to cancel or pause a download.