public void Test08DocRevisions() { const string TEST_NAME = "test8"; if (!PerformanceTestsEnabled) { return; } var docs = new Document[GetNumberOfDocuments(TEST_NAME)]; var success = database.RunInTransaction(() => { for (int i = 0; i < GetNumberOfDocuments(TEST_NAME); i++) { var props = new Dictionary <string, object> { { "toggle", true } }; var doc = database.CreateDocument(); try { doc.PutProperties(props); docs[i] = doc; } catch (CouchbaseLiteException e) { Log.E(TAG, "Document creation failed"); return(false); } } return(true); }); Assert.IsTrue(success); TimeBlock(String.Format("{0}, {1}", GetNumberOfDocuments(TEST_NAME), GetNumberOfUpdates(TEST_NAME)), () => { foreach (var doc in docs) { for (int i = 0; i < GetNumberOfUpdates(TEST_NAME); i++) { var contents = new Dictionary <string, object>(doc.Properties); var wasChecked = contents.GetCast <bool>("toggle"); contents["toggle"] = !wasChecked; doc.PutProperties(contents); } } }); }
/// <summary> /// Gets a value that is a byte array. /// </summary> /// <remarks> /// Gets a value that is a byte array. Note that this method will not convert /// any other types to byte arrays. /// </remarks> /// <param name="key">the value to get</param> /// <returns>the byte[] value, or null is the value is missing or not a byte[]</returns> public byte[] GetAsByteArray(string key) { return(mValues.GetCast <byte[]>(key)); }
private void UploadChanges(IList <RevisionInternal> changes, IDictionary <string, object> revsDiffResults) { // 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(); IDictionary <string, object> revResults = null; foreach (var rev in changes) { // Is this revision in the server's 'missing' list? if (revsDiffResults != null) { revResults = revsDiffResults.Get(rev.DocID).AsDictionary <string, object>(); if (revResults == null) { //SafeIncrementCompletedChangesCount(); continue; } var revs = revResults.Get("missing").AsList <string>(); if (revs == null || !revs.Any(id => id.Equals(rev.RevID, StringComparison.OrdinalIgnoreCase))) { RemovePending(rev); //SafeIncrementCompletedChangesCount(); continue; } } IDictionary <string, object> properties = null; // Get the revision's properties: var contentOptions = DocumentContentOptions.IncludeAttachments; if (!_dontSendMultipart && RevisionBodyTransformationFunction == null) { contentOptions |= DocumentContentOptions.BigAttachmentsFollow; } RevisionInternal loadedRev; try { loadedRev = LocalDatabase.LoadRevisionBody(rev); if (loadedRev == null) { throw Misc.CreateExceptionAndLog(Log.To.Sync, StatusCode.DbError, TAG, "Unable to load revision body"); } properties = new Dictionary <string, object>(rev.GetProperties()); } catch (Exception e1) { Log.To.Sync.E(TAG, String.Format("Couldn't get local contents of {0}, marking revision failed", rev), e1); RevisionFailed(); continue; } var populatedRev = TransformRevision(loadedRev); IList <string> possibleAncestors = null; if (revResults != null && revResults.ContainsKey("possible_ancestors")) { possibleAncestors = revResults["possible_ancestors"].AsList <string>(); } properties = new Dictionary <string, object>(populatedRev.GetProperties()); try { var history = LocalDatabase.GetRevisionHistory(populatedRev, possibleAncestors); if (history == null) { throw Misc.CreateExceptionAndLog(Log.To.Sync, StatusCode.DbError, TAG, "Unable to load revision history"); } properties["_revisions"] = Database.MakeRevisionHistoryDict(history); } catch (Exception e1) { Log.To.Sync.E(TAG, "Error getting revision history, marking revision failed", e1); RevisionFailed(); continue; } populatedRev.SetProperties(properties); if (properties.GetCast <bool>("_removed")) { RemovePending(rev); continue; } // Strip any attachments already known to the target db: if (properties.ContainsKey("_attachments")) { // Look for the latest common ancestor and stuf out older attachments: var minRevPos = FindCommonAncestor(populatedRev, possibleAncestors); try { LocalDatabase.ExpandAttachments(populatedRev, minRevPos + 1, !_dontSendMultipart, false); } catch (Exception ex) { Log.To.Sync.E(TAG, "Error expanding attachments, marking revision failed", ex); RevisionFailed(); continue; } properties = populatedRev.GetProperties(); if (!_dontSendMultipart && UploadMultipartRevision(populatedRev)) { continue; } } if (properties == null || !properties.ContainsKey("_id")) { throw Misc.CreateExceptionAndLog(Log.To.Sync, StatusCode.BadParam, TAG, "properties must contain a document _id"); } // Add the _revisions list: revsToSend.Add(rev); //now add it to the docs to send docsToSend.Add(properties); } UploadBulkDocs(docsToSend, revsToSend); }
internal override void ProcessInbox(RevisionList inbox) { if (Status == ReplicationStatus.Offline) { Log.V(TAG, "Offline, so skipping inbox process"); return; } if(_requests.Count > ManagerOptions.Default.MaxOpenHttpConnections) { Task.Delay(1000).ContinueWith(t => ProcessInbox(inbox), CancellationToken.None, TaskContinuationOptions.None, WorkExecutor.Scheduler); 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.Add(rev.GetRevId()); AddPending(rev); } // Call _revs_diff on the target db: Log.D(TAG, "posting to /_revs_diff: {0}", String.Join(Environment.NewLine, new[] { Manager.GetObjectMapper().WriteValueAsString(diffs) })); SendAsyncRequest(HttpMethod.Post, "/_revs_diff", diffs, (response, e) => { try { if(!LocalDatabase.IsOpen) { return; } 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) { //SafeIncrementCompletedChangesCount(); continue; } var revs = revResults.Get("missing").AsList<string>(); if (revs == null || !revs.Any( id => id.Equals(rev.GetRevId(), StringComparison.OrdinalIgnoreCase))) { RemovePending(rev); //SafeIncrementCompletedChangesCount(); continue; } // Get the revision's properties: var contentOptions = DocumentContentOptions.IncludeAttachments; if (!_dontSendMultipart && RevisionBodyTransformationFunction == null) { contentOptions |= DocumentContentOptions.BigAttachmentsFollow; } RevisionInternal loadedRev; try { loadedRev = LocalDatabase.LoadRevisionBody (rev); if(loadedRev == null) { throw new CouchbaseLiteException("DB is closed", StatusCode.DbError); } properties = new Dictionary<string, object>(rev.GetProperties()); } catch (Exception e1) { Log.W(TAG, String.Format("{0} Couldn't get local contents of", rev), e); RevisionFailed(); 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()); try { var history = LocalDatabase.GetRevisionHistory(populatedRev, possibleAncestors); if(history == null) { throw new CouchbaseLiteException("DB closed", StatusCode.DbError); } properties["_revisions"] = Database.MakeRevisionHistoryDict(history); } catch(Exception e1) { Log.W(TAG, "Error getting revision history", e1); RevisionFailed(); continue; } populatedRev.SetProperties(properties); if(properties.GetCast<bool>("_removed")) { RemovePending(rev); continue; } // Strip any attachments already known to the target db: if (properties.ContainsKey("_attachments")) { // Look for the latest common ancestor and stuf out older attachments: var minRevPos = FindCommonAncestor(populatedRev, possibleAncestors); try { LocalDatabase.ExpandAttachments(populatedRev, minRevPos + 1, !_dontSendMultipart, false); } catch(Exception ex) { Log.W(TAG, "Error expanding attachments!", ex); RevisionFailed(); continue; } properties = populatedRev.GetProperties(); if (!_dontSendMultipart && UploadMultipartRevision(populatedRev)) { 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.Add (properties); } UploadBulkDocs(docsToSend, revsToSend); } else { foreach (var revisionInternal in inbox) { RemovePending(revisionInternal); } SafeAddToCompletedChangesCount(inbox.Count); } } } catch (Exception ex) { Log.E(TAG, "Unhandled exception in Pusher.ProcessInbox", ex); } }); }
public void Test08DocRevisions() { const string TEST_NAME = "test8"; if (!PerformanceTestsEnabled) { return; } var docs = new Document[GetNumberOfDocuments(TEST_NAME)]; var success = database.RunInTransaction(() => { for(int i = 0; i < GetNumberOfDocuments(TEST_NAME); i++) { var props = new Dictionary<string, object> { { "toggle", true } }; var doc = database.CreateDocument(); try { doc.PutProperties(props); docs[i] = doc; } catch(CouchbaseLiteException e) { Log.E(TAG, "Document creation failed"); return false; } } return true; }); Assert.IsTrue(success); TimeBlock(String.Format("{0}, {1}", GetNumberOfDocuments(TEST_NAME), GetNumberOfUpdates(TEST_NAME)), () => { foreach(var doc in docs) { for(int i = 0; i < GetNumberOfUpdates(TEST_NAME); i++) { var contents = new Dictionary<string, object>(doc.Properties); var wasChecked = contents.GetCast<bool>("toggle"); contents["toggle"] = !wasChecked; doc.PutProperties(contents); } } }); }
internal override void ProcessInbox(RevisionList inbox) { if (Status == ReplicationStatus.Offline) { Log.To.Sync.I(TAG, "Offline, so skipping inbox process"); return; } if (_requests.Count > ReplicationOptions.MaxOpenHttpConnections) { Task.Delay(1000).ContinueWith(t => ProcessInbox(inbox), CancellationToken.None, TaskContinuationOptions.None, WorkExecutor.Scheduler); 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> >(); var inboxCount = inbox.Count; foreach (var rev in inbox) { var docID = rev.DocID; var revs = diffs.Get(docID); if (revs == null) { revs = new List <String>(); diffs[docID] = revs; } revs.Add(rev.RevID); AddPending(rev); } // Call _revs_diff on the target db: Log.To.Sync.D(TAG, "posting to /_revs_diff: {0}", String.Join(Environment.NewLine, new[] { Manager.GetObjectMapper().WriteValueAsString(diffs) })); SendAsyncRequest(HttpMethod.Post, "/_revs_diff", diffs, (response, e) => { try { if (!LocalDatabase.IsOpen) { return; } var results = response.AsDictionary <string, object>(); Log.To.Sync.D(TAG, "/_revs_diff response: {0}\r\n{1}", response, results); if (e != null) { LastError = e; for (int i = 0; i < inboxCount; i++) { RevisionFailed(); } if (Continuous) { FireTrigger(ReplicationTrigger.WaitingForChanges); } else { FireTrigger(ReplicationTrigger.StopImmediate); } } 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.DocID).AsDictionary <string, object>(); if (revResults == null) { //SafeIncrementCompletedChangesCount(); continue; } var revs = revResults.Get("missing").AsList <string>(); if (revs == null || !revs.Any(id => id.Equals(rev.RevID, StringComparison.OrdinalIgnoreCase))) { RemovePending(rev); //SafeIncrementCompletedChangesCount(); continue; } // Get the revision's properties: var contentOptions = DocumentContentOptions.IncludeAttachments; if (!_dontSendMultipart && RevisionBodyTransformationFunction == null) { contentOptions |= DocumentContentOptions.BigAttachmentsFollow; } RevisionInternal loadedRev; try { loadedRev = LocalDatabase.LoadRevisionBody(rev); if (loadedRev == null) { throw Misc.CreateExceptionAndLog(Log.To.Sync, StatusCode.DbError, TAG, "Unable to load revision body"); } properties = new Dictionary <string, object>(rev.GetProperties()); } catch (Exception e1) { Log.To.Sync.E(TAG, String.Format("Couldn't get local contents of {0}, marking revision failed", rev), e1); RevisionFailed(); 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()); try { var history = LocalDatabase.GetRevisionHistory(populatedRev, possibleAncestors); if (history == null) { throw Misc.CreateExceptionAndLog(Log.To.Sync, StatusCode.DbError, TAG, "Unable to load revision history"); } properties["_revisions"] = Database.MakeRevisionHistoryDict(history); } catch (Exception e1) { Log.To.Sync.E(TAG, "Error getting revision history, marking revision failed", e1); RevisionFailed(); continue; } populatedRev.SetProperties(properties); if (properties.GetCast <bool>("_removed")) { RemovePending(rev); continue; } // Strip any attachments already known to the target db: if (properties.ContainsKey("_attachments")) { // Look for the latest common ancestor and stuf out older attachments: var minRevPos = FindCommonAncestor(populatedRev, possibleAncestors); try { LocalDatabase.ExpandAttachments(populatedRev, minRevPos + 1, !_dontSendMultipart, false); } catch (Exception ex) { Log.To.Sync.E(TAG, "Error expanding attachments, marking revision failed", ex); RevisionFailed(); continue; } properties = populatedRev.GetProperties(); if (!_dontSendMultipart && UploadMultipartRevision(populatedRev)) { continue; } } if (properties == null || !properties.ContainsKey("_id")) { throw Misc.CreateExceptionAndLog(Log.To.Sync, StatusCode.BadParam, TAG, "properties must contain a document _id"); } // Add the _revisions list: revsToSend.Add(rev); //now add it to the docs to send docsToSend.Add(properties); } UploadBulkDocs(docsToSend, revsToSend); } else { foreach (var revisionInternal in inbox) { RemovePending(revisionInternal); } //SafeAddToCompletedChangesCount(inbox.Count); } } } catch (Exception ex) { Log.To.Sync.E(TAG, "Unhandled exception in Pusher.ProcessInbox, continuing...", ex); } }); }
private void UploadChanges(IList<RevisionInternal> changes, IDictionary<string, object> revsDiffResults) { // 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(); IDictionary<string, object> revResults = null; foreach (var rev in changes) { // Is this revision in the server's 'missing' list? if (revsDiffResults != null) { revResults = revsDiffResults.Get(rev.DocID).AsDictionary<string, object>(); if (revResults == null) { continue; } var revs = revResults.Get("missing").AsList<string>(); if (revs == null || !revs.Any(id => id.Equals(rev.RevID.ToString()))) { RemovePending(rev); continue; } } IDictionary<string, object> properties = null; RevisionInternal loadedRev; try { loadedRev = LocalDatabase.LoadRevisionBody (rev); if(loadedRev == null) { throw Misc.CreateExceptionAndLog(Log.To.Sync, StatusCode.NotFound, TAG, "Unable to load revision body"); } properties = new Dictionary<string, object>(rev.GetProperties()); } catch (Exception e1) { Log.To.Sync.E(TAG, String.Format("Couldn't get local contents of {0}, marking revision failed", rev), e1); RevisionFailed(); continue; } if (properties.GetCast<bool> ("_removed")) { RemovePending (rev); continue; } var populatedRev = TransformRevision(loadedRev); var backTo = revResults?.Get("possible_ancestors")?.AsList<RevisionID>(); try { var history = LocalDatabase.GetRevisionHistory(populatedRev, backTo); if(history == null) { throw Misc.CreateExceptionAndLog(Log.To.Sync, StatusCode.DbError, TAG, "Unable to load revision history"); } properties["_revisions"] = TreeRevisionID.MakeRevisionHistoryDict(history); populatedRev.SetPropertyForKey("_revisions", properties["_revisions"]); } catch(Exception e1) { Log.To.Sync.E(TAG, "Error getting revision history, marking revision failed", e1); RevisionFailed(); continue; } // Strip any attachments already known to the target db: if (properties.Get("_attachments") != null) { // Look for the latest common ancestor and stuf out older attachments: var minRevPos = FindCommonAncestor(populatedRev, backTo); try { LocalDatabase.ExpandAttachments(populatedRev, minRevPos + 1, !_dontSendMultipart, false); } catch(Exception ex) { Log.To.Sync.E(TAG, "Error expanding attachments, marking revision failed", ex); RevisionFailed(); continue; } properties = populatedRev.GetProperties(); if (!_dontSendMultipart && UploadMultipartRevision(populatedRev)) { continue; } } if (properties == null || !properties.ContainsKey("_id")) { throw Misc.CreateExceptionAndLog(Log.To.Sync, StatusCode.BadParam, TAG, "properties must contain a document _id"); } // Add the _revisions list: revsToSend.Add(rev); //now add it to the docs to send docsToSend.Add (properties); } UploadBulkDocs(docsToSend, revsToSend); }