public RevisionInternal PutLocalRevision(RevisionInternal revision, RevisionID prevRevId, bool obeyMVCC)
        {
            var docId = revision.DocID;
            if(!docId.StartsWith("_local/")) {
                throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.BadId, TAG,
                    "Invalid document ID ({0}) in write operation, it must start with _local/",
                    new SecureLogString(docId, LogMessageSensitivity.PotentiallyInsecure));
            }

            if(revision.Deleted) {
                DeleteLocalRevision(docId, prevRevId, obeyMVCC);
                return revision;
            }

            var result = default(RevisionInternal);
            RunInTransaction(() =>
            {
                var json = Manager.GetObjectMapper().WriteValueAsString(revision.GetProperties(), true);
                WithC4Raw(docId, "_local", doc =>
                {
                    var generation = prevRevId == null ? 0 : prevRevId.Generation;
                    if(obeyMVCC) {
                        var currentRevId = (doc != null ? doc->meta.AsRevID() : null);
                        if(prevRevId != null) {
                            if(prevRevId != currentRevId) {
                                throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.Conflict, TAG,
                                    "Attempt to write new revision on {0} of {1} when a newer revision ({2}) exists",
                                    prevRevId, new SecureLogString(docId, LogMessageSensitivity.PotentiallyInsecure),
                                    currentRevId);
                            }

                            if(generation == 0) {
                                throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.BadId, TAG,
                                    "Attempt to write new revision on invalid revision ID ({0}) for document {1}",
                                    prevRevId, new SecureLogString(docId, LogMessageSensitivity.PotentiallyInsecure));
                            }
                        } else if(doc != null) {
                            throw Misc.CreateExceptionAndLog(Log.To.Database, StatusCode.Conflict, TAG,
                                "Revision ID not specified, but document {0} already exists (current rev: {1})",
                                new SecureLogString(docId, LogMessageSensitivity.PotentiallyInsecure), currentRevId);
                        }
                    }

                    var newRevId = String.Format("{0}-local", ++generation).AsRevID();
                    ForestDBBridge.Check(err => Native.c4raw_put(Forest, "_local", docId, newRevId.ToString(), json, err));
                    result = revision.Copy(docId, newRevId);
                });

                return true;
            });

            return result;
        }
예제 #2
0
        // Uploads the revision as JSON instead of multipart.
        private void UploadJsonRevision(RevisionInternal originalRev)
        {
            // Expand all attachments inline:
            var rev = originalRev.Copy(originalRev.DocID, originalRev.RevID);
            try {
                LocalDatabase.ExpandAttachments(rev, 0, false, false);
            } catch(Exception e) {
                LastError = e;
                RevisionFailed();
                return;
            }

            var path = string.Format("/{0}?new_edits=false", Uri.EscapeUriString(rev.DocID));
            _remoteSession.SendAsyncRequest(HttpMethod.Put, path, rev.GetProperties(), (result, e) =>
            {
                if (e != null) 
                {
                    LastError = e;
                    RevisionFailed();
                } 
                else 
                {
                    Log.To.Sync.V(TAG, "{0} sent {1} (JSON), response={2}", this, rev, new LogJsonString(result));
                    SafeIncrementCompletedChangesCount();
                    RemovePending (rev);
                }
            });
        }
예제 #3
0
        // This is used by the listener
        internal RevisionInternal RevisionByLoadingBody(RevisionInternal rev, Status outStatus)
        {
            // First check for no-op -- if we just need the default properties and already have them:
            if(rev.Sequence != 0) {
                var props = rev.GetProperties();
                if(props != null && props.ContainsKey("_rev") && props.ContainsKey("_id")) {
                    if(outStatus != null) {
                        outStatus.Code = StatusCode.Ok;
                    }

                    return rev;
                }
            }

            RevisionInternal nuRev = rev.Copy(rev.DocID, rev.RevID);
            try {
                LoadRevisionBody(nuRev);
            } catch(CouchbaseLiteException e) {
                if(outStatus != null) {
                    outStatus.Code = e.CBLStatus.Code;
                }

                nuRev = null;
            }

            return nuRev;
        }