Description
Branch: release/lithium (https://github.com/couchbase/couchbase-lite-C/tree/release/lithium)
Scenarios:
1. Open a database (either new or existing database)
2. Create a mutable document with id = "foo" and add one property with key = "greeting" and value = "Hello".
3. Save the document.
4. Reopen the database.
5. Get the mutable document with id = "foo" and update the property key = "greeting" with value = "Hey".
6. Save the document.
Test Code:
TEST_CASE_METHOD(DatabaseTest, "Open Database and Save Document Twice") { |
CBLError error;
|
CBLDocument* doc = CBLDocument_CreateWithID("foo"_sl); |
FLMutableDict props = CBLDocument_MutableProperties(doc);
|
FLMutableDict_SetString(props, FLSTR("greeting"), FLSTR("Hello")); |
CHECK(CBLDatabase_SaveDocument(db, doc, NULL));
|
CBLDocument_Release(doc);
|
|
// Open database and modify the same field again: |
CBLDatabase_Release(db);
|
db = CBLDatabase_Open(kDatabaseName, &kDatabaseConfiguration, &error);
|
doc = CBLDatabase_GetMutableDocument(db, FLSTR("foo"), NULL); |
props = CBLDocument_MutableProperties(doc);
|
FLMutableDict_SetString(props, FLSTR("greeting"), FLSTR("Hey")); |
CHECK(CBLDatabase_SaveDocument(db, doc, NULL));
|
CBLDocument_Release(doc);
|
}
|
Result:
An exception thrown in Step 6 as :
FAILED PRECONDITION: `index<_items.size()` not true when calling fleece::impl::ValueSlot &fleece::impl::internal::HeapArray::setting(uint32_t) (at HeapArray.cc line 123) |
{}Backtrace:
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1 |
* frame #0: 0x00000001b3983b7c libc++abi.dylib`__cxa_throw |
frame #1: 0x0000000107f46c8c libcblite.dylib`fleece::_precondition_failed(cond="index<_items.size()", fn="fleece::impl::ValueSlot &fleece::impl::internal::HeapArray::setting(uint32_t)", file="HeapArray.cc", line=123) at betterassert.cc:63:9 |
frame #2: 0x0000000107b0571c libcblite.dylib`fleece::impl::internal::HeapArray::setting(this=0x000000010aa89b90, index=2) at HeapArray.cc:123:9 |
frame #3: 0x0000000107ab5344 libcblite.dylib`void fleece::impl::internal::HeapArray::set<fleece::slice>(this=0x000000010aa89b90, index=2, t=slice @ 0x0000000104eac3a0) at HeapArray.hh:55:54 |
frame #4: 0x0000000107ab4cf4 libcblite.dylib`fleece::impl::internal::HeapDict::kvArray(this=0x000000010600f4c0) at HeapDict.cc:207:28 |
frame #5: 0x0000000107aaae20 libcblite.dylib`fleece::impl::Array::impl::impl(this=0x0000000105f4ee60, v=0x000000010600f4cd) at Array.cc:57:48 |
frame #6: 0x0000000107aab72c libcblite.dylib`fleece::impl::Array::impl::impl(this=0x0000000105f4ee60, v=0x000000010600f4cd) at Array.cc:29:48 |
frame #7: 0x0000000107bbe13c libcblite.dylib`fleece::impl::DictIterator::DictIterator(this=0x0000000105f4ee60, d=0x000000010600f4cd, sk=0x0000000000000000) at Dict.cc:408:6 |
frame #8: 0x0000000107bbe3f4 libcblite.dylib`fleece::impl::DictIterator::DictIterator(this=0x0000000105f4ee60, d=0x000000010600f4cd, sk=0x0000000000000000) at Dict.cc:409:5 |
frame #9: 0x0000000107c2c148 libcblite.dylib`fleece::impl::DeepIterator::iterateContainer(this=0x000000010600f400, container=0x000000010600f4cd) at DeepIterator.cc:92:32 |
frame #10: 0x0000000107c2ae78 libcblite.dylib`fleece::impl::DeepIterator::next(this=0x000000010600f400) at DeepIterator.cc:33:13 |
frame #11: 0x0000000107b244c8 libcblite.dylib`::FLDeepIterator_Next(i=0x000000010600f400) at Fleece.cc:510:8 |
frame #12: 0x0000000106830100 libcblite.dylib`fleece::DeepIterator::next(this=0x0000000105074660) at Fleece.hh:306:65 |
frame #13: 0x000000010682a584 libcblite.dylib`fleece::DeepIterator::operator++(this=0x0000000105074660) at Fleece.hh:309:58 |
frame #14: 0x000000010631ca2c libcblite.dylib`CBLDocument::saveBlobsAndCheckEncryptables(this=0x000000010ac0dd80, db=0x0000000110c04d80, releaseNewBlob=false) const at CBLDocument.cc:353:43 |
frame #15: 0x000000010631ba50 libcblite.dylib`CBLDocument::encodeBody(this=0x000000010ac0dd80, db=0x0000000110c04d80, c4db=0x000000010ad05080, releaseNewBlob=false, outRevFlags=0x00000001050fa880) const at CBLDocument.cc:184:21 |
frame #16: 0x000000010632a5f0 libcblite.dylib`CBLDocument::save(this=0x0000000104f9a820, c4db=0x000000010ad05080)::$_0::operator()(C4Database*) const at CBLDocument.cc:105:24 |
frame #17: 0x0000000106329b44 libcblite.dylib`void litecore::access_lock<fleece::Retained<C4Database>, std::__1::recursive_mutex>::useLocked<CBLDocument::save(this=0x0000000110c04d98, callback=(anonymous class) @ 0x0000000104f9a820)::$_0>(CBLDocument::save(CBLDatabase*, CBLDocument::SaveOptions const&)::$_0) at access_lock.hh:160:13 |
frame #18: 0x000000010631b754 libcblite.dylib`void CBLDatabase::useLocked<CBLDocument::save(CBLDatabase*, CBLDocument::SaveOptions const&)::$_0>(this=0x0000000110c04d80, callback=(anonymous class) @ 0x00000001050740d0)::$_0) at CBLDatabase_Internal.hh:284:47 |
frame #19: 0x000000010631ae08 libcblite.dylib`CBLDocument::save(this=0x000000010ac0dd80, db=0x0000000110c04d80, opt=0x0000000104ea8020) at CBLDocument.cc:77:13 |
frame #20: 0x00000001062c4c68 libcblite.dylib`::CBLDatabase_SaveDocumentWithConcurrencyControl(db=0x0000000110c04d80, doc=0x000000010ac0dd80, concurrency=kCBLConcurrencyControlLastWriteWins, outError=0x0000000000000000) at CBLDatabase_CAPI.cc:194:18 |
frame #21: 0x00000001062c4abc libcblite.dylib`::CBLDatabase_SaveDocument(db=0x0000000110c04d80, doc=0x000000010ac0dd80, outError=0x0000000000000000) at CBLDatabase_CAPI.cc:183:12 |
frame #22: 0x00000001004455d8 CBL_Tests`(anonymous namespace)::____C_A_T_C_H____T_E_S_T____34::test(this=0x0000000104d36d60) at DatabaseTest.cc:505:5 |
frame #23: 0x000000010050698c CBL_Tests`Catch::TestInvokerAsMethod<(anonymous namespace)::____C_A_T_C_H____T_E_S_T____34>::invoke(this=0x000000010a8462d0) const at catch.hpp:965:9 |
frame #24: 0x000000010005b208 CBL_Tests`Catch::TestCase::invoke(this=0x0000000111219d40) const at catch.hpp:14101:15 |
frame #25: 0x000000010005af7c CBL_Tests`Catch::RunContext::invokeActiveTestCase(this=0x00000001050dec50) at catch.hpp:12960:27 |
frame #26: 0x0000000100051bc0 CBL_Tests`Catch::RunContext::runCurrentTest(this=0x00000001050dec50, redirectedCout="", redirectedCerr="") at catch.hpp:12933:17 |
frame #27: 0x000000010004f3e4 CBL_Tests`Catch::RunContext::runTest(this=0x00000001050dec50, testCase=0x0000000111219d40) at catch.hpp:12694:13 |
frame #28: 0x000000010006731c CBL_Tests`Catch::(anonymous namespace)::TestGroup::execute(this=0x00000001050dec40) at catch.hpp:13288:45 |
frame #29: 0x00000001000649cc CBL_Tests`Catch::Session::runInternal(this=0x0000000104ffc020) at catch.hpp:13494:39 |
frame #30: 0x00000001000641b8 CBL_Tests`Catch::Session::run(this=0x0000000104ffc020) at catch.hpp:13450:24 |
frame #31: 0x00000001000d10dc CBL_Tests`int Catch::Session::run<char>(this=0x0000000104ffc020, argc=5, argv=0x000000016fdff260) at catch.hpp:13172:30 |
frame #32: 0x00000001000d0de0 CBL_Tests`main(argc=5, argv=0x000000016fdff260) at catch.hpp:17445:29 |
frame #33: 0x00000001010710f4 dyld`start + 520 |
For some reason the DeepIterator couldn't read the updated FLMutableDict properly. The same problem doesn't occur if not re-opening the database.