Esempio n. 1
0
        public ICollection <BlobKey> FindAllAttachmentKeys()
        {
            var keys    = new HashSet <BlobKey>();
            var options = C4EnumeratorOptions.DEFAULT;

            options.flags &= ~C4EnumeratorFlags.IncludeBodies;
            options.flags |= C4EnumeratorFlags.IncludeDeleted;
            var e = new CBForestDocEnumerator(Forest, null, null, options);

            foreach (var next in e)
            {
                var docInfo = next.DocumentInfo;
                if (!docInfo->HasAttachments || (docInfo->IsDeleted && !docInfo->IsConflicted))
                {
                    continue;
                }

                var doc = next.GetDocument();
                // Since db is assumed to have just been compacted, we know that non-current revisions
                // won't have any bodies. So only scan the current revs.
                do
                {
                    if (doc->selectedRev.IsActive && doc->selectedRev.HasAttachments)
                    {
                        ForestDBBridge.Check(err => Native.c4doc_loadRevisionBody(doc, err));
                        var body = doc->selectedRev.body;
                        if (body.size > 0)
                        {
                            var rev = Manager.GetObjectMapper().ReadValue <IDictionary <string, object> >(body);
                            foreach (var entry in rev.Get("_attachments").AsDictionary <string, IDictionary <string, object> >())
                            {
                                try {
                                    var key = new BlobKey(entry.Value.GetCast <string>("digest"));
                                    keys.Add(key);
                                } catch (Exception) {
                                    Log.W(TAG, "Invalid digest {0}; skipping", entry.Value.GetCast <string>("digest"));
                                }
                            }
                        }
                    }
                } while(Native.c4doc_selectNextLeafRevision(doc, true, true, null));
            }

            return(keys);
        }
Esempio n. 2
0
        private CBForestDocEnumerator GetDocEnumerator(QueryOptions options, out List <string> remainingIDs)
        {
            var forestOps  = options.AsC4EnumeratorOptions();
            var enumerator = default(CBForestDocEnumerator);

            remainingIDs = new List <string>();
            if (options.Keys != null)
            {
                try {
                    remainingIDs = options.Keys.Cast <string>().ToList();
                    enumerator   = new CBForestDocEnumerator(Forest, remainingIDs.ToArray(), forestOps);
                } catch (InvalidCastException) {
                    Log.E(TAG, "options.keys must contain strings");
                    throw;
                }
            }
            else
            {
                enumerator = new CBForestDocEnumerator(Forest, options.StartKey as string, options.EndKey as string, forestOps);
            }

            return(enumerator);
        }
        public ICollection<BlobKey> FindAllAttachmentKeys()
        {
            var keys = new HashSet<BlobKey>();
            var options = C4EnumeratorOptions.DEFAULT;
            options.flags &= ~C4EnumeratorFlags.IncludeBodies;
            options.flags |= C4EnumeratorFlags.IncludeDeleted;
            var e = new CBForestDocEnumerator(Forest, null, null, options);
            foreach(var next in e) {
                var doc = next.Document;
                if (!doc->HasAttachments || (doc->IsDeleted && !doc->IsConflicted)) {
                    continue;
                }

                // Since db is assumed to have just been compacted, we know that non-current revisions
                // won't have any bodies. So only scan the current revs.
                do {
                    if(doc->selectedRev.IsActive && doc->selectedRev.HasAttachments) {
                        ForestDBBridge.Check(err => Native.c4doc_loadRevisionBody(doc, err));
                        var body = doc->selectedRev.body;
                        if(body.size > 0) {
                            var rev = Manager.GetObjectMapper().ReadValue<IDictionary<string, object>>(body);
                            foreach(var entry in rev.Get("_attachments").AsDictionary<string, IDictionary<string, object>>()) {
                                try {
                                    var key = new BlobKey(entry.Value.GetCast<string>("digest"));
                                    keys.Add(key);
                                } catch(Exception){
                                    Log.W(TAG, "Invalid digest {0}; skipping", entry.Value.GetCast<string>("digest"));
                                }
                            }
                        }
                    }
                } while(Native.c4doc_selectNextLeafRevision(doc, true, true, null));
            }

            return keys;
        }
        public RevisionList ChangesSince(Int64 lastSequence, ChangesOptions options, RevisionFilter filter)
        {
            // http://wiki.apache.org/couchdb/HTTP_database_API#Changes
            // Translate options to ForestDB:
            if (options.Descending) {
                // https://github.com/couchbase/couchbase-lite-ios/issues/641
                throw new CouchbaseLiteException(StatusCode.NotImplemented);
            }

            var forestOps = C4EnumeratorOptions.DEFAULT;
            forestOps.flags |= C4EnumeratorFlags.IncludeDeleted | C4EnumeratorFlags.IncludeNonConflicted;
            if (options.IncludeDocs || options.IncludeConflicts || filter != null) {
                forestOps.flags |= C4EnumeratorFlags.IncludeBodies;
            }

            var changes = new RevisionList();
            var e = new CBForestDocEnumerator(Forest, lastSequence, forestOps);
            foreach (var next in e) {
                var doc = next.Document;
                var revs = default(IEnumerable<RevisionInternal>);
                if (options.IncludeConflicts) {
                    using (var enumerator = new CBForestHistoryEnumerator(doc, true, false)) {
                        var includeBody = forestOps.flags.HasFlag(C4EnumeratorFlags.IncludeBodies);
                        revs = enumerator.Select(x => new RevisionInternal(x.Document, includeBody)).ToList();
                    }
                } else {
                    revs = new List<RevisionInternal> { new RevisionInternal(doc, forestOps.flags.HasFlag(C4EnumeratorFlags.IncludeBodies)) };
                }

                foreach (var rev in revs) {
                    Debug.Assert(rev != null);
                    if (filter == null || filter(rev)) {
                        if (!options.IncludeDocs) {
                            rev.SetBody(null);
                        }

                        if(filter == null || filter(rev)) {
                            changes.Add(rev);
                        }
                    }
                }
            }

            if (options.SortBySequence) {
                changes.SortBySequence(!options.Descending);
                changes.Limit(options.Limit);
            }

            return changes;
        }
        private CBForestDocEnumerator GetDocEnumerator(QueryOptions options, out List<string> remainingIDs)
        {
            var forestOps = options.AsC4EnumeratorOptions();
            var enumerator = default(CBForestDocEnumerator);
            remainingIDs = new List<string>();
            if(options.Keys != null) {
                try {
                    remainingIDs = options.Keys.Cast<string>().ToList();
                    enumerator = new CBForestDocEnumerator(Forest, remainingIDs.ToArray(), forestOps);
                } catch(InvalidCastException) {
                    Log.E(TAG, "options.keys must contain strings");
                    throw;
                }
            } else {
                enumerator = new CBForestDocEnumerator(Forest, options.StartKey as string, options.EndKey as string, forestOps);
            }

            return enumerator;
        }
Esempio n. 6
0
        public RevisionList ChangesSince(Int64 lastSequence, ChangesOptions options, RevisionFilter filter)
        {
            // http://wiki.apache.org/couchdb/HTTP_database_API#Changes
            // Translate options to ForestDB:
            if (options.Descending)
            {
                // https://github.com/couchbase/couchbase-lite-ios/issues/641
                throw new CouchbaseLiteException(StatusCode.NotImplemented);
            }

            var forestOps = C4EnumeratorOptions.DEFAULT;

            forestOps.flags |= C4EnumeratorFlags.IncludeDeleted | C4EnumeratorFlags.IncludeNonConflicted;
            if (options.IncludeDocs || options.IncludeConflicts || filter != null)
            {
                forestOps.flags |= C4EnumeratorFlags.IncludeBodies;
            }

            var changes = new RevisionList();
            var e       = new CBForestDocEnumerator(Forest, lastSequence, forestOps);

            foreach (var next in e)
            {
                var revs = default(IEnumerable <RevisionInternal>);
                if (options.IncludeConflicts)
                {
                    using (var enumerator = new CBForestHistoryEnumerator(next.GetDocument(), true, false)) {
                        var includeBody = forestOps.flags.HasFlag(C4EnumeratorFlags.IncludeBodies);
                        revs = enumerator.Select(x => new RevisionInternal(x.GetDocument(), includeBody)).ToList();
                    }
                }
                else
                {
                    revs = new List <RevisionInternal> {
                        new RevisionInternal(next.GetDocument(), forestOps.flags.HasFlag(C4EnumeratorFlags.IncludeBodies))
                    };
                }

                foreach (var rev in revs)
                {
                    Debug.Assert(rev != null);
                    if (filter == null || filter(rev))
                    {
                        if (!options.IncludeDocs)
                        {
                            rev.SetBody(null);
                        }

                        if (filter == null || filter(rev))
                        {
                            changes.Add(rev);
                        }
                    }
                }
            }

            if (options.SortBySequence)
            {
                changes.SortBySequence(!options.Descending);
                changes.Limit(options.Limit);
            }

            return(changes);
        }
Esempio n. 7
0
        public bool UpdateIndexes(IEnumerable <IViewStore> views)
        {
            Log.To.Query.V(Tag, "Checking indexes of ({0}) for {1}", ViewNames(views), Name);

            // Creates an array of tuples -> [[view1, view1 last sequence, view1 native handle],
            // [view2, view2 last sequence, view2 native handle], ...]
            var viewsArray = views.Where(x => {
                var viewDelegate = x.Delegate;
                if (viewDelegate == null || viewDelegate.Map == null)
                {
                    Log.To.Query.V(Tag, "    {0} has no map block; skipping it", x.Name);
                    return(false);
                }

                return(true);
            }).Cast <ForestDBViewStore> ().ToArray();

            var nativeViews = new C4View *[viewsArray.Length];

            for (int i = 0; i < viewsArray.Length; i++)
            {
                nativeViews[i] = viewsArray[i].IndexDB;
            }

            var indexer = (C4Indexer *)ForestDBBridge.Check(err => Native.c4indexer_begin(_dbStorage.Forest, nativeViews, err));

            var enumerator = new CBForestDocEnumerator(indexer);

            var commit = false;

            try {
                foreach (var next in enumerator)
                {
                    var seq = next.Sequence;

                    for (int i = 0; i < viewsArray.Length; i++)
                    {
                        var info = viewsArray [i];
                        if (seq <= info.LastSequenceIndexed)
                        {
                            continue; // This view has already indexed this sequence
                        }

                        var rev    = new ForestRevisionInternal(next, true);
                        var keys   = new List <object>();
                        var values = new List <string>();

                        var conflicts = default(List <string>);
                        foreach (var leaf in new CBForestHistoryEnumerator(_dbStorage.Forest, next.Sequence, true))
                        {
                            if (leaf.SelectedRev.revID.Equals(leaf.CurrentRevID))
                            {
                                continue;
                            }

                            if (leaf.IsDeleted)
                            {
                                break;
                            }

                            if (conflicts == null)
                            {
                                conflicts = new List <string>();
                            }

                            conflicts.Add((string)leaf.SelectedRev.revID);
                        }

                        if (conflicts != null)
                        {
                            rev.SetPropertyForKey("_conflicts", conflicts);
                        }

                        try {
                            var props = rev.GetProperties();
                            info.Delegate.Map(props, (key, value) =>
                            {
                                if (key == null)
                                {
                                    Log.To.Query.W(Tag, "Emit function called with a null key; ignoring");
                                    return;
                                }

                                keys.Add(key);
                                if (props == value)
                                {
                                    values.Add("*");
                                }
                                else
                                {
                                    values.Add(Manager.GetObjectMapper().WriteValueAsString(value));
                                }
                            });
                        } catch (Exception e) {
                            Log.To.Query.W(Tag, String.Format("Exception thrown in map function of {0}, continuing", info.Name), e);
                            continue;
                        }

                        WithC4Keys(keys.ToArray(), true, c4keys =>
                                   ForestDBBridge.Check(err => Native.c4indexer_emit(indexer, next.GetDocument(), (uint)i, c4keys, values.ToArray(), err))
                                   );
                    }
                }

                commit = true;
            } catch (Exception e) {
                Log.To.Query.W(Tag, "Error updates indexes, returning false", e);
                return(false);
            } finally {
                ForestDBBridge.Check(err => Native.c4indexer_end(indexer, commit, err));
            }

            return(true);
        }
Esempio n. 8
0
        public bool UpdateIndexes(IEnumerable <IViewStore> views)
        {
            Log.D(TAG, "Checking indexes of ({0}) for {1}", ViewNames(views), Name);

            // Creates an array of tuples -> [[view1, view1 last sequence, view1 native handle],
            // [view2, view2 last sequence, view2 native handle], ...]
            var viewsArray  = views.Cast <ForestDBViewStore>().ToArray();
            var viewInfo    = viewsArray.Select(x => Tuple.Create(x, x.LastSequenceIndexed)).ToArray();
            var nativeViews = new C4View *[viewsArray.Length];

            for (int i = 0; i < viewsArray.Length; i++)
            {
                nativeViews[i] = viewsArray[i]._indexDB;
            }

            var indexer = (C4Indexer *)ForestDBBridge.Check(err => Native.c4indexer_begin(_dbStorage.Forest, nativeViews, err));

            var enumerator = new CBForestDocEnumerator(indexer);

            var commit = false;

            try {
                foreach (var next in enumerator)
                {
                    var seq = next.SelectedRev.sequence;

                    for (int i = 0; i < viewInfo.Length; i++)
                    {
                        var info = viewInfo[i];
                        if (seq <= (ulong)info.Item2)
                        {
                            continue; // This view has already indexed this sequence
                        }

                        var viewDelegate = info.Item1.Delegate;
                        if (viewDelegate == null || viewDelegate.Map == null)
                        {
                            Log.V(TAG, "    {0} has no map block; skipping it", info.Item1.Name);
                            continue;
                        }

                        var rev    = new RevisionInternal(next, true);
                        var keys   = new List <object>();
                        var values = new List <string>();
                        try {
                            viewDelegate.Map(rev.GetProperties(), (key, value) =>
                            {
                                keys.Add(key);
                                values.Add(Manager.GetObjectMapper().WriteValueAsString(value));
                            });
                        } catch (Exception e) {
                            Log.W(TAG, String.Format("Exception thrown in map function of {0}", info.Item1.Name), e);
                            continue;
                        }

                        WithC4Keys(keys.ToArray(), true, c4keys =>
                                   ForestDBBridge.Check(err => Native.c4indexer_emit(indexer, next.Document, (uint)i, c4keys, values.ToArray(), err))
                                   );
                    }
                }

                commit = true;
            } catch (Exception e) {
                Log.W(TAG, "Error updates indexes", e);
            } finally {
                ForestDBBridge.Check(err => Native.c4indexer_end(indexer, commit, err));
            }

            return(true);
        }
        private CBForestDocEnumerator GetDocEnumerator(QueryOptions options, out List<string> remainingIDs)
        {
            var forestOps = options.AsC4EnumeratorOptions();
            var enumerator = default(CBForestDocEnumerator);
            remainingIDs = new List<string>();
            if(options.Keys != null) {
                try {
                    remainingIDs = options.Keys.Cast<string>().ToList();
                    enumerator = new CBForestDocEnumerator(Forest, remainingIDs.ToArray(), forestOps);
                } catch(InvalidCastException) {
                    Log.To.Database.E(TAG, "options.keys must contain strings");
                    throw;
                }
            } else {
                string startKey, endKey;
                if(options.Descending) {
                    startKey = Misc.KeyForPrefixMatch(options.StartKey, options.PrefixMatchLevel) as string;
                    endKey = options.EndKey as string;
                } else {
                    startKey = options.StartKey as string;
                    endKey = Misc.KeyForPrefixMatch(options.EndKey, options.PrefixMatchLevel) as string;
                }
                enumerator = new CBForestDocEnumerator(Forest, startKey, endKey, forestOps);
            }

            return enumerator;
        }