Ejemplo n.º 1
0
 public int GetViewId()
 {
     if (viewId < 0)
     {
         string   sql    = "SELECT view_id FROM views WHERE name=?";
         string[] args   = new string[] { name };
         Cursor   cursor = null;
         try
         {
             cursor = database.GetDatabase().RawQuery(sql, args);
             if (cursor.MoveToNext())
             {
                 viewId = cursor.GetInt(0);
             }
             else
             {
                 viewId = 0;
             }
         }
         catch (SQLException e)
         {
             Log.E(Log.TagView, "Error getting view id", e);
             viewId = 0;
         }
         finally
         {
             if (cursor != null)
             {
                 cursor.Close();
             }
         }
     }
     return(viewId);
 }
Ejemplo n.º 2
0
        /// <exception cref="System.Exception"></exception>
        public virtual void DumpTableRevs()
        {
            Cursor cursor = database.GetDatabase().RawQuery("SELECT * FROM revs", null);

            while (cursor.MoveToNext())
            {
                int    sequence = cursor.GetInt(0);
                int    doc_id   = cursor.GetInt(1);
                byte[] revid    = cursor.GetBlob(2);
                string revIdStr = null;
                if (revid != null)
                {
                    revIdStr = Sharpen.Runtime.GetStringForBytes(revid);
                }
                int parent  = cursor.GetInt(3);
                int current = cursor.GetInt(4);
                int deleted = cursor.GetInt(5);
                Log.D(Tag, string.Format("Revs row seq: %s doc_id: %s, revIdStr: %s, parent: %s, current: %s, deleted: %s"
                                         , sequence, doc_id, revIdStr, parent, current, deleted));
            }
        }
Ejemplo n.º 3
0
        /// <exception cref="System.Exception"></exception>
        public virtual void DumpTableMaps()
        {
            Cursor cursor = database.GetDatabase().RawQuery("SELECT * FROM maps", null);

            while (cursor.MoveToNext())
            {
                int    viewId   = cursor.GetInt(0);
                int    sequence = cursor.GetInt(1);
                byte[] key      = cursor.GetBlob(2);
                string keyStr   = null;
                if (key != null)
                {
                    keyStr = Sharpen.Runtime.GetStringForBytes(key);
                }
                byte[] value    = cursor.GetBlob(3);
                string valueStr = null;
                if (value != null)
                {
                    valueStr = Sharpen.Runtime.GetStringForBytes(value);
                }
                Log.D(Tag, string.Format("Maps row viewId: %s seq: %s, key: %s, val: %s", viewId,
                                         sequence, keyStr, valueStr));
            }
        }
Ejemplo n.º 4
0
        internal IList <IDictionary <string, object> > Dump()
        {
            if (Id < 0)
            {
                return(null);
            }

            var result = new List <IDictionary <string, object> >();

            var selectArgs = new string[] { Id.ToString() };

            Cursor cursor = null;

            try
            {
                cursor = Database.StorageEngine.RawQuery(
                    "SELECT sequence, key, value FROM maps WHERE view_id=? ORDER BY key", selectArgs);

                while (cursor.MoveToNext())
                {
                    var row = new Dictionary <string, object>();
                    row.Put("seq", cursor.GetInt(0));
                    row.Put("key", cursor.GetString(1));
                    row.Put("value", cursor.GetString(2));
                    result.AddItem(row);
                }
            }
            catch (SQLException e)
            {
                Log.E(Tag, "Error dumping view", e);
                result = null;
            }
            finally
            {
                if (cursor != null)
                {
                    cursor.Close();
                }
            }

            return(result);
        }
Ejemplo n.º 5
0
        public IList <IDictionary <string, object> > Dump()
        {
            if (GetViewId() < 0)
            {
                return(null);
            }
            string[] selectArgs = new string[] { Sharpen.Extensions.ToString(GetViewId()) };
            Cursor   cursor     = null;
            IList <IDictionary <string, object> > result = null;

            try
            {
                cursor = database.GetDatabase().RawQuery("SELECT sequence, key, value FROM maps WHERE view_id=? ORDER BY key"
                                                         , selectArgs);
                cursor.MoveToNext();
                result = new AList <IDictionary <string, object> >();
                while (!cursor.IsAfterLast())
                {
                    IDictionary <string, object> row = new Dictionary <string, object>();
                    row.Put("seq", cursor.GetInt(0));
                    row.Put("key", cursor.GetString(1));
                    row.Put("value", cursor.GetString(2));
                    result.AddItem(row);
                    cursor.MoveToNext();
                }
            }
            catch (SQLException e)
            {
                Log.E(Log.TagView, "Error dumping view", e);
                return(null);
            }
            finally
            {
                if (cursor != null)
                {
                    cursor.Close();
                }
            }
            return(result);
        }
Ejemplo n.º 6
0
        internal void UpdateIndex()
        {
            Log.I(Database.Tag, "Re-indexing view {0} ...", Name);
            System.Diagnostics.Debug.Assert((Map != null));

            if (Id <= 0)
            {
                var msg = string.Format("View.Id <= 0");
                throw new CouchbaseLiteException(msg, new Status(StatusCode.NotFound));
            }

            var    result  = new Status(StatusCode.InternalServerError);
            Cursor cursor  = null;
            Cursor cursor2 = null;

            try
            {
                Database.RunInTransaction(() =>
                {
                    var lastSequence  = LastSequenceIndexed;
                    var dbMaxSequence = Database.LastSequenceNumber;

                    if (lastSequence >= dbMaxSequence)
                    {
                        // nothing to do (eg,  kCBLStatusNotModified)
                        Log.V(Database.Tag, "lastSequence ({0}) == dbMaxSequence ({1}), nothing to do", lastSequence, dbMaxSequence);
                        result.SetCode(StatusCode.NotModified);
                        return(false);
                    }

                    // First remove obsolete emitted results from the 'maps' table:
                    var sequence = lastSequence;
                    if (lastSequence < 0)
                    {
                        var msg = string.Format("lastSequence < 0 ({0})", lastSequence);
                        throw new CouchbaseLiteException(msg, new Status(StatusCode.InternalServerError));
                    }
                    if (lastSequence == 0)
                    {
                        // If the lastSequence has been reset to 0, make sure to remove
                        // any leftover rows:
                        var whereArgs = new string[] { Id.ToString() };
                        Database.StorageEngine.Delete("maps", "view_id=?", whereArgs);
                    }
                    else
                    {
                        Database.OptimizeSQLIndexes();
                        // Delete all obsolete map results (ones from since-replaced
                        // revisions):
                        var args = new [] {
                            Id.ToString(),
                            lastSequence.ToString(),
                            lastSequence.ToString()
                        };

                        Database.StorageEngine.ExecSQL(
                            "DELETE FROM maps WHERE view_id=? AND sequence IN ("
                            + "SELECT parent FROM revs WHERE sequence>? " + "AND +parent>0 AND +parent<=?)",
                            args);
                    }

                    var deleted = 0;
                    cursor      = Database.StorageEngine.IntransactionRawQuery("SELECT changes()");
                    cursor.MoveToNext();
                    deleted = cursor.GetInt(0);
                    cursor.Close();

                    // Find a better way to propagate this back
                    // Now scan every revision added since the last time the view was indexed:
                    var selectArgs = new[] { lastSequence.ToString(), dbMaxSequence.ToString() };
                    cursor         = Database.StorageEngine.IntransactionRawQuery("SELECT revs.doc_id, sequence, docid, revid, json, no_attachments FROM revs, docs "
                                                                                  + "WHERE sequence>? AND sequence<=? AND current!=0 AND deleted=0 "
                                                                                  + "AND revs.doc_id = docs.doc_id "
                                                                                  + "ORDER BY revs.doc_id, revid DESC", selectArgs);

                    var lastDocID = 0L;
                    var keepGoing = cursor.MoveToNext();
                    while (keepGoing)
                    {
                        long docID = cursor.GetLong(0);
                        if (docID != lastDocID)
                        {
                            // Only look at the first-iterated revision of any document,
                            // because this is the
                            // one with the highest revid, hence the "winning" revision
                            // of a conflict.
                            lastDocID = docID;
                            // Reconstitute the document as a dictionary:
                            sequence     = cursor.GetLong(1);
                            string docId = cursor.GetString(2);
                            if (docId.StartsWith("_design/", StringComparison.InvariantCultureIgnoreCase))
                            {
                                // design docs don't get indexed!
                                keepGoing = cursor.MoveToNext();
                                continue;
                            }
                            var revId = cursor.GetString(3);
                            var json  = cursor.GetBlob(4);

                            var noAttachments = cursor.GetInt(5) > 0;

                            // Skip rows with the same doc_id -- these are losing conflicts.
                            while ((keepGoing = cursor.MoveToNext()) && cursor.GetLong(0) == docID)
                            {
                            }

                            if (lastSequence > 0)
                            {
                                // Find conflicts with documents from previous indexings.
                                var selectArgs2 = new[] { Convert.ToString(docID), Convert.ToString(lastSequence) };
                                cursor2         = Database.StorageEngine.IntransactionRawQuery("SELECT revid, sequence FROM revs "
                                                                                               + "WHERE doc_id=? AND sequence<=? AND current!=0 AND deleted=0 " + "ORDER BY revID DESC "
                                                                                               + "LIMIT 1", selectArgs2);
                                if (cursor2.MoveToNext())
                                {
                                    var oldRevId = cursor2.GetString(0);

                                    // This is the revision that used to be the 'winner'.
                                    // Remove its emitted rows:
                                    var oldSequence = cursor2.GetLong(1);
                                    var args        = new[] { Sharpen.Extensions.ToString(Id), Convert.ToString(oldSequence) };
                                    Database.StorageEngine.ExecSQL("DELETE FROM maps WHERE view_id=? AND sequence=?", args);

                                    if (RevisionInternal.CBLCompareRevIDs(oldRevId, revId) > 0)
                                    {
                                        // It still 'wins' the conflict, so it's the one that
                                        // should be mapped [again], not the current revision!
                                        revId           = oldRevId;
                                        sequence        = oldSequence;
                                        var selectArgs3 = new[] { Convert.ToString(sequence) };
                                        json            = Misc.ByteArrayResultForQuery(
                                            Database.StorageEngine,
                                            "SELECT json FROM revs WHERE sequence=?",
                                            selectArgs3
                                            );
                                    }
                                }

                                cursor2.Close();
                                cursor2 = null;
                            }
                            // Get the document properties, to pass to the map function:
                            var contentOptions = DocumentContentOptions.None;
                            if (noAttachments)
                            {
                                contentOptions |= DocumentContentOptions.NoAttachments;
                            }

                            var properties = Database.DocumentPropertiesFromJSON(
                                json, docId, revId, false, sequence, DocumentContentOptions.None
                                );
                            if (properties != null)
                            {
                                // Call the user-defined map() to emit new key/value
                                // pairs from this revision:

                                // This is the emit() block, which gets called from within the
                                // user-defined map() block
                                // that's called down below.

                                var enclosingView = this;
                                var thisSequence  = sequence;
                                var map           = Map;

                                if (map == null)
                                {
                                    throw new CouchbaseLiteException("Map function is missing.");
                                }

                                EmitDelegate emitBlock = (key, value) =>
                                {
                                    // TODO: Do we need to do any null checks on key or value?
                                    try
                                    {
                                        var keyJson   = Manager.GetObjectMapper().WriteValueAsString(key);
                                        var valueJson = value == null ? null : Manager.GetObjectMapper().WriteValueAsString(value);

                                        var insertValues = new ContentValues();
                                        insertValues.Put("view_id", enclosingView.Id);
                                        insertValues["sequence"] = thisSequence;
                                        insertValues["key"]      = keyJson;
                                        insertValues["value"]    = valueJson;

                                        enclosingView.Database.StorageEngine.Insert("maps", null, insertValues);
                                    }
                                    catch (Exception e)
                                    {
                                        Log.E(Database.Tag, "Error emitting", e);
                                    }
                                };

                                map(properties, emitBlock);
                            }
                        }
                        else
                        {
                            keepGoing = cursor.MoveToNext();
                        }
                    }

                    // Finally, record the last revision sequence number that was
                    // indexed:
                    var updateValues             = new ContentValues();
                    updateValues["lastSequence"] = dbMaxSequence;
                    var whereArgs_1 = new string[] { Id.ToString() };
                    Database.StorageEngine.Update("views", updateValues, "view_id=?", whereArgs_1);

                    // FIXME actually count number added :)
                    Log.V(Database.Tag, "...Finished re-indexing view {0} up to sequence {1} (deleted {2} added ?)", Name, Convert.ToString(dbMaxSequence), deleted);
                    result.SetCode(StatusCode.Ok);

                    return(true);
                });
            }
            catch (Exception e)
            {
                throw new CouchbaseLiteException(e, new Status(StatusCode.DbError));
            }
            finally
            {
                if (cursor2 != null)
                {
                    cursor2.Close();
                }

                if (cursor != null)
                {
                    cursor.Close();
                }

                if (!result.IsSuccessful)
                {
                    Log.W(Database.Tag, "Failed to rebuild view {0}:{1}", Name, result.GetCode());
                }
            }
        }
Ejemplo n.º 7
0
        public void UpdateIndex()
        {
            Log.V(Log.TagView, "Re-indexing view: %s", name);
            System.Diagnostics.Debug.Assert((mapBlock != null));
            if (GetViewId() <= 0)
            {
                string msg = string.Format("getViewId() < 0");
                throw new CouchbaseLiteException(msg, new Status(Status.NotFound));
            }
            database.BeginTransaction();
            Status result = new Status(Status.InternalServerError);
            Cursor cursor = null;

            try
            {
                long lastSequence  = GetLastSequenceIndexed();
                long dbMaxSequence = database.GetLastSequenceNumber();
                if (lastSequence == dbMaxSequence)
                {
                    // nothing to do (eg,  kCBLStatusNotModified)
                    Log.V(Log.TagView, "lastSequence (%s) == dbMaxSequence (%s), nothing to do", lastSequence
                          , dbMaxSequence);
                    result.SetCode(Status.NotModified);
                    return;
                }
                // First remove obsolete emitted results from the 'maps' table:
                long sequence = lastSequence;
                if (lastSequence < 0)
                {
                    string msg = string.Format("lastSequence < 0 (%s)", lastSequence);
                    throw new CouchbaseLiteException(msg, new Status(Status.InternalServerError));
                }
                if (lastSequence == 0)
                {
                    // If the lastSequence has been reset to 0, make sure to remove
                    // any leftover rows:
                    string[] whereArgs = new string[] { Sharpen.Extensions.ToString(GetViewId()) };
                    database.GetDatabase().Delete("maps", "view_id=?", whereArgs);
                }
                else
                {
                    // Delete all obsolete map results (ones from since-replaced
                    // revisions):
                    string[] args = new string[] { Sharpen.Extensions.ToString(GetViewId()), System.Convert.ToString
                                                       (lastSequence), System.Convert.ToString(lastSequence) };
                    database.GetDatabase().ExecSQL("DELETE FROM maps WHERE view_id=? AND sequence IN ("
                                                   + "SELECT parent FROM revs WHERE sequence>? " + "AND parent>0 AND parent<=?)",
                                                   args);
                }
                int deleted = 0;
                cursor = database.GetDatabase().RawQuery("SELECT changes()", null);
                cursor.MoveToNext();
                deleted = cursor.GetInt(0);
                cursor.Close();
                // This is the emit() block, which gets called from within the
                // user-defined map() block
                // that's called down below.
                AbstractTouchMapEmitBlock emitBlock = new _AbstractTouchMapEmitBlock_428(this);
                //Log.v(Log.TAG_VIEW, "    emit(" + keyJson + ", "
                //        + valueJson + ")");
                // find a better way to propagate this back
                // Now scan every revision added since the last time the view was
                // indexed:
                string[] selectArgs = new string[] { System.Convert.ToString(lastSequence) };
                cursor = database.GetDatabase().RawQuery("SELECT revs.doc_id, sequence, docid, revid, json, no_attachments FROM revs, docs "
                                                         + "WHERE sequence>? AND current!=0 AND deleted=0 " + "AND revs.doc_id = docs.doc_id "
                                                         + "ORDER BY revs.doc_id, revid DESC", selectArgs);
                long lastDocID = 0;
                bool keepGoing = cursor.MoveToNext();
                while (keepGoing)
                {
                    long docID = cursor.GetLong(0);
                    if (docID != lastDocID)
                    {
                        // Only look at the first-iterated revision of any document,
                        // because this is the
                        // one with the highest revid, hence the "winning" revision
                        // of a conflict.
                        lastDocID = docID;
                        // Reconstitute the document as a dictionary:
                        sequence = cursor.GetLong(1);
                        string docId = cursor.GetString(2);
                        if (docId.StartsWith("_design/"))
                        {
                            // design docs don't get indexed!
                            keepGoing = cursor.MoveToNext();
                            continue;
                        }
                        string revId         = cursor.GetString(3);
                        byte[] json          = cursor.GetBlob(4);
                        bool   noAttachments = cursor.GetInt(5) > 0;
                        while ((keepGoing = cursor.MoveToNext()) && cursor.GetLong(0) == docID)
                        {
                        }
                        // Skip rows with the same doc_id -- these are losing conflicts.
                        if (lastSequence > 0)
                        {
                            // Find conflicts with documents from previous indexings.
                            string[] selectArgs2 = new string[] { System.Convert.ToString(docID), System.Convert.ToString
                                                                      (lastSequence) };
                            Cursor cursor2 = database.GetDatabase().RawQuery("SELECT revid, sequence FROM revs "
                                                                             + "WHERE doc_id=? AND sequence<=? AND current!=0 AND deleted=0 " + "ORDER BY revID DESC "
                                                                             + "LIMIT 1", selectArgs2);
                            if (cursor2.MoveToNext())
                            {
                                string oldRevId = cursor2.GetString(0);
                                // This is the revision that used to be the 'winner'.
                                // Remove its emitted rows:
                                long     oldSequence = cursor2.GetLong(1);
                                string[] args        = new string[] { Sharpen.Extensions.ToString(GetViewId()), System.Convert.ToString
                                                                          (oldSequence) };
                                database.GetDatabase().ExecSQL("DELETE FROM maps WHERE view_id=? AND sequence=?",
                                                               args);
                                if (RevisionInternal.CBLCompareRevIDs(oldRevId, revId) > 0)
                                {
                                    // It still 'wins' the conflict, so it's the one that
                                    // should be mapped [again], not the current revision!
                                    revId    = oldRevId;
                                    sequence = oldSequence;
                                    string[] selectArgs3 = new string[] { System.Convert.ToString(sequence) };
                                    json = Utils.ByteArrayResultForQuery(database.GetDatabase(), "SELECT json FROM revs WHERE sequence=?"
                                                                         , selectArgs3);
                                }
                            }
                        }
                        // Get the document properties, to pass to the map function:
                        EnumSet <Database.TDContentOptions> contentOptions = EnumSet.NoneOf <Database.TDContentOptions
                                                                                             >();
                        if (noAttachments)
                        {
                            contentOptions.AddItem(Database.TDContentOptions.TDNoAttachments);
                        }
                        IDictionary <string, object> properties = database.DocumentPropertiesFromJSON(json
                                                                                                      , docId, revId, false, sequence, contentOptions);
                        if (properties != null)
                        {
                            // Call the user-defined map() to emit new key/value
                            // pairs from this revision:
                            emitBlock.SetSequence(sequence);
                            mapBlock.Map(properties, emitBlock);
                        }
                    }
                }
                // Finally, record the last revision sequence number that was
                // indexed:
                ContentValues updateValues = new ContentValues();
                updateValues.Put("lastSequence", dbMaxSequence);
                string[] whereArgs_1 = new string[] { Sharpen.Extensions.ToString(GetViewId()) };
                database.GetDatabase().Update("views", updateValues, "view_id=?", whereArgs_1);
                // FIXME actually count number added :)
                Log.V(Log.TagView, "Finished re-indexing view: %s " + " up to sequence %s" + " (deleted %s added ?)"
                      , name, dbMaxSequence, deleted);
                result.SetCode(Status.Ok);
            }
            catch (SQLException e)
            {
                throw new CouchbaseLiteException(e, new Status(Status.DbError));
            }
            finally
            {
                if (cursor != null)
                {
                    cursor.Close();
                }
                if (!result.IsSuccessful())
                {
                    Log.W(Log.TagView, "Failed to rebuild view %s.  Result code: %d", name, result.GetCode
                              ());
                }
                if (database != null)
                {
                    database.EndTransaction(result.IsSuccessful());
                }
            }
        }
Ejemplo n.º 8
0
        internal void UpdateIndex()
        {
            Log.V(Database.Tag, "Re-indexing view " + Name + " ...");
            System.Diagnostics.Debug.Assert((Map != null));

            if (Id < 0)
            {
                var msg = string.Format("View.Id < 0");
                throw new CouchbaseLiteException(msg, new Status(StatusCode.NotFound));
            }

            Database.BeginTransaction();

            var    result = new Status(StatusCode.InternalServerError);
            Cursor cursor = null;

            try
            {
                var lastSequence  = LastSequenceIndexed;
                var dbMaxSequence = Database.LastSequenceNumber;

                if (lastSequence == dbMaxSequence)
                {
                    // nothing to do (eg,  kCBLStatusNotModified)
                    var msg = String.Format("lastSequence ({0}) == dbMaxSequence ({1}), nothing to do", lastSequence, dbMaxSequence);
                    Log.D(Database.Tag, msg);
                    result.SetCode(StatusCode.Ok);
                    return;
                }

                // First remove obsolete emitted results from the 'maps' table:
                var sequence = lastSequence;
                if (lastSequence < 0)
                {
                    var msg = string.Format("lastSequence < 0 ({0})", lastSequence);
                    throw new CouchbaseLiteException(msg, new Status(StatusCode.InternalServerError));
                }
                if (lastSequence == 0)
                {
                    // If the lastSequence has been reset to 0, make sure to remove
                    // any leftover rows:
                    var whereArgs = new string[] { Sharpen.Extensions.ToString(Id) };
                    Database.StorageEngine.Delete("maps", "view_id=@", whereArgs);
                }
                else
                {
                    // Delete all obsolete map results (ones from since-replaced
                    // revisions):
                    var args = new [] {
                        Id.ToString(),
                        lastSequence.ToString(),
                        lastSequence.ToString()
                    };

                    Database.StorageEngine.ExecSQL(
                        "DELETE FROM maps WHERE view_id=@ AND sequence IN ("
                        + "SELECT parent FROM revs WHERE sequence>@ " + "AND parent>0 AND parent<=@)",
                        args);
                }
                var deleted = 0;
                cursor = Database.StorageEngine.RawQuery("SELECT changes()", null); // TODO: Convert to ADO params.
                cursor.MoveToNext();
                deleted = cursor.GetInt(0);
                cursor.Close();

                // find a better way to propagate this back
                // Now scan every revision added since the last time the view was
                // indexed:
                var selectArgs = new[] { Convert.ToString(lastSequence) };
                cursor = Database.StorageEngine.RawQuery("SELECT revs.doc_id, sequence, docid, revid, json FROM revs, docs "
                                                         + "WHERE sequence>@ AND current!=0 AND deleted=0 " + "AND revs.doc_id = docs.doc_id "
                                                         + "ORDER BY revs.doc_id, revid DESC", CommandBehavior.SequentialAccess, selectArgs);
                cursor.MoveToNext();

                var lastDocID = 0L;
                while (!cursor.IsAfterLast())
                {
                    long docID = cursor.GetLong(0);
                    if (docID != lastDocID)
                    {
                        // Only look at the first-iterated revision of any document,
                        // because this is the
                        // one with the highest revid, hence the "winning" revision
                        // of a conflict.
                        lastDocID = docID;
                        // Reconstitute the document as a dictionary:
                        sequence = cursor.GetLong(1);
                        string docId = cursor.GetString(2);
                        if (docId.StartsWith("_design/", StringComparison.InvariantCultureIgnoreCase))
                        {
                            // design docs don't get indexed!
                            cursor.MoveToNext();
                            continue;
                        }
                        var revId      = cursor.GetString(3);
                        var json       = cursor.GetBlob(4);
                        var properties = Database.DocumentPropertiesFromJSON(
                            json, docId, revId, false, sequence, EnumSet.NoneOf <TDContentOptions>()
                            );
                        if (properties != null)
                        {
                            // Call the user-defined map() to emit new key/value
                            // pairs from this revision:
                            Log.V(Database.Tag, "  call map for sequence=" + System.Convert.ToString(sequence
                                                                                                     ));
                            // This is the emit() block, which gets called from within the
                            // user-defined map() block
                            // that's called down below.

                            var enclosingView = this;
                            var thisSequence  = sequence;
                            var map           = Map;

                            if (map == null)
                            {
                                throw new CouchbaseLiteException("Map function is missing.");
                            }

                            EmitDelegate emitBlock = (key, value) =>
                            {
                                // TODO: Do we need to do any null checks on key or value?
                                try
                                {
                                    var keyJson   = Manager.GetObjectMapper().WriteValueAsString(key);
                                    var valueJson = value == null ? null : Manager.GetObjectMapper().WriteValueAsString(value);
                                    Log.V(Database.Tag, String.Format("    emit({0}, {1})", keyJson, valueJson));

                                    var insertValues = new ContentValues();
                                    insertValues.Put("view_id", enclosingView.Id);
                                    insertValues["sequence"] = thisSequence;
                                    insertValues["key"]      = keyJson;
                                    insertValues["value"]    = valueJson;

                                    enclosingView.Database.StorageEngine.Insert("maps", null, insertValues);
                                }
                                catch (Exception e)
                                {
                                    Log.E(Database.Tag, "Error emitting", e);
                                }
                            };

                            map(properties, emitBlock);
                        }
                    }
                    cursor.MoveToNext();
                }
                // Finally, record the last revision sequence number that was
                // indexed:
                ContentValues updateValues = new ContentValues();
                updateValues["lastSequence"] = dbMaxSequence;
                var whereArgs_1 = new string[] { Sharpen.Extensions.ToString(Id) };
                Database.StorageEngine.Update("views", updateValues, "view_id=@", whereArgs_1);
                // FIXME actually count number added :)
                Log.V(Database.Tag, "...Finished re-indexing view " + Name + " up to sequence " +
                      System.Convert.ToString(dbMaxSequence) + " (deleted " + deleted + " added " + "?" + ")");
                result.SetCode(StatusCode.Ok);
            }
            catch (SQLException e)
            {
                throw new CouchbaseLiteException(e, new Status(StatusCode.DbError));
            }
            finally
            {
                if (cursor != null)
                {
                    cursor.Close();
                }
                if (!result.IsSuccessful())
                {
                    Log.W(Database.Tag, "Failed to rebuild view " + Name + ": " + result.GetCode());
                }
                if (Database != null)
                {
                    Database.EndTransaction(result.IsSuccessful());
                }
            }
        }
Ejemplo n.º 9
0
        public void UpdateIndex()
        {
            Log.V(Database.Tag, "Re-indexing view " + name + " ...");
            System.Diagnostics.Debug.Assert((mapBlock != null));
            if (GetViewId() < 0)
            {
                string msg = string.Format("getViewId() < 0");
                throw new CouchbaseLiteException(msg, new Status(Status.NotFound));
            }
            database.BeginTransaction();
            Status result = new Status(Status.InternalServerError);
            Cursor cursor = null;

            try
            {
                long lastSequence  = GetLastSequenceIndexed();
                long dbMaxSequence = database.GetLastSequenceNumber();
                if (lastSequence == dbMaxSequence)
                {
                    // nothing to do (eg,  kCBLStatusNotModified)
                    string msg = string.Format("lastSequence (%d) == dbMaxSequence (%d), nothing to do"
                                               , lastSequence, dbMaxSequence);
                    Log.D(Database.Tag, msg);
                    result.SetCode(Status.Ok);
                    return;
                }
                // First remove obsolete emitted results from the 'maps' table:
                long sequence = lastSequence;
                if (lastSequence < 0)
                {
                    string msg = string.Format("lastSequence < 0 (%s)", lastSequence);
                    throw new CouchbaseLiteException(msg, new Status(Status.InternalServerError));
                }
                if (lastSequence == 0)
                {
                    // If the lastSequence has been reset to 0, make sure to remove
                    // any leftover rows:
                    string[] whereArgs = new string[] { Sharpen.Extensions.ToString(GetViewId()) };
                    database.GetDatabase().Delete("maps", "view_id=?", whereArgs);
                }
                else
                {
                    // Delete all obsolete map results (ones from since-replaced
                    // revisions):
                    string[] args = new string[] { Sharpen.Extensions.ToString(GetViewId()), System.Convert.ToString
                                                       (lastSequence), System.Convert.ToString(lastSequence) };
                    database.GetDatabase().ExecSQL("DELETE FROM maps WHERE view_id=? AND sequence IN ("
                                                   + "SELECT parent FROM revs WHERE sequence>? " + "AND parent>0 AND parent<=?)",
                                                   args);
                }
                int deleted = 0;
                cursor = database.GetDatabase().RawQuery("SELECT changes()", null);
                cursor.MoveToNext();
                deleted = cursor.GetInt(0);
                cursor.Close();
                // This is the emit() block, which gets called from within the
                // user-defined map() block
                // that's called down below.
                AbstractTouchMapEmitBlock emitBlock = new _AbstractTouchMapEmitBlock_446(this);
                // find a better way to propagate this back
                // Now scan every revision added since the last time the view was
                // indexed:
                string[] selectArgs = new string[] { System.Convert.ToString(lastSequence) };
                cursor = database.GetDatabase().RawQuery("SELECT revs.doc_id, sequence, docid, revid, json FROM revs, docs "
                                                         + "WHERE sequence>? AND current!=0 AND deleted=0 " + "AND revs.doc_id = docs.doc_id "
                                                         + "ORDER BY revs.doc_id, revid DESC", selectArgs);
                cursor.MoveToNext();
                long lastDocID = 0;
                while (!cursor.IsAfterLast())
                {
                    long docID = cursor.GetLong(0);
                    if (docID != lastDocID)
                    {
                        // Only look at the first-iterated revision of any document,
                        // because this is the
                        // one with the highest revid, hence the "winning" revision
                        // of a conflict.
                        lastDocID = docID;
                        // Reconstitute the document as a dictionary:
                        sequence = cursor.GetLong(1);
                        string docId = cursor.GetString(2);
                        if (docId.StartsWith("_design/"))
                        {
                            // design docs don't get indexed!
                            cursor.MoveToNext();
                            continue;
                        }
                        string revId = cursor.GetString(3);
                        byte[] json  = cursor.GetBlob(4);
                        IDictionary <string, object> properties = database.DocumentPropertiesFromJSON(json
                                                                                                      , docId, revId, false, sequence, EnumSet.NoneOf <Database.TDContentOptions>());
                        if (properties != null)
                        {
                            // Call the user-defined map() to emit new key/value
                            // pairs from this revision:
                            Log.V(Database.Tag, "  call map for sequence=" + System.Convert.ToString(sequence
                                                                                                     ));
                            emitBlock.SetSequence(sequence);
                            mapBlock.Map(properties, emitBlock);
                        }
                    }
                    cursor.MoveToNext();
                }
                // Finally, record the last revision sequence number that was
                // indexed:
                ContentValues updateValues = new ContentValues();
                updateValues.Put("lastSequence", dbMaxSequence);
                string[] whereArgs_1 = new string[] { Sharpen.Extensions.ToString(GetViewId()) };
                database.GetDatabase().Update("views", updateValues, "view_id=?", whereArgs_1);
                // FIXME actually count number added :)
                Log.V(Database.Tag, "...Finished re-indexing view " + name + " up to sequence " +
                      System.Convert.ToString(dbMaxSequence) + " (deleted " + deleted + " added " + "?"
                      + ")");
                result.SetCode(Status.Ok);
            }
            catch (SQLException e)
            {
                throw new CouchbaseLiteException(e, new Status(Status.DbError));
            }
            finally
            {
                if (cursor != null)
                {
                    cursor.Close();
                }
                if (!result.IsSuccessful())
                {
                    Log.W(Database.Tag, "Failed to rebuild view " + name + ": " + result.GetCode());
                }
                if (database != null)
                {
                    database.EndTransaction(result.IsSuccessful());
                }
            }
        }