private void WithC4Document(string docId, string revId, bool withBody, bool create, C4DocumentActionDelegate block)
        {
            var doc = default(C4Document*);
            try {
                doc = (C4Document*)ForestDBBridge.Check(err => Native.c4doc_get(Forest, docId, !create, err));
                if(revId != null) {
                    ForestDBBridge.Check(err => Native.c4doc_selectRevision(doc, revId, withBody, err));
                }

                if(withBody) {
                    ForestDBBridge.Check(err => Native.c4doc_loadRevisionBody(doc, err));
                }
            } catch(CBForestException e) {
                var is404 = e.Domain == C4ErrorDomain.ForestDB && e.Code == (int)ForestDBStatus.KeyNotFound;
                is404 |= e.Domain == C4ErrorDomain.HTTP && e.Code == 404;
                var is410 = e.Domain == C4ErrorDomain.HTTP && e.Code == 410; // Body compacted

                if (!is404 && !is410) {
                    throw;
                }

                Native.c4doc_free(doc); // In case the failure was in selectRevision
                doc = null;
            }

            try {
                block(doc);
            } finally {
                Native.c4doc_free(doc);
            }
        }
        private void WithC4Document(string docId, long sequence, C4DocumentActionDelegate block)
        {
            var doc = default(C4Document*);
            try {
                doc = (C4Document*)ForestDBBridge.Check(err => Native.c4doc_getBySequence(Forest, (ulong)sequence, err));
            } catch(CBForestException e) {
                if (e.Domain != C4ErrorDomain.ForestDB && (ForestDBStatus)e.Code != ForestDBStatus.KeyNotFound) {
                    throw;
                }
            }

            try {
                block(doc);
            } finally {
                Native.c4doc_free(doc);
            }
        }
        private void WithC4Document(string docId, RevisionID revId, bool withBody, bool create, C4DocumentActionDelegate block)
        {
            if(!IsOpen) {
                return;
            }

            var doc = default(C4Document*);
            try { 
                doc = (C4Document *)RetryHandler.RetryIfBusy().AllowErrors(
                    new C4Error() { code = 404, domain = C4ErrorDomain.HTTP },
                    new C4Error() { code = (int)ForestDBStatus.KeyNotFound, domain = C4ErrorDomain.ForestDB })
                    .Execute(err => Native.c4doc_get(Forest, docId, !create, err));
                if(doc != null) {
                    var selected = true;
                    if(revId != null) {
                        selected = RetryHandler.RetryIfBusy().HandleExceptions(e =>
                        {
                            if(e.Code == 404) {
                                Native.c4doc_free(doc);
                                doc = null;
                                return;
                            }

                            throw e;
                        }).AllowError(410, C4ErrorDomain.HTTP).Execute(err =>
                        {
                            bool result = false;
                            revId.PinAndUse(slice =>
                            {
                                result = Native.c4doc_selectRevision(doc, slice, withBody, err);
                            });

                            return result;
                        });
                    }

                    if(selected && withBody) {
                        RetryHandler.RetryIfBusy().AllowError(410, C4ErrorDomain.HTTP).Execute((err => Native.c4doc_loadRevisionBody(doc, err)));
                    }
                }

                block(doc);
            } finally {
                Native.c4doc_free(doc);
            }
        }