Ejemplo n.º 1
0
        /// <summary>
        /// Similar to the LINQ method, but returns all objects converted to standard
        /// .NET types
        /// </summary>
        /// <returns>A list of standard .NET typed objects in the array</returns>
        public List <object> ToList()
        {
            var count  = _array.Count;
            var result = new List <object>(count);

            _threadSafety.DoLocked(() =>
            {
                for (var i = 0; i < count; i++)
                {
                    result.Add(DataOps.ToNetObject(GetObject(_array, i)));
                }
            });

            return(result);
        }
Ejemplo n.º 2
0
        public IList <string> GetIndexes()
        {
            object retVal = null;

            ThreadSafety.DoLocked(() =>
            {
                CheckOpen();
                var result = new C4SliceResult();
                LiteCoreBridge.Check(err =>
                {
                    result = NativeRaw.c4db_getIndexes(c4db, err);
                    return(result.buf != null);
                });

                var val = NativeRaw.FLValue_FromTrustedData(new FLSlice(result.buf, result.size));
                if (val == null)
                {
                    Native.c4slice_free(result);
                    throw new LiteCoreException(new C4Error(C4ErrorCode.CorruptIndexData));
                }

                retVal = FLValueConverter.ToCouchbaseObject(val, this, true, typeof(string));
                Native.c4slice_free(result);
            });

            return(retVal as IList <string> ?? new List <string>());
        }
Ejemplo n.º 3
0
        public void InBatch(Action action)
        {
            CBDebug.MustNotBeNull(Log.To.Database, Tag, nameof(action), action);

            ThreadSafety.DoLocked(() =>
            {
                CheckOpen();
                PerfTimer.StartEvent("InBatch_BeginTransaction");
                LiteCoreBridge.Check(err => Native.c4db_beginTransaction(_c4db, err));
                PerfTimer.StopEvent("InBatch_BeginTransaction");
                var success = true;
                try {
                    action();
                } catch (Exception e) {
                    Log.To.Database.W(Tag, "Exception during InBatch, rolling back...", e);
                    success = false;
                    throw;
                } finally {
                    PerfTimer.StartEvent("InBatch_EndTransaction");
                    LiteCoreBridge.Check(err => Native.c4db_endTransaction(_c4db, success, err));
                    PerfTimer.StopEvent("InBatch_EndTransaction");
                }
            });

            PostDatabaseChanged();
        }
Ejemplo n.º 4
0
        public void Purge(Document document)
        {
            CBDebug.MustNotBeNull(Log.To.Database, Tag, nameof(document), document);

            ThreadSafety.DoLocked(() =>
            {
                CheckOpen();
                VerifyDB(document);

                if (!document.Exists)
                {
                    var docID = new SecureLogString(document.Id, LogMessageSensitivity.PotentiallyInsecure);
                    Log.To.Database.V(Tag, $"Ignoring purge of non-existent document {docID}");
                    return;
                }

                InBatch(() =>
                {
                    var result = Native.c4doc_purgeRevision(document.c4Doc.RawDoc, null, null);
                    if (result >= 0)
                    {
                        LiteCoreBridge.Check(err => Native.c4doc_save(document.c4Doc.RawDoc, 0, err));
                    }
                });
            });
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            GC.SuppressFinalize(this);

            ThreadSafety.DoLocked(() =>
            {
                ThrowIfActiveItems();
                Dispose(true);
            });
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Creates a database given a name and some configuration
        /// </summary>
        /// <param name="name">The name of the database</param>
        /// <param name="configuration">The configuration to open it with</param>
        public Database(string name, DatabaseConfiguration configuration = null)
        {
            Name   = CBDebug.MustNotBeNull(Log.To.Database, Tag, nameof(name), name);
            Config = configuration?.Freeze() ?? new DatabaseConfiguration(true);
            Open();
            FLSharedKeys *keys = null;

            ThreadSafety.DoLocked(() => keys = Native.c4db_getFLSharedKeys(_c4db));
            _sharedStrings = new SharedStringCache(keys);
        }
Ejemplo n.º 7
0
        public void Delete(Document document)
        {
            CBDebug.MustNotBeNull(Log.To.Database, Tag, nameof(document), document);

            ThreadSafety.DoLocked(() =>
            {
                CheckOpen();
                Save(document, true);
            });
        }
Ejemplo n.º 8
0
        public Document Save(MutableDocument document)
        {
            CBDebug.MustNotBeNull(Log.To.Database, Tag, nameof(document), document);

            return(ThreadSafety.DoLocked(() =>
            {
                CheckOpen();
                return Save(document, false);
            }));
        }
Ejemplo n.º 9
0
 /// <summary>
 /// Deletes the database
 /// </summary>
 public void Delete()
 {
     ThreadSafety.DoLocked(() =>
     {
         CheckOpen();
         ThrowIfActiveItems();
         LiteCoreBridge.Check(err => Native.c4db_delete(_c4db, err));
         Native.c4db_free(_c4db);
         _c4db = null;
         _obs?.Dispose();
         _obs = null;
     });
 }
Ejemplo n.º 10
0
        public ListenerToken AddChangeListener([CanBeNull] TaskScheduler scheduler,
                                               EventHandler <DatabaseChangedEventArgs> handler)
        {
            CBDebug.MustNotBeNull(Log.To.Database, Tag, nameof(handler), handler);

            return(ThreadSafety.DoLocked(() =>
            {
                CheckOpen();

                var cbHandler = new CouchbaseEventHandler <DatabaseChangedEventArgs>(handler, scheduler);
                _databaseChanged.Add(cbHandler);

                return new ListenerToken(cbHandler, "db");
            }));
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Removes a database changed listener by token
        /// </summary>
        /// <param name="token">The token received from <see cref="AddChangeListener(TaskScheduler, EventHandler{DatabaseChangedEventArgs})"/>
        /// and family</param>
        public void RemoveChangeListener(ListenerToken token)
        {
            ThreadSafety.DoLocked(() =>
            {
                CheckOpen();

                if (token.Type == "db")
                {
                    _databaseChanged.Remove(token);
                }
                else
                {
                    _documentChanged.Remove(token);
                }
            });
        }
Ejemplo n.º 12
0
        private void PostDocChanged([NotNull] string documentID)
        {
            DocumentChangedEventArgs change = null;

            ThreadSafety.DoLocked(() =>
            {
                if (!_docObs.ContainsKey(documentID) || _c4db == null || Native.c4db_isInTransaction(_c4db))
                {
                    return;
                }

                change = new DocumentChangedEventArgs(documentID, this);
            });

            _documentChanged.Fire(documentID, this, change);
        }
Ejemplo n.º 13
0
        private void Open()
        {
            if (_c4db != null)
            {
                return;
            }

            Directory.CreateDirectory(Config.Directory);
            var path   = DatabasePath(Name, Config.Directory);
            var config = DBConfig;

            var encrypted = "";

            #if COUCHBASE_ENTERPRISE
            if (Config.EncryptionKey != null)
            {
                var key = Config.EncryptionKey;
                var i   = 0;
                config.encryptionKey.algorithm = C4EncryptionAlgorithm.AES256;
                foreach (var b in key.KeyData)
                {
                    config.encryptionKey.bytes[i++] = b;
                }

                encrypted = "encrypted ";
            }
            #endif

            Log.To.Database.I(Tag, $"Opening {encrypted}database at {path}");
            var localConfig1 = config;
            ThreadSafety.DoLocked(() =>
            {
                _c4db = (C4Database *)NativeHandler.Create()
                        .AllowError((int)C4ErrorCode.NotADatabaseFile, C4ErrorDomain.LiteCoreDomain).Execute(err =>
                {
                    var localConfig2 = localConfig1;
                    return(Native.c4db_open(path, &localConfig2, err));
                });

                if (_c4db == null)
                {
                    throw new CouchbaseLiteException(StatusCode.Unauthorized);
                }

                _obs = Native.c4dbobs_create(_c4db, _DbObserverCallback, this);
            });
        }
Ejemplo n.º 14
0
        private void PostDatabaseChanged()
        {
            var allChanges = new List <DatabaseChangedEventArgs>();

            ThreadSafety.DoLocked(() =>
            {
                if (_obs == null || _c4db == null || InTransaction)
                {
                    return;
                }

                const uint maxChanges = 100u;
                var external          = false;
                uint nChanges;
                var changes = new C4DatabaseChange[maxChanges];
                var docIDs  = new List <string>();
                do
                {
                    // Read changes in batches of MaxChanges:
                    bool newExternal;
                    nChanges = Native.c4dbobs_getChanges(_obs.Observer, changes, maxChanges, &newExternal);
                    if (nChanges == 0 || external != newExternal || docIDs.Count > 1000)
                    {
                        if (docIDs.Count > 0)
                        {
                            // Only notify if there are actually changes to send
                            var args = new DatabaseChangedEventArgs(this, docIDs);
                            allChanges.Add(args);
                            docIDs = new List <string>();
                        }
                    }

                    external = newExternal;
                    for (var i = 0; i < nChanges; i++)
                    {
                        docIDs.Add(changes[i].docID.CreateString());
                    }
                } while (nChanges > 0);
            });

            foreach (var args in allChanges)
            {
                _databaseChanged.Fire(this, args);
            }
        }
Ejemplo n.º 15
0
        public void Save(Couchbase.Lite.Linq.IDocumentModel model)
        {
            CBDebug.MustNotBeNull(Log.To.Database, Tag, nameof(model), model);

            ThreadSafety.DoLocked(() =>
            {
                CheckOpen();
                MutableDocument md = (model.Document as MutableDocument) ?? model.Document?.ToMutable() ?? new MutableDocument();
                md.SetFromModel(model);

                try {
                    var retVal     = Save(md, false);
                    model.Document = retVal;
                } finally {
                    md.Dispose();
                }
            });
        }
Ejemplo n.º 16
0
        public IImmutableSet <string> GetPendingDocumentIDs()
        {
            var result = new HashSet <string>();

            if (!IsPushing())
            {
                CBDebug.LogAndThrow(WriteLog.To.Sync,
                                    new CouchbaseLiteException(C4ErrorCode.Unsupported, CouchbaseLiteErrorMessage.PullOnlyPendingDocIDs),
                                    Tag, CouchbaseLiteErrorMessage.PullOnlyPendingDocIDs, true);
            }

            DispatchQueue.DispatchSync(() => {
                var errSetupRepl = SetupC4Replicator();
                if (errSetupRepl.code > 0)
                {
                    CBDebug.LogAndThrow(WriteLog.To.Sync, CouchbaseException.Create(errSetupRepl), Tag, errSetupRepl.ToString(), true);
                }
            });

            byte[] pendingDocIds = LiteCoreBridge.Check(err =>
            {
                return(Native.c4repl_getPendingDocIDs(_repl, err));
            });

            if (pendingDocIds != null)
            {
                _databaseThreadSafety.DoLocked(() => {
                    var flval = Native.FLValue_FromData(pendingDocIds, FLTrust.Trusted);
                    var flarr = Native.FLValue_AsArray(flval);
                    var cnt   = (int)Native.FLArray_Count(flarr);
                    for (int i = 0; i < cnt; i++)
                    {
                        var flv = Native.FLArray_Get(flarr, (uint)i);
                        result.Add(Native.FLValue_AsString(flv));
                    }

                    Array.Clear(pendingDocIds, 0, pendingDocIds.Length);
                    pendingDocIds = null;
                });
            }

            _pendingDocIds = result.ToImmutableHashSet <string>();
            return(_pendingDocIds);
        }
Ejemplo n.º 17
0
        public ListenerToken AddDocumentChangeListener(string id, [CanBeNull] TaskScheduler scheduler,
                                                       EventHandler <DocumentChangedEventArgs> handler)
        {
            CBDebug.MustNotBeNull(Log.To.Database, Tag, nameof(id), id);
            CBDebug.MustNotBeNull(Log.To.Database, Tag, nameof(handler), handler);

            return(ThreadSafety.DoLocked(() =>
            {
                CheckOpen();

                var cbHandler =
                    new CouchbaseEventHandler <string, DocumentChangedEventArgs>(handler, id, scheduler);
                var count = _documentChanged.Add(cbHandler);
                if (count == 0)
                {
                    var docObs = new DocumentObserver(_c4db, id, _DocObserverCallback, this);
                    _docObs[id] = docObs;
                }

                return new ListenerToken(cbHandler, "doc");
            }));
        }
Ejemplo n.º 18
0
        public void CreateIndex(string name, IIndex index)
        {
            CBDebug.MustNotBeNull(Log.To.Database, Tag, nameof(name), name);
            CBDebug.MustNotBeNull(Log.To.Database, Tag, nameof(index), index);

            ThreadSafety.DoLocked(() =>
            {
                CheckOpen();
                var concreteIndex = Misc.TryCast <IIndex, QueryIndex>(index);
                var jsonObj       = concreteIndex.ToJSON();
                var json          = JsonConvert.SerializeObject(jsonObj);
                LiteCoreBridge.Check(err =>
                {
                    var internalOpts = concreteIndex.Options;

                    // For some reason a "using" statement here causes a compiler error
                    try {
                        return(Native.c4db_createIndex(c4db, name, json, concreteIndex.IndexType, &internalOpts, err));
                    } finally {
                        internalOpts.Dispose();
                    }
                });
            });
        }
Ejemplo n.º 19
0
        // Must be called from within the ThreadSafety
        private void StartInternal()
        {
            _desc = ToString(); // Cache this; it may be called a lot when logging

            // Target:
            var      addr      = new C4Address();
            var      scheme    = new C4String();
            var      host      = new C4String();
            var      path      = new C4String();
            Database otherDB   = null;
            var      remoteUrl = Config.RemoteUrl;
            string   dbNameStr = null;

            if (remoteUrl != null)
            {
                var pathStr = String.Concat(remoteUrl.Segments.Take(remoteUrl.Segments.Length - 1));
                dbNameStr     = remoteUrl.Segments.Last().TrimEnd('/');
                scheme        = new C4String(remoteUrl.Scheme);
                host          = new C4String(remoteUrl.Host);
                path          = new C4String(pathStr);
                addr.scheme   = scheme.AsC4Slice();
                addr.hostname = host.AsC4Slice();
                addr.port     = (ushort)remoteUrl.Port;
                addr.path     = path.AsC4Slice();
            }
            else
            {
                otherDB = Config.OtherDB;
            }

            var options  = Config.Options;
            var userInfo = remoteUrl?.UserInfo?.Split(':');

            if (userInfo?.Length == 2)
            {
                throw new ArgumentException(
                          "Embedded credentials in a URL (username:password@url) are not allowed; use the BasicAuthenticator class instead");
            }

            Config.Authenticator?.Authenticate(options);

            options.Build();
            var push       = Config.ReplicatorType.HasFlag(ReplicatorType.Push);
            var pull       = Config.ReplicatorType.HasFlag(ReplicatorType.Pull);
            var continuous = Config.Continuous;

            // Clear the reset flag, it is a one-time thing
            Config.Options.Reset = false;

            var socketFactory = Config.SocketFactory;

            socketFactory.context = GCHandle.ToIntPtr(GCHandle.Alloc(this)).ToPointer();
            _nativeParams         = new ReplicatorParameters(options)
            {
                Push            = Mkmode(push, continuous),
                Pull            = Mkmode(pull, continuous),
                Context         = this,
                OnDocumentError = OnDocError,
                OnStatusChanged = StatusChangedCallback,
                SocketFactory   = &socketFactory
            };

            var err    = new C4Error();
            var status = default(C4ReplicatorStatus);

            _stopping = false;
            _databaseThreadSafety.DoLocked(() =>
            {
                C4Error localErr;
                _repl = Native.c4repl_new(Config.Database.c4db, addr, dbNameStr, otherDB != null ? otherDB.c4db : null,
                                          _nativeParams.C4Params, &localErr);
                err = localErr;
                if (_repl != null)
                {
                    status = Native.c4repl_getStatus(_repl);
                    Config.Database.ActiveReplications.Add(this);
                }
                else
                {
                    status = new C4ReplicatorStatus {
                        error    = err,
                        level    = C4ReplicatorActivityLevel.Stopped,
                        progress = new C4Progress()
                    };
                }
            });

            scheme.Dispose();
            path.Dispose();
            host.Dispose();

            UpdateStateProperties(status);
            DispatchQueue.DispatchSync(() => StatusChangedCallback(status));
        }
Ejemplo n.º 20
0
        internal void ResolveConflict([NotNull] string docID, [NotNull] IConflictResolver resolver)
        {
            Debug.Assert(docID != null);

            Document doc = null, otherDoc = null, baseDoc = null;
            var      inConflict = true;

            while (inConflict)
            {
                ThreadSafety.DoLocked(() =>
                {
                    LiteCoreBridge.Check(err => Native.c4db_beginTransaction(_c4db, err));
                    try {
                        doc = new Document(this, docID);
                        if (!doc.Exists)
                        {
                            doc.Dispose();
                            return;
                        }

                        otherDoc = new Document(this, docID);
                        if (!otherDoc.Exists)
                        {
                            doc.Dispose();
                            otherDoc.Dispose();
                            return;
                        }

                        otherDoc.SelectConflictingRevision();
                        baseDoc = new Document(this, docID);
                        if (!baseDoc.SelectCommonAncestor(doc, otherDoc) || baseDoc.ToDictionary() == null)
                        {
                            baseDoc.Dispose();
                            baseDoc = null;
                        }

                        LiteCoreBridge.Check(err => Native.c4db_endTransaction(_c4db, true, err));
                    } catch (Exception) {
                        doc?.Dispose();
                        otherDoc?.Dispose();
                        baseDoc?.Dispose();
                        LiteCoreBridge.Check(err => Native.c4db_endTransaction(_c4db, false, err));
                    }
                });

                var conflict = new Conflict(doc, otherDoc, baseDoc);
                var logID    = new SecureLogString(doc.Id, LogMessageSensitivity.PotentiallyInsecure);
                Log.To.Database.I(Tag, $"Resolving doc '{logID}' with {resolver.GetType().Name} (mine={doc.RevID}, theirs={otherDoc.RevID}, base={baseDoc?.RevID})");
                Document resolved = null;
                try {
                    resolved = resolver.Resolve(conflict);
                    if (resolved == null)
                    {
                        throw new LiteCoreException(new C4Error(C4ErrorCode.Conflict));
                    }

                    SaveResolvedDocument(resolved, conflict);
                    inConflict = false;
                } catch (LiteCoreException e) {
                    if (e.Error.domain == C4ErrorDomain.LiteCoreDomain && e.Error.code == (int)C4ErrorCode.Conflict)
                    {
                        continue;
                    }

                    throw;
                } finally {
                    resolved?.Dispose();
                    if (resolved != doc)
                    {
                        doc?.Dispose();
                    }

                    if (resolved != otherDoc)
                    {
                        otherDoc?.Dispose();
                    }

                    if (resolved != baseDoc)
                    {
                        baseDoc?.Dispose();
                    }
                }
            }
        }
Ejemplo n.º 21
0
        private Document Save([NotNull] Document document, bool deletion)
        {
            if (document.IsInvalidated)
            {
                throw new CouchbaseLiteException(StatusCode.NotAllowed, "Cannot save or delete a MutableDocument that has already been used to save or delete");
            }

            if (deletion && document.RevID == null)
            {
                throw new CouchbaseLiteException(StatusCode.NotAllowed, "Cannot delete a document that has not yet been saved");
            }

            var         docID = document.Id;
            var         doc = document;
            Document    baseDoc = null, otherDoc = null;
            C4Document *newDoc = null;
            Document    retVal = null;

            while (true)
            {
                var resolve = false;
                retVal = ThreadSafety.DoLocked(() =>
                {
                    VerifyDB(doc);
                    LiteCoreBridge.Check(err => Native.c4db_beginTransaction(_c4db, err));
                    try {
                        if (deletion)
                        {
                            // Check for no-op case if the document does not exist
                            var curDoc = (C4Document *)NativeHandler.Create().AllowError(new C4Error(C4ErrorCode.NotFound))
                                         .Execute(err => Native.c4doc_get(_c4db, docID, true, err));
                            if (curDoc == null)
                            {
                                (document as MutableDocument)?.MarkAsInvalidated();
                                return(null);
                            }

                            Native.c4doc_free(curDoc);
                        }

                        var newDocOther = newDoc;
                        Save(doc, &newDocOther, baseDoc?.c4Doc?.HasValue == true ? baseDoc.c4Doc.RawDoc : null, deletion);
                        if (newDocOther != null)
                        {
                            // Save succeeded, so commit
                            newDoc = newDocOther;
                            LiteCoreBridge.Check(err =>
                            {
                                var success = Native.c4db_endTransaction(_c4db, true, err);
                                if (!success)
                                {
                                    Native.c4doc_free(newDoc);
                                }

                                return(success);
                            });

                            (document as MutableDocument)?.MarkAsInvalidated();
                            baseDoc?.Dispose();
                            return(new Document(this, docID, new C4DocumentWrapper(newDoc)));
                        }

                        // There was a conflict
                        if (deletion && !doc.IsDeleted)
                        {
                            var deletedDoc = doc.ToMutable();
                            deletedDoc.MarkAsDeleted();
                            doc = deletedDoc;
                        }

                        if (doc.c4Doc != null)
                        {
                            baseDoc = new Document(this, docID, doc.c4Doc.Retain <C4DocumentWrapper>());
                        }

                        otherDoc = new Document(this, docID);
                        if (!otherDoc.Exists)
                        {
                            LiteCoreBridge.Check(err => Native.c4db_endTransaction(_c4db, false, err));
                            return(null);
                        }
                    } catch (Exception) {
                        baseDoc?.Dispose();
                        otherDoc?.Dispose();
                        LiteCoreBridge.Check(err => Native.c4db_endTransaction(_c4db, false, err));
                        throw;
                    }

                    resolve = true;
                    LiteCoreBridge.Check(err => Native.c4db_endTransaction(_c4db, false, err));
                    return(null);
                });

                if (!resolve)
                {
                    return(retVal);
                }

                // Resolve Conflict
                Document resolved = null;
                try {
                    var resolver = Config.ConflictResolver;
                    var conflict = new Conflict(doc, otherDoc, baseDoc);
                    resolved = resolver.Resolve(conflict);
                    if (resolved == null)
                    {
                        throw new LiteCoreException(new C4Error(C4ErrorCode.Conflict));
                    }
                } finally {
                    baseDoc?.Dispose();
                    if (!ReferenceEquals(resolved, otherDoc))
                    {
                        otherDoc?.Dispose();
                    }
                }

                retVal = ThreadSafety.DoLocked(() =>
                {
                    var current = new Document(this, docID);
                    if (resolved.RevID == current.RevID)
                    {
                        (document as MutableDocument)?.MarkAsInvalidated();
                        current.Dispose();
                        return(resolved); // Same as current
                    }

                    // For saving
                    doc      = resolved;
                    baseDoc  = current;
                    deletion = resolved.IsDeleted;
                    return(null);
                });

                if (retVal != null)
                {
                    return(retVal);
                }
            }
        }
Ejemplo n.º 22
0
        private void Save([NotNull] Document doc, C4Document **outDoc, C4Document *baseDoc, bool deletion)
        {
            var revFlags = (C4RevisionFlags)0;

            if (deletion)
            {
                revFlags = C4RevisionFlags.Deleted;
            }

            byte[] body = null;
            if (!deletion && !doc.IsEmpty)
            {
                body = doc.Encode();
                var root = Native.FLValue_FromTrustedData(body);
                if (root == null)
                {
                    Log.To.Database.E(Tag, "Failed to encode document body properly.  Aborting save of document!");
                    return;
                }

                var rootDict = Native.FLValue_AsDict(root);
                if (rootDict == null)
                {
                    Log.To.Database.E(Tag, "Failed to encode document body properly.  Aborting save of document!");
                    return;
                }

                ThreadSafety.DoLocked(() =>
                {
                    if (Native.c4doc_dictContainsBlobs(rootDict, SharedStrings.SharedKeys))
                    {
                        revFlags |= C4RevisionFlags.HasAttachments;
                    }
                });
            }
            else if (doc.IsEmpty)
            {
                FLEncoder *encoder = SharedEncoder;
                Native.FLEncoder_BeginDict(encoder, 0);
                Native.FLEncoder_EndDict(encoder);
                body = Native.FLEncoder_Finish(encoder, null);
                Native.FLEncoder_Reset(encoder);
            }

            var rawDoc = baseDoc != null ? baseDoc :
                         doc.c4Doc?.HasValue == true ? doc.c4Doc.RawDoc : null;

            if (rawDoc != null)
            {
                doc.ThreadSafety.DoLocked(() =>
                {
                    ThreadSafety.DoLocked(() =>
                    {
                        *outDoc = (C4Document *)NativeHandler.Create()
                                  .AllowError((int)C4ErrorCode.Conflict, C4ErrorDomain.LiteCoreDomain).Execute(
                            err => Native.c4doc_update(rawDoc, body, revFlags, err));
                    });
                });
            }
            else
            {
                ThreadSafety.DoLocked(() =>
                {
                    *outDoc = (C4Document *)NativeHandler.Create()
                              .AllowError((int)C4ErrorCode.Conflict, C4ErrorDomain.LiteCoreDomain).Execute(
                        err => Native.c4doc_create(_c4db, doc.Id, body, revFlags, err));
                });
            }
        }
Ejemplo n.º 23
0
 public Document GetDocument(string id)
 {
     CBDebug.MustNotBeNull(Log.To.Database, Tag, nameof(id), id);
     return(ThreadSafety.DoLocked(() => GetDocumentInternal(id)));
 }