Skip to content

Commit

Permalink
Merge branch 'issue/449'
Browse files Browse the repository at this point in the history
Fixes #449
  • Loading branch information
borrrden committed Jul 21, 2015
2 parents e0b8719 + d02bcb1 commit b2ae33f
Show file tree
Hide file tree
Showing 10 changed files with 254 additions and 23 deletions.
23 changes: 17 additions & 6 deletions src/Couchbase.Lite.Shared/Database.cs
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,11 @@ internal void ForgetReplication(Replication replication)

internal void AddActiveReplication(Replication replication)
{
if (ActiveReplicators == null) {
Log.W(TAG, "ActiveReplicators is null, so replication will not be added");
return;
}

ActiveReplicators.Add(replication);
replication.Changed += (sender, e) =>
{
Expand Down Expand Up @@ -1327,9 +1332,9 @@ internal void ProcessAttachmentsForRevision(IDictionary<string, AttachmentIntern
}

/// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception>
internal void InstallAttachment(AttachmentInternal attachment, IDictionary<String, Object> attachInfo)
internal void InstallAttachment(AttachmentInternal attachment)
{
var digest = (string)attachInfo.Get("digest");
var digest = attachment.Digest;
if (digest == null) {
throw new CouchbaseLiteException(StatusCode.BadAttachment);
}
Expand Down Expand Up @@ -1379,6 +1384,12 @@ internal Uri FileForAttachmentDict(IDictionary<String, Object> attachmentDict)
return retval;
}

internal IList<RevisionInternal> GetRevisionHistory(RevisionInternal rev, IList<string> ancestorRevIds)
{
HashSet<string> ancestors = ancestorRevIds != null ? new HashSet<string>(ancestorRevIds) : null;
return Storage.GetRevisionHistory(rev, ancestors);
}

internal bool ExpandAttachments(RevisionInternal rev, int minRevPos, bool allowFollows,
bool decodeAttachments, Status outStatus)
{
Expand Down Expand Up @@ -1559,7 +1570,7 @@ internal bool ProcessAttachmentsForRevision(RevisionInternal rev, string prevRev
AttachmentInternal attachment = null;
try {
attachment = new AttachmentInternal(name, attachInfo);
} catch(CouchbaseLiteException e) {
} catch(CouchbaseLiteException) {
return null;
}
Expand All @@ -1576,7 +1587,7 @@ internal bool ProcessAttachmentsForRevision(RevisionInternal rev, string prevRev
// "follows" means the uploader provided the attachment in a separate MIME part.
// This means it's already been registered in _pendingAttachmentsByDigest;
// I just need to look it up by its "digest" property and install it into the store:
InstallAttachment(attachment, attachInfo);
InstallAttachment(attachment);
} else if(attachInfo.GetCast<bool>("stub")) {
// "stub" on an incoming revision means the attachment is the same as in the parent.
if(parentAttachments == null && prevRevId != null) {
Expand All @@ -1603,7 +1614,7 @@ internal bool ProcessAttachmentsForRevision(RevisionInternal rev, string prevRev
// Set or validate the revpos:
if(attachment.RevPos == 0) {
attachment.RevPos = generation;
} else if(attachment.RevPos >= generation) {
} else if(attachment.RevPos > generation) {
status.Code = StatusCode.BadAttachment;
return null;
}
Expand Down Expand Up @@ -1678,7 +1689,7 @@ internal IDictionary<String, AttachmentInternal> GetAttachmentsFromRevision(Revi
// "follows" means the uploader provided the attachment in a separate MIME part.
// This means it's already been registered in _pendingAttachmentsByDigest;
// I just need to look it up by its "digest" property and install it into the store:
InstallAttachment(attachment, attachInfo);
InstallAttachment(attachment);
}
else
{
Expand Down
9 changes: 1 addition & 8 deletions src/Couchbase.Lite.Shared/Database/ICouchStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,14 +149,7 @@ internal interface ICouchStore
/// Returns the given revision's list of direct ancestors (as Revision objects) in _reverse_
/// chronological order, starting with the revision itself.
/// </summary>
IList<RevisionInternal> GetRevisionHistory(RevisionInternal rev);

/// <summary>
/// Returns the revision history as a _revisions dictionary, as returned by the REST API's ?revs=true option.
/// If 'ancestorRevIDs' is present, the revision history will only go back as far as any of the revision ID
/// strings in that array.
/// </summary>
IDictionary<string, object> GetRevisionHistory(RevisionInternal rev, IList<string> ancestorRevIds);
IList<RevisionInternal> GetRevisionHistory(RevisionInternal rev, ICollection<string> ancestorRevIds);

/// <summary>
/// Returns all the known revisions (or all current/conflicting revisions) of a document.
Expand Down
9 changes: 9 additions & 0 deletions src/Couchbase.Lite.Shared/Documents/AttachmentInternal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,15 @@ public AttachmentInternal(string name, IDictionary<string, object> info)
if (Digest == null) {
throw new CouchbaseLiteException(StatusCode.BadAttachment);
}

if(info.ContainsKey("revpos")) {
var revPos = info.GetCast<int>("revpos");
if (revPos <= 0) {
throw new CouchbaseLiteException(StatusCode.BadAttachment);
}

RevPos = revPos;
}
} else {
throw new CouchbaseLiteException(StatusCode.BadAttachment);
}
Expand Down
132 changes: 130 additions & 2 deletions src/Couchbase.Lite.Shared/Replication/Pusher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,134 @@ private void RemovePending(RevisionInternal revisionInternal)
}
}

/*internal override void ProcessInbox(RevisionList inbox)
{
if (!online) {
Log.V(Tag, "Offline, so skipping inbox process");
return;
}
// Generate a set of doc/rev IDs in the JSON format that _revs_diff wants:
// <http://wiki.apache.org/couchdb/HttpPostRevsDiff>
var diffs = new Dictionary<String, IList<String>>();
foreach (var rev in inbox) {
var docID = rev.GetDocId();
var revs = diffs.Get(docID);
if (revs == null) {
revs = new List<String>();
diffs[docID] = revs;
}
revs.AddItem(rev.GetRevId());
AddPending(rev);
}
// Call _revs_diff on the target db:
Log.D(Tag, "processInbox() calling asyncTaskStarted()");
Log.D(Tag, "posting to /_revs_diff: {0}", String.Join(Environment.NewLine, new[] { Manager.GetObjectMapper().WriteValueAsString(diffs) }));
AsyncTaskStarted();
SendAsyncRequest(HttpMethod.Post, "/_revs_diff", diffs, (response, e) =>
{
try {
var results = response.AsDictionary<string, object>();
Log.D(Tag, "/_revs_diff response: {0}\r\n{1}", response, results);
if (e != null) {
LastError = e;
RevisionFailed();
} else {
if (results.Count != 0) {
// Go through the list of local changes again, selecting the ones the destination server
// said were missing and mapping them to a JSON dictionary in the form _bulk_docs wants:
var docsToSend = new List<object> ();
var revsToSend = new RevisionList();
foreach (var rev in inbox) {
// Is this revision in the server's 'missing' list?
IDictionary<string, object> properties = null;
var revResults = results.Get(rev.GetDocId()).AsDictionary<string, object>();
if (revResults == null) {
continue;
}
var revs = revResults.Get("missing").AsList<string>();
if (revs == null || !revs.Any( id => id.Equals(rev.GetRevId(), StringComparison.OrdinalIgnoreCase))) {
RemovePending(rev);
continue;
}
RevisionInternal loadedRev;
try {
loadedRev = LocalDatabase.LoadRevisionBody (rev);
properties = new Dictionary<string, object>(rev.GetProperties());
} catch (CouchbaseLiteException e1) {
Log.W(Tag, string.Format("{0} Couldn't get local contents of {1}", rev, this), e1);
RevisionFailed();
continue;
}
if(loadedRev.GetProperties().GetCast<bool>("_removed")) {
// Filter out _removed revision
RemovePending(rev);
continue;
}
var populatedRev = TransformRevision(loadedRev);
IList<string> possibleAncestors = null;
if (revResults.ContainsKey("possible_ancestors")) {
possibleAncestors = revResults["possible_ancestors"].AsList<string>();
}
properties = new Dictionary<string, object>(populatedRev.GetProperties());
var history = LocalDatabase.GetRevisionHistory(populatedRev, possibleAncestors);
properties["_revisions"] = Database.MakeRevisionHistoryDict(history);
populatedRev.SetProperties(properties);
// Strip any attachments already known to the target db:
if (properties.ContainsKey("_attachments")) {
// Look for the latest common ancestor and stub out older attachments:
var minRevPos = FindCommonAncestor(populatedRev, possibleAncestors);
Status status = new Status();
if(!LocalDatabase.ExpandAttachments(populatedRev, minRevPos + 1, !dontSendMultipart, false, status)) {
Log.W(Tag, "Error expanding attachments!");
RevisionFailed();
continue;
}
properties = populatedRev.GetProperties();
if (!dontSendMultipart && UploadMultipartRevision(populatedRev)) {
SafeIncrementCompletedChangesCount();
continue;
}
}
if (properties == null || !properties.ContainsKey("_id")) {
throw new InvalidOperationException("properties must contain a document _id");
}
// Add the _revisions list:
revsToSend.Add(rev);
//now add it to the docs to send
docsToSend.AddItem (properties);
}
UploadBulkDocs(docsToSend, revsToSend);
} else {
foreach (var revisionInternal in inbox) {
RemovePending(revisionInternal);
}
}
}
} catch (Exception ex) {
Log.E(Tag, "Unhandled exception in Pusher.ProcessInbox", ex);
} finally {
Log.D(Tag, "processInbox() calling AsyncTaskFinished()");
AsyncTaskFinished(1);
}
});
}*/

private void UploadBulkDocs(IList<object> docsToSend, RevisionList revChanges)
{
// Post the revisions to the destination. "new_edits":false means that the server should
Expand Down Expand Up @@ -617,8 +745,8 @@ internal override void ProcessInbox(RevisionList inbox)
}
properties = new Dictionary<string, object>(populatedRev.GetProperties());
var revisions = LocalDatabase.Storage.GetRevisionHistory(populatedRev, possibleAncestors);
properties["_revisions"] = revisions;
var history = LocalDatabase.GetRevisionHistory(populatedRev, possibleAncestors);
properties["_revisions"] = Database.MakeRevisionHistoryDict(history);
populatedRev.SetProperties(properties);
// Strip any attachments already known to the target db:
Expand Down
2 changes: 1 addition & 1 deletion src/Couchbase.Lite.Shared/Revisions/SavedRevision.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ public override String ParentId {
public override IEnumerable<SavedRevision> RevisionHistory {
get {
var revisions = new List<SavedRevision>();
var internalRevisions = Database.Storage.GetRevisionHistory(RevisionInternal);
var internalRevisions = Database.Storage.GetRevisionHistory(RevisionInternal, null);

foreach (var internalRevision in internalRevisions)
{
Expand Down
10 changes: 7 additions & 3 deletions src/Couchbase.Lite.Shared/Store/SqliteCouchStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ internal static string ParseRevIDSuffix(string rev)

internal IDictionary<string, object> GetRevisionHistoryDictStartingFromAnyAncestor(RevisionInternal rev, IList<string>ancestorRevIDs)
{
var history = GetRevisionHistory(rev); // This is in reverse order, newest ... oldest
var history = GetRevisionHistory(rev, null); // This is in reverse order, newest ... oldest
if (ancestorRevIDs != null && ancestorRevIDs.Any())
{
for (var i = 0; i < history.Count; i++)
Expand Down Expand Up @@ -1234,7 +1234,7 @@ public RevisionInternal GetParentRevision(RevisionInternal rev)
return result;
}

public IList<RevisionInternal> GetRevisionHistory(RevisionInternal rev)
public IList<RevisionInternal> GetRevisionHistory(RevisionInternal rev, ICollection<string> ancestorRevIds)
{
string docId = rev.GetDocId();
string revId = rev.GetRevId();
Expand Down Expand Up @@ -1272,6 +1272,10 @@ public IList<RevisionInternal> GetRevisionHistory(RevisionInternal rev)
if(lastSequence == 0) {
return false;
}
if(ancestorRevIds != null && ancestorRevIds.Contains(revId)) {
return false;
}
}
return true;
Expand All @@ -1285,7 +1289,7 @@ public IList<RevisionInternal> GetRevisionHistory(RevisionInternal rev)
return history;
}

public IDictionary<string, object> GetRevisionHistory(RevisionInternal rev, IList<string> ancestorRevIds)
public IDictionary<string, object> GetRevisionHistoryDict(RevisionInternal rev, IList<string> ancestorRevIds)
{
string docId = rev.GetDocId();
string revId = rev.GetRevId();
Expand Down
2 changes: 1 addition & 1 deletion src/Couchbase.Lite.Tests.Shared/CRUDOperationsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public void TestCRUDOperations()
Assert.IsTrue(changeRevisions.Count == 1);

// Get Revision History:
IList<RevisionInternal> history = database.Storage.GetRevisionHistory(revD);
IList<RevisionInternal> history = database.Storage.GetRevisionHistory(revD, null);
Assert.AreEqual(revD, history[0]);
Assert.AreEqual(rev2, history[1]);
Assert.AreEqual(rev1, history[2]);
Expand Down
Loading

0 comments on commit b2ae33f

Please sign in to comment.