protected internal override void ProcessInbox(RevisionList inbox)
        {
            // Ask the local database which of the revs are not known to it:
            //Log.w(Database.TAG, String.format("%s: Looking up %s", this, inbox));
            string lastInboxSequence = ((PulledRevision)inbox[inbox.Count - 1]).GetRemoteSequenceID
                                           ();
            int total = GetChangesCount() - inbox.Count;

            if (!db.FindMissingRevisions(inbox))
            {
                Log.W(Database.Tag, string.Format("%s failed to look up local revs", this));
                inbox = null;
            }
            //introducing this to java version since inbox may now be null everywhere
            int inboxCount = 0;

            if (inbox != null)
            {
                inboxCount = inbox.Count;
            }
            if (GetChangesCount() != total + inboxCount)
            {
                SetChangesCount(total + inboxCount);
            }
            if (inboxCount == 0)
            {
                // Nothing to do. Just bump the lastSequence.
                Log.W(Database.Tag, string.Format("%s no new remote revisions to fetch", this));
                long seq = pendingSequences.AddValue(lastInboxSequence);
                pendingSequences.RemoveSequence(seq);
                SetLastSequence(pendingSequences.GetCheckpointedValue());
                return;
            }
            Log.V(Database.Tag, this + " fetching " + inboxCount + " remote revisions...");
            //Log.v(Database.TAG, String.format("%s fetching remote revisions %s", this, inbox));
            // Dump the revs into the queue of revs to pull from the remote db:
            lock (this)
            {
                if (revsToPull == null)
                {
                    revsToPull = new AList <RevisionInternal>(200);
                }
                for (int i = 0; i < inbox.Count; i++)
                {
                    PulledRevision rev = (PulledRevision)inbox[i];
                    // FIXME add logic here to pull initial revs in bulk
                    rev.SetSequence(pendingSequences.AddValue(rev.GetRemoteSequenceID()));
                    revsToPull.AddItem(rev);
                }
            }
            PullRemoteRevisions();
        }
Exemple #2
0
 public void OnCompletion(object result, Exception e)
 {
     try
     {
         if (e != null)
         {
             Log.E(Log.TagSync, "Error pulling remote revision", e);
             this._enclosing.SetError(e);
             this._enclosing.RevisionFailed();
             Log.D(Log.TagSync, "%s: pullRemoteRevision() updating completedChangesCount from %d  ->  due to error pulling remote revision"
                   , this, this._enclosing.GetCompletedChangesCount(), this._enclosing.GetCompletedChangesCount
                       () + 1);
             this._enclosing.AddToCompletedChangesCount(1);
         }
         else
         {
             IDictionary <string, object> properties = (IDictionary <string, object>)result;
             PulledRevision gotRev = new PulledRevision(properties, this._enclosing.db);
             gotRev.SetSequence(rev.GetSequence());
             // Add to batcher ... eventually it will be fed to -insertDownloads:.
             Log.V(Log.TagSync, "%s | %s: pullRemoteRevision.sendAsyncMultipartDownloaderRequest() calling asyncTaskStarted()"
                   , this, Sharpen.Thread.CurrentThread());
             this._enclosing.AsyncTaskStarted();
             // TODO: [gotRev.body compact];
             Log.D(Log.TagSync, "%s: pullRemoteRevision add rev: %s to batcher", this, gotRev);
             this._enclosing.downloadsToInsert.QueueObject(gotRev);
         }
     }
     finally
     {
         Log.V(Log.TagSync, "%s | %s: pullRemoteRevision.sendAsyncMultipartDownloaderRequest() calling asyncTaskFinished()"
               , this, Sharpen.Thread.CurrentThread());
         this._enclosing.AsyncTaskFinished(1);
     }
     // Note that we've finished this task; then start another one if there
     // are still revisions waiting to be pulled:
     --this._enclosing.httpConnectionCount;
     this._enclosing.PullRemoteRevisions();
 }
Exemple #3
0
        /// <summary>Fetches the contents of a revision from the remote db, including its parent revision ID.
        ///     </summary>
        /// <remarks>
        /// Fetches the contents of a revision from the remote db, including its parent revision ID.
        /// The contents are stored into rev.properties.
        /// </remarks>
        internal void PullRemoteRevision(RevisionInternal rev)
        {
            Log.D(Tag, "PullRemoteRevision with rev: {0}", rev);

            Log.D(Tag, "PullRemoteRevision() calling AsyncTaskStarted()");
            AsyncTaskStarted();

            httpConnectionCount++;

            // Construct a query. We want the revision history, and the bodies of attachments that have
            // been added since the latest revisions we have locally.
            // See: http://wiki.apache.org/couchdb/HTTP_Document_API#Getting_Attachments_With_a_Document
            var path      = new StringBuilder("/" + Uri.EscapeUriString(rev.GetDocId()) + "?rev=" + Uri.EscapeUriString(rev.GetRevId()) + "&revs=true&attachments=true");
            var knownRevs = KnownCurrentRevIDs(rev);

            if (knownRevs == null)
            {
                //this means something is wrong, possibly the replicator has shut down
                Log.D(Tag, "PullRemoteRevision() calling AsyncTaskFinished()");
                AsyncTaskFinished(1);

                httpConnectionCount--;
                return;
            }

            if (knownRevs.Count > 0)
            {
                path.Append("&atts_since=");
                path.Append(JoinQuotedEscaped(knownRevs));
            }

            //create a final version of this variable for the log statement inside
            //FIXME find a way to avoid this
            var pathInside = path.ToString();

            SendAsyncMultipartDownloaderRequest(HttpMethod.Get, pathInside, null, LocalDatabase, (result, e) =>
            {
                try
                {
                    // OK, now we've got the response revision:
                    Log.D(Tag, "PullRemoteRevision got response for rev: " + rev);

                    if (e != null)
                    {
                        Log.E(Tag, "Error pulling remote revision", e);
                        SetLastError(e);
                        RevisionFailed();
                        Log.D(Tag, "PullRemoteRevision updating completedChangesCount from " +
                              CompletedChangesCount + " -> " + (CompletedChangesCount + 1)
                              + " due to error pulling remote revision");
                        SafeIncrementCompletedChangesCount();
                    }
                    else
                    {
                        var properties = result.AsDictionary <string, object>();
                        var gotRev     = new PulledRevision(properties);
                        gotRev.SetSequence(rev.GetSequence());
                        AsyncTaskStarted();
                        Log.D(Tag, "PullRemoteRevision add rev: " + gotRev + " to batcher");

                        if (downloadsToInsert != null)
                        {
                            downloadsToInsert.QueueObject(gotRev);
                        }
                        else
                        {
                            Log.E(Tag, "downloadsToInsert is null");
                        }
                    }
                }
                finally
                {
                    Log.D(Tag, "PullRemoteRevision.onCompletion() calling AsyncTaskFinished()");
                    AsyncTaskFinished(1);
                }

                // Note that we've finished this task; then start another one if there
                // are still revisions waiting to be pulled:
                --httpConnectionCount;
                PullRemoteRevisions();
            });
        }
Exemple #4
0
        protected internal override void ProcessInbox(RevisionList inbox)
        {
            if (canBulkGet == null)
            {
                canBulkGet = ServerIsSyncGatewayVersion("0.81");
            }
            // Ask the local database which of the revs are not known to it:
            string lastInboxSequence = ((PulledRevision)inbox[inbox.Count - 1]).GetRemoteSequenceID
                                           ();
            int numRevisionsRemoved = 0;

            try
            {
                // findMissingRevisions is the local equivalent of _revs_diff. it looks at the
                // array of revisions in ‘inbox’ and removes the ones that already exist. So whatever’s left in ‘inbox’
                // afterwards are the revisions that need to be downloaded.
                numRevisionsRemoved = db.FindMissingRevisions(inbox);
            }
            catch (SQLException e)
            {
                Log.E(Log.TagSync, string.Format("%s failed to look up local revs", this), e);
                inbox = null;
            }
            //introducing this to java version since inbox may now be null everywhere
            int inboxCount = 0;

            if (inbox != null)
            {
                inboxCount = inbox.Count;
            }
            if (numRevisionsRemoved > 0)
            {
                Log.V(Log.TagSync, "%s: processInbox() setting changesCount to: %s", this, GetChangesCount
                          () - numRevisionsRemoved);
                // May decrease the changesCount, to account for the revisions we just found out we don’t need to get.
                AddToChangesCount(-1 * numRevisionsRemoved);
            }
            if (inboxCount == 0)
            {
                // Nothing to do. Just bump the lastSequence.
                Log.W(Log.TagSync, "%s no new remote revisions to fetch", this);
                long seq = pendingSequences.AddValue(lastInboxSequence);
                pendingSequences.RemoveSequence(seq);
                SetLastSequence(pendingSequences.GetCheckpointedValue());
                return;
            }
            Log.V(Log.TagSync, "%s: fetching %s remote revisions...", this, inboxCount);
            // Dump the revs into the queue of revs to pull from the remote db:
            lock (this)
            {
                int numBulked = 0;
                for (int i = 0; i < inbox.Count; i++)
                {
                    PulledRevision rev = (PulledRevision)inbox[i];
                    //TODO: add support for rev isConflicted
                    if (canBulkGet || (rev.GetGeneration() == 1 && !rev.IsDeleted()))
                    {
                        // &&!rev.isConflicted)
                        //optimistically pull 1st-gen revs in bulk
                        if (bulkRevsToPull == null)
                        {
                            bulkRevsToPull = new AList <RevisionInternal>(100);
                        }
                        bulkRevsToPull.AddItem(rev);
                        ++numBulked;
                    }
                    else
                    {
                        QueueRemoteRevision(rev);
                    }
                    rev.SetSequence(pendingSequences.AddValue(rev.GetRemoteSequenceID()));
                }
            }
            PullRemoteRevisions();
        }
Exemple #5
0
        /// <summary>Fetches the contents of a revision from the remote db, including its parent revision ID.
        ///     </summary>
        /// <remarks>
        /// Fetches the contents of a revision from the remote db, including its parent revision ID.
        /// The contents are stored into rev.properties.
        /// </remarks>
        private void PullRemoteRevision(RevisionInternal rev)
        {
            Log.D(TAG, "PullRemoteRevision with rev: {0}", rev);
            _httpConnectionCount++;

            // Construct a query. We want the revision history, and the bodies of attachments that have
            // been added since the latest revisions we have locally.
            // See: http://wiki.apache.org/couchdb/HTTP_Document_API#Getting_Attachments_With_a_Document
            var path      = new StringBuilder("/" + Uri.EscapeUriString(rev.GetDocId()) + "?rev=" + Uri.EscapeUriString(rev.GetRevId()) + "&revs=true&attachments=true");
            var knownRevs = default(IList <string>);

            try {
                var tmp = LocalDatabase.Storage.GetPossibleAncestors(rev, MAX_ATTS_SINCE, true);
                knownRevs = tmp == null ? null : tmp.ToList();
            } catch (Exception) {
                Log.W(TAG, "Error getting possible ancestors (probably database closed)");
            }
            if (knownRevs == null)
            {
                //this means something is wrong, possibly the replicator has shut down
                _httpConnectionCount--;
                return;
            }

            if (knownRevs.Count > 0)
            {
                path.Append("&atts_since=");
                path.Append(JoinQuotedEscaped(knownRevs));
            }

            //create a final version of this variable for the log statement inside
            //FIXME find a way to avoid this
            var pathInside = path.ToString();

            SendAsyncMultipartDownloaderRequest(HttpMethod.Get, pathInside, null, LocalDatabase, (result, e) =>
            {
                // OK, now we've got the response revision:
                Log.D(TAG, "PullRemoteRevision got response for rev: " + rev);

                if (e != null)
                {
                    Log.E(TAG, "Error pulling remote revision", e);
                    LastError = e;
                    RevisionFailed();
                    Log.D(TAG, "PullRemoteRevision updating completedChangesCount from " +
                          CompletedChangesCount + " -> " + (CompletedChangesCount + 1)
                          + " due to error pulling remote revision");
                    SafeIncrementCompletedChangesCount();
                    if (IsDocumentError(e as HttpResponseException))
                    {
                        // Make sure this document is skipped because it is not available
                        // even though the server is functioning
                        _pendingSequences.RemoveSequence(rev.GetSequence());
                        LastSequence = _pendingSequences.GetCheckpointedValue();
                    }
                }
                else
                {
                    var properties = result.AsDictionary <string, object>();
                    var gotRev     = new PulledRevision(properties);
                    gotRev.SetSequence(rev.GetSequence());
                    Log.D(TAG, "PullRemoteRevision add rev: " + gotRev + " to batcher");

                    if (_downloadsToInsert != null)
                    {
                        _downloadsToInsert.QueueObject(gotRev);
                    }
                    else
                    {
                        Log.E(TAG, "downloadsToInsert is null");
                    }
                }

                // Note that we've finished this task; then start another one if there
                // are still revisions waiting to be pulled:
                --_httpConnectionCount;
                PullRemoteRevisions();
            });
        }