Skip to content

Commit

Permalink
Error convergence changes:
Browse files Browse the repository at this point in the history
Save(document, ConcurrencyMode) and Delete(document, ConcurrencyMode) return bool now (false for conflict when failonconflict is indicated, true otherwise)
GetIndexes will throw unexpected error when index data is unreadable
When replication / live queries are still active through CouchbaseLiteException (busy) instead of InvalidOperationException
  • Loading branch information
borrrden committed Mar 10, 2018
1 parent c53506a commit 909022e
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 16 deletions.
32 changes: 21 additions & 11 deletions src/Couchbase.Lite.Shared/API/Database/Database.cs
Original file line number Diff line number Diff line change
Expand Up @@ -557,11 +557,12 @@ public void Delete()
/// <param name="concurrencyControl">The rule to use when encountering a conflict in the database</param>
/// <exception cref="InvalidOperationException">Thrown when trying to save a document into a database
/// other than the one it was previously added to</exception>
/// <returns><c>true</c> if the delete succeeded, <c>false</c> if there was a conflict</returns>
[ContractAnnotation("document:null => halt")]
public void Delete(Document document, ConcurrencyControl concurrencyControl)
public bool Delete(Document document, ConcurrencyControl concurrencyControl)
{
var doc = CBDebug.MustNotBeNull(Log.To.Database, Tag, nameof(document), document);
Save(doc, concurrencyControl, true);
return Save(doc, concurrencyControl, true);
}

/// <summary>
Expand Down Expand Up @@ -615,7 +616,7 @@ public IList<string> GetIndexes()
var val = NativeRaw.FLValue_FromTrustedData(new FLSlice(result.buf, result.size));
if (val == null) {
Native.c4slice_free(result);
throw new CouchbaseLiteException(C4ErrorCode.CorruptIndexData);
throw new CouchbaseLiteException(C4ErrorCode.UnexpectedError);
}

retVal = FLValueConverter.ToCouchbaseObject(val, this, true, typeof(string));
Expand Down Expand Up @@ -726,11 +727,12 @@ public void RemoveChangeListener(ListenerToken token)
/// <param name="concurrencyControl">The rule to use when encountering a conflict in the database</param>
/// <exception cref="InvalidOperationException">Thrown when trying to save a document into a database
/// other than the one it was previously added to</exception>
/// <returns><c>true</c> if the save succeeded, <c>false</c> if there was a conflict</returns>
[ContractAnnotation("document:null => halt")]
public void Save(MutableDocument document, ConcurrencyControl concurrencyControl)
public bool Save(MutableDocument document, ConcurrencyControl concurrencyControl)
{
var doc = CBDebug.MustNotBeNull(Log.To.Database, Tag, nameof(document), document);
Save(doc, concurrencyControl, false);
return Save(doc, concurrencyControl, false);
}

#if CBL_LINQ
Expand Down Expand Up @@ -1030,12 +1032,13 @@ private Document ResolveConflict([NotNull]Document localDoc, [NotNull]Document r
return String.CompareOrdinal(localDoc.RevID, remoteDoc.RevID) > 0 ? localDoc : remoteDoc;
}

private void Save([NotNull]Document document, ConcurrencyControl concurrencyControl, bool deletion)
private bool Save([NotNull]Document document, ConcurrencyControl concurrencyControl, bool deletion)
{
if (deletion && document.RevID == null) {
throw new CouchbaseLiteException(C4ErrorCode.InvalidParameter, "Cannot delete a document that has not yet been saved");
}

var success = true;
ThreadSafety.DoLocked(() =>
{
CheckOpen();
Expand All @@ -1049,13 +1052,16 @@ private void Save([NotNull]Document document, ConcurrencyControl concurrencyCont
if (newDoc == null) {
// Handle conflict:
if (concurrencyControl == ConcurrencyControl.FailOnConflict) {
throw new CouchbaseLiteException(C4ErrorCode.Conflict);
success = false;
committed = true; // Weird, but if the next call fails I don't want to call it again in the catch block
LiteCoreBridge.Check(e => Native.c4db_endTransaction(_c4db, true, e));
return;
}

C4Error err;
curDoc = Native.c4doc_get(_c4db, document.Id, true, &err);

// If deletion and the current oc has already been deleted
// If deletion and the current doc has already been deleted
// or doesn't exist:
if (deletion) {
if (curDoc == null) {
Expand Down Expand Up @@ -1094,6 +1100,8 @@ private void Save([NotNull]Document document, ConcurrencyControl concurrencyCont
Native.c4doc_free(newDoc);
}
});

return success;
}

private void Save([NotNull]Document doc, C4Document** outDoc, C4Document* baseDoc, bool deletion)
Expand Down Expand Up @@ -1200,13 +1208,15 @@ private void SaveResolvedDocument([NotNull]Document resolved, [NotNull]Document
private void ThrowIfActiveItems()
{
if (ActiveReplications.Any()) {
throw new InvalidOperationException(
var c4err = Native.c4error_make(C4ErrorDomain.LiteCoreDomain, (int) C4ErrorCode.Busy,
"Cannot close the database. Please stop all of the replicators before closing the database.");
throw new CouchbaseLiteException(c4err);
}

if (ActiveLiveQueries.Any()) {
throw new InvalidOperationException(
"Cannot close the database. Please remove all of the query listeners before closing the database");
var c4err = Native.c4error_make(C4ErrorDomain.LiteCoreDomain, (int) C4ErrorCode.Busy,
"Cannot close the database. Please remove all of the query listeners before closing the database.");
throw new CouchbaseLiteException(c4err);
}
}

Expand Down
6 changes: 2 additions & 4 deletions src/Couchbase.Lite.Tests.Shared/DatabaseTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -289,10 +289,8 @@ public void TestSaveConcurrencyControl()
doc1a.SetString("name", "Jim");
Db.Save(doc1a);
doc1b.SetString("name", "Tim");
Db.Invoking(db => db.Save(doc1b, ConcurrencyControl.FailOnConflict))
.ShouldThrow<CouchbaseLiteException>().Where(x =>
x.Domain == CouchbaseLiteErrorType.CouchbaseLite &&
x.Error == CouchbaseLiteError.Conflict);
Db.Save(doc1b, ConcurrencyControl.FailOnConflict).Should()
.BeFalse("beacuse a conflict should not be allowed in this mode");
using (var gotDoc = Db.GetDocument(doc1a.Id)) {
gotDoc.GetString("name").Should().Be("Jim");
}
Expand Down

0 comments on commit 909022e

Please sign in to comment.