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); }
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); } }