private void SaveLastSequence(SaveLastSequenceCompletionBlock completionHandler)
        {
            
            if (!lastSequenceChanged) {
                if (completionHandler != null) {
                    completionHandler();
                }
                return;
            }

            if (_savingCheckpoint) {
                // If a save is already in progress, don't do anything. (The completion block will trigger
                // another save after the first one finishes.)
                Task.Delay(500).ContinueWith(t => SaveLastSequence(completionHandler));
            }

            lastSequenceChanged = false;

            Log.D(TAG, "saveLastSequence() called. lastSequence: " + LastSequence);

            var body = new Dictionary<String, Object>();
            if (_remoteCheckpoint != null) {
                body.PutAll(_remoteCheckpoint);
            }

            body["lastSequence"] = LastSequence;
            var remoteCheckpointDocID = RemoteCheckpointDocID();
            if (String.IsNullOrEmpty(remoteCheckpointDocID)) {
                Log.W(TAG, "remoteCheckpointDocID is null, aborting saveLastSequence()");
                return;
            }

            _savingCheckpoint = true;
            var message = SendAsyncRequest(HttpMethod.Put, "/_local/" + remoteCheckpointDocID, body, (result, e) => 
            {
                _savingCheckpoint = false;
                if (e != null) {
                    Log.V(TAG, "Unable to save remote checkpoint", e);
                }
                    
                

                if (e != null) {
                    switch (GetStatusFromError(e)) {
                        case StatusCode.NotFound:
                            _remoteCheckpoint = null;
                            break;
                        case StatusCode.Conflict:
                            RefreshRemoteCheckpointDoc();
                            break;
                        default:
                            // TODO: On 401 or 403, and this is a pull, remember that remote
                            // TODO: is read-only & don't attempt to read its checkpoint next time.
                            break;
                    }
                } else {
                    Log.D(TAG, "Save checkpoint response: " + result);
                    var response = result.AsDictionary<string, object>();
                    body.Put ("_rev", response.Get ("rev"));
                    _remoteCheckpoint = body;
                    var localDb = LocalDatabase;
                    if(localDb == null || localDb.Storage == null) {
                        Log.W(TAG, "Database is null, ignoring remote checkpoint response");
                        if(completionHandler != null) {
                            completionHandler();
                        }
                        return;
                    }
                    localDb.SetLastSequence(LastSequence, remoteCheckpointDocID);
                }

                if (completionHandler != null) {
                    completionHandler ();
                }
            });

            // This request should not be canceled when the replication is told to stop:
            Task dummy;
            _requests.TryRemove(message, out dummy);
        }
예제 #2
0
        private void SaveLastSequence(SaveLastSequenceCompletionBlock completionHandler)
        {
            if (!lastSequenceChanged) {
                if (completionHandler != null) {
                    completionHandler();
                }
                return;
            }

            if (_savingCheckpoint) {
                // If a save is already in progress, don't do anything. (The completion block will trigger
                // another save after the first one finishes.)
                _overdueForSave = true;
                return;
            }

            lastSequenceChanged = false;
            _overdueForSave = false;

            Log.D(TAG, "saveLastSequence() called. lastSequence: " + LastSequence);

            var body = new Dictionary<String, Object>();
            if (_remoteCheckpoint != null) {
                body.PutAll(_remoteCheckpoint);
            }

            body["lastSequence"] = LastSequence;
            var remoteCheckpointDocID = RemoteCheckpointDocID();
            if (String.IsNullOrEmpty(remoteCheckpointDocID)) {
                Log.W(TAG, "remoteCheckpointDocID is null, aborting saveLastSequence()");
                return;
            }

            _savingCheckpoint = true;
            SendAsyncRequest(HttpMethod.Put, "/_local/" + remoteCheckpointDocID, body, (result, e) => 
            {
                _savingCheckpoint = false;
                if (e != null) {
                    Log.V (TAG, "Unable to save remote checkpoint", e);
                }

                if (LocalDatabase == null) {
                    Log.W(TAG, "Database is null, ignoring remote checkpoint response");
                    if (completionHandler != null) {
                        completionHandler ();
                    }
                    return;
                }

                if (!LocalDatabase.Open()) {
                    Log.W(TAG, "Database is closed, ignoring remote checkpoint response");
                    if (completionHandler != null)
                    {
                        completionHandler ();
                    }
                    return;
                }

                if (e != null) {
                    switch (GetStatusFromError(e)) {
                        case StatusCode.NotFound:
                            _remoteCheckpoint = null;
                            _overdueForSave = true;
                            break;
                        case StatusCode.Conflict:
                            RefreshRemoteCheckpointDoc();
                            break;
                        default:
                            // TODO: On 401 or 403, and this is a pull, remember that remote
                            // TODO: is read-only & don't attempt to read its checkpoint next time.
                            break;
                    }
                } else {
                    Log.D(TAG, "Save checkpoint response: " + result.ToString());
                    var response = result.AsDictionary<string, object>();
                    body.Put ("_rev", response.Get ("rev"));
                    _remoteCheckpoint = body;
                    LocalDatabase.SetLastSequence(LastSequence, RemoteCheckpointDocID(), !IsPull);
                }

                if (_overdueForSave) {
                    SaveLastSequence (completionHandler);
                } else if (completionHandler != null) {
                    completionHandler ();
                }
            });
        }
        private void SaveLastSequence(SaveLastSequenceCompletionBlock completionHandler)
        {
            if (!lastSequenceChanged) {
                if (completionHandler != null) {
                    completionHandler();
                }
                return;
            }

            if (_savingCheckpoint) {
                // If a save is already in progress, don't do anything. (The completion block will trigger
                // another save after the first one finishes.)
                Task.Delay(500).ContinueWith(t => SaveLastSequence(completionHandler));
                return;
            }

            lastSequenceChanged = false;
            var lastSequence = LastSequence;
            Log.To.Sync.I(Tag, "{0} checkpointing sequence={1}", this, lastSequence);
            var body = new Dictionary<String, Object>();
            if (_remoteCheckpoint != null) {
                foreach (var pair in _remoteCheckpoint) {
                    body[pair.Key] = pair.Value;
                }
            }

            body["lastSequence"] = lastSequence;
            var remoteCheckpointDocID = RemoteCheckpointDocID();
            if (String.IsNullOrEmpty(remoteCheckpointDocID)) {
                Log.To.Sync.W(Tag, "remoteCheckpointDocID is null for {0}, aborting SaveLastSequence", this);
                if (completionHandler != null) { completionHandler(); }
                return;
            }

            _savingCheckpoint = true;
            var message = _remoteSession.SendAsyncRequest(HttpMethod.Put, "/_local/" + remoteCheckpointDocID, body, (result, e) => 
            {
                _savingCheckpoint = false;
                if (e != null) {
                    switch (GetStatusFromError(e)) {
                        case StatusCode.NotFound:
                            Log.To.Sync.I(Tag, "Got 404 from _local, ignoring...");
                            _remoteCheckpoint = null;
                            break;
                        case StatusCode.Conflict:
                            Log.To.Sync.I(Tag, "Got 409 from _local, retrying...");
                            RefreshRemoteCheckpointDoc();
                            break;
                        default:
                            Log.To.Sync.W(Tag, String.Format("Unable to save remote checkpoint for {0}", _replicatorID), e);
                            // TODO: On 401 or 403, and this is a pull, remember that remote
                            // TODO: is read-only & don't attempt to read its checkpoint next time.
                            break;
                    }
                } else {
                    var response = result.AsDictionary<string, object>();
                    var rev = response.GetCast<string>("rev");
                    if(rev != null) {
                        body.SetRevID(rev);
                    }

                    _remoteCheckpoint = body;
                    var localDb = LocalDatabase;
                    if(localDb.Storage == null) {
                        Log.To.Sync.I(Tag, "Database is null or closed, ignoring remote checkpoint response");
                        if(completionHandler != null) {
                            completionHandler();
                        }
                        return;
                    }

                    localDb.SetLastSequence(LastSequence, remoteCheckpointDocID);
                    Log.To.Sync.I(Tag, "{0} saved remote checkpoint '{1}' (_rev={2})", this, lastSequence, rev);
                }

                if (completionHandler != null) {
                    completionHandler ();
                }
            }, true);

            // This request should not be canceled when the replication is told to stop:
            if(message != null) {
                Task dummy;
                _remoteSession?._requests.TryRemove(message, out dummy);
            }
        }