コード例 #1
0
        public void ForceInsert(RevisionInternal inRev, IList <string> revHistory, StoreValidation validationBlock, Uri source)
        {
            if (_config.HasFlag(C4DatabaseFlags.ReadOnly))
            {
                throw new CouchbaseLiteException("Attempting to write to a readonly database", StatusCode.Forbidden);
            }

            var json   = Manager.GetObjectMapper().WriteValueAsString(inRev.GetProperties(), true);
            var change = default(DocumentChange);

            RunInTransaction(() =>
            {
                // First get the CBForest doc:
                WithC4Document(inRev.GetDocId(), null, false, true, doc =>
                {
                    ForestDBBridge.Check(err => Native.c4doc_insertRevisionWithHistory(doc, json, inRev.IsDeleted(),
                                                                                       inRev.GetAttachments() != null, revHistory.ToArray(), err));

                    // Save updated doc back to the database:
                    var isWinner = SaveDocument(doc, revHistory[0], inRev.GetProperties());
                    inRev.SetSequence((long)doc->sequence);
                    change = ChangeWithNewRevision(inRev, isWinner, doc, source);
                });

                return(true);
            });

            if (change != null && Delegate != null)
            {
                Delegate.DatabaseStorageChanged(change);
            }
        }
コード例 #2
0
ファイル: Puller.cs プロジェクト: z000z/couchbase-lite-net
            public void OnCompletion(object result, Exception e)
            {
                IDictionary <string, object> res = (IDictionary <string, object>)result;

                if (e != null)
                {
                    this._enclosing.SetError(e);
                    this._enclosing.RevisionFailed();
                    this._enclosing.completedChangesCount.AddAndGet(bulkRevs.Count);
                }
                else
                {
                    // Process the resulting rows' documents.
                    // We only add a document if it doesn't have attachments, and if its
                    // revID matches the one we asked for.
                    IList <IDictionary <string, object> > rows = (IList <IDictionary <string, object> >)res
                                                                 .Get("rows");
                    Log.V(Log.TagSync, "%s checking %d bulk-fetched remote revisions", this, rows.Count
                          );
                    foreach (IDictionary <string, object> row in rows)
                    {
                        IDictionary <string, object> doc = (IDictionary <string, object>)row.Get("doc");
                        if (doc != null && doc.Get("_attachments") == null)
                        {
                            RevisionInternal rev = new RevisionInternal(doc, this._enclosing.db);
                            int pos = remainingRevs.IndexOf(rev);
                            if (pos > -1)
                            {
                                rev.SetSequence(remainingRevs[pos].GetSequence());
                                remainingRevs.Remove(pos);
                                this._enclosing.QueueDownloadedRevision(rev);
                            }
                        }
                    }
                }
                // Any leftover revisions that didn't get matched will be fetched individually:
                if (remainingRevs.Count > 0)
                {
                    Log.V(Log.TagSync, "%s bulk-fetch didn't work for %d of %d revs; getting individually"
                          , this, remainingRevs.Count, bulkRevs.Count);
                    foreach (RevisionInternal rev in remainingRevs)
                    {
                        this._enclosing.QueueRemoteRevision(rev);
                    }
                    this._enclosing.PullRemoteRevisions();
                }
                // Note that we've finished this task:
                Log.V(Log.TagSync, "%s | %s: pullBulkWithAllDocs() calling asyncTaskFinished()",
                      this, Sharpen.Thread.CurrentThread());
                this._enclosing.AsyncTaskFinished(1);
                --this._enclosing.httpConnectionCount;
                // Start another task if there are still revisions waiting to be pulled:
                this._enclosing.PullRemoteRevisions();
            }
コード例 #3
0
        public RevisionInternal GetParentRevision(RevisionInternal rev)
        {
            var retVal = default(RevisionInternal);

            WithC4Document(rev.GetDocId(), rev.GetRevId(), false, false, doc =>
            {
                if (!Native.c4doc_selectParentRevision(doc))
                {
                    return;
                }

                ForestDBBridge.Check(err => Native.c4doc_loadRevisionBody(doc, err));
                retVal = new RevisionInternal((string)doc->docID, (string)doc->selectedRev.revID, doc->selectedRev.IsDeleted);
                retVal.SetSequence((long)doc->selectedRev.sequence);
                retVal.SetBody(new Body(doc->selectedRev.body));
            });

            return(retVal);
        }
コード例 #4
0
        public RevisionInternal PutRevision(string inDocId, string inPrevRevId, IDictionary <string, object> properties,
                                            bool deleting, bool allowConflict, StoreValidation validationBlock)
        {
            if (_config.HasFlag(C4DatabaseFlags.ReadOnly))
            {
                throw new CouchbaseLiteException("Attempting to write to a readonly database", StatusCode.Forbidden);
            }

            var json = default(string);

            if (properties != null)
            {
                json = Manager.GetObjectMapper().WriteValueAsString(Database.StripDocumentJSON(properties), true);
            }
            else
            {
                json = "{}";
            }

            if (inDocId == null)
            {
                inDocId = Misc.CreateGUID();
            }

            var putRev  = default(RevisionInternal);
            var change  = default(DocumentChange);
            var success = RunInTransaction(() =>
            {
                var docId              = inDocId;
                var prevRevId          = inPrevRevId;
                var transactionSuccess = false;
                WithC4Document(docId, null, false, true, doc =>
                {
                    if (prevRevId != null)
                    {
                        // Updating an existing revision; make sure it exists and is a leaf:
                        ForestDBBridge.Check(err => Native.c4doc_selectRevision(doc, prevRevId, false, err));
                        if (!allowConflict && !doc->selectedRev.IsLeaf)
                        {
                            throw new CouchbaseLiteException(StatusCode.Conflict);
                        }
                    }
                    else
                    {
                        // No parent revision given:
                        if (deleting)
                        {
                            // Didn't specify a revision to delete: NotFound or a Conflict, depending
                            throw new CouchbaseLiteException(doc->Exists ? StatusCode.Conflict : StatusCode.NotFound);
                        }

                        // If doc exists, current rev must be in a deleted state or there will be a conflict:
                        if (Native.c4doc_selectCurrentRevision(doc))
                        {
                            if (doc->selectedRev.IsDeleted)
                            {
                                // New rev will be child of the tombstone:
                                prevRevId = (string)doc->revID;
                            }
                            else
                            {
                                throw new CouchbaseLiteException(StatusCode.Conflict);
                            }
                        }
                    }

                    // Compute the new revID. (Can't be done earlier because prevRevID may have changed.)
                    var newRevID = Delegate != null ? Delegate.GenerateRevID(Encoding.UTF8.GetBytes(json), deleting, prevRevId) : null;
                    if (newRevID == null)
                    {
                        throw new CouchbaseLiteException(StatusCode.BadId);
                    }

                    putRev = new RevisionInternal(docId, newRevID, deleting);
                    if (properties != null)
                    {
                        properties["_id"]  = docId;
                        properties["_rev"] = newRevID;
                        putRev.SetProperties(properties);
                    }

                    // Run any validation blocks:
                    if (validationBlock != null)
                    {
                        var prevRev = default(RevisionInternal);
                        if (prevRevId != null)
                        {
                            prevRev = new RevisionInternal(docId, prevRevId, doc->selectedRev.IsDeleted);
                        }

                        var status = validationBlock(putRev, prevRev, prevRevId);
                        if (status.IsError)
                        {
                            throw new CouchbaseLiteException(String.Format("{0} failed validation", putRev),
                                                             status.Code);
                        }
                    }

                    // Add the revision to the database:
                    ForestDBBridge.Check(err => Native.c4doc_insertRevision(doc, newRevID, json, deleting,
                                                                            putRev.GetAttachments() != null, allowConflict, err));
                    var isWinner = SaveDocument(doc, newRevID, properties);
                    putRev.SetSequence((long)doc->sequence);
                    change             = ChangeWithNewRevision(putRev, isWinner, doc, null);
                    transactionSuccess = true;
                });

                return(transactionSuccess);
            });

            if (!success)
            {
                return(null);
            }

            if (Delegate != null && change != null)
            {
                Delegate.DatabaseStorageChanged(change);
            }

            return(putRev);
        }
コード例 #5
0
        // Get as many revisions as possible in one _all_docs request.
        // This is compatible with CouchDB, but it only works for revs of generation 1 without attachments.
        internal void PullBulkWithAllDocs(IList <RevisionInternal> bulkRevs)
        {
            // http://wiki.apache.org/couchdb/HTTP_Bulk_Document_API
            Log.V(Tag, "PullBulkWithAllDocs() calling AsyncTaskStarted()");
            AsyncTaskStarted();

            ++httpConnectionCount;

            var remainingRevs = new List <RevisionInternal>(bulkRevs);
            var keys          = bulkRevs.Select(rev => rev.GetDocId()).ToArray();
            var body          = new Dictionary <string, object>();

            body.Put("keys", keys);

            SendAsyncRequest(HttpMethod.Post, "/_all_docs?include_docs=true", body, (result, e) =>
            {
                var res = result.AsDictionary <string, object>();
                if (e != null)
                {
                    SetLastError(e);
                    RevisionFailed();
                    SafeAddToCompletedChangesCount(bulkRevs.Count);
                }
                else
                {
                    // Process the resulting rows' documents.
                    // We only add a document if it doesn't have attachments, and if its
                    // revID matches the one we asked for.
                    var rows = res.Get("rows").AsList <IDictionary <string, object> >();
                    Log.V(Tag, "Checking {0} bulk-fetched remote revisions", rows.Count);

                    foreach (var row in rows)
                    {
                        var doc = row.Get("doc").AsDictionary <string, object>();
                        if (doc != null && doc.Get("_attachments") == null)
                        {
                            var rev = new RevisionInternal(doc);
                            var pos = remainingRevs.IndexOf(rev);
                            if (pos > -1)
                            {
                                rev.SetSequence(remainingRevs[pos].GetSequence());
                                remainingRevs.Remove(pos);
                                QueueDownloadedRevision(rev);
                            }
                        }
                    }
                }

                // Any leftover revisions that didn't get matched will be fetched individually:
                if (remainingRevs.Count > 0)
                {
                    Log.V(Tag, "Bulk-fetch didn't work for {0} of {1} revs; getting individually", remainingRevs.Count, bulkRevs.Count);
                    foreach (var rev in remainingRevs)
                    {
                        QueueRemoteRevision(rev);
                    }
                    PullRemoteRevisions();
                }

                // Note that we've finished this task:
                Log.V(Tag, "PullBulkWithAllDocs() calling AsyncTaskFinished()");
                AsyncTaskFinished(1);

                --httpConnectionCount;

                // Start another task if there are still revisions waiting to be pulled:
                PullRemoteRevisions();
            });
        }