示例#1
0
        internal Object FromJSON(IEnumerable <Byte> json)
        {
            if (json == null)
            {
                return(null);
            }
            object result = null;

            try
            {
                result = Manager.GetObjectMapper().ReadValue <Object>(json);
            }
            catch (Exception e)
            {
                Log.W(Database.Tag, "Exception parsing json", e);
            }
            return(result);
        }
示例#2
0
        public object FromJSON(byte[] json)
        {
            if (json == null)
            {
                return(null);
            }
            object result = null;

            try
            {
                result = Manager.GetObjectMapper().ReadValue <object>(json);
            }
            catch (Exception e)
            {
                Log.W(Database.Tag, "Exception parsing json", e);
            }
            return(result);
        }
示例#3
0
        public string ToJSONString(object @object)
        {
            if (@object == null)
            {
                return(null);
            }
            string result = null;

            try
            {
                result = Manager.GetObjectMapper().WriteValueAsString(@object);
            }
            catch (Exception e)
            {
                Log.W(Database.Tag, "Exception serializing object to json: " + @object, e);
            }
            return(result);
        }
示例#4
0
        /// <summary>
        /// Determines whether this instance is valid JSON.
        /// </summary>
        /// <returns><c>true</c> if this instance is valid JSON; otherwise, <c>false</c>.</returns>
        public bool IsValidJSON()
        {
            if (_jsonObject == null)
            {
                if (_json == null)
                {
                    Log.To.NoDomain.W(Tag, "Both _json and _jsonObject are null, returning false...");
                    return(false);
                }

                try {
                    _jsonObject = Manager.GetObjectMapper().ReadValue <object>(_json);
                } catch (Exception e) {
                    Log.To.NoDomain.W(Tag, "Exception during deserialization, returning false...", e);
                }
            }
            return(_jsonObject != null);
        }
示例#5
0
        public void TestAllDocuments()
        {
            var db = manager.GetExistingDatabase(DefaultTestDb);

            const int docsCount = 5;

            CreateDocuments(db, n: docsCount);

            // clear the cache so all documents/revisions will be re-fetched:
            db.DocumentCache.EvictAll();

            Console.WriteLine("----- all documents -----");

            var query = db.CreateAllDocumentsQuery();

            //query.prefetch = YES;

            Console.WriteLine("Getting all documents: " + query);

            var rows = query.Run();

            Assert.AreEqual(docsCount, rows.Count);

            var n = 0;

            foreach (var row in rows)
            {
                Console.WriteLine("    --> " + Manager.GetObjectMapper().WriteValueAsString(row.AsJSONDictionary()));

                var doc = row.Document;

                Assert.IsNotNull(doc, "Couldn't get doc from query");
                Assert.IsNotNull(doc.CurrentRevision.PropertiesAvailable, "QueryRow should have preloaded revision contents");

                Console.WriteLine("        Properties =" + Manager.GetObjectMapper().WriteValueAsString(doc.Properties));

                Assert.IsNotNull(doc.Properties, "Couldn't get doc properties");
                Assert.AreEqual("testDatabase", doc.GetProperty("testName"));

                n++;
            }

            Assert.AreEqual(n, docsCount);
        }
示例#6
0
        /// <summary>Indexing</summary>
        internal string ToJSONString(Object obj)
        {
            if (obj == null)
            {
                return(null);
            }

            String result = null;

            try
            {
                result = Manager.GetObjectMapper().WriteValueAsString(obj);
            }
            catch (Exception e)
            {
                Log.W(Database.Tag, "Exception serializing object to json: " + obj, e);
            }
            return(result);
        }
示例#7
0
        internal void SendAsyncRequest(HttpMethod method, Uri url, Object body, RemoteRequestCompletionBlock completionHandler)
        {
            var message = new HttpRequestMessage(method, url);
            var mapper  = Manager.GetObjectMapper();

            if (body != null)
            {
                var bytes       = mapper.WriteValueAsBytes(body).ToArray();
                var byteContent = new ByteArrayContent(bytes);
                message.Content = byteContent;
            }
            message.Headers.Add("Accept", new[] { "multipart/related", "application/json" });

            PreemptivelySetAuthCredentials(message);

            var client = clientFactory.GetHttpClient();

            client.CancelPendingRequests();
            client.SendAsync(message, HttpCompletionOption.ResponseHeadersRead, CancellationTokenSource.Token)
            .ContinueWith(response => {
                if (response.Status != TaskStatus.RanToCompletion)
                {
                    Log.E(Tag, "SendAsyncRequest did not run to completion.", response.Exception);
                    return(null);
                }
                return(response.Result);
            }, CancellationTokenSource.Token)
            .ContinueWith(response => {
                if (completionHandler != null)
                {
                    var fullBody = mapper.ReadValue <Object>(response.Result.Content.ReadAsStreamAsync().Result);

                    Exception error = response.Exception;
                    if (error == null && !response.Result.IsSuccessStatusCode)
                    {
                        error = new HttpResponseException(response.Result.StatusCode);
                    }

                    completionHandler(fullBody, response.Exception);
                }
            });
        }
示例#8
0
        /// <summary>
        /// Returns a serialized JSON byte enumerable object containing the properties
        /// of this object in human readable form.
        /// </summary>
        /// <returns>JSON bytes</returns>
        public IEnumerable <Byte> AsPrettyJson()
        {
            object properties = AsObject();

            if (properties != null)
            {
                ObjectWriter writer = Manager.GetObjectMapper().WriterWithDefaultPrettyPrinter();

                try {
                    _json = writer.WriteValueAsBytes(properties).ToArray();
                } catch (CouchbaseLiteException) {
                    Log.To.NoDomain.E(Tag, "Error writing body as pretty JSON, rethrowing...");
                } catch (Exception e) {
                    throw Misc.CreateExceptionAndLog(Log.To.NoDomain, e, Tag,
                                                     "Error writing body as pretty JSON");
                }
            }

            return(AsJson());
        }
示例#9
0
        private sqlite3_stmt BuildCommand(sqlite3 db, string sql, object[] paramArgs)
        {
            if (db == null)
            {
                throw new ArgumentNullException("db");
            }

            if (!IsOpen)
            {
                throw new CouchbaseLiteException("BuildCommand called on closed database", StatusCode.BadRequest);
            }

            sqlite3_stmt command = null;

            try {
                lock (Cursor.StmtDisposeLock) {
                    LastErrorCode = raw.sqlite3_prepare_v2(db, sql, out command);
                }

                if (LastErrorCode != raw.SQLITE_OK || command == null)
                {
                    Log.E(TAG, "sqlite3_prepare_v2: " + LastErrorCode);
                }

                if (paramArgs != null && paramArgs.Length > 0 && command != null && LastErrorCode != raw.SQLITE_ERROR)
                {
                    command.bind(paramArgs);
                }
            } catch (CouchbaseLiteException) {
                Log.E(TAG, "Error when building sql '{0}' with params {1}", sql, Manager.GetObjectMapper().WriteValueAsString(paramArgs));
                throw;
            } catch (Exception e) {
                throw new CouchbaseLiteException(String.Format("Error when building sql '{0}' with params {1}", sql,
                                                               Manager.GetObjectMapper().WriteValueAsString(paramArgs)), e);
            }

            return(command);
        }
示例#10
0
        protected void AddDocToSyncGateway(string docId, IDictionary <string, object> properties,
                                           string attachmentName, string attachmentContentType)
        {
            if (!StringEx.IsNullOrWhiteSpace(attachmentName))
            {
                var attachmentStream = (InputStream)GetAsset(attachmentName);
                var memStream        = new MemoryStream();
                attachmentStream.Wrapped.CopyTo(memStream);
                var attachmentBase64 = Convert.ToBase64String(memStream.ToArray());

                var attachment = new Dictionary <string, object>();
                attachment["content_type"] = attachmentContentType;
                attachment["data"]         = attachmentBase64;

                var attachments = new Dictionary <string, object>();
                attachments[attachmentName] = attachment;

                properties["_attachments"] = attachments;
            }

            var docJson = Manager.GetObjectMapper().WriteValueAsString(properties);

            PushDocumentToSyncGateway(docId, docJson);
        }
示例#11
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());
                }
            }
        }
示例#12
0
        protected void RunTest(string name, Test test)
        {
            var enabled = (Boolean)_config["enabled"];

            if (!enabled)
            {
                PrintMessage(name, "Performance tests are not enabled. " +
                             "Enabled performance tests on performance-test.json.");
                return;
            }

            JObject config = (JObject)_config[name];

            if (config == null)
            {
                PrintMessage(name, "No configuration of the test found.");
                return;
            }

            enabled = (Boolean)config["enabled"];
            if (!enabled)
            {
                PrintMessage(name, "Test is not enabled. " +
                             "Enabled the test on performance-test.json.");
                return;
            }

            var numDocs           = (JArray)config["numbers_of_documents"];
            var docSizes          = (JArray)config["sizes_of_document"];
            var kpis              = (JArray)config["kpi"];
            var baselines         = (JArray)config["baseline"];
            var needsPerDocResult = true;

            if (config["kpi_is_total"] != null && !(Boolean)config["kpi_is_total"])
            {
                needsPerDocResult = false;
            }
            var repeatCount = (Int32)config["repeat_count"];

            double[,] finalResults  = new double[numDocs.Count, docSizes.Count];
            double[,] baselineDelta = new double[numDocs.Count, docSizes.Count];

            var testCount = 0;
            var failCount = 0;

            for (var i = 0; i < numDocs.Count; i++)
            {
                for (var j = 0; j < docSizes.Count; j++)
                {
                    testCount++;
                    var numDoc  = (Int32)numDocs[i];
                    var docSize = (Int32)docSizes[j];
                    var kpi     = (double)((JArray)kpis[i])[j];
                    if (kpi < 0 || numDoc < 0 || docSize < 0)
                    {
                        finalResults[i, j]  = kpi;
                        baselineDelta[i, j] = -1.0;
                        PrintMessage(name, String.Format(
                                         "skip: #test {0}, #docs {1}, size {2}B",
                                         testCount, numDoc, docSize));
                        continue;
                    }

                    double[] results = new double[repeatCount];
                    for (var k = 0; k < repeatCount; k++)
                    {
                        base.TearDown();
                        Thread.Sleep(200);
                        base.SetUp();
                        //Thread.Sleep(2000);

                        // Execute test
                        var parameters = new Dictionary <string, object>()
                        {
                            { NUMDOCS_KEY, numDoc },
                            { DOCSIZE_KEY, docSize }
                        };
                        var time = test(parameters);
                        results[k] = time;
                    }

                    var min    = results.Min <double>();
                    var result = needsPerDocResult ? (min / numDoc) : min;
                    finalResults[i, j] = result;

                    var baseline          = (double)((JArray)baselines[i])[j];
                    var deltaFromBaseline = (result - baseline) / baseline * 100;
                    baselineDelta[i, j] = deltaFromBaseline;

                    Boolean pass = result <= kpi && deltaFromBaseline <= 20;
                    if (!pass)
                    {
                        failCount++;
                    }

                    var message = String.Format(
                        "stats: #test {0}, pass {1}, #docs {2}, size {3}B, " +
                        "avg {4:F2}, max {5:F2}, min {6:F2}, " +
                        "result {7:F2}, kpi {8:F2}, " +
                        "baseline {9:F2}, diffBaseLine {10:F2}%, " +
                        "allResult {11}",
                        testCount, pass, numDoc, docSize,
                        results.Average(), results.Max(), results.Min(),
                        result, kpi, baseline, deltaFromBaseline,
                        Manager.GetObjectMapper().WriteValueAsString(results));
                    PrintMessage(name, message);
                }
            }

            // Print Summary
            PrintMessage(name, "Result:");
            PrintMessage(name, String.Format(
                             "summary: pass {0}, #test {1}, #fail {2}",
                             (failCount == 0), testCount, failCount));

            // Print Result Table
            var header = new StringBuilder("#docs,");

            for (var i = 0; i < docSizes.Count; i++)
            {
                if (i > 0)
                {
                    header.Append(",");
                }
                header.Append(docSizes[i]);
            }
            PrintMessage(Tag, header.ToString());
            for (var i = 0; i < numDocs.Count; i++)
            {
                var sb = new StringBuilder(String.Format("{0}", numDocs[i]));
                for (var j = 0; j < finalResults.GetLength(1); j++)
                {
                    sb.Append(",");
                    sb.Append(String.Format("{0:F2}", finalResults[i, j]));
                }
                PrintMessage(Tag, sb.ToString());
            }

            // Print delta from baselines
            PrintMessage(name, "Percentage of Deviation from baselines:");
            PrintMessage(Tag, header.ToString());
            for (var i = 0; i < numDocs.Count; i++)
            {
                var sb = new StringBuilder(String.Format("{0}", numDocs[i]));
                for (var j = 0; j < baselineDelta.GetLength(1); j++)
                {
                    sb.Append(",");
                    sb.Append(String.Format("{0:F2}", baselineDelta[i, j]));
                }
                PrintMessage(Tag, sb.ToString());
            }

            Assert.IsTrue(failCount == 0);
        }
示例#13
0
        internal void SendAsyncMultipartDownloaderRequest(HttpMethod method, string relativePath, object body, Database db, RemoteRequestCompletionBlock onCompletion)
        {
            try
            {
                var urlStr = BuildRelativeURLString(relativePath);
                var url    = new Uri(urlStr);

                var message = new HttpRequestMessage(method, url);
                message.Headers.Add("Accept", "*/*");
                AddRequestHeaders(message);

                var httpClient = clientFactory.GetHttpClient();
                httpClient.SendAsync(message, HttpCompletionOption.ResponseHeadersRead, CancellationTokenSource.Token)
                .ContinueWith(new Action <Task <HttpResponseMessage> >(responseMessage => {
                    object fullBody = null;
                    Exception error = null;
                    try
                    {
                        var response = responseMessage.Result;
                        // add in cookies to global store
                        CouchbaseLiteHttpClientFactory.Instance.AddCookies(clientFactory.HttpHandler.CookieContainer.GetCookies(url));

                        var status = response.StatusCode;
                        if ((Int32)status.GetStatusCode() >= 300)
                        {
                            Log.E(Database.Tag, "Got error " + Sharpen.Extensions.ToString(status.GetStatusCode
                                                                                               ()));
                            Log.E(Database.Tag, "Request was for: " + message);
                            Log.E(Database.Tag, "Status reason: " + response.ReasonPhrase);
                            error = new HttpException((Int32)status.GetStatusCode(), response.ReasonPhrase);
                        }
                        else
                        {
                            var entity              = response.Content;
                            var contentTypeHeader   = response.Content.Headers.ContentType;
                            InputStream inputStream = null;
                            if (contentTypeHeader != null && contentTypeHeader.ToString().Contains("multipart/related"))
                            {
                                try
                                {
                                    var reader = new MultipartDocumentReader(responseMessage.Result, LocalDatabase);
                                    reader.SetContentType(contentTypeHeader.MediaType);

                                    var inputStreamTask = entity.ReadAsStreamAsync();
                                    inputStreamTask.Wait(90000, CancellationTokenSource.Token);

                                    const int bufLen = 1024;
                                    var buffer       = new byte[bufLen];

                                    int numBytesRead = 0;
                                    while ((numBytesRead = inputStream.Read(buffer)) != -1)
                                    {
                                        if (numBytesRead != bufLen)
                                        {
                                            var bufferToAppend = new ArraySegment <Byte>(buffer, 0, numBytesRead).Array;
                                            reader.AppendData(bufferToAppend);
                                        }
                                        else
                                        {
                                            reader.AppendData(buffer);
                                        }
                                    }

                                    reader.Finish();
                                    fullBody = reader.GetDocumentProperties();

                                    if (onCompletion != null)
                                    {
                                        onCompletion(fullBody, error);
                                    }
                                }
                                finally
                                {
                                    try
                                    {
                                        inputStream.Close();
                                    }
                                    catch (IOException)
                                    {
                                        // NOTE: swallow?
                                    }
                                }
                            }
                            else
                            {
                                if (entity != null)
                                {
                                    try
                                    {
                                        var readTask = entity.ReadAsStreamAsync();
                                        readTask.Wait(); // TODO: This should be scaled based on content length.
                                        inputStream = readTask.Result;
                                        fullBody    = Manager.GetObjectMapper().ReadValue <Object>(inputStream);
                                        if (onCompletion != null)
                                        {
                                            onCompletion(fullBody, error);
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        Log.E(Tag, ex.Message);
                                    }
                                    finally
                                    {
                                        try
                                        {
                                            inputStream.Close();
                                        }
                                        catch (IOException)
                                        {
                                        }
                                    }
                                }
                            }
                        }
                    }
                    catch (ProtocolViolationException e)
                    {
                        Log.E(Database.Tag, "client protocol exception", e);
                        error = e;
                    }
                    catch (IOException e)
                    {
                        Log.E(Database.Tag, "io exception", e);
                        error = e;
                    }
                }));
            }
            catch (UriFormatException e)
            {
                Log.E(Database.Tag, "Malformed URL for async request", e);
            }
        }
示例#14
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());
                }
            }
        }
 internal static IDictionary <TKey, TValue> AsDictionary <TKey, TValue>(this object attachmentProps)
 {
     return(Manager.GetObjectMapper().ConvertToDictionary <TKey, TValue>(attachmentProps));
 }
 internal static IList <TValue> AsList <TValue>(this object value)
 {
     return(Manager.GetObjectMapper().ConvertToList <TValue>(value));
 }
示例#17
0
        public void TestRemoteConflictResolution()
        {
            // Create a document with two conflicting edits.
            var doc   = database.CreateDocument();
            var rev1  = doc.CreateRevision().Save();
            var rev2a = CreateRevisionWithRandomProps(rev1, false);
            var rev2b = CreateRevisionWithRandomProps(rev1, true);

            // make sure we can query the db to get the conflict
            var allDocsQuery = database.CreateAllDocumentsQuery();

            allDocsQuery.AllDocsMode = allDocsQuery.AllDocsMode = AllDocsMode.OnlyConflicts;

            var rows = allDocsQuery.Run();

            Assert.AreEqual(1, rows.Count);
            Assert.IsTrue(rows.Aggregate(false, (found, row) => found |= row.Document.Id.Equals(doc.Id)));

            // Push the conflicts to the remote DB.
            var pusher = database.CreatePushReplication(GetReplicationURL());

            RunReplication(pusher);
            Assert.IsNull(pusher.LastError);

            var rev3aBody = new JObject();

            rev3aBody.Put("_id", doc.Id);
            rev3aBody.Put("_rev", rev2a.Id);

            // Then, delete rev 2b.
            var rev3bBody = new JObject();

            rev3bBody.Put("_id", doc.Id);
            rev3bBody.Put("_rev", rev2b.Id);
            rev3bBody.Put("_deleted", true);

            // Combine into one _bulk_docs request.
            var requestBody = new JObject();
            var docs        = new JArray {
                rev3aBody, rev3bBody
            };

            requestBody.Put("docs", docs);

            // Make the _bulk_docs request.
            var client      = new HttpClient();
            var bulkDocsUrl = GetReplicationURL() + "/_bulk_docs";
            var request     = new HttpRequestMessage(HttpMethod.Post, bulkDocsUrl);

            //request.Headers.Add("Accept", "*/*");
            request.Content = new StringContent(requestBody.ToString(), Encoding.UTF8, "application/json");

            var response = client.SendAsync(request).Result;

            // Check the response to make sure everything worked as it should.
            Assert.AreEqual(HttpStatusCode.Created, response.StatusCode);

            var rawResponse = response.Content.ReadAsStringAsync().Result;
            var resultArray = Manager.GetObjectMapper().ReadValue <JArray>(rawResponse);

            Assert.AreEqual(2, resultArray.Count);

            foreach (var value in resultArray.Values <JObject>())
            {
                var err = (string)value["error"];
                Assert.IsNull(err);
            }

            WorkaroundSyncGatewayRaceCondition();

            // Pull the remote changes.
            var puller = database.CreatePullReplication(GetReplicationURL());

            RunReplication(puller);
            Assert.IsNull(puller.LastError);

            // Make sure the conflict was resolved locally.
            Assert.AreEqual(1, doc.ConflictingRevisions.Count());
        }